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
+32 -8
View File
@@ -1,4 +1,4 @@
.PHONY: help up down rebuild logs status clean-data health psql build-engine seed-ui seed-geoip
.PHONY: help up down rebuild logs status clean-data health psql build-engine seed-ui seed-site seed-geoip
.DEFAULT_GOAL := help
@@ -6,6 +6,9 @@ REPO_ROOT := $(realpath $(CURDIR)/../..)
ENGINE_IMAGE := galaxy-engine:dev
STACK_LABEL := galaxy.stack=dev-deploy
ENGINE_LABEL := org.opencontainers.image.title=galaxy-game-engine
# Public host the in-front host Caddy serves the single-origin stack on.
# Used only by `make health` probes; override for a different domain.
GALAXY_DEV_HOST ?= galaxy.lan
# Game-state root lives under the invoking user's home by default so
# `make up` works without sudo. Override `GALAXY_DEV_GAME_STATE_DIR`
# in the environment or `.env` to relocate (e.g. /var/lib/galaxy-dev/
@@ -17,11 +20,12 @@ export GALAXY_DEV_GAME_STATE_DIR ?= $(HOME)/.galaxy-dev/game-state
COMPOSE := docker compose
help:
@echo "Long-lived Galaxy dev environment (https://*.galaxy.lan):"
@echo "Long-lived Galaxy dev environment (single-origin, e.g. https://galaxy.lan):"
@echo " make up Build images, ensure engine image, seed geoip, bring stack up"
@echo " make rebuild Force rebuild of backend / gateway images and bring up"
@echo " make build-engine Build $(ENGINE_IMAGE) from game/Dockerfile (no-op if present)"
@echo " make seed-ui Build ui/frontend and load into galaxy-dev-ui-dist volume"
@echo " make seed-site Build site/ (VitePress) and load into galaxy-dev-site-dist volume"
@echo " make seed-geoip Copy GeoIP fixture into galaxy-dev-geoip-data volume"
@echo " make down Stop containers, keep named volumes"
@echo " make logs Tail all logs"
@@ -33,7 +37,7 @@ help:
@echo "Requires:"
@echo " - external Docker network '$${GALAXY_EDGE_NETWORK:-edge}'"
@echo " (docker network create edge)"
@echo " - host Caddy proxying *.galaxy.lan into that network"
@echo " - host Caddy proxying the public host into that network"
@echo " - game-state dir: $(GALAXY_DEV_GAME_STATE_DIR) (auto-created)"
up: build-engine seed-geoip
@@ -76,7 +80,8 @@ seed-ui:
fi
@echo "building UI (vite build)…"
(cd $(REPO_ROOT)/ui/frontend && \
VITE_GATEWAY_BASE_URL=https://api.galaxy.lan \
VITE_GATEWAY_BASE_URL= \
BASE_PATH=/game \
VITE_GALAXY_DEV_AFFORDANCES=true \
VITE_GATEWAY_RESPONSE_PUBLIC_KEY=$$(cat $(REPO_ROOT)/ui/frontend/.env.development \
| sed -n 's/^VITE_GATEWAY_RESPONSE_PUBLIC_KEY=//p') \
@@ -88,6 +93,23 @@ seed-ui:
-v $(REPO_ROOT)/ui/frontend/build:/src:ro \
alpine sh -c 'rm -rf /dst/* /dst/.??* 2>/dev/null; cp -a /src/. /dst/'
# Build the project site (VitePress) and load the static output into the
# named volume Caddy serves at the root. Used by the dev-deploy workflow
# and by anyone bringing the stack up by hand.
seed-site:
@if [ ! -d $(REPO_ROOT)/site/node_modules ]; then \
echo "installing site dependencies…"; \
(cd $(REPO_ROOT)/site && pnpm install --frozen-lockfile); \
fi
@echo "building project site (vitepress build)…"
(cd $(REPO_ROOT)/site && pnpm build)
@echo "loading site dist into galaxy-dev-site-dist volume…"
docker volume create galaxy-dev-site-dist >/dev/null
docker run --rm \
-v galaxy-dev-site-dist:/dst \
-v $(REPO_ROOT)/site/.vitepress/dist:/src:ro \
alpine sh -c 'rm -rf /dst/* /dst/.??* 2>/dev/null; cp -a /src/. /dst/'
down:
$(COMPOSE) down
@@ -98,10 +120,12 @@ status:
$(COMPOSE) ps
health:
@echo "Frontend (https://www.galaxy.lan):"
@curl -sS -o /dev/null -w " HTTP %{http_code}\n" https://www.galaxy.lan/ || echo " unreachable"
@echo "API healthz (https://api.galaxy.lan/healthz):"
@curl -sS -o /dev/null -w " HTTP %{http_code}\n" https://api.galaxy.lan/healthz || echo " unreachable"
@echo "Site (https://$(GALAXY_DEV_HOST)/):"
@curl -sS -o /dev/null -w " HTTP %{http_code}\n" https://$(GALAXY_DEV_HOST)/ || echo " unreachable"
@echo "Game (https://$(GALAXY_DEV_HOST)/game/):"
@curl -sS -o /dev/null -w " HTTP %{http_code}\n" https://$(GALAXY_DEV_HOST)/game/ || echo " unreachable"
@echo "API healthz (https://$(GALAXY_DEV_HOST)/healthz):"
@curl -sS -o /dev/null -w " HTTP %{http_code}\n" https://$(GALAXY_DEV_HOST)/healthz || echo " unreachable"
psql:
$(COMPOSE) exec galaxy-postgres psql -U galaxy -d galaxy_backend