Configuration system
One typedConfigType per environment. process.env is read exactly once, in the matching configuration module — nowhere else in the codebase.
How it works
Docker Compose injects.env.development at the container boundary. The backend reads NODE_ENV, loads the matching configuration module, and assembles a single ConfigType object that’s passed everywhere.
Configuration modules
Each module exports a plain object matching
ConfigType. Tool choices are set here — for example, test.ts sets paymentProcessor.client to stripeMock so tests never hit the real Stripe API.
What ConfigType covers
ConfigType is the single source of truth for all app config. Key sections:
Canonical local URL: APP_URL and the dev proxy
Default local setup: Compose publishes the dev-proxy (Caddy) on host port 8888. That is the unified browser origin: marketing, portal, and API on one URL. Set APP_URL=http://localhost:8888 in .env.development so OAuth redirects, CORS, email links, Astro site / sitemap, and the line make start prints all match what you open in the browser.
Production uses your real HTTPS origin for APP_URL — same variable, different value.
Local service ports
Day-to-day URLs after first start: What you get.
Dev proxy routing (Caddyfile.dev)
Caddy on 8888 is local development only. It forwards to three Compose services while the browser sees a single origin:
Do not reorder
handle blocks in Caddyfile.dev — API/auth must stay before /__portal/*. New top-level portal paths need a matching handle before the marketing catch-all. After edits: docker compose restart dev-proxy. Verify with make verify-dev-proxy — see Make commands.
Deeper frontend routing notes: Frontend routing.
Local .env.development
Copy .env.example → .env.development (Quickstart). Compose defaults already point Postgres at rds and Redis at memory.
Never commit
.env.development.
Changing which tool implementation you use
When you swap a tool adapter, three things must change together:apps/backend/package.json— add/remove thetooling-*workspace dependency.apps/backend/src/configuration/<env>.ts— update theclientdiscriminator and any adapter-specific fields.- Environment variables — add/remove the env vars the new adapter reads.
make deps-install to update the lockfile, and make test module=backend to verify.
What’s next?
- Quickstart — get the stack running.
- Tooling system — loaders, workspace packages, and the dynamic-import pattern.
- Architecture overview — how configuration fits into the full system.
