feat(infra): add dev.sh wrapper for the local-dev compose stack #68

Merged
julien merged 1 commits from feat/infra/dev-sh-wrapper into main 2026-05-09 21:50:38 +02:00
Owner

Summary

Two recurring frictions on the local-dev stack:

  1. Compose-profile asymmetrydocker 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 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.
## 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.
julien added 1 commit 2026-05-09 21:48:55 +02:00
feat(infra): add dev.sh wrapper for the local-dev compose stack
CI / commits (pull_request) Successful in 1m19s
CI / check (pull_request) Successful in 1m25s
CI / scan (pull_request) Successful in 1m28s
CI / a11y (pull_request) Successful in 1m37s
CI / perf (pull_request) Successful in 3m37s
7a475a52fb
Direct `docker compose -f infra/local/dev.compose.yml ...` works
fine, but two things kept biting on this stack:

- Compose-profile asymmetry — `down` only operates on services
  whose profile is currently active, so anything brought up with
  `--profile X` keeps running unless the same flag is on `down`.
  pgweb and Jaeger silently survived several `down -v` invocations
  before we spotted it.
- Verbose invocations — typing the compose-file flag and the
  profile flags on every command for routine ops gets old fast.

Add `infra/local/dev.sh` as a thin wrapper:

  ./infra/local/dev.sh up                 # core only
  ./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]          # always with all profiles
  ./infra/local/dev.sh stop <service>     # stop one service
  ./infra/local/dev.sh restart <service>  # restart one service
  ./infra/local/dev.sh status             # ps with all profiles
  ./infra/local/dev.sh logs [service]     # follow logs
  ./infra/local/dev.sh exec <svc> <cmd>   # run 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 without losing
the profile-symmetry guarantee.

Docs:

- `infra/README.md` "Local-dev stack" — new "Convenience script"
  subsection with the cheat-sheet table; "First-time setup" walk-
  through rewritten to use the script; the previous standalone
  "Profiles must match on `down` as on `up`" tip is collapsed
  into a one-liner since the script handles it.
- `docs/development.md` §3 — point at the script for the typical
  setup flow.

The compose file itself is unchanged.
julien merged commit fc9b63f24a into main 2026-05-09 21:50:38 +02:00
julien deleted branch feat/infra/dev-sh-wrapper 2026-05-09 21:50:38 +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#68