# `tools/dev-deploy/` — long-lived Galaxy dev environment A docker-compose stack that runs the Galaxy backend, gateway, supporting services, and a small Caddy in front of them, reachable through the host Caddy at `https://www.galaxy.lan` and `https://api.galaxy.lan`. Used by the `dev-deploy.yaml` Gitea Actions workflow as the canonical dev target on every merge into the `development` branch, and runnable by hand through this Makefile for local debugging of the deploy plumbing itself. This stack is **not** the developer's primary playground for UI work — that role still belongs to [`tools/local-dev/`](../local-dev/README.md), which is faster (Vite HMR, host-side dev server) and isolated to one developer. The two stacks coexist on the same host because every name is distinct: | | `tools/local-dev/` | `tools/dev-deploy/` | |------------------|------------------------------|-----------------------------| | Compose project | `local-dev` | `galaxy-dev` | | Container prefix | `galaxy-local-dev-*` | `galaxy-dev-*` | | Network | `galaxy-local-dev-net` | `galaxy-dev-internal`, `edge` | | Volumes | `galaxy-local-dev-*` | `galaxy-dev-*` | | Host ports | 5433/6380/8025/8080/9090 | none (only `edge` network) | | Game state | `/tmp/galaxy-game-state` | `/var/lib/galaxy-dev/game-state` | | Engine image | `galaxy-engine:local-dev` | `galaxy-engine:dev` | ## Prerequisites The host must already provide: - Docker daemon reachable as the user running `make` (member of the `docker` group, no sudo). - An external bridge network named `edge` (or whatever `GALAXY_EDGE_NETWORK` overrides to): ```sh docker network create edge ``` - A host Caddy listening on `:80`/`:443`, attached to the `edge` network, and proxying `www.galaxy.lan` and `api.galaxy.lan` to `galaxy-caddy:80`. Example fragment for the host Caddyfile: ```caddy www.galaxy.lan, api.galaxy.lan { tls internal reverse_proxy galaxy-caddy:80 } ``` - Game-state directory writable by the user running `make`. Default is `${HOME}/.galaxy-dev/game-state`; `make up` creates it on demand. Override by exporting `GALAXY_DEV_GAME_STATE_DIR` (e.g. to `/var/lib/galaxy-dev/game-state` once the host is provisioned for it). ## Bring it up ```sh make -C tools/dev-deploy up ``` `up` (re)builds the local-dev backend and gateway images, makes sure the engine image `galaxy-engine:dev` exists, and waits for healthchecks. It does **not** seed the UI volume — that is normally done by CI. The first time you run by hand: ```sh make -C tools/dev-deploy seed-ui make -C tools/dev-deploy up make -C tools/dev-deploy health ``` `seed-ui` runs `pnpm build` in `ui/frontend/`, then copies the resulting `build/` tree into the `galaxy-dev-ui-dist` volume. Subsequent CI deploys overwrite this volume automatically. ## Daily flow ```sh make -C tools/dev-deploy rebuild # rebuild backend/gateway images + up make -C tools/dev-deploy logs # tail compose logs make -C tools/dev-deploy health # probe https://*.galaxy.lan make -C tools/dev-deploy down # stop, keep state ``` State persists in named volumes between `up`/`down` cycles. The `development` branch keeps the dev environment continuously usable — games created last week survive into this week unless somebody calls `make clean-data`. ## Logging in The same dev-mode email-code override as `tools/local-dev/` applies: 1. Enter `dev@galaxy.lan` (or whatever `BACKEND_DEV_SANDBOX_EMAIL` resolves to) in the login form. 2. Submit `123456` as the code if `BACKEND_AUTH_DEV_FIXED_CODE` is non-empty. Otherwise open Mailpit at `http://galaxy-mailpit:8025/` from inside the network or proxy it through the host Caddy when needed. The fixed-code override is rejected by production env loaders, so it cannot leak into the prod environment. ## Networking ``` Browser │ https://www.galaxy.lan, https://api.galaxy.lan ▼ host-Caddy (:80, :443, TLS, attached to `edge` network) │ reverse_proxy *.galaxy.lan → galaxy-caddy:80 ▼ galaxy-caddy (networks: edge + galaxy-dev-internal) │ www.galaxy.lan → file_server /srv/galaxy-ui (volume galaxy-dev-ui-dist) │ api.galaxy.lan → reverse_proxy galaxy-api:8080 ▼ galaxy-dev-internal ├─ galaxy-api (gateway: :8080 REST, :9090 gRPC) ├─ galaxy-backend (backend: :8080 HTTP, :8081 gRPC push) ├─ galaxy-postgres (postgres: :5432) ├─ galaxy-redis (redis: :6379) ├─ galaxy-mailpit (mailpit: :8025 UI, :1025 SMTP) └─ engine containers (spawned by backend on demand) ``` The compose project deliberately exposes no host ports. Diagnostics that used to go through `localhost:8025` etc. now go through the container network: `docker compose -f tools/dev-deploy/docker-compose.yml exec galaxy-mailpit wget -qO- localhost:8025/messages` and similar. ## Persistent state and schema changes The dev Postgres volume `galaxy-dev-postgres-data` survives redeploys. Until the pre-production migration rule is lifted, every backward-incompatible change to `backend/internal/postgres/migrations/00001_init.sql` needs a manual wipe before the next deploy succeeds: ```sh make -C tools/dev-deploy clean-data make -C tools/dev-deploy up ``` This is the same caveat as `tools/local-dev/`, just with a different volume name. ## Make targets ```text make up Build images, ensure engine image, bring stack up (waits for health) make rebuild Rebuild backend / gateway images (ignores cache), then up make seed-ui pnpm build + load build/ into galaxy-dev-ui-dist volume make build-engine Build galaxy-engine:dev (no-op if image already present) make down Stop containers, keep named volumes make logs Tail compose logs make status docker compose ps make health curl https://www.galaxy.lan + https://api.galaxy.lan/healthz make psql psql as galaxy@galaxy_backend make clean-data Stop everything and wipe volumes + game-state dir ``` ## Files - `docker-compose.yml` — six services: postgres, redis, mailpit, galaxy-backend, galaxy-api, galaxy-caddy. Reuses the alpine-runtime Dockerfiles from `../local-dev/` so the backend healthcheck can run `wget`. Reuses the dev keypair from `../local-dev/keys/`. - `Caddyfile.dev` — the application-routing Caddy config, mounted into `galaxy-caddy` at `/etc/caddy/Caddyfile`. - `Caddyfile.prod` — placeholder for a future prod deployment; not used by this compose. - `Makefile` — wrapper over `docker compose` with helpers for engine, UI seeding, health probes, and full wipe. - `.env.example` — non-secret defaults for the compose `${VAR:-}` expansions. Copy to `.env` if you want host-local overrides. ## Relationship to other infrastructure - `tools/local-dev/` — single-developer playground, host-port mapped, Vite dev server on the side. Recommended for active UI work. - `tools/local-ci/` — Gitea + act runner for **fallback** workflow testing without `gitea.lan`. Optional, not part of the per-stage CI gate anymore. - `.gitea/workflows/dev-deploy.yaml` — the CI side of this stack: builds images, seeds the UI volume, runs `docker compose up -d` on every merge into `development`. The Makefile in this directory is what that workflow ultimately calls into.