Skip to main content

Configuration system

One typed ConfigType 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.
Do not set APP_URL to http://localhost:3000 if you want the full product in the browser. 3000 is the Express API only. Use the dev-proxy URL (8888 by default) for routine work.
Port 8888 already in use? Change both (1) the host side of dev-proxy ports: in compose.yml (e.g. "9999:8888") and (2) APP_URL to http://localhost:9999. APP_URL does not change Compose — edit infrastructure first, then align APP_URL.

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:
  1. apps/backend/package.json — add/remove the tooling-* workspace dependency.
  2. apps/backend/src/configuration/<env>.ts — update the client discriminator and any adapter-specific fields.
  3. Environment variables — add/remove the env vars the new adapter reads.
Then run make deps-install to update the lockfile, and make test module=backend to verify.

What’s next?