This service is being refactored to follow the Well-Known Components (WKC) pattern strictly. Apply these rules when adding or modifying code.
See the dcl-wkc-components skill for the full reference (factory pattern, DI, lifecycle, JSDoc, OpenAPI).
- Adapter (
src/adapters/<name>/) β does I/O. Database pool, repositories (per-domain SQL), file storage, HTTP clients, blockchain providers, external SDK wrappers, in-memory caches/state, scheduled-job runners. - Logic (
src/logic/<name>/) β rules and orchestration. Depends on adapters and/or other logic. Can be pure.
Every component lives in its own folder with these files:
component.tsβ exports the async factorycreate<Name>(components: Pick<AppComponents, '...'>)types.tsβ the component's interfaces and supporting typesindex.tsβ re-exports the public surfaceerrors.tsβ optional; custom exception classes the component throws
- Components throw typed exceptions defined in their
errors.ts. No error codes, noResult/Eitherwrappers. - Controllers are NOT components. They live under
src/controllers/handlers/and only: (1) validate HTTP-shape input, (2) call logic components, (3) catch typed errors and map to HTTP status via the central error middleware insrc/controllers/middlewares.ts. - Repositories own SQL, not transactions. Repo methods take
db: DatabaseClientas a parameter on every call. The orchestrating logic component opensdatabase.transaction(tx => ...)and threadstxthrough repo calls. - Dependency injection. Factories take deps as
Pick<AppComponents, '...'>listing only what they need. - Lifecycle. Stateful components implement
START_COMPONENT/STOP_COMPONENT. Examples: DB pool open/drain, scheduled jobs cancel-on-stop, in-memory caches warm-up at start.
The codebase is migrating from a legacy ports/ + service/ layout to the WKC adapters/ + logic/ layout. New code should be written in the WKC layout from the start; existing code is being moved phase-by-phase.