--- id: config-hub-startup-system name: Specify Hub Config System and Startup Sequence status: completed depends_on: [] scope: broad risk: high impact: project level: planning --- ## Summary Architecture specifications completed 2026-04-23. The original task was split into two concerns: 1. **Config system** → [docs/architecture/hub-config.md](../../docs/architecture/hub-config.md) — schemas, file format, two-layer key model (master key via Docker secret + data encryption keys in encrypted config file), `_encrypted` wrapper pattern, `alkhub-config` CLI tool. 2. **Startup sequence** → [docs/architecture/hub-startup.md](../../docs/architecture/hub-startup.md) — 11-step ordered startup, fail-fast on missing prerequisites, health check contract with step-level progress, graceful shutdown mirroring startup. ADR-008 revised to replace env var pattern with Docker secret + encrypted config file pattern. ## Key Decisions - **No env vars for secrets** — Hard rule. No important keys or config in environment variables. Sensitive values arrive via Docker secret (master key) or encrypted config fields (postgres, redis, data encryption keys). - **Two-layer keys** — Master key (Docker secret) decrypts config file. Data encryption keys (`v1:base64,v2:base64`, inside the encrypted config) are used for `client_secrets`. Independent rotation schedules. - **Whole-value encryption** — `postgres` and `redis` sections are each encrypted as a single `EncryptedData` blob, not field-by-field. This leaks less topology information. - **Fail-fast startup** — No retry loops. If Postgres, Redis, or config is unavailable, exit immediately. Container orchestrator handles restarts. - **Config read-once** — Config file is loaded and validated once at startup. Runtime changes require restart. - **Module-scope side effects prohibited** — All initialization inside `startHub()`. No globals, no `export const db = drizzle(pool)`. ## Acceptance Criteria — Completed - [x] HubConfig TypeBox schema specified — hub-config.md § Config Schema Hierarchy - [x] SpokeConfig / BaseConfig schema hierarchy specified — hub-config.md - [x] Master key provisioning mechanism documented — Docker secret `/run/secrets/hub_master_key`, hub-config.md § Master Key Provisioning - [x] Config loading startup sequence specified — hub-startup.md § Startup Sequence (11 steps) - [x] Multi-key encryption format documented — hub-config.md § Multi-Key Format; services.md updated to reference hub-config.md - [x] Naming consistent — "data encryption keys" (in config), not env var references. ADR-008 revised. services.md updated. - [x] crypto.ts bridge documented — hub-config.md § loadConfig (master key → decrypt config → resolveEncryptionKeys for data keys). Master key is a passphrase string consumed by PBKDF2; data encryption keys are base64 values used directly. - [x] Docker deployment notes — hub-config.md § Master Key Provisioning, infrastructure.md updated with Docker secret + config file mounting ## Cascade Updates The following docs were updated to align with the no-env-vars pattern: - `docs/architecture/storage/services.md` — replaced `HUB_ENCRYPTION_KEY` env var references with data encryption key ring from hub config - `docs/architecture/infrastructure.md` — replaced `docker run -e DATABASE_URL=... -e REDIS_URL=...` with Docker secret + config file mounting - `docs/architecture/storage/README.md` — removed `Deno.env.get()` from DB connection code; updated test setup to use test config files - `docs/decisions/ADR-008-secrets-encrypted-at-rest-with-key-versioning.md` — revised from env var to Docker secret + two-layer key model ## Open Items - `SpokeConfig.auth` field format is blocked on spoke-runner.md WebSocket auth design (hub-config.md Open Question #3) - Both specs are draft-stage — need another review pass before marking stable