compose: drive app config from .env (env_file, blanket passthrough) #243

Merged
justin merged 1 commits from compose-env-file into main 2026-06-10 08:46:16 -04:00
Owner

Replaces the per-setting environment: allow-list on the backend/worker/migrate services with env_file: .env, so every setting in app/core/config.py is configurable from .env with no compose edit — killing the recurring trap where a documented var (OWNER_EMAIL, AI keys, SMTP, APP_BASE_URL) silently never reached the app.

  • env_file is required: false, so local/CI without a .env still works (falls back to ${VAR:-default} + code defaults). Validated with docker compose config -q both with and without .env.
  • The remaining tiny environment: block pins only what must NOT come from .env: RUN_MIGRATIONS=1 (deploy flag) and DATABASE_URL (compose-internal host; code default is localhost). environment wins over env_file.
  • Trade-off (accepted): env_file also injects infra secrets (POSTGRES_*, MINIO_*, CLOUDFLARE_TUNNEL_TOKEN) into the app process env; the app ignores unknown vars.

Verified live on prod after recreate: DATABASE_URLpostgres:5432, RUN_MIGRATIONS=1 + OWNER_EMAIL intact, COOKIE_SECURE=true (checked beforehand — no security posture change), migrate exit 0, /health/ready 200, /api/v1/public/trees 200. Supersedes the explicit AI/SMTP/OWNER passthrough from #241/#242.

🤖 Generated with Claude Code

Replaces the per-setting `environment:` allow-list on the backend/worker/migrate services with `env_file: .env`, so **every** setting in `app/core/config.py` is configurable from `.env` with no compose edit — killing the recurring trap where a documented var (`OWNER_EMAIL`, AI keys, SMTP, `APP_BASE_URL`) silently never reached the app. - `env_file` is `required: false`, so local/CI without a `.env` still works (falls back to `${VAR:-default}` + code defaults). Validated with `docker compose config -q` both with and without `.env`. - The remaining tiny `environment:` block pins only what must NOT come from `.env`: `RUN_MIGRATIONS=1` (deploy flag) and `DATABASE_URL` (compose-internal host; code default is localhost). `environment` wins over `env_file`. - **Trade-off (accepted):** `env_file` also injects infra secrets (`POSTGRES_*`, `MINIO_*`, `CLOUDFLARE_TUNNEL_TOKEN`) into the app process env; the app ignores unknown vars. **Verified live on prod** after recreate: `DATABASE_URL`→`postgres:5432`, `RUN_MIGRATIONS=1` + `OWNER_EMAIL` intact, `COOKIE_SECURE=true` (checked beforehand — no security posture change), migrate exit 0, `/health/ready` 200, `/api/v1/public/trees` 200. Supersedes the explicit AI/SMTP/OWNER passthrough from #241/#242. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
justin added 1 commit 2026-06-10 08:46:15 -04:00
Replace the per-setting environment allow-list with `env_file: .env` on the
three app-image services, so every setting in app/core/config.py is configurable
from .env with no compose edit. This kills the recurring trap where a documented
env var (OWNER_EMAIL, the AI keys, SMTP, APP_BASE_URL) silently didn't reach the
app because it wasn't on the hand-maintained list.

`env_file` is `required: false` so local/CI without a .env still works (falls
back to ${VAR:-default} interpolation + code defaults). The small `environment:`
block that remains is only for values that must NOT come from .env:
  - RUN_MIGRATIONS=1 (backend) — a deploy flag, not an app setting.
  - DATABASE_URL — pinned to the compose-internal host, because the code default
    points at localhost (wrong inside the network). environment wins over
    env_file, so this is a safety net if .env ever omits it.

Trade-off (accepted, see comment): env_file also injects infra secrets
(POSTGRES_*, MINIO_*, CLOUDFLARE_TUNNEL_TOKEN) into the app process env; the app
ignores unknown vars (pydantic extra="ignore").

Verified on prod: DATABASE_URL resolves to postgres:5432, RUN_MIGRATIONS=1 and
OWNER_EMAIL intact, COOKIE_SECURE=true (no posture change), health 200, trees
200. The earlier explicit AI/SMTP/OWNER passthrough is now subsumed by this.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Paul <justin@jpaul.me>
justin merged commit 0388b9b99f into main 2026-06-10 08:46:16 -04:00
justin deleted branch compose-env-file 2026-06-10 08:46:16 -04:00
Sign in to join this conversation.