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 (dev branch): Services suffixed with -dev. Cloudflare Pages preview deployments at dev.<cf-name>.pages.dev and dev.<cf-name>-parent.pages.dev.
  • Production (main branch): Services without -dev suffix. 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: true

Environment 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:

  1. Auth: Authenticate to GCP via service account (GCP_SA_KEY secret)
  2. Build backend: Docker build with CHATBOT_VARIANT build arg, push to Artifact Registry
  3. Deploy to Cloud Run: With environment variables file containing CHATBOT_VARIANT, CORS__ALLOWED_ORIGINS, FRONTEND_*_URL, and APP_ENV
  4. Build frontend: npm cinpm run build:{dev|prod} with VITE_API_URL pointing to the Cloud Run service URL
  5. Deploy frontend: gsutil rsync to GCS bucket, set cache headers (max-age=86400 for pages, max-age=31536000 for assets)
  6. 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:

  1. Change detection: Only runs when doc/** files change (on push to dev or PR)
  2. Last-modified updates: update_last_modified.py scans git history per file
  3. Quarto render: Renders all .qmd files to doc/build/
  4. Deploy: Uses peaceiris/actions-gh-pages to publish to cf-pages branch
  5. Cloudflare Pages picks up the cf-pages branch 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-image

How It Works

  1. Environment Resolution: Reads configuration from environment variables or --env-file. Key variables: PROJECT_ID, REGION, DL_CONNINFO.
  2. Temp Env Files: Creates temporary .env files for the GCloud deploy command and Vite build. Always cleaned up after deployment.
  3. Backend Build: Optionally builds and pushes the env base image, then builds the final application Docker image tagged with variant and suffix.
  4. Frontend Build: Writes a temporary .env.development file with VITE_API_URL pointing to the deployed backend, runs npm run build, syncs frontend/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-bot

The 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 :8080 for uptime monitoring; errors logged to stdout
  • Cloudflare Pages: Analytics available in Cloudflare dashboard (bandwidth, requests, cache hit ratio)