From af4428fd8a59f6a1d32566bb0b5d08d02cf5ae4c Mon Sep 17 00:00:00 2001 From: ulfrxdev Date: Fri, 24 Apr 2026 18:21:40 +0200 Subject: [PATCH 1/3] feat(01-06): add docker-compose.yml with postgres:16 for local dev - Single postgres service pinned to postgres:16 - Credentials recipe/recipe/recipe match application.conf HOCON defaults - Named volume recipe-pgdata for persistence across restarts - Healthcheck via pg_isready enables docker compose up --wait usage - No version key (modern compose v2); Authentik stays on homelab (D-17) --- docker-compose.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..418981c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,20 @@ +services: + postgres: + image: postgres:16 + container_name: recipe-postgres + environment: + POSTGRES_DB: recipe + POSTGRES_USER: recipe + POSTGRES_PASSWORD: recipe + ports: + - "5432:5432" + volumes: + - recipe-pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U recipe -d recipe"] + interval: 5s + timeout: 5s + retries: 5 + +volumes: + recipe-pgdata: From f691400f2b9a18a4047bff5e324436e94196c5d4 Mon Sep 17 00:00:00 2001 From: ulfrxdev Date: Fri, 24 Apr 2026 18:22:41 +0200 Subject: [PATCH 2/3] docs(01-06): add Local development section and drop js target - New "Local development" section documents docker compose + gradlew dev loop - Covers /health smoke test, env-var overrides (DATABASE_* and PORT) - Adds spotlessApply + check + down -v reference commands - Removes legacy js target docs (D-01); wasmJs target preserved --- README.md | 53 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index cdfea20..4f4458c 100644 --- a/README.md +++ b/README.md @@ -74,21 +74,56 @@ in your IDE's toolbar or run it directly from the terminal: ```shell .\gradlew.bat :composeApp:wasmJsBrowserDevelopmentRun ``` -- for the JS target (slower, supports older browsers): - - on macOS/Linux - ```shell - ./gradlew :composeApp:jsBrowserDevelopmentRun - ``` - - on Windows - ```shell - .\gradlew.bat :composeApp:jsBrowserDevelopmentRun - ``` ### Build and Run iOS Application To build and run the development version of the iOS app, use the run configuration from the run widget in your IDE’s toolbar or open the [/iosApp](./iosApp) directory in Xcode and run it from there. +### Local development + +The server requires Postgres. A `docker-compose.yml` at the repo root ships a local Postgres +instance whose credentials match `application.conf` defaults (`recipe`/`recipe`/`recipe`). + +Boot the database and server: + +```shell +docker compose up -d postgres +./gradlew :server:run +``` + +Verify the server is up: + +```shell +curl http://localhost:8080/health +# expected: {"status":"ok"} +``` + +Environment overrides (optional — set any of these to override `application.conf` defaults): + +- `DATABASE_URL` — JDBC URL (default `jdbc:postgresql://localhost:5432/recipe`) +- `DATABASE_USER` — DB user (default `recipe`) +- `DATABASE_PASSWORD` — DB password (default `recipe`) +- `PORT` — Ktor port (default `8080`) + +Before committing, format all Kotlin + Gradle + Markdown files: + +```shell +./gradlew spotlessApply +``` + +The full check (Spotless + all tests across all targets): + +```shell +./gradlew check +``` + +Reset the local database (destroys the `recipe-pgdata` volume): + +```shell +docker compose down -v +``` + --- Learn more about [Kotlin Multiplatform](https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html), From f9d3a0c2d4d7b2638a46e549b3b2f236a4163aa6 Mon Sep 17 00:00:00 2001 From: ulfrxdev Date: Fri, 24 Apr 2026 18:24:24 +0200 Subject: [PATCH 3/3] docs(01-06): add SUMMARY for dev-ergonomics plan --- .../01-06-SUMMARY.md | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 .planning/phases/01-project-infrastructure-module-wiring/01-06-SUMMARY.md diff --git a/.planning/phases/01-project-infrastructure-module-wiring/01-06-SUMMARY.md b/.planning/phases/01-project-infrastructure-module-wiring/01-06-SUMMARY.md new file mode 100644 index 0000000..99abe7b --- /dev/null +++ b/.planning/phases/01-project-infrastructure-module-wiring/01-06-SUMMARY.md @@ -0,0 +1,155 @@ +--- +phase: 01-project-infrastructure-module-wiring +plan: 06 +subsystem: dev-ergonomics +tags: [docker-compose, postgres, readme, local-dev, infra] +dependency_graph: + requires: [] + provides: + - "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" + affects: + - "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" +tech_stack: + added: + - "postgres:16 (Docker image, pinned major version)" + patterns: + - "Dev-local compose file committed to repo (non-secret literal creds)" + - "Healthcheck via pg_isready gating sequencing" + - "Named Docker volume for data persistence" +key_files: + created: + - "docker-compose.yml" + modified: + - "README.md" +decisions: + - "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." +metrics: + duration_seconds: 92 + duration_human: "1m32s" + tasks_completed: 2 + files_created: 1 + files_modified: 1 + completed_at: "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.yml` → `3`. + +## 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 `` 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 `` 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 `-c` → `1` each) +- `jsBrowserDevelopmentRun` absent; `wasmJsBrowserDevelopmentRun` present +- Top introduction (lines 1-20) unchanged + +## Manual sanity checks (optional, not blocking) + +Skipped per plan ``: +- `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