feat(infra): add dev.sh wrapper for the local-dev compose stack (#68)
CI / check (push) Successful in 1m36s
CI / commits (push) Has been skipped
CI / scan (push) Successful in 2m9s
CI / a11y (push) Successful in 1m9s
CI / perf (push) Successful in 3m1s

## Summary

Two recurring frictions on the local-dev stack:

1. **Compose-profile asymmetry** — `docker compose down` only operates on services whose profile is currently active. Anything brought up with `--profile X` keeps running unless the same flag is passed on `down`. pgweb and Jaeger silently survived several `down -v` invocations before we noticed (#67 documented the gotcha; this PR makes it impossible to hit if you use the wrapper).
2. **Verbose invocations** — typing `docker compose -f infra/local/dev.compose.yml --profile … <verb>` for routine ops gets old fast.

Add [`infra/local/dev.sh`](infra/local/dev.sh) as a thin wrapper. Always passes every profile in scope on teardown / status / log commands, exposes ergonomic verbs:

| Command                                       | Effect                                                          |
| --------------------------------------------- | --------------------------------------------------------------- |
| `./infra/local/dev.sh up`                     | Core only (postgres + redis + otel-collector)                   |
| `./infra/local/dev.sh up all`                 | Core + every profile                                            |
| `./infra/local/dev.sh up dbtools`             | Core + pgweb                                                    |
| `./infra/local/dev.sh up observability`       | Core + Jaeger                                                   |
| `./infra/local/dev.sh down [-v]`              | Tear down (every profile in scope, no orphaned services)        |
| `./infra/local/dev.sh stop <service>`         | Stop one service (containers stay around)                       |
| `./infra/local/dev.sh restart <service>`      | Restart one service                                             |
| `./infra/local/dev.sh status`                 | `ps` with every profile visible                                 |
| `./infra/local/dev.sh logs [service]`         | Follow logs                                                     |
| `./infra/local/dev.sh exec <service> <cmd>`   | Run a command inside a container                                |

Anything not matching one of the named verbs is passed through to `docker compose -f dev.compose.yml ...` (with every profile flagged in), so the full Compose surface remains available.

## Doc updates

- **`infra/README.md`** — new "Convenience script" subsection with the cheat-sheet table; "First-time setup" rewritten to use the script; the standalone "Profile symmetry" tip from #67 is collapsed into a one-liner since the script now handles it (the note remains as a fallback for direct `docker compose` users).
- **`docs/development.md` §3** — points at the script for the typical setup flow.

The compose file itself is unchanged.

## Test plan

- [ ] `./infra/local/dev.sh help` prints the usage block.
- [ ] `./infra/local/dev.sh up` brings up the 3 core services (no pgweb / no jaeger).
- [ ] `./infra/local/dev.sh up all` adds pgweb and Jaeger.
- [ ] `./infra/local/dev.sh down -v` stops and removes all 5 containers (incl. pgweb and Jaeger), wipes the postgres-data and redis-data volumes.
- [ ] `./infra/local/dev.sh stop pgweb` stops just pgweb.
- [ ] `./infra/local/dev.sh logs otel-collector` follows that service's logs.
- [ ] `./infra/local/dev.sh exec postgres psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\du"` lists the audit roles.
- [ ] `./infra/local/dev.sh stop` (no arg) errors with a clear message.

---------

Co-authored-by: Julien Gautier <julien.gautier@apf.asso.fr>
Reviewed-on: #68
This commit was merged in pull request #68.
This commit is contained in:
2026-05-09 21:50:37 +02:00
parent 4d2d4d652a
commit fc9b63f24a
3 changed files with 190 additions and 25 deletions
+6 -5
View File
@@ -99,7 +99,7 @@ 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 the local infrastructure stack — Postgres, Redis, OpenTelemetry Collector — provisioned via Docker Compose:
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. A thin wrapper script ([`infra/local/dev.sh`](../infra/local/dev.sh)) hides Compose-profile quirks and gives ergonomic verbs:
```bash
# 1. Configure infra secrets (copy template, edit, do not commit).
@@ -108,11 +108,12 @@ $EDITOR infra/local/.env
# Set strong dev values for POSTGRES_PASSWORD and REDIS_PASSWORD.
# 2. Bring up the core stack (postgres + redis + otel-collector).
docker compose -f infra/local/dev.compose.yml up -d
./infra/local/dev.sh up
# 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
./infra/local/dev.sh up dbtools # adds pgweb (http://localhost:8081)
./infra/local/dev.sh up observability # adds Jaeger UI (http://localhost:16686)
./infra/local/dev.sh up all # core + every profile
# 4. App-side env from .env.example, then fill in DATABASE_URL pointing
# to the compose-managed Postgres (matches the values you set in
@@ -120,7 +121,7 @@ docker compose -f infra/local/dev.compose.yml --profile observability up -d #
cp apps/portal-bff/.env.example apps/portal-bff/.env
```
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".
`./infra/local/dev.sh help` lists the rest of the verbs (`down`, `status`, `logs`, `stop`, `restart`, `exec`). Full reference — service inventory, port table, persistence, bootstrap re-run procedure — lives in [`infra/README.md`](../infra/README.md) → "Local-dev stack".
---