Files
recipe/.planning/phases/01-project-infrastructure-module-wiring/01-06-SUMMARY.md

7.9 KiB

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics
01-project-infrastructure-module-wiring 06 dev-ergonomics
docker-compose
postgres
readme
local-dev
infra
requires provides affects
Local Postgres 16 dev instance matching application.conf HOCON defaults (recipe/recipe/recipe)
Named volume recipe-pgdata for persistence across container restarts
pg_isready healthcheck enabling docker compose up --wait usage
README 'Local development' section documenting the two-command dev loop
server/src/main/resources/application.conf (Plan 05 — credentials match contract)
Phase 3 (Households + DB migrations) — depends on a working local Postgres
Phase 11 (homelab deployment) — separate compose config will diverge from this dev-local one
added patterns
postgres:16 (Docker image, pinned major version)
Dev-local compose file committed to repo (non-secret literal creds)
Healthcheck via pg_isready gating sequencing
Named Docker volume for data persistence
created modified
docker-compose.yml
README.md
Kept it single-service: postgres only. Authentik stays on homelab (CONTEXT.md D-17); Ktor server runs via Gradle on the dev host for fast iteration.
Pinned postgres:16 (not :latest, not :15) matching D-17 scope statement.
No version: key in compose file — modern docker compose v2 treats it as legacy and emits warnings.
No .env file in this plan — inline POSTGRES_* is fine for single-dev + matching application.conf defaults (D-17 / PATTERNS.md recommendation).
Port binding 5432:5432 is dev-local; README calls it out. Phase 11 homelab compose will use a different approach.
duration_seconds duration_human tasks_completed files_created files_modified completed_at
92 1m32s 2 1 1 2026-04-24T16:22:48Z

Phase 01 Plan 06: Dev ergonomics — docker-compose + README Local development summary

Shipped docker-compose.yml (single postgres:16 service, named volume, healthcheck — credentials matching Plan 05's application.conf HOCON defaults exactly) and a "Local development" README section documenting the docker compose up -d postgres && ./gradlew :server:run && curl /health dev loop, while dropping the legacy js target docs per D-01.

What was built

docker-compose.yml (20 lines)

  • services.postgres:
    • image: postgres:16 (pinned major version)
    • container_name: recipe-postgres
    • environment: POSTGRES_DB / POSTGRES_USER / POSTGRES_PASSWORD all literal recipe
    • ports: "5432:5432" (dev-local loopback via host Docker)
    • volumes: recipe-pgdata:/var/lib/postgresql/data (persistence)
    • healthcheck: pg_isready -U recipe -d recipe every 5s, timeout 5s, 5 retries
  • Top-level volumes.recipe-pgdata: (named volume declaration)
  • No version: key (modern compose v2)
  • No additional services (no Authentik — lives on user's homelab per D-17)

README.md edits

Edit A — dropped js target block (lines 77-85 of previous README): the "- for the JS target (slower, supports older browsers)" paragraph and its two command blocks were deleted. The wasmJs paragraph is preserved intact.

Edit B — inserted new "Local development" section (after the iOS subsection, before the trailing --- horizontal rule):

  • Two-command boot: docker compose up -d postgres + ./gradlew :server:run
  • Smoke test: curl http://localhost:8080/health with expected {"status":"ok"} response
  • Documented env-var overrides: DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD, PORT
  • Pre-commit formatter hint: ./gradlew spotlessApply (D-10)
  • Full-suite: ./gradlew check
  • DB reset: docker compose down -v (destroys recipe-pgdata)

All other existing headings (Android, Desktop/JVM, Server, iOS, web wasmJs) and the top introduction (lines 1-20) are unchanged. The trailing --- + learn-more links paragraph is unchanged.

Credential-match contract with Plan 05

The three compose env-vars are byte-identical to the literals in server/src/main/resources/application.conf:

compose env application.conf
POSTGRES_DB: recipe JDBC URL path /recipe
POSTGRES_USER: recipe user = "recipe"
POSTGRES_PASSWORD: recipe password = "recipe"

Verified via grep -c '^\s*POSTGRES_\(DB\|USER\|PASSWORD\): recipe$' docker-compose.yml3.

Requirements addressed

  • INFRA-02 — local development environment via docker-compose.yml and README dev loop documentation.

Tasks executed

Task Name Commit Files
1 Create docker-compose.yml at repo root af4428f docker-compose.yml (new)
2 Add "Local development" section to README.md and drop js target docs f691400 README.md (modified)

Deviations from Plan

None — plan executed exactly as written. No Rule 1-3 auto-fixes, no checkpoints, no auth gates. Both <automated> verify blocks and every acceptance criterion passed on first attempt.

Threat surface scan

No new network endpoints, auth paths, file access patterns, or schema changes at trust boundaries were introduced beyond what the plan's <threat_model> already covers (T-01-06-01..04). The 5432:5432 host binding and literal recipe/recipe/recipe credentials are the exact surface the plan's STRIDE register dispositions (mitigate/accept) already cover. No new flags.

Known stubs

None. Both deliverables are complete — no placeholders, no TODOs, no empty data paths.

Verification

Task 1 automated check:

test -f docker-compose.yml && grep -q 'image: postgres:16' ... && grep -q 'pg_isready -U recipe -d recipe' ... && grep -q '^volumes:$' ...
→ VERIFY PASS
grep -c '^\s*POSTGRES_\(DB\|USER\|PASSWORD\): recipe$' docker-compose.yml → 3

Task 2 automated check:

grep -q 'Local development' && grep -q 'docker compose up -d postgres' && grep -q 'curl http://localhost:8080/health' && grep -q 'DATABASE_URL' && grep -q 'gradlew spotlessApply' && grep -q 'docker compose down -v' && ! grep -q 'jsBrowserDevelopmentRun' && grep -q 'wasmJsBrowserDevelopmentRun'
→ VERIFY PASS

Acceptance criteria — Task 2 individually confirmed:

  • Local development appears exactly once (section heading)
  • All 4 env-vars listed: DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD, PORT
  • gradlew check present
  • Existing section headings (Android / Desktop (JVM) / Server / iOS) all preserved (grep -c1 each)
  • jsBrowserDevelopmentRun absent; wasmJsBrowserDevelopmentRun present
  • Top introduction (lines 1-20) unchanged

Manual sanity checks (optional, not blocking)

Skipped per plan <verification>:

  • docker compose config YAML parse — not blocking per plan; docker may not be running in this worktree sandbox.
  • docker compose up -d postgres && pg_isready live test — not required; will be validated in Phase 3 when migrations land.

Notes for downstream plans

  • Plan 05 (this wave) — credential contract lives in both files; any future change to the recipe/recipe/recipe triple MUST update both application.conf AND docker-compose.yml in the same commit.
  • Phase 3 (Households + DB migrations) — can add depends_on: { postgres: { condition: service_healthy } } to a future server service in compose if we ever run the Ktor server in Docker; the healthcheck is already wired for it.
  • Phase 11 (homelab deployment) — will ship a separate compose file (not editing this one) because homelab creds are secret and this file's creds are deliberately non-secret literals.

Self-Check: PASSED

  • docker-compose.yml exists at repo root: FOUND
  • README.md contains "Local development" section: FOUND
  • Commit af4428f (Task 1): FOUND in git log
  • Commit f691400 (Task 2): FOUND in git log
  • All acceptance criteria from both tasks verified via grep
  • No file deletions in either commit