ADR-0002. One deployable, split into api and worker roles at runtime
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-03-30 |
| Deciders | ledger-team |
| Supersedes | — |
Context
- The REST surface (enqueue, lifecycle, download) and the heavy generation pipeline have very different resource and scaling profiles.
- Bundling everything into every replica wastes CPU on API pods and couples ingress to render capacity.
- Splitting into two separate packages would duplicate schemas, DI wiring, and deployment plumbing.
Decision
We will ship a single image and select behavior at boot with APP_ENV_APPLICATION_ROLES (CSV of api, worker; invalid/empty falls back to both). configureControllers() registers controllers only for api; configureServices()/configureComponents() register the worker pipeline (LedgerWorkerService, generators), the WebSocket emitter, and the recovery sweep only for worker. The Kafka consumer and recovery components are registered unconditionally but self-skip when the worker role is absent.
Consequences
| Pros | Cons |
|---|---|
| Scale API and worker independently | Role gating spread across application.ts + components |
| One image, one CI artifact, shared schema/DI | A misconfigured APP_ENV_APPLICATION_ROLES silently falls back to both |
worker-only pods need no ingress | Must verify role in two places (registration + component self-skip) |
Alternatives Considered
| Option | Pros | Cons | Why rejected |
|---|---|---|---|
| Two separate packages | Hard isolation | Schema/DI duplication, double deploy | Too much duplication for one bounded context |
| Always run both roles per replica | Simplest config | Wasted CPU on API pods; coupled scaling | Defeats the purpose of the split |
| Feature flags per component | Fine-grained | Combinatorial config surface | Two coarse roles cover all real topologies |
References
ledger/src/common/roles.ts(getAppRoles)ledger/src/application.ts(configureComponents/Services/Controllers)ledger/src/components/kafka.component.ts,recovery.component.ts(self-skip)- Configuration