6f6a854337
vite.config.ts now proxies `/api` and `/galaxy.gateway.v1.EdgeGateway` to the gateway, so the browser sees only `localhost:5173` and never trips a cross-origin preflight. `.env.development` accordingly points `VITE_GATEWAY_BASE_URL` at the Vite origin. The proxy target is overridable via `VITE_DEV_PROXY_TARGET=...` for non-default gateways without touching the compose file. `gateway/Dockerfile` previously failed to build because gateway imports `galaxy/core` (replaced to `../ui/core` in `gateway/go.mod`) but the Dockerfile did not copy `ui/core/` into the build context nor declare the replace in the synthesised `go.work`. Adding both makes `docker build -f gateway/Dockerfile .` succeed; this is the same fix already shipped in `tools/local-dev/gateway.Dockerfile`, back-ported to upstream. Verified: - docker build -f gateway/Dockerfile . — builds cleanly - pnpm test 14/14, pnpm exec playwright test 44/44 (with CI=1 to force a fresh dev server; reuse keeps the previous startup env) - curl POST through localhost:5173/api/* and /galaxy.gateway.v1.* — reach the gateway, no CORS preflight on the browser side tools/local-dev/README.md updated with the new network map and the `VITE_DEV_PROXY_TARGET` override. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
174 lines
8.0 KiB
Markdown
174 lines
8.0 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"
|
|
┌────────────────────────────────┐ ┌──────────────────────────────┐
|
|
│ browser localhost:5173 │── pnpm dev (Vite, host) ──┐ │
|
|
│ ↳ /api/* proxied ───┼──────────────────────────▶│ gateway:8080 │
|
|
│ ↳ /galaxy.gateway... ┼──────────────────────────▶│ │
|
|
│ browser localhost:8025 │─────────────────────────▶│ mailpit:8025 │
|
|
│ psql localhost:5433 │─────────────────────────▶│ postgres:5432 │
|
|
│ redis-cli localhost:6380 │─────────────────────────▶│ redis:6379 │
|
|
└────────────────────────────────┘ │ ↳ backend:8080 (HTTP) │
|
|
│ ↳ backend:8081 (gRPC push) │
|
|
│ ↳ mailpit:1025 (SMTP in) │
|
|
└────────────────────────────────┘
|
|
```
|
|
|
|
Vite's dev server proxies `/api` and `/galaxy.gateway.v1.EdgeGateway`
|
|
to the gateway, so every browser request stays same-origin (no CORS
|
|
preflight). The gateway is therefore reachable only through Vite at
|
|
<http://localhost:5173>, not at <http://localhost:8080> from the
|
|
browser tab. Direct curl/wget against <http://localhost:8080> still
|
|
works for diagnostic probes — only the browser-side requests are
|
|
proxied.
|
|
|
|
Mailpit (8025), postgres (5433), and redis (6380) remain directly
|
|
reachable for diagnostics (`make psql`, `redis-cli -h localhost -p
|
|
6380 -a galaxy-dev`).
|
|
|
|
To point the proxy at a non-local gateway, run
|
|
`VITE_DEV_PROXY_TARGET=http://gateway.host:8080 pnpm -C ui/frontend dev`
|
|
— no compose changes needed.
|
|
|
|
## 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.
|