merge(01-06): docker-compose + README Local development

This commit is contained in:
2026-04-24 18:41:51 +02:00
3 changed files with 219 additions and 9 deletions

View File

@@ -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 `<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 `-c``1` 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

View File

@@ -74,21 +74,56 @@ in your IDE's toolbar or run it directly from the terminal:
```shell ```shell
.\gradlew.bat :composeApp:wasmJsBrowserDevelopmentRun .\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 ### Build and Run iOS Application
To build and run the development version of the iOS app, use the run configuration from the run widget To build and run the development version of the iOS app, use the run configuration from the run widget
in your IDEs toolbar or open the [/iosApp](./iosApp) directory in Xcode and run it from there. in your IDEs 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), Learn more about [Kotlin Multiplatform](https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html),

20
docker-compose.yml Normal file
View File

@@ -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: