feat(infra): add local-dev Docker Compose stack #57

Merged
julien merged 1 commits from feat/infra/local-dev-stack into main 2026-05-08 19:23:43 +02:00
Owner

Summary

Bring up Postgres + Redis + OTel Collector in one command so contributors can run the BFF end-to-end without manually wiring each service. Replaces the throwaway docker run postgres:17-alpine one-liner that was in docs/development.md §3.

What lands

  • infra/local/dev.compose.yml — three core services (postgres:17.2-alpine, redis:7.4-alpine, otel/opentelemetry-collector-contrib:0.115.0) plus two viewers gated behind Compose profiles:
    • --profile dbtoolssosedoff/pgweb:0.16.2 (Postgres GUI on port 8081)
    • --profile observabilityjaegertracing/all-in-one:1.62 (Jaeger UI on 16686)
    • All ports overridable via .env. State in named volumes. Healthchecks on data services.
  • infra/local/.env.example — credentials + ports template. POSTGRES_PASSWORD and REDIS_PASSWORD are mandatory (compose refuses to boot without them); other keys default sensibly.
  • infra/local/init/postgres/01-init.sql — bootstrap SQL per ADR-0013: audit_owner / audit_writer / audit_reader / audit_archiver roles + audit schema. Default privileges encode the append-only contract (INSERT to writer, SELECT to reader, DELETE to archiver, no UPDATE/TRUNCATE to anyone). Applied on first Postgres boot only; documented re-run procedure.
  • infra/local/otel-collector.yaml — pipeline: OTLP gRPC/HTTP → batch → debug exporter (always) + forward to jaeger:4317. When the observability profile is off, the Jaeger export logs warn-level retries but doesn't block the debug pipeline.

Surrounding doc updates

  • infra/README.md — new "Local-dev stack" section: service inventory, port table, first-time setup walkthrough, persistence/bootstrap-replay tips. The previous local/ placeholder line is removed.
  • docs/development.md §3 — rewritten to walk through the compose-based setup; cross-links to infra/README.md for the full reference. Roadmap entry for "Local infra recipe" removed from §8 (now implemented); "Observability dev-loop" line adjusted to point at the new Jaeger profile.

Out of scope

  • Production parity — HA Postgres, Redis Sentinel, real OTel backend (Tempo / Loki / etc.) — defer to the on-prem infrastructure ADR (phase 3b). The dev-only nature of this stack is called out explicitly in infra/README.md.
  • Wiring the BFF to actually use these endpoints (NestJS config, Prisma datasource URL, OTel SDK init) — that's the B — Observability foundations chantier, next up.

Test plan

  • cd infra/local && cp .env.example .env && docker compose -f dev.compose.yml up -d → all three core services come up healthy; verify with docker compose ps.
  • psql postgres://portal:<pwd>@localhost:5432/portal_dev -c "\dn" shows the audit schema; \dg shows the four audit roles.
  • redis-cli -a <pwd> PINGPONG.
  • Send a fake OTLP trace via grpcurl → see it printed by docker compose logs otel-collector.
  • --profile dbtools up -dhttp://localhost:8081 shows pgweb UI, can navigate to the audit schema.
  • --profile observability up -dhttp://localhost:16686 shows Jaeger UI; collector logs no longer report Jaeger export retries.
  • docker compose down -v cleanly removes everything; next up -d re-runs the bootstrap SQL.
## Summary Bring up Postgres + Redis + OTel Collector in one command so contributors can run the BFF end-to-end without manually wiring each service. Replaces the throwaway `docker run postgres:17-alpine` one-liner that was in `docs/development.md` §3. ### What lands - **`infra/local/dev.compose.yml`** — three core services (`postgres:17.2-alpine`, `redis:7.4-alpine`, `otel/opentelemetry-collector-contrib:0.115.0`) plus two viewers gated behind Compose profiles: - `--profile dbtools` → `sosedoff/pgweb:0.16.2` (Postgres GUI on port 8081) - `--profile observability` → `jaegertracing/all-in-one:1.62` (Jaeger UI on 16686) - All ports overridable via `.env`. State in named volumes. Healthchecks on data services. - **`infra/local/.env.example`** — credentials + ports template. `POSTGRES_PASSWORD` and `REDIS_PASSWORD` are mandatory (compose refuses to boot without them); other keys default sensibly. - **`infra/local/init/postgres/01-init.sql`** — bootstrap SQL per **ADR-0013**: `audit_owner` / `audit_writer` / `audit_reader` / `audit_archiver` roles + `audit` schema. Default privileges encode the append-only contract (INSERT to writer, SELECT to reader, DELETE to archiver, no UPDATE/TRUNCATE to anyone). Applied on first Postgres boot only; documented re-run procedure. - **`infra/local/otel-collector.yaml`** — pipeline: OTLP gRPC/HTTP → batch → debug exporter (always) + forward to `jaeger:4317`. When the observability profile is off, the Jaeger export logs warn-level retries but doesn't block the debug pipeline. ### Surrounding doc updates - **`infra/README.md`** — new "Local-dev stack" section: service inventory, port table, first-time setup walkthrough, persistence/bootstrap-replay tips. The previous `local/` placeholder line is removed. - **`docs/development.md`** §3 — rewritten to walk through the compose-based setup; cross-links to `infra/README.md` for the full reference. Roadmap entry for "Local infra recipe" removed from §8 (now implemented); "Observability dev-loop" line adjusted to point at the new Jaeger profile. ### Out of scope - **Production parity** — HA Postgres, Redis Sentinel, real OTel backend (Tempo / Loki / etc.) — defer to the on-prem infrastructure ADR (phase 3b). The dev-only nature of this stack is called out explicitly in `infra/README.md`. - **Wiring the BFF** to actually use these endpoints (NestJS config, Prisma datasource URL, OTel SDK init) — that's the **B — Observability foundations** chantier, next up. ## Test plan - [x] `cd infra/local && cp .env.example .env && docker compose -f dev.compose.yml up -d` → all three core services come up healthy; verify with `docker compose ps`. - [x] `psql postgres://portal:<pwd>@localhost:5432/portal_dev -c "\dn"` shows the `audit` schema; `\dg` shows the four audit roles. - [ ] `redis-cli -a <pwd> PING` → `PONG`. - [ ] Send a fake OTLP trace via grpcurl → see it printed by `docker compose logs otel-collector`. - [ ] `--profile dbtools up -d` → http://localhost:8081 shows pgweb UI, can navigate to the audit schema. - [ ] `--profile observability up -d` → http://localhost:16686 shows Jaeger UI; collector logs no longer report Jaeger export retries. - [ ] `docker compose down -v` cleanly removes everything; next `up -d` re-runs the bootstrap SQL.
julien added 1 commit 2026-05-08 19:13:19 +02:00
feat(infra): add local-dev Docker Compose stack
CI / commits (pull_request) Successful in 1m4s
CI / check (pull_request) Successful in 1m12s
CI / scan (pull_request) Successful in 1m12s
CI / a11y (pull_request) Successful in 37s
CI / perf (pull_request) Successful in 1m29s
6123953165
Bring up Postgres + Redis + OTel Collector in one command so
contributors can run the BFF end-to-end without each setting up
the runtime services manually. Replaces the throwaway
`docker run postgres:17-alpine` one-liner that was in §3 of
docs/development.md.

What lands:

- `infra/local/dev.compose.yml` — three core services
  (postgres 17.2-alpine, redis 7.4-alpine,
  otel/opentelemetry-collector-contrib 0.115.0) plus two
  viewers gated behind Compose profiles (pgweb under
  `--profile dbtools`, Jaeger 1.62 under
  `--profile observability`). All ports overridable via .env;
  state in named volumes; healthchecks on the data services.
- `infra/local/.env.example` — credentials + ports template.
  POSTGRES_PASSWORD and REDIS_PASSWORD are mandatory (compose
  refuses to boot without them); other keys default sensibly.
- `infra/local/init/postgres/01-init.sql` — bootstrap SQL per
  ADR-0013: `audit_owner` / `audit_writer` / `audit_reader` /
  `audit_archiver` roles plus `audit` schema, with default
  privileges encoding the append-only contract (INSERT to
  writer, SELECT to reader, DELETE to archiver, no UPDATE /
  TRUNCATE to anyone). Applied on first Postgres boot only;
  documented re-run procedure in infra/README.md.
- `infra/local/otel-collector.yaml` — pipeline: OTLP gRPC/HTTP
  → batch → debug exporter (always) + forward to `jaeger:4317`
  (no-op when the observability profile is off; logs warn-level
  retry but doesn't block other exporters).

Surrounding docs updated:

- `infra/README.md` — new "Local-dev stack" section with
  service inventory, port table, first-time setup, operational
  tips. The `local/` row replaces the previous placeholder.
- `docs/development.md` §3 — rewritten to walk through the
  compose-based setup; cross-links to `infra/README.md` for
  the full reference. Roadmap entry for "Local infra recipe"
  removed from §8 (now implemented); "Observability dev-loop"
  entry adjusted to point at the new Jaeger profile.

Production parity is intentionally left for the on-prem
infrastructure ADR (phase 3b) — this is the dev-only stack.
julien merged commit 0f00d6d93f into main 2026-05-08 19:23:43 +02:00
julien deleted branch feat/infra/local-dev-stack 2026-05-08 19:23:44 +02:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: julien/apf_portal#57