Files
famapp/docs/tasks/05-compose-caddy.md
ginnoir b89690a9f2 Initial scaffold: tooling, plan, task briefs
- pnpm 10 workspace + TypeScript strict + ESLint flat + Prettier
- CLAUDE.md as canonical brief
- docs/tasks/ — 22 task briefs broken out by phase for sub-sessions
- docs/decisions/ — ADR scaffold

Implements task 01 (repo-init).
2026-05-06 00:05:50 -05:00

1.9 KiB

05 — Compose stack & Caddy

Goal

Produce the production deploy artifacts: Dockerfile, deploy/compose.yaml, Caddy snippet, .env.production.example.

Depends on

  • 02 (so output: "standalone" exists)
  • 03 (so DB service is defined)

Scope

Dockerfile (multi-stage)

  • Stage 1: node:22-alpine + pnpm, install deps, build (pnpm build).
  • Stage 2: node:22-alpine runtime, copy .next/standalone, .next/static, public/. Run as non-root. CMD ["node", "server.js"].

deploy/compose.yaml

Services:

  • famapp (built from Dockerfile)
  • famapp-db (postgres:16, volume famapp_db_data)
  • authentik-server, authentik-worker, authentik-db (postgres:16, volume authentik_db_data), authentik-redis — leave fully configured but task 06 will tune env

All services on a famapp_net network. famapp depends on famapp-db. No host port exposure for the DBs/redis.

Caddy snippet (deploy/Caddyfile.snippet)

fam.ginnoir.com {
    reverse_proxy famapp:3000
}

auth.ginnoir.com {
    reverse_proxy authentik-server:9000
}

Comment at the top: "Include from main Caddyfile or paste into the existing one."

.env.production.example

All vars needed by the compose stack, with comments explaining each.

Out of scope

  • Actually running the stack against ginnoir.com (Matt does that).
  • Backups, log shipping (later tasks).

Acceptance criteria

  • docker build -t famapp . succeeds.
  • docker compose -f deploy/compose.yaml config validates without errors.
  • famapp container starts against famapp-db when given a populated .env.
  • Image size under ~300 MB.
  • No secrets committed; only .env.production.example.

Notes

  • Use pnpm fetch + pnpm install --offline in the build stage for cache locality.
  • output: "standalone" (set in task 02) means we copy .next/standalone/server.js, not run next start.