Stage 7 · Master
Phase 1 — Project Foundation
PostgreSQL Setup
Add a real, healthchecked PostgreSQL service to compose and prove the database the organization service will own in Phase 2 is actually reachable.
One Database, One Owning Service — Even in Local Development
ADR 0001 established that Organization is the sole writer of its own data. That rule is worth honoring even at the level of local database naming: this Postgres instance runs one database named hoa_organization, not a shared hoa database every future service dumps tables into. When a Resident service exists in a later phase, it gets its own database name (hoa_resident) — whether that means a second container or a second database inside a shared instance is a decision for that phase, made deliberately rather than inherited by accident from how this lesson names things.
Extending docker-compose.yml With a Real Postgres Service
+volumes:
+ pg-data:
+
services:
+ postgres:
+ image: postgres:16-alpine
+ environment:
+ POSTGRES_USER: hoa
+ POSTGRES_PASSWORD: hoa_dev_password
+ POSTGRES_DB: hoa_organization
+ ports: ["5432:5432"]
+ volumes: ["pg-data:/var/lib/postgresql/data"]
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U hoa -d hoa_organization"]
+ interval: 5s
+ retries: 5
adminer:The named volume is the line most often forgotten. Without pg-data, Postgres writes into the container's writable layer, and docker compose down quietly deletes the database along with the container — which is exactly the confusing data-loss the verification section at the end of this lesson reproduces on purpose.
A Healthcheck pg_isready Actually Trusts
pg_isready queries Postgres's own readiness signal rather than merely checking whether the container process is alive — a container can be running for several seconds while Postgres is still initializing its data directory on first boot. Anything that depends on postgres later (a future depends_on: with condition: service_healthy) can trust this healthcheck to mean 'accepting connections', not just 'process started'.
Connecting From the Host vs. From Another Container
From your own terminal (the host), Postgres is reachable at localhost:5432 because of the ports: mapping. From another container on the hoa-net network — the organization service's own container, once it exists in Phase 2's Dockerization lesson — the correct host is the service name, postgres, on its unmapped internal port 5432. Connection strings therefore differ by context, and the Configuration Management pattern from earlier in this phase is exactly what will let that difference live in an environment variable instead of hardcoded application code.
Postgres bakes its credentials into the data directory the first time it initializes — inside the pg-data named volume. Editing POSTGRES_PASSWORD in docker-compose.yml and restarting will not change the running database's password, because Postgres only reads those environment variables on an empty data directory. Fixing a credential change requires wiping the volume first.
Confirming Readiness, Connectivity, and the Volume-Reset Gotcha
Applied exercise
Reproduce the volume-reset gotcha end to end
The callout above describes the gotcha in prose. Confirm it with your own hands so it's memorable the first time it costs you real debugging time in a future service.
- Start postgres, connect, and confirm the current password (hoa_dev_password) works.
- Edit docker-compose.yml's POSTGRES_PASSWORD to a different value and run docker compose up -d postgres again (without -v).
- Attempt to connect with the new password from the compose file and confirm it fails — the running instance still expects the old password.
- Run docker compose down -v, then docker compose up -d postgres, and confirm the new password from the compose file now works against the freshly initialized volume.
Deliverable
A short note recording the exact authentication failure message from step 3, and confirmation of success after the volume reset in step 4.
Completion checks
- Step 3's connection attempt fails with a password authentication error, not a connectivity error.
- Step 4 succeeds only after -v removes the existing volume.
After Postgres has already initialized its data directory once, what happens if you change POSTGRES_PASSWORD in docker-compose.yml and restart the container without removing its volume?
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.