feat(deploy): single-origin path-based deployment + project site
Build · Site / build (push) Successful in 8s
Tests · Go / test (push) Successful in 2m22s
Tests · UI / test (push) Failing after 2m42s

Serve the whole stack behind one host: site at /, game UI at /game/,
gateway REST at /api + /healthz, Connect at /rpc (prefix stripped by the
edge Caddy). The built artifact is domain-agnostic — the UI talks to the
gateway same-origin via relative URLs, so the same bundle runs under any
host with no rebuild and with CORS disabled.

- Rename the Connect proto service galaxy.gateway.v1.EdgeGateway ->
  edge.v1.Gateway; regenerate Go + TS; public path /rpc/edge.v1.Gateway.
- Move the game UI under base path /game (env BASE_PATH); make the
  manifest, service-worker scope, WASM loader, and all navigation
  base-aware via a withBase helper.
- Relative API + /rpc Connect prefix; Vite dev proxy mirrors the strip.
- Rewrite the edge Caddy (dev + prod) for path-based routing; empty CORS
  allow-lists (same-origin); single host.
- New VitePress project site (site/): i18n en/ru with switcher, LaTeX
  math, minimal monospace theme; built and served at /.
- dev-deploy compose/Makefile + CI (dev-deploy, prod-build, new
  site-build) build and seed the site; probes hit /, /game/, /healthz.
- Sync docs (ARCHITECTURE, gateway README/openapi, dev-deploy &
  local-dev READMEs, CLAUDE.md, ui/PLAN).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-23 18:19:07 +02:00
parent fa0df5183a
commit 8565942392
104 changed files with 2967 additions and 787 deletions
+57 -29
View File
@@ -2,11 +2,26 @@
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.
Caddy at a single origin (`https://galaxy.lan` in dev). The stack is
single-origin and path-based: the project site, the game UI, and both
gateway surfaces live behind one host with no host name baked into the
artifacts. 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.
The application Caddy (`Caddyfile.dev`) is the authoritative routing
source; its header comment documents the exact topology:
```text
/ -> project site (galaxy-dev-site-dist -> /srv/galaxy-site)
/game/* -> game UI (galaxy-dev-ui-dist -> /srv/galaxy-ui)
/api/*, /healthz -> gateway public REST (galaxy-api:8080)
/rpc/* -> gateway Connect/gRPC-web (galaxy-api:9090)
```
The `/rpc` prefix is stripped before the gateway, and the game UI bundle
is built with base path `/game`.
This stack is **not** the developer's primary playground for UI work —
that role still belongs to [`tools/local-dev/`](../local-dev/README.md),
@@ -38,11 +53,13 @@ The host must already provide:
```
- 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:
network, and proxying the single dev host `galaxy.lan` to
`galaxy-caddy:80`. The host Caddy only needs that one host;
`Caddyfile.dev` does the path-based fan-out behind it. Example
fragment for the host Caddyfile:
```caddy
www.galaxy.lan, api.galaxy.lan {
galaxy.lan {
tls internal
reverse_proxy galaxy-caddy:80
}
@@ -62,25 +79,28 @@ 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:
does **not** seed the UI or site volumes — that is normally done by CI.
The first time you run by hand:
```sh
make -C tools/dev-deploy seed-site
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.
`seed-ui` runs `pnpm build` in `ui/frontend/` (base path `/game`), then
copies the resulting `build/` tree into the `galaxy-dev-ui-dist` volume.
`seed-site` builds the VitePress project site in `site/` and copies its
`.vitepress/dist/` output into the `galaxy-dev-site-dist` volume.
Subsequent CI deploys overwrite both volumes 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 health # probe https://galaxy.lan/ , /game/ , /healthz
make -C tools/dev-deploy down # stop, keep state
```
@@ -109,14 +129,16 @@ cannot leak into the prod environment.
```
Browser
│ https://www.galaxy.lan, https://api.galaxy.lan
│ https://galaxy.lan/ (one origin, path-based)
host-Caddy (:80, :443, TLS, attached to `edge` network)
│ reverse_proxy *.galaxy.lan → galaxy-caddy:80
│ 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
/ -> file_server /srv/galaxy-site (volume galaxy-dev-site-dist)
/game/* -> file_server /srv/galaxy-ui (volume galaxy-dev-ui-dist)
│ /api/*, /healthz -> reverse_proxy galaxy-api:8080
│ /rpc/* -> reverse_proxy galaxy-api:9090 (strips /rpc)
galaxy-dev-internal
├─ galaxy-api (gateway: :8080 REST, :9090 gRPC)
@@ -155,13 +177,14 @@ The same volume-persistence model applies to `tools/local-dev/`.
```text
make up Build images, ensure engine image, seed geoip, bring stack up
make rebuild Rebuild backend / gateway images (ignores cache), then up
make seed-ui pnpm build + load build/ into galaxy-dev-ui-dist volume
make seed-ui pnpm build (base /game) + load build/ into galaxy-dev-ui-dist volume
make seed-site vitepress build + load site dist into galaxy-dev-site-dist volume
make seed-geoip Copy pkg/geoip fixture into galaxy-dev-geoip-data 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 health curl https://galaxy.lan/ , /game/ , and /healthz
make psql psql as galaxy@galaxy_backend
make clean-data Stop everything and wipe volumes + game-state dir
```
@@ -169,15 +192,20 @@ 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`.
galaxy-backend, galaxy-api, galaxy-caddy. `galaxy-caddy` mounts both
the `galaxy-dev-site-dist` (`/srv/galaxy-site`) and
`galaxy-dev-ui-dist` (`/srv/galaxy-ui`) volumes and reverse-proxies
both gateway tiers (REST/health on `:8080`, Connect/gRPC-web on
`:9090`). 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 and the
authoritative single-origin path topology, 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.
site/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.
@@ -212,6 +240,6 @@ behind. There is no separate state to clean up between the two paths.
- `tools/local-dev/` — single-developer playground, host-port mapped,
Vite dev server on the side. Recommended for active UI work.
- `.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.
builds images, seeds the site and UI volumes, runs `docker compose
up -d` on every merge into `development`. The Makefile in this
directory is what that workflow ultimately calls into.