- loadConfig: pure over env object, accumulates all problems, names var names only - DATABASE_URL now required at startup; PORT/HOST/LOG_LEVEL/NODE_ENV/REDIS_URL defaulted - flags module behind FeatureFlagProvider; unknown flags OFF; runtime setEnabled (no redeploy) - buildApp decorates app.flags; server.ts fail-fast before app boot - tests caught and fixed flag-store case-normalization bug before gates - zero new dependencies; all gates approved; verify.sh green
34 lines
1.7 KiB
Markdown
34 lines
1.7 KiB
Markdown
# Architect — F-004 Typed config and feature flags
|
|
|
|
done -> work/artifacts/F-004/architect.md
|
|
|
|
## Deliverables
|
|
- specs/F-004-config-flags/SPEC.md
|
|
- specs/F-004-config-flags/DESIGN.md
|
|
- specs/F-004-config-flags/TASKS.md
|
|
- specs/F-004-config-flags/TESTS.md
|
|
|
|
## Key decisions
|
|
1. **Config loader lives in `infrastructure/config`** and is a pure function over an env
|
|
object. No reads of `process.env` inside the loader → deterministic unit tests. It
|
|
accumulates every problem and throws ONE `ConfigError` (fail fast AND clear). It names
|
|
var NAMES only — never values — so secrets cannot leak into error messages.
|
|
2. **Feature flags are a real module (`src/modules/flags`)** behind a
|
|
`FeatureFlagProvider` interface with an in-memory store. Unknown flags default to OFF
|
|
(fail-safe). `setEnabled` mutates live state → activation ≠ deployment, no redeploy.
|
|
3. **Inversion to keep the module clean:** `infrastructure/config` parses `FLAG_*` into a
|
|
plain record and the composition root hands it to the flags store. The flags module never
|
|
imports config. The boundary checker enforces this.
|
|
4. **buildApp gains an optional `flags` dep**, decorated onto the instance (`app.flags`),
|
|
establishing the wiring point future risky routes will consume. Default: empty store →
|
|
everything off.
|
|
5. **No new dependencies.** Hand-rolled validation is small and boring.
|
|
|
|
## Boundaries
|
|
- `flags` module imports nothing outside its subtree (no shared needed). Config → flags
|
|
only via composition root. server.ts pulls config + passes flags into buildApp.
|
|
|
|
## Risks
|
|
- server now requires DATABASE_URL to start (intentional fail-fast). Smoke/QA must pass it.
|
|
- ConfigError must not echo values. Covered by name-only messages + test.
|