Files
red/.planning/phases/17-docker-deployment/17-02-SUMMARY.md
Chandler Copeland 9117dc4c02 initial install
2026-04-08 12:54:58 -06:00

6.2 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
17-docker-deployment 02 infra
docker
dockerfile
docker-compose
nodejs
nextjs
standalone
smtp
neon
phase provides
17-01 output standalone in next.config.ts, GET /api/health endpoint
Dockerfile with three-stage node:20-slim linux/amd64 build
docker-compose.yml with env_file secrets, DNS fix, named uploads volume
.dockerignore for build context exclusions
.env.production.example template with 11 required vars
DEPLOYMENT.md with migration step and startup instructions
deployment
production-ops
added patterns
Three-stage Dockerfile: deps (npm ci --omit=dev) → builder (npm run build) → runner (node server.js)
env_file secrets injection — secrets stay in .env.production on host, never baked into image
SMTP DNS fix: dns array [8.8.8.8, 1.1.1.1] + NODE_OPTIONS=--dns-result-order=ipv4first
Named Docker volume uploads:/app/uploads for persistent PDF storage across restarts
created modified
teressa-copeland-homes/Dockerfile
teressa-copeland-homes/docker-compose.yml
teressa-copeland-homes/.dockerignore
teressa-copeland-homes/.env.production.example
teressa-copeland-homes/DEPLOYMENT.md
teressa-copeland-homes/.gitignore
--platform=linux/amd64 on all 3 FROM lines — home server is x86_64; Mac ARM cross-compiles correctly
node:20-slim (Debian) not Alpine — @napi-rs/canvas requires glibc, Alpine musl incompatible
seeds/ copied into runner stage at /app/seeds — runtime dependency for form library import feature
uploads/ pre-created in runner stage, owned by nextjs user — volume mount works without root
HEALTHCHECK uses wget (in Debian slim by default) not curl (not installed)
.env.production.example force-added past .env* gitignore glob — example template should be committed
Migrations run from host, not inside container — CMD is simply node server.js per D-02
Docker deployment: build on host → push or deploy to server → run migrations → docker compose up
DEPLOY-01
DEPLOY-02
DEPLOY-03
DEPLOY-04
DEPLOY-05
3min 2026-04-03

Phase 17 Plan 02: Docker Deployment Files Summary

Three-stage node:20-slim Dockerfile with linux/amd64, env_file secrets injection, SMTP DNS fix, named uploads volume, and DEPLOYMENT.md documenting host-side migration workflow

Performance

  • Duration: 3 min
  • Started: 2026-04-03T22:55:35Z
  • Completed: 2026-04-03T22:58:30Z
  • Tasks: 3
  • Files modified: 6

Accomplishments

  • Created three-stage Dockerfile using node:20-slim with --platform=linux/amd64 on all 3 FROM lines; seeds/ copied for form library; HEALTHCHECK via wget on /api/health
  • Created docker-compose.yml with runtime env_file secrets injection, SMTP DNS fix (dns array + NODE_OPTIONS), named volume uploads:/app/uploads, and restart: unless-stopped
  • Created .dockerignore (excludes node_modules, .next, .git, .env*, uploads/, *.md), .env.production.example with exactly 11 required vars (no BLOB token, no dev scraping creds), and DEPLOYMENT.md documenting the full workflow

Task Commits

Each task was committed atomically:

  1. Task 1: Dockerfile, .dockerignore, .env.production.example - e83ced5 (feat)
  2. Task 2: docker-compose.yml and .gitignore update - a107970 (feat)
  3. Task 3: DEPLOYMENT.md - 72c23f8 (feat)

Files Created/Modified

  • teressa-copeland-homes/Dockerfile - Three-stage linux/amd64 build; seeds/ for form library; HEALTHCHECK
  • teressa-copeland-homes/docker-compose.yml - env_file secrets, DNS fix, named uploads volume
  • teressa-copeland-homes/.dockerignore - Excludes dev artifacts from Docker build context
  • teressa-copeland-homes/.env.production.example - Template with 11 required runtime vars
  • teressa-copeland-homes/DEPLOYMENT.md - Step-by-step deploy guide with migration and health check steps
  • teressa-copeland-homes/.gitignore - Added /uploads/ entry for Docker volume path

Decisions Made

  • .env.production.example force-added past .env* gitignore glob — it's a template with no real secrets and should be committed for operator reference
  • wget used in HEALTHCHECK (not curl) because Debian slim includes wget by default; curl is not pre-installed in node:20-slim
  • seeds/ directory is explicitly copied into the runner stage at /app/seedssrc/app/api/documents/route.ts reads from path.join(process.cwd(), 'seeds', 'forms') at runtime for the form library import feature; without it, importing forms returns 404

Deviations from Plan

None - plan executed exactly as written.

Issues Encountered

  • docker compose config --quiet fails locally because .env.production does not exist on dev machine (expected — it's server-only). Verified with a temporary empty stub file; compose syntax parsed cleanly.

User Setup Required

The operator (Teressa) must perform these steps on the server before first deploy:

  1. Copy .env.production.example to .env.production and fill in all 11 values
  2. Run DATABASE_URL=<neon-url> npx drizzle-kit migrate from the project directory
  3. Run docker compose up -d --build
  4. Verify with curl http://localhost:3000/api/health

See teressa-copeland-homes/DEPLOYMENT.md for full instructions.

Next Phase Readiness

Phase 17 is complete. All Docker deployment infrastructure is in place:

  • Plan 01: standalone output, health endpoint, pool limit, @vercel/blob removal
  • Plan 02: Dockerfile, compose, ignore files, env template, deployment docs

The app is ready to be deployed to Teressa's home server via docker compose up -d --build.


Phase: 17-docker-deployment Completed: 2026-04-03

Self-Check: PASSED

  • FOUND: teressa-copeland-homes/Dockerfile
  • FOUND: teressa-copeland-homes/docker-compose.yml
  • FOUND: teressa-copeland-homes/.dockerignore
  • FOUND: teressa-copeland-homes/.env.production.example
  • FOUND: teressa-copeland-homes/DEPLOYMENT.md
  • FOUND: .planning/phases/17-docker-deployment/17-02-SUMMARY.md
  • FOUND commit e83ced5 (Task 1)
  • FOUND commit a107970 (Task 2)
  • FOUND commit 72c23f8 (Task 3)
  • FOUND commit 4a7605b (metadata)