Embedded reference demo
The React demo at /demo is an actual API consumer included in every application image. It does not import server internals or keep a second state model. Persona changes exchange a public demo persona for a short-lived, HttpOnly session cookie; every later request passes through the normal API authentication, authorization, tenant scoping, and MySQL store.
Fixture and reset model
Canonical content lives in demo-data/harbour-yoga.json. The runtime validates the file before writing it. Change that file to adjust people, locations, durations, recurring events, products, entitlements, or roster bookings.
npm run build
DATABASE_URL="<mysql-url>" npm run db:migrate:runtime
DATABASE_URL="<mysql-url>" npm run demo:reset:runtimedemo:reset:runtime replaces all application state and is used for CI and pull requests. demo:seed:runtime removes and recreates only the account whose slug is harbour-yoga-demo; production demo deployment uses this mode so other sandbox accounts in the demo database remain intact.
Environment boundary
- The real production container has
DEMO_AUTH_ENABLED=falseand uses the production database. - A second production-demo container has
DEMO_AUTH_ENABLED=true,DEMO_PUBLIC_API_BASE=/demo/api, and uses the dedicated demo database. - Caddy sends
/demoand/demo/apito that second container. - PRs use their isolated database and reset it before every redeploy.
- GitHub Actions starts MySQL 8.4, migrates, resets, starts the compiled application, and captures Playwright evidence from
/demobefore reports are generated.
Email delivery and MobilePay are the only mocked boundaries in CI, previews, and the canonical production demo. The API still creates real payment, entitlement, and booking records in the applicable demo database.