tools/local-dev: docker-compose stack for UI development
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>
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
# Local development stack for the Galaxy UI.
|
||||
#
|
||||
# Brings up postgres + redis + mailpit + backend + gateway so the UI
|
||||
# Vite dev server (run on the host with `pnpm -C ui/frontend dev`) can
|
||||
# talk to a real authenticated stack without any cloud dependency.
|
||||
#
|
||||
# Browser: http://localhost:8080 (gateway public REST + Connect-Web)
|
||||
# Mailpit UI: http://localhost:8025
|
||||
# Postgres: localhost:5433 (host-mapped)
|
||||
# Redis: localhost:6380 (host-mapped)
|
||||
#
|
||||
# Bring up: make -C tools/local-dev up
|
||||
# Tear down: make -C tools/local-dev down
|
||||
# Wipe state: make -C tools/local-dev clean
|
||||
#
|
||||
# The backend reads `BACKEND_AUTH_DEV_FIXED_CODE=123456` from the
|
||||
# `.env` file alongside this compose; ConfirmEmailCode accepts that
|
||||
# literal in addition to the real bcrypt-verified code, so a developer
|
||||
# can log in without touching Mailpit. Real codes still arrive in
|
||||
# Mailpit; both paths coexist.
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: galaxy-local-dev-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: galaxy
|
||||
POSTGRES_PASSWORD: galaxy
|
||||
POSTGRES_DB: galaxy_backend
|
||||
ports:
|
||||
- "5433:5432"
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- galaxy-net
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U galaxy -d galaxy_backend"]
|
||||
interval: 3s
|
||||
timeout: 3s
|
||||
retries: 30
|
||||
start_period: 5s
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: galaxy-local-dev-redis
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- redis-server
|
||||
- --requirepass
|
||||
- galaxy-dev
|
||||
- --appendonly
|
||||
- "no"
|
||||
- --save
|
||||
- ""
|
||||
ports:
|
||||
- "6380:6379"
|
||||
networks:
|
||||
- galaxy-net
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "galaxy-dev", "PING"]
|
||||
interval: 3s
|
||||
timeout: 3s
|
||||
retries: 30
|
||||
start_period: 3s
|
||||
|
||||
mailpit:
|
||||
image: axllent/mailpit:v1.21
|
||||
container_name: galaxy-local-dev-mailpit
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8025:8025"
|
||||
networks:
|
||||
- galaxy-net
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "-O-", "http://localhost:8025/livez"]
|
||||
interval: 3s
|
||||
timeout: 3s
|
||||
retries: 30
|
||||
start_period: 3s
|
||||
|
||||
backend:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: tools/local-dev/backend.Dockerfile
|
||||
image: galaxy/backend:local-dev
|
||||
container_name: galaxy-local-dev-backend
|
||||
restart: unless-stopped
|
||||
user: "0:0"
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
mailpit:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
BACKEND_LOGGING_LEVEL: debug
|
||||
BACKEND_HTTP_LISTEN_ADDR: ":8080"
|
||||
BACKEND_GRPC_PUSH_LISTEN_ADDR: ":8081"
|
||||
BACKEND_POSTGRES_DSN: "postgres://galaxy:galaxy@postgres:5432/galaxy_backend?search_path=backend&sslmode=disable"
|
||||
BACKEND_SMTP_HOST: mailpit
|
||||
BACKEND_SMTP_PORT: "1025"
|
||||
BACKEND_SMTP_FROM: "galaxy-backend@galaxy.local"
|
||||
BACKEND_SMTP_TLS_MODE: none
|
||||
BACKEND_DOCKER_NETWORK: galaxy-local-dev-net
|
||||
BACKEND_GAME_STATE_ROOT: /var/lib/galaxy/game-state
|
||||
BACKEND_GEOIP_DB_PATH: /var/lib/galaxy/geoip.mmdb
|
||||
BACKEND_NOTIFICATION_ADMIN_EMAIL: admin@galaxy.local
|
||||
BACKEND_AUTH_CHALLENGE_THROTTLE_MAX: "100"
|
||||
BACKEND_MAIL_WORKER_INTERVAL: 500ms
|
||||
BACKEND_NOTIFICATION_WORKER_INTERVAL: 500ms
|
||||
BACKEND_OTEL_TRACES_EXPORTER: none
|
||||
BACKEND_OTEL_METRICS_EXPORTER: none
|
||||
BACKEND_AUTH_DEV_FIXED_CODE: ${BACKEND_AUTH_DEV_FIXED_CODE:-}
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- game-state:/var/lib/galaxy/game-state
|
||||
- ../../pkg/geoip/test-data/test-data/GeoIP2-Country-Test.mmdb:/var/lib/galaxy/geoip.mmdb:ro
|
||||
networks:
|
||||
- galaxy-net
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "-O-", "http://localhost:8080/healthz"]
|
||||
interval: 3s
|
||||
timeout: 3s
|
||||
retries: 60
|
||||
start_period: 10s
|
||||
|
||||
gateway:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: tools/local-dev/gateway.Dockerfile
|
||||
image: galaxy/gateway:local-dev
|
||||
container_name: galaxy-local-dev-gateway
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
GATEWAY_LOG_LEVEL: debug
|
||||
GATEWAY_PUBLIC_HTTP_ADDR: ":8080"
|
||||
GATEWAY_AUTHENTICATED_GRPC_ADDR: ":9090"
|
||||
GATEWAY_BACKEND_HTTP_URL: "http://backend:8080"
|
||||
GATEWAY_BACKEND_GRPC_PUSH_URL: "backend:8081"
|
||||
GATEWAY_BACKEND_GATEWAY_CLIENT_ID: local-dev-gateway-1
|
||||
GATEWAY_RESPONSE_SIGNER_PRIVATE_KEY_PEM_PATH: /run/secrets/gateway-response.pem
|
||||
GATEWAY_REDIS_MASTER_ADDR: "redis:6379"
|
||||
GATEWAY_REDIS_PASSWORD: galaxy-dev
|
||||
# Loosen anti-abuse so a developer hammering the form does not
|
||||
# rate-limit themselves between cycles.
|
||||
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_AUTH_RATE_LIMIT_REQUESTS: "10000"
|
||||
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_AUTH_RATE_LIMIT_BURST: "1000"
|
||||
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_SEND_EMAIL_CODE_IDENTITY_RATE_LIMIT_REQUESTS: "10000"
|
||||
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_SEND_EMAIL_CODE_IDENTITY_RATE_LIMIT_BURST: "1000"
|
||||
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_CONFIRM_EMAIL_CODE_IDENTITY_RATE_LIMIT_REQUESTS: "10000"
|
||||
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_CONFIRM_EMAIL_CODE_IDENTITY_RATE_LIMIT_BURST: "1000"
|
||||
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_IP_RATE_LIMIT_REQUESTS: "10000"
|
||||
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_IP_RATE_LIMIT_BURST: "1000"
|
||||
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_SESSION_RATE_LIMIT_REQUESTS: "10000"
|
||||
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_SESSION_RATE_LIMIT_BURST: "1000"
|
||||
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_USER_RATE_LIMIT_REQUESTS: "10000"
|
||||
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_USER_RATE_LIMIT_BURST: "1000"
|
||||
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_MESSAGE_CLASS_RATE_LIMIT_REQUESTS: "10000"
|
||||
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_MESSAGE_CLASS_RATE_LIMIT_BURST: "1000"
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- ./keys/gateway-response.pem:/run/secrets/gateway-response.pem:ro
|
||||
networks:
|
||||
- galaxy-net
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "-O-", "http://localhost:8080/healthz"]
|
||||
interval: 3s
|
||||
timeout: 3s
|
||||
retries: 30
|
||||
start_period: 5s
|
||||
|
||||
networks:
|
||||
galaxy-net:
|
||||
name: galaxy-local-dev-net
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
name: galaxy-local-dev-postgres-data
|
||||
game-state:
|
||||
name: galaxy-local-dev-game-state
|
||||
Reference in New Issue
Block a user