docs: approve manual constructor injection

This commit is contained in:
2026-08-20 13:10:02 +03:30
parent 98b615b6fc
commit 2426c1ed33
3 changed files with 31 additions and 7 deletions

View File

@@ -19,6 +19,7 @@ For every Go-related task, always invoke and follow the `golang-how-to` skill, t
## Go baseline after approval ## Go baseline after approval
- Keep `main` packages thin under `cmd/`; business code lives under `internal/`. - Keep `main` packages thin under `cmd/`; business code lives under `internal/`.
- Wire dependencies manually with explicit constructors at the composition root. Do not introduce a DI container or code generator unless a later ADR documents measured wiring/lifecycle complexity.
- Use explicit constructors; avoid `init()` side effects and mutable globals. - Use explicit constructors; avoid `init()` side effects and mutable globals.
- Configuration comes from validated environment variables. Logs go to stdout as structured records without credentials, card keys, or sensitive payloads. - Configuration comes from validated environment variables. Logs go to stdout as structured records without credentials, card keys, or sensitive payloads.
- Propagate `context.Context`; bound external calls, queues, batches, and database pools. - Propagate `context.Context`; bound external calls, queues, batches, and database pools.
@@ -36,4 +37,3 @@ For every Go-related task, always invoke and follow the `golang-how-to` skill, t
## AI boundary (post-MVP) ## AI boundary (post-MVP)
AvalAI is accessed only from the backend using a server-held API key. Prefer the simplest bounded LLM call/workflow that satisfies the approved use case. Send minimized, sanitized aggregates with explicit budgets/timeouts; persist trace metadata and deterministic inputs, not unnecessary sensitive prompts. AI output is advisory and must cite underlying deterministic metrics. AvalAI is accessed only from the backend using a server-held API key. Prefer the simplest bounded LLM call/workflow that satisfies the approved use case. Send minimized, sanitized aggregates with explicit budgets/timeouts; persist trace metadata and deterministic inputs, not unnecessary sensitive prompts. AI output is advisory and must cite underlying deterministic metrics.

View File

@@ -148,11 +148,12 @@ This ERD is a logical baseline, not an approved physical schema. In particular,
Resolved: use a capability-oriented modular monolith, with lightweight ports/adapters at external boundaries such as PostgreSQL and AvalAI. See ADR 0001. Resolved: use a capability-oriented modular monolith, with lightweight ports/adapters at external boundaries such as PostgreSQL and AvalAI. See ADR 0001.
Resolved: use manual constructor injection with explicit wiring at thin `cmd/` composition roots. See ADR 0002.
Remaining approval gates: Remaining approval gates:
1. Dependency injection: manual constructor injection, compile-time/runtime DI library, or none. 1. PostgreSQL access stack: ORM choice plus a bulk-ingest path suitable for 2.2M+ rows.
2. PostgreSQL access stack: ORM choice plus a bulk-ingest path suitable for 2.2M+ rows. 2. Source timestamp timezone and daylight-saving assumptions.
3. Source timestamp timezone and daylight-saving assumptions. 3. Whether `payer_card_key` must be retained, irreversibly transformed, or omitted after derived analytics.
4. Whether `payer_card_key` must be retained, irreversibly transformed, or omitted after derived analytics. 4. Minimum cohort size and suppression policy for peer benchmarks.
5. Minimum cohort size and suppression policy for peer benchmarks. 5. Physical partitioning/materialization strategy, which must follow measured query needs rather than the logical ERD alone.
6. Physical partitioning/materialization strategy, which must follow measured query needs rather than the logical ERD alone.

View File

@@ -0,0 +1,23 @@
# ADR 0002: Manual constructor injection
- Status: Accepted
- Date: 2026-08-20
## Context
The capability-oriented modular monolith needs testable components and explicit lifecycle ownership. At this stage its dependency graph is small and still evolving. A compile-time generator or runtime container would introduce tooling, indirection, and debugging costs without a demonstrated wiring problem.
## Decision
Use manual constructor injection. Each component declares required dependencies as constructor parameters, and thin `cmd/` entry points act as composition roots that create configuration, infrastructure adapters, capability services, handlers, and process lifecycle in an explicit order.
Interfaces are defined by the consuming package where substitution is useful. Constructors return concrete implementations unless callers benefit from an interface. Database pools and other stateful resources are created once, passed explicitly, health-checked, and closed during graceful shutdown.
## Consequences
- Dependency graphs remain visible to readers, the compiler, and tests.
- Tests can supply focused fakes at real boundaries without a service locator.
- Packages must not initialize services through globals or `init()`.
- Containers must never be passed through the application as dependency lookup mechanisms.
- Manual wiring may become verbose as the graph grows. A DI tool may be reconsidered only through a new ADR based on measured composition or lifecycle complexity; preference is compile-time safety over runtime reflection if that need arises.