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
devbranch deploys to a development environment. Cloud Run services and GCS buckets for this environment are typically suffixed with-dev. - Production: Pushing to the
mainbranch deploys to the production environment.
- Development: Pushing to the
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-imageHow It Works
- Environment Resolution: Reads configuration from environment variables or an
--env-file. Key variables:PROJECT_ID,REGION,DL_CONNINFO. - Temp Env Files: Creates temporary
.envfiles for both the GCloud backend deploy command and the Vite frontend build. These are always cleaned up after the deployment. - Backend Build: Optionally builds and pushes the
envbase image, then builds the final application Docker image tagged with the variant and suffix. - Frontend Build: Writes a temporary
.env.developmentfile withVITE_API_URLpointing to the deployed backend, runsnpm run build, then syncsfrontend/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
devandmainbranches. app_envparametrization: Theapp_envinput (devorprod) 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-changesstep usesdorny/paths-filterto determine which parts of the application (backend,frontend,requirements) have been modified, skipping unnecessary build steps. - Multi-Stage Docker Build:
- Environment Image (
build-env-image): A base Docker image containing all Python dependencies is built usingdeployment/env.Dockerfile. This job only runs ifrequirements.txtorenv.Dockerfilechanged. - Application Image: Built using the pre-built environment image as a base, making this step fast.
- Environment Image (
- Reusable Deploy Trigger: For each variant (
teenagerandparent), this workflow callsreusable-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.
- Authentication: Authenticates to GCP using a service account stored in GitHub Secrets.
- Build & Push Backend: Builds the application Docker image with
CHATBOT_VARIANTas a build argument and pushes to Google Artifact Registry. - Deploy to Cloud Run: Deploys the new image with environment variables including
CHATBOT_VARIANT,CORS_ORIGINS,FRONTEND_TEENAGER_URL,FRONTEND_PARENT_URL, andAPP_ENV. - Build & Deploy Frontend: Injects
VITE_API_URL(the Cloud Run URL), runsnpm run buildin the correct mode, and syncs the resultingdist/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 |