How to Implement and Wire a New Module in `operations`
This guide shows the minimal steps to add a new module in a component repository, following the patterns used by existing modules (e.g. itemModule, businessAffiliateModule).
Implement Module.kt¶
- Create a
Module.ktunder a new package (example:operations/src/main/kotlin/cards/arda/operations/<area>/<module>/Module.kt). - Add a module entrypoint function shaped like other modules:
- It is a Ktor extension on
Application. - It accepts
ComponentConfiguration,EndpointLocator.Rest,ModuleConfig, andAuthentication. - It optionally accepts injected Universe(s) and/or a Service for tests.
- It returns the Service instance used by the module.
- It is a Ktor extension on
Example skeleton:
fun Application.myModule(
inComponent: ComponentConfiguration,
locator: EndpointLocator.Rest,
cfg: ModuleConfig,
authentication: Authentication,
injectedUniverse: MyUniverse? = null,
injectedService: MyService? = null,
): MyService {
val dsCfg = cfg.dataSource ?: throw AppError.ArgumentValidation(
"cfg.dataSource",
"DataSource is required for My Module"
)
val db: Database = DataSource(dsCfg.db, dsCfg.pool).newDb(dsCfg.flywayConfig)
val service = injectedService ?: MyService.Impl(injectedUniverse ?: MyUniverse(), db)
val endpoint = MyEndpoint.Impl(cfg, locator, service)
MultiEndpointKtorModule(inComponent, cfg, authentication, listOf(endpoint))
.configureServer(this)
return service
}
Wire the module in runtime/Main.kt¶
- In your module
Module.kt, add a thin wiring function that:- Is a Ktor extension on
Application(example:fun Application.<moduleName>(cfgProvider: ConfigurationProvider, authentication: Authentication, ...): <Service>). - Reads the
ModuleConfigfromcfgProvider.moduleConfiguration("<module-config-key>"). - Creates an
EndpointLocator.RestwithcfgProvider.component.baseUrl,cfg.version,cfg.name, and the moduleresource. - Calls your module entry point (
Application.myModule(...)) and returns the service.
- Is a Ktor extension on
- In
cards.arda.operations.runtime.Main.kt, keep only generic application bootstrap:- Create
Authenticationonce fromcfgProvider.globalAuthConfiguration. - Install component-wide features (OpenAPI, auth realms, etc.).
- Call the module wiring functions so each module stays responsible for its own configuration key and route locator setup.
- Create
Notes¶
- Prefer the
injected*parameters inModule.ktfor unit tests to avoid requiring external dependencies. - If the module needs a DB, use
DataSource(...).newDb(...)with the modulecfg.dataSourceand Flyway configuration, like other modules. - For unit tests that rely on a configuration, currently the required values that are provided by the ci/cd environment need to be set in the
build.gradle.ktsdefinition. See theoperationsrepobuild.gradle.ktsfor examples.
Copyright: © Arda Systems 2025-2026, All rights reserved