69fa6b30e1
Adds tools/local-dev/ with postgres + redis + mailpit + backend + gateway plus a Make wrapper, so `make -C tools/local-dev up` brings the full authenticated stack online and `pnpm -C ui/frontend dev` talks to it directly. The committed `.env.development` already points at the stack and pins the matching gateway response public key from the dev keypair under tools/local-dev/keys/. The backend ships a new opt-in env, BACKEND_AUTH_DEV_FIXED_CODE (`tools/local-dev/.env` defaults it to 123456). When set, ConfirmEmailCode accepts that literal in addition to the real bcrypt-verified code; SendEmailCode still queues a real email so Mailpit captures the issued code at http://localhost:8025/, and both paths coexist. The override is rejected as non-six-digit by config validation and emits a loud warning at backend startup. The local-dev Dockerfiles mirror backend/Dockerfile and gateway/Dockerfile but switch the runtime stage to alpine so docker-compose healthchecks can wget /healthz; the gateway Dockerfile additionally copies ui/core/ into the build context because gateway/go.mod's `replace galaxy/core => ../ui/core` is required to compile the gateway main. Smoke tested: - `make -C tools/local-dev up` boots all five services to healthy. - send-email-code + confirm-email-code with code=123456 returns a device_session_id; a real code in Mailpit also redeems successfully. - `pnpm test` 14/14, `pnpm exec playwright test` 44/44. - `go test ./backend/internal/config/...` green. Docs: tools/local-dev/README.md, tools/local-dev/keys/README.md, new "Local development stack" section in ui/docs/testing.md, and a short pointer in ui/README.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
162 lines
7.1 KiB
Markdown
162 lines
7.1 KiB
Markdown
# `tools/local-dev/` — Galaxy local development stack
|
|
|
|
A docker-compose stack that brings up postgres + redis + mailpit +
|
|
backend + gateway so the UI Vite dev server (run on the host) can
|
|
talk to a real authenticated stack without any cloud dependency.
|
|
|
|
The stack is the recommended baseline for UI work that goes beyond
|
|
the mocked Playwright fixtures: every payload exercises the real
|
|
FlatBuffers wire, every authenticated call verifies the response
|
|
signature against the dev keypair, and every email passes through
|
|
Mailpit's web UI for inspection.
|
|
|
|
This stack is **not** a CI gate (that role belongs to
|
|
[`tools/local-ci/`](../local-ci/README.md), which boots a Gitea +
|
|
Actions runner and replays workflow files). The two stacks are
|
|
independent and can coexist on the same machine; they bind different
|
|
ports and use different networks.
|
|
|
|
## Bring it up
|
|
|
|
```sh
|
|
make -C tools/local-dev up
|
|
```
|
|
|
|
`up` builds the local-dev backend and gateway images on first run
|
|
(pulls postgres, redis, mailpit), waits for every service to report
|
|
healthy, and returns. Subsequent invocations reuse the built images.
|
|
|
|
After the stack is healthy:
|
|
|
|
```sh
|
|
pnpm -C ui/frontend dev
|
|
```
|
|
|
|
Open <http://localhost:5173> for the UI and
|
|
<http://localhost:8025> for Mailpit.
|
|
|
|
## Daily flow
|
|
|
|
```sh
|
|
make -C tools/local-dev up # bring up (idempotent, fast on warm cache)
|
|
pnpm -C ui/frontend dev # in another terminal
|
|
# ...edit UI, browse, repeat...
|
|
make -C tools/local-dev down # stop containers, keep state
|
|
```
|
|
|
|
State persists in named Docker volumes between `up`/`down` cycles, so
|
|
games created on Tuesday survive into Wednesday. Wipe with
|
|
`make clean` when you want a fresh database.
|
|
|
|
## Logging in
|
|
|
|
Two paths coexist by default:
|
|
|
|
1. **Fixed dev code (fast).** `tools/local-dev/.env` ships
|
|
`BACKEND_AUTH_DEV_FIXED_CODE=123456`. After requesting a code in
|
|
the UI, type `123456` — `ConfirmEmailCode` accepts that literal
|
|
in addition to the real bcrypt-verified code stored on the
|
|
challenge row. The override emits a loud warning at backend boot
|
|
and is rejected by the production env loader (`BACKEND_ENV` guard
|
|
in `backend/internal/config`).
|
|
2. **Real Mailpit code.** Open <http://localhost:8025>, find the
|
|
most recent message, copy the six-digit code, paste it into the
|
|
UI. This exercises the full mail outbox path, including SMTP
|
|
handoff and gomail TLS-mode handling.
|
|
|
|
To force the second path (no fast-bypass), edit
|
|
`tools/local-dev/.env` and clear `BACKEND_AUTH_DEV_FIXED_CODE`, then
|
|
`make rebuild` (or simply `docker compose up -d backend` to recreate
|
|
the backend with the new env).
|
|
|
|
## Network map
|
|
|
|
```
|
|
host compose network "galaxy-local-dev-net"
|
|
┌────────────────────────────┐ ┌──────────────────────────────┐
|
|
│ pnpm dev localhost:5173 │──HMR──▶│ host (Vite) │
|
|
│ browser localhost:8080 │──REST/Connect─▶│ gateway:8080 │
|
|
│ browser localhost:8025 │─────▶│ mailpit:8025 (web UI) │
|
|
│ psql localhost:5433 │─────▶│ postgres:5432 │
|
|
│ redis-cli localhost:6380 │─────▶│ redis:6379 │
|
|
└────────────────────────────┘ │ ↳ backend:8080 (HTTP) │
|
|
│ ↳ backend:8081 (gRPC push) │
|
|
│ ↳ mailpit:1025 (SMTP in) │
|
|
└──────────────────────────────┘
|
|
```
|
|
|
|
Only the gateway public port (8080) and the mailpit web UI (8025)
|
|
are needed for normal UI work. Postgres (5433) and Redis (6380) are
|
|
exposed for direct inspection (`make psql`, `redis-cli -h localhost
|
|
-p 6380 -a galaxy-dev`).
|
|
|
|
## Make targets
|
|
|
|
```text
|
|
make up Bring up the stack (build if needed) and wait for health
|
|
make rebuild Rebuild the backend / gateway images (ignores cache)
|
|
make down Stop containers, keep volumes
|
|
make clean Stop and wipe volumes (postgres + game-state)
|
|
make logs Tail every service's logs
|
|
make logs-backend Tail backend only
|
|
make logs-gateway Tail gateway only
|
|
make logs-mail Tail mailpit only
|
|
make psql Open a psql shell as galaxy@galaxy_backend
|
|
make status docker compose ps
|
|
```
|
|
|
|
## Files
|
|
|
|
- `docker-compose.yml` — five services: postgres, redis, mailpit,
|
|
backend, gateway, plus shared network and volumes.
|
|
- `backend.Dockerfile`, `gateway.Dockerfile` — local-dev runtime
|
|
images built on alpine (so `wget` is available for the compose
|
|
healthchecks). The build stage mirrors `backend/Dockerfile` and
|
|
`gateway/Dockerfile` exactly.
|
|
- `Makefile` — wrapper over `docker compose` that keeps the muscle
|
|
memory close to `tools/local-ci/`'s Makefile.
|
|
- `.env` — committed defaults for the compose `${VAR:-}`
|
|
expansions. Edit per-developer or override via your shell.
|
|
- `keys/gateway-response.pem`, `keys/gateway-response.pub` — dev-only
|
|
Ed25519 keypair used by the gateway for response signing. Pairs
|
|
with the `VITE_GATEWAY_RESPONSE_PUBLIC_KEY` value in
|
|
`ui/frontend/.env.development`. See `keys/README.md` before
|
|
rotating.
|
|
- `keys/regenerate.go` — one-shot Go helper that regenerates the
|
|
pair and prints the new base64 public key.
|
|
|
|
## Troubleshooting
|
|
|
|
- **`make up` reports a build error mentioning `pkg/cronutil`** —
|
|
upstream module list drifted; copy any new `pkg/<name>/` line into
|
|
the local-dev `backend.Dockerfile` / `gateway.Dockerfile` to match
|
|
`backend/Dockerfile` / `gateway/Dockerfile`.
|
|
- **Gateway exits at boot with "redis: …"** — the redis container is
|
|
still bootstrapping. `make up --wait` waits for healthchecks; if
|
|
it times out, increase `start_period` in the gateway service or
|
|
inspect `make logs-redis`.
|
|
- **Login form rejects every code** — confirm
|
|
`BACKEND_AUTH_DEV_FIXED_CODE` is set in `tools/local-dev/.env` and
|
|
the backend has been recreated since the last edit
|
|
(`docker compose up -d backend`). Real Mailpit codes work
|
|
regardless.
|
|
- **UI talks to old gateway**: Vite caches `import.meta.env` at boot.
|
|
Restart `pnpm dev` after editing
|
|
`ui/frontend/.env.development.local`.
|
|
- **Port 8080 already in use** — stop the conflicting service or
|
|
edit the host-side mapping in `docker-compose.yml` (gateway's
|
|
`ports:` entry) plus the matching `VITE_GATEWAY_BASE_URL` in
|
|
`ui/frontend/.env.development.local`.
|
|
|
|
## Relationship to other infrastructure
|
|
|
|
- `tools/local-ci/` — Gitea + Actions runner, replays
|
|
`.gitea/workflows/*` against a pushed branch. Different stack,
|
|
different purpose; coexists with local-dev on the same machine.
|
|
- `integration/testenv/` — testcontainers harness used by
|
|
`make -C integration integration`. Uses the same images
|
|
(`backend/Dockerfile`, `gateway/Dockerfile`) at production
|
|
defaults; do not confuse with this local-dev stack, which carries
|
|
alpine-runtime images for ergonomics and the dev-mode auth
|
|
override.
|