Deployment
Last updated: 2026-05-28
Overview
Deployment of the Monstermessenger application uses a hybrid cloud architecture: the backend runs on Google Cloud Platform (Cloud Run), while frontends and documentation are served through Cloudflare Pages with GCS buckets as origin storage. Three separate deployable units exist:
| Component | Platform | Technology |
|---|---|---|
| Backend API | GCP Cloud Run | Docker container (FastAPI, managed) |
| Frontend (teenager + parent) | Cloudflare Pages + GCS Buckets | Static SPA (React/Vite) |
| Documentation | Cloudflare Pages | Quarto-rendered HTML (via GitHub Pages source) |
| Discord Bot | Self-hosted VM / Docker | Python process with health server |
Target Architecture
┌─────────────────────────┐
│ Cloudflare Pages │
│ ┌─────────────────────┐ │
│ │ Frontend (teenager) │ │
│ │ Frontend (parent) │ │
│ │ Documentation │ │
│ └────────┬────────────┘ │
└───────────┼──────────────┘
│ origin pull
┌───────────▼──────────────┐
│ GCP Cloud Storage │
│ ┌─────────────────────┐ │
│ │ frontend-teenager/ │ │
│ │ frontend-parent/ │ │
│ └─────────────────────┘ │
└──────────────────────────┘
┌─────────────────────────┐
│ GCP Cloud Run │
│ ┌─────────────────────┐ │
│ │ Backend (teenager) │ │
│ │ Backend (parent) │ │
│ └─────────────────────┘ │
└──────────────────────────┘
┌─────────────────────────┐
│ Self-Hosted │
│ ┌─────────────────────┐ │
│ │ Discord Bot │ │
│ └─────────────────────┘ │
└──────────────────────────┘
Variant Deployment
A single codebase serves two audiences, each deployed as separate services:
| Variant | Backend (Cloud Run) | Frontend (Cloudflare Pages) | Build flag |
|---|---|---|---|
| Teenager/Child | <name>-child / -dev |
<cf-name>.pages.dev |
CHATBOT_VARIANT=teenager |
| Parent/Adult | <name>-parent / -dev |
<cf-name>-parent.pages.dev |
CHATBOT_VARIANT=parent |
Environments:
- Development (
devbranch): Services suffixed with-dev. Cloudflare Pages preview deployments atdev.<cf-name>.pages.devanddev.<cf-name>-parent.pages.dev. - Production (
mainbranch): Services without-devsuffix. Primary Cloudflare Pages deployments.
Frontend Hosting: Cloudflare Pages
The frontend is served through Cloudflare Pages, providing global CDN, automatic HTTPS, and fast content delivery. GCS buckets act as the origin storage; Cloudflare Pages pulls from them.
URL Structure
Production URLs are configured via the FRONTEND_CF_NAME repository variable:
| Environment | Teenager URL | Parent URL |
|---|---|---|
| Production | https://<FRONTEND_CF_NAME>.pages.dev |
https://<FRONTEND_CF_NAME>-parent.pages.dev |
| Development | https://dev.<FRONTEND_CF_NAME>.pages.dev |
https://dev.<FRONTEND_CF_NAME>-parent.pages.dev |
The deployment workflow uses these URLs for: - Setting CORS__ALLOWED_ORIGINS on the backend (allowing cross-origin requests from both frontends) - Injecting FRONTEND_TEENAGER_URL / FRONTEND_PARENT_URL into the backend for authorization links - Passing VITE_API_URL to the Vite build
If FRONTEND_CF_NAME is not set (legacy), the workflow falls back to direct GCS bucket URLs (https://<bucket>.storage.googleapis.com).
Cloudflare Build Script
A minimal build script exists at frontend/cloudflare_build.sh for Cloudflare Pages direct integration (CI-less deployment). For production, the GitHub Actions workflows handle the full build pipeline.
Backend: GCP Cloud Run
The Python FastAPI application is containerized and deployed to Google Cloud Run as a fully managed serverless service.
Service Configuration
platform: managed
memory: 1Gi
cpu: 1
max_instances: 5
timeout: 300s
port: 8000
allow_unauthenticated: trueEnvironment Variables
| Variable | Description |
|---|---|
CHATBOT_VARIANT |
teenager or parent |
APP_ENV |
dev or prod |
LANGFUSE__ENABLED |
"true" for observability |
SKIP_ENV_CONFIRMATION |
"true" — bypass env confirmation prompt |
CORS__ALLOWED_ORIGINS |
JSON array of allowed frontend origins (both teenager and parent URLs) |
FRONTEND_TEENAGER_URL |
Teenager frontend base URL (for authorization links in cross-variant flows) |
FRONTEND_PARENT_URL |
Parent frontend base URL |
GEOIP__PROVIDER |
Geo-IP provider: ipapi, maxmind, or null |
DATABASE_URL |
PostgreSQL connection string (from GCP Secret Manager) |
GOOGLE_API_KEY |
Gemini API key (from GCP Secret Manager) |
DB_SCHEMA |
Database schema name (defaults to app) |
Container Startup
The application Dockerfile runs alembic upgrade head on container startup before launching the API server. This ensures the database schema is always up-to-date with the deployed code, eliminating the need for manual migration runs.
CI/CD Workflows
All deployment logic is managed by GitHub Actions workflows in .github/workflows/.
deploy-variants.yaml (Main Orchestrator)
Triggered on every push to dev and main. Orchestrates the full deployment pipeline:
check-changes ──┬── build-env-image (if requirements changed)
├── prebuild-devcontainer (if devcontainer changed)
├── run-alembic (always)
├── deploy-parent (if backend/frontend changed)
│ └── reset-parent-cache (i18n + manifest)
└── deploy-child (if backend/frontend changed)
└── reset-child-cache (i18n + manifest)
Path filtering via dorny/paths-filter ensures only changed components are rebuilt: - api/**, rag/**, backend.Dockerfile → backend rebuild - frontend/** → frontend rebuild + deploy - requirements.txt, env.Dockerfile → environment base image rebuild
The app_env parameter (dev or prod) is derived from the target branch and threaded through all jobs to control service naming, bucket naming, Cloudflare URLs, and Vite build mode.
reusable-deploy.yaml (Per-Variant Deploy)
Reusable workflow called twice (once per variant). Steps:
- Auth: Authenticate to GCP via service account (
GCP_SA_KEYsecret) - Build backend: Docker build with
CHATBOT_VARIANTbuild arg, push to Artifact Registry - Deploy to Cloud Run: With environment variables file containing
CHATBOT_VARIANT,CORS__ALLOWED_ORIGINS,FRONTEND_*_URL, andAPP_ENV - Build frontend:
npm ci→npm run build:{dev|prod}withVITE_API_URLpointing to the Cloud Run service URL - Deploy frontend:
gsutil rsyncto GCS bucket, set cache headers (max-age=86400for pages,max-age=31536000for assets) - Summary: Prints deployed URLs
build_quarto_docs.yaml (Documentation)
Renders the Quarto documentation and publishes to the cf-pages branch, which is served by Cloudflare Pages:
- Change detection: Only runs when
doc/**files change (on push todevor PR) - Last-modified updates:
update_last_modified.pyscans git history per file - Quarto render: Renders all
.qmdfiles todoc/build/ - Deploy: Uses
peaceiris/actions-gh-pagesto publish tocf-pagesbranch - Cloudflare Pages picks up the
cf-pagesbranch and serves it at the configured domain
Deployment CLI (deployment/deploy.py)
A Python CLI tool provides fully automated multi-variant builds and GCP deployments for hot-stage or staging environments.
Usage
# Deploy both variants to staging (default)
python deployment/deploy.py
# Deploy only the teenager variant
python deployment/deploy.py --variant teenager
# Deploy only the parent variant with a custom suffix
python deployment/deploy.py --variant parent --suffix feature-x
# Deploy shared backend + both frontends
python deployment/deploy.py --variant shared
# Backend only / Frontend only
python deployment/deploy.py --backend-only
python deployment/deploy.py --frontend-only
# Load environment variables from a file
python deployment/deploy.py --env-file .env.staging
# Stream build output to terminal
python deployment/deploy.py --pass-through
# Build the env image locally before deploying backend
python deployment/deploy.py --build-env-imageHow It Works
- Environment Resolution: Reads configuration from environment variables or
--env-file. Key variables:PROJECT_ID,REGION,DL_CONNINFO. - Temp Env Files: Creates temporary
.envfiles for the GCloud deploy command and Vite build. Always cleaned up after deployment. - Backend Build: Optionally builds and pushes the
envbase image, then builds the final application Docker image tagged with variant and suffix. - Frontend Build: Writes a temporary
.env.developmentfile withVITE_API_URLpointing to the deployed backend, runsnpm run build, syncsfrontend/dist/to the GCS bucket.
Discord Bot Deployment
The Discord bot is a separate deployable unit with its own Dockerfile. See Discord Bot for architecture details.
docker build -t discord-bot -f discord_bot/Dockerfile discord_bot/
docker run -e DISCORD_BOT_TOKEN="..." \
-e BACKEND_URL="https://<backend-url>/api/v1" \
discord-botThe bot runs as a single long-lived process with an embedded health server on port 8080. For production, run behind a process manager (systemd, supervisord) or deploy to a cloud VM.
Frontend Environment Variables (Vite Build)
Set at build time via the deployment workflow:
| Variable | Description |
|---|---|
VITE_API_URL |
Backend Cloud Run service URL |
VITE_SITE_VARIANT |
teenager or parent (used by Tailwind for theme) |
CHATBOT_VARIANT |
teenager or parent (used by runtime config) |
FRONTEND_TEENAGER_URL |
Teenager frontend public URL |
FRONTEND_PARENT_URL |
Parent frontend public URL |
Monitoring & Observability
- Cloud Run: Metrics available in GCP Console (request count, latency, instance count, memory/CPU)
- Langfuse: LLM tracing enabled in production (
LANGFUSE__ENABLED=true) - Discord Bot: Health server on
:8080for uptime monitoring; errors logged to stdout - Cloudflare Pages: Analytics available in Cloudflare dashboard (bandwidth, requests, cache hit ratio)