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

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.
This commit is contained in:
Julien Gautier
2026-05-08 18:54:22 +02:00
parent a93ee16091
commit 6123953165
6 changed files with 390 additions and 37 deletions
+32 -24
View File
@@ -97,19 +97,28 @@ cd apps/portal-bff && pnpm exec prisma generate && cd ../..
pnpm nx run-many -t lint test build
```
For the BFF to actually run end-to-end, you'll also need:
For the BFF to actually run end-to-end, you'll also need the local infrastructure stack — Postgres, Redis, OpenTelemetry Collector — provisioned via Docker Compose:
```bash
# .env from .env.example, then fill in DATABASE_URL with your local Postgres
cp apps/portal-bff/.env.example apps/portal-bff/.env
# 1. Configure infra secrets (copy template, edit, do not commit).
cp infra/local/.env.example infra/local/.env
$EDITOR infra/local/.env
# Set strong dev values for POSTGRES_PASSWORD and REDIS_PASSWORD.
# Local Postgres via Docker (one-liner; will be replaced by a Docker Compose file in a later doc)
docker run -d --name apf-postgres -p 5432:5432 \
-e POSTGRES_USER=portal -e POSTGRES_PASSWORD=portal -e POSTGRES_DB=portal_dev \
postgres:17-alpine
# 2. Bring up the core stack (postgres + redis + otel-collector).
docker compose -f infra/local/dev.compose.yml up -d
# 3. (Optional) Activate viewers when debugging:
docker compose -f infra/local/dev.compose.yml --profile dbtools up -d # pgweb
docker compose -f infra/local/dev.compose.yml --profile observability up -d # Jaeger UI
# 4. App-side env from .env.example, then fill in DATABASE_URL pointing
# to the compose-managed Postgres (matches the values you set in
# infra/local/.env).
cp apps/portal-bff/.env.example apps/portal-bff/.env
```
A proper local-dev infra spec (Postgres HA-like, Redis, OTel collector) will land with the on-prem infrastructure ADR; in the meantime the one-liner above is sufficient to run the BFF.
Full reference for the local stack — service inventory, port table, persistence, bootstrap re-run procedure — lives in [`infra/README.md`](../infra/README.md) → "Local-dev stack".
---
@@ -350,19 +359,18 @@ This doc starts as a phase-1 + cross-cutting reference. As features for later ph
When a section grows beyond a short subsection, it is extracted to its own file under `docs/development/`. Per the documentation convention (see [README.md](README.md)), we group into a folder once we have at least three related files; this doc is then re-organised into an index pointing at the extracted files. Until then, all sections live here.
| Future section | Phase | Triggered by |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Local infra recipe** — Docker Compose for Postgres, Redis, OTel Collector, and a Postgres-friendly viewer. | 2 / 3b | First feature that needs Redis (sessions, ADR-0010). Earlier if the BFF gains a meaningful amount of business code. |
| **Auth dev-loop** — Microsoft 365 Developer tenant configuration, MSAL Node connection, OIDC code-flow walkthrough, switching between dev and prod-like tenants. | 2 | Auth flow code lands ([ADR-0009](decisions/0009-auth-flow-oidc-pkce-msal-node.md)) once the dev tenant is provisioned by IT. |
| **Session inspection** — reading the Redis session store in dev, decrypting the AES-GCM `tokens` blob with the dev key, force-logout patterns. | 2 | Sessions module lands ([ADR-0010](decisions/0010-session-management-redis.md)). |
| **MFA step-up debugging** — triggering claims-challenge flows, verifying `mfaVerifiedAt` freshness, testing the SPA HTTP interceptor that handles 401 + claims challenge. | 2 | First `@RequireMfa()` route lands ([ADR-0011](decisions/0011-mfa-enforcement-entra-conditional-access.md)). |
| **Observability dev-loop** — running an OTel collector container locally, viewing traces (Tempo / Jaeger UI), reading Pino logs with `pino-pretty`, correlating front spans to BFF spans via `traceparent`. | 2 | OTel SDK setup lands ([ADR-0012](decisions/0012-observability-pino-opentelemetry.md)); needs the local collector from "Local infra recipe". |
| **Audit-log inspection workflow** — querying `audit.events` as `audit_reader`, joining with app logs by `trace_id`, validating the append-only role grants in dev. | 2 | Audit module lands ([ADR-0013](decisions/0013-audit-trail-separated-postgres-append-only.md)). |
| **Downstream API integration recipe** — adding a new `DownstreamApiConfig`, choosing the auth strategy (OBO vs service+assertion), wiring resilience policies, testing with a mocked downstream. | 2 | First downstream client lands ([ADR-0014](decisions/0014-downstream-api-access-obo-pattern.md)). |
| **Component patterns library** — the in-house, spartan-style components (Angular CDK + Tailwind) as they ship, with a11y notes per component (keyboard model, ARIA, screen-reader expectations). | 5b suite | First non-placeholder component in `libs/shared/ui/`. |
| **a11y testing workflow** — running axe-core via Playwright locally, screen-reader testing notes (NVDA / VoiceOver / TalkBack), the APF user-panel cadence and how to triage findings. | 3a | First Playwright e2e suite touching real screens ([ADR-0016](decisions/0016-accessibility-baseline-wcag-aa-targeted-aaa.md)). |
| **Performance debugging** — running Lighthouse CI locally with full config, reading the HTML reports, using `source-map-explorer` to investigate bundle bloat, interpreting BFF p95/p99 from OTel. | 3a | Lighthouse already wired in CI ([ADR-0017](decisions/0017-performance-budgets-lighthouse-ci.md)); section grows when first real route is added to the critical-routes list. |
| **Debugging tips** — Angular DevTools, NestJS inspector, Prisma query log, OTel trace navigation, common gotchas. | cross | Accumulates organically as the team encounters them. |
| **Release workflow** — tag-driven release, what `release.yml` does, version bumping, changelog generation from Conventional Commits. | 3b | On-prem infrastructure ADR + populated `release.yml`. |
| **GitLab migration runbook** — when the org migrates Gitea → GitLab, how the workflows are ported, which level-2 sections of [ADR-0015](decisions/0015-cicd-gitea-actions.md) get superseded. | future | GitLab migration ADR (618 months horizon). |
| **Architecture overview diagrams** — high-level component diagrams, data-flow diagrams, trust boundaries (for security review). | cross | First major architecture review or onboarding cohort ≥ 3 contributors. |
| Future section | Phase | Triggered by |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Auth dev-loop** — Microsoft 365 Developer tenant configuration, MSAL Node connection, OIDC code-flow walkthrough, switching between dev and prod-like tenants. | 2 | Auth flow code lands ([ADR-0009](decisions/0009-auth-flow-oidc-pkce-msal-node.md)) once the dev tenant is provisioned by IT. |
| **Session inspection** — reading the Redis session store in dev, decrypting the AES-GCM `tokens` blob with the dev key, force-logout patterns. | 2 | Sessions module lands ([ADR-0010](decisions/0010-session-management-redis.md)). |
| **MFA step-up debugging** — triggering claims-challenge flows, verifying `mfaVerifiedAt` freshness, testing the SPA HTTP interceptor that handles 401 + claims challenge. | 2 | First `@RequireMfa()` route lands ([ADR-0011](decisions/0011-mfa-enforcement-entra-conditional-access.md)). |
| **Observability dev-loop** — viewing traces in the Jaeger UI provisioned by `infra/local/dev.compose.yml --profile observability`, reading Pino logs with `pino-pretty`, correlating front spans to BFF spans via `traceparent`. | 2 | OTel SDK setup lands ([ADR-0012](decisions/0012-observability-pino-opentelemetry.md)). |
| **Audit-log inspection workflow** — querying `audit.events` as `audit_reader`, joining with app logs by `trace_id`, validating the append-only role grants in dev. | 2 | Audit module lands ([ADR-0013](decisions/0013-audit-trail-separated-postgres-append-only.md)). |
| **Downstream API integration recipe** — adding a new `DownstreamApiConfig`, choosing the auth strategy (OBO vs service+assertion), wiring resilience policies, testing with a mocked downstream. | 2 | First downstream client lands ([ADR-0014](decisions/0014-downstream-api-access-obo-pattern.md)). |
| **Component patterns library** — the in-house, spartan-style components (Angular CDK + Tailwind) as they ship, with a11y notes per component (keyboard model, ARIA, screen-reader expectations). | 5b suite | First non-placeholder component in `libs/shared/ui/`. |
| **a11y testing workflow** — running axe-core via Playwright locally, screen-reader testing notes (NVDA / VoiceOver / TalkBack), the APF user-panel cadence and how to triage findings. | 3a | First Playwright e2e suite touching real screens ([ADR-0016](decisions/0016-accessibility-baseline-wcag-aa-targeted-aaa.md)). |
| **Performance debugging** — running Lighthouse CI locally with full config, reading the HTML reports, using `source-map-explorer` to investigate bundle bloat, interpreting BFF p95/p99 from OTel. | 3a | Lighthouse already wired in CI ([ADR-0017](decisions/0017-performance-budgets-lighthouse-ci.md)); section grows when first real route is added to the critical-routes list. |
| **Debugging tips** — Angular DevTools, NestJS inspector, Prisma query log, OTel trace navigation, common gotchas. | cross | Accumulates organically as the team encounters them. |
| **Release workflow** — tag-driven release, what `release.yml` does, version bumping, changelog generation from Conventional Commits. | 3b | On-prem infrastructure ADR + populated `release.yml`. |
| **GitLab migration runbook**when the org migrates Gitea → GitLab, how the workflows are ported, which level-2 sections of [ADR-0015](decisions/0015-cicd-gitea-actions.md) get superseded. | future | GitLab migration ADR (618 months horizon). |
| **Architecture overview diagrams** — high-level component diagrams, data-flow diagrams, trust boundaries (for security review). | cross | First major architecture review or onboarding cohort ≥ 3 contributors. |