Files
website/deploy/demo/docker-compose.yml
wtclaude d48d8c473c
All checks were successful
PR Checks / bot-tests (pull_request) Successful in 50s
PR Checks / client-build (pull_request) Successful in 57s
PR Checks / server-tests (pull_request) Successful in 12m25s
feat(demo): deploy/demo and the wipe + baseline workflows (step 5)
The public demo's deployment (docs/website/DEMO_MODE.md §7, §10 step 5):

- deploy/demo/docker-compose.yml: the app and its database only, DEMO_MODE
  on, a /status healthcheck, the fixture mounted for seed:demo, MODULES read
  from state/modules.env so the workflow never edits the .env with secrets.
- deploy/demo/.env.example: every variable the host needs, including
  BOT_INTERNAL_KEY (the app refuses to start in production without it) and
  MODULE_SOURCE_HOSTS (a fresh database's install allowlist).
- deploy/demo/seed.json: the four logins, settings, two posts, a wiki page,
  a published "Server greeting" event on a Rust console step, the rig's
  server link and demo-player's Steam link; secrets as "$env:NAME".
- deploy/demo/rig.mjs: plan (latest Rust bundle + newest Module-Rust on the
  same protocol, keeping the previous set when none matches), restore (kill,
  write a changed bundle, delete + unpack demo-baseline.tar.gz, start),
  baseline (power stop saves the world, DM22; compress, rename, start) and
  smoke (the site, then the rig reporting in), on the Pterodactyl client API.
- .gitea/workflows/demo-wipe.yml: every 2 h on the hour UTC, on a push to
  deploy/demo/, and by hand; rig first, then down -v / pull / up / seed.
- .gitea/workflows/demo-baseline.yml: by hand only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-26 12:23:52 -05:00

71 lines
2.5 KiB
YAML

# The public demo, demo.runicgateway.com (docs/website/DEMO_MODE.md).
#
# The same image as every other deployment, switched by DEMO_MODE=true (§2). Only
# the app and its database: no bot and no ntfy, because the demo sends nothing
# outward (§5). The wipe workflow (.gitea/workflows/demo-wipe.yml) copies this
# file into the deploy directory on the `demo-site` host and runs it from there;
# the host's own `.env` beside it holds every secret.
#
# The project name is fixed so the network is `rg-demo_default` whatever the
# directory is called: the workflow's smoke check joins it to reach the app.
name: rg-demo
services:
db:
image: mariadb:11
restart: unless-stopped
environment:
MARIADB_DATABASE: ${DB_NAME}
MARIADB_USER: ${DB_USER}
MARIADB_PASSWORD: ${DB_PASSWORD}
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
# Dropped at every wipe (`down -v`) with the uploads volume: that is the wipe.
- dbdata:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 10
app:
image: gitea.whitlocktech.com/runicgateway/website-app:${IMAGE_TAG:-latest}
restart: unless-stopped
# modules.env is written by the wipe (rig.mjs plan): MODULES=rust@<version>=…,
# the newest Module-Rust release on the bundle's protocol (§7.5). Kept out of
# .env so the workflow never edits the file holding the secrets.
env_file:
- .env
- state/modules.env
environment:
DEMO_MODE: "true"
DB_HOST: db
UPLOAD_DIR: /app/uploads
LOG_DIR: /app/logs
MODULES_DIR: /app/modules
depends_on:
db:
condition: service_healthy
volumes:
- uploads:/app/uploads
- ./logs:/app/logs
# A bind mount, not a volume, so `down -v` keeps the unpacked module and a
# wipe does not download it again. Must be writable by uid 1000.
- ./modules:/app/modules
# The seed fixture (§7.3), read by `seed:demo` after every wipe.
- ./seed.json:/app/deploy/demo/seed.json:ro
# Busybox wget is in the Alpine image; `/status` answers once the server listens.
healthcheck:
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:3000/api/v1/public/status"]
interval: 10s
timeout: 5s
start_period: 30s
retries: 30
# The external reverse proxy (DNS + HTTPS) forwards here.
ports:
- "${DEMO_HOST_PORT:-3000}:3000"
volumes:
dbdata:
uploads: