Deployment

Last updated: 2026-05-08

Overview

Deployment of the Monstermessenger application is fully automated using GitHub Actions. The CI/CD pipeline is configured to build, test, and deploy the application to Google Cloud Platform (GCP). The process distinguishes between development and production environments based on the Git branch, and it intelligently deploys only the components that have changed.

Target Architecture

The application is deployed as two separate but connected services on GCP, with distinct teenager and parent variants for each environment.

  • Backend: The Python FastAPI application is containerized using Docker and deployed to Google Cloud Run. Each variant (teenager, parent) runs as a separate Cloud Run service with its own environment variables and configuration.
  • Frontend: The React single-page application is deployed as a static website to Google Cloud Storage. Each variant has its own GCS bucket mapped to a distinct URL (FRONTEND_TEENAGER_URL / FRONTEND_PARENT_URL), which is essential for the consent authorization flow where the parent authorization link requires a separate origin.
  • Environments:
    • Development: Pushing to the dev branch deploys to a development environment. Cloud Run services and GCS buckets for this environment are typically suffixed with -dev.
    • Production: Pushing to the main branch deploys to the production environment.

Automated Deployment CLI (deployment/deploy.py)

A Python CLI tool (deployment/deploy.py) provides fully automated multi-variant builds and GCP deployments, primarily for hot-stage or staging environments. It uses the fire library for its interface and asyncio for parallel variant builds.

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
python deployment/deploy.py --backend-only

# Frontend only
python deployment/deploy.py --frontend-only

# Load environment variables from a file
python deployment/deploy.py --env-file .env.staging

# Stream docker/npm 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 an --env-file. Key variables: PROJECT_ID, REGION, DL_CONNINFO.
  2. Temp Env Files: Creates temporary .env files for both the GCloud backend deploy command and the Vite frontend build. These are always cleaned up after the deployment.
  3. Backend Build: Optionally builds and pushes the env base image, then builds the final application Docker image tagged with the 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, then syncs frontend/dist/ to the GCS bucket.

CI/CD Workflows

The deployment logic is managed by a set of GitHub Actions workflows located in the .github/workflows/ directory.

deploy-variants.yaml

This is the main workflow that orchestrates the entire deployment process.

  • Trigger: Runs automatically on every push to the dev and main branches.
  • app_env parametrization: The app_env input (dev or prod) is derived from the target branch and threaded through the workflow to control service naming, bucket naming, and Vite build mode.
  • Path Filtering: The check-changes step uses dorny/paths-filter to determine which parts of the application (backend, frontend, requirements) have been modified, skipping unnecessary build steps.
  • Multi-Stage Docker Build:
    1. Environment Image (build-env-image): A base Docker image containing all Python dependencies is built using deployment/env.Dockerfile. This job only runs if requirements.txt or env.Dockerfile changed.
    2. Application Image: Built using the pre-built environment image as a base, making this step fast.
  • Reusable Deploy Trigger: For each variant (teenager and parent), this workflow calls reusable-deploy.yaml, passing the correct names, variants, environment, and change-detection results.

deploy-main-variants.yaml (New)

A dedicated production deployment workflow for the main branch. Similar to deploy-variants.yaml but with production environment IDs and configuration. Deploys both teenager and parent variants to production Cloud Run services and GCS buckets.

reusable-deploy.yaml

Contains the core logic for building and deploying a single variant.

  1. Authentication: Authenticates to GCP using a service account stored in GitHub Secrets.
  2. Build & Push Backend: Builds the application Docker image with CHATBOT_VARIANT as a build argument and pushes to Google Artifact Registry.
  3. Deploy to Cloud Run: Deploys the new image with environment variables including CHATBOT_VARIANT, CORS_ORIGINS, FRONTEND_TEENAGER_URL, FRONTEND_PARENT_URL, and APP_ENV.
  4. Build & Deploy Frontend: Injects VITE_API_URL (the Cloud Run URL), runs npm run build in the correct mode, and syncs the resulting dist/ to the GCS bucket.

i18n_db_sync.yml (New)

A scheduled and on-demand workflow that synchronizes i18n YAML content from the repository into the LocalizedContent database table. Runs the sync_to_db.py CLI script against the target environment. Triggered on pushes to dev that affect api/i18n/ files and on a weekly schedule.

build_quarto_docs.yaml

Renders the Quarto documentation project and deploys it to Cloudflare Pages. Triggered on pushes to dev or devdocs. Also automatically updates the “Last modified” date on each page based on its Git history.

Container startup (New)

The application Dockerfile now 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 or separate migration jobs.

Environment Variables

Backend (Cloud Run)

Variable Description
CHATBOT_VARIANT teenager or parent
DATABASE_URL PostgreSQL connection string (from GCP Secret Manager)
GOOGLE_API_KEY Gemini API key (from GCP Secret Manager)
CORS_ORIGINS Comma-separated list of allowed frontend origins (both teenager and parent URLs)
APP_ENV dev or prod — controls environment-specific defaults
FRONTEND_TEENAGER_URL Base URL of the teenager frontend (for authorization links)
FRONTEND_PARENT_URL Base URL of the parent frontend (for authorization links)
GEOIP_PROVIDER Geo-IP provider: ipapi, maxmind, or null
GEOIP_IPAPI_API_KEY API key for ipapi.co (if GEOIP_PROVIDER=ipapi)
DB_SCHEMA Database schema name (defaults to app)

Frontend (Vite build)

Variable Description
VITE_API_URL Backend Cloud Run service URL
VITE_CHATBOT_VARIANT teenager or parent
VITE_SITE_VARIANT Same as VITE_CHATBOT_VARIANT, used by Tailwind