Skip to main content

GCP Cloud Run Configuration

This guide covers deploying ForgeX microservices to Google Cloud Platform using Cloud Run, Cloud SQL, and Cloud Storage.

Prerequisites

Ensure these tools are installed and authenticated:

# Verify GCP authentication
gcloud auth list

# Set project
gcloud config set project forge-475221

# Verify Node.js and npm
node --version # Should be 18+
npm --version

Frontend Deployment

Frontend applications are built as static sites and deployed to Google Cloud Storage, served via Cloud CDN.

Portal Frontend

cd services/portal/frontend

# Build with production environment variables
VITE_API_URL=https://bids.precisionsiteservices.com/api \
VITE_BIDS_URL=https://bids.precisionsiteservices.com \
VITE_PROJECTS_URL=https://projects.precisionsiteservices.com \
VITE_FIELD_URL=https://field.precisionsiteservices.com \
VITE_GOOGLE_CLIENT_ID=45561947981-6ils22m4mcjlr9q43cn11q8kq2vl6mod.apps.googleusercontent.com \
VITE_COOKIE_DOMAIN=.precisionsiteservices.com \
npm run build

# Upload to Cloud Storage
cd ../../..
gcloud storage rsync -r services/portal/frontend/dist gs://forge-475221-portal --delete-unmatched-destination-objects

# Invalidate CDN cache
gcloud compute url-maps invalidate-cdn-cache forge-lb --path "/*" --async

Bids Frontend

warning

CRITICAL: Environment variables must be production URLs. Localhost references will break production!

cd services/bids/frontend

# Build with production URLs
VITE_API_URL=https://bids.precisionsiteservices.com/api \
VITE_PORTAL_URL=https://forge.precisionsiteservices.com \
VITE_GOOGLE_CLIENT_ID=45561947981-6ils22m4mcjlr9q43cn11q8kq2vl6mod.apps.googleusercontent.com \
VITE_COOKIE_DOMAIN=.precisionsiteservices.com \
npm run build

# Verify no localhost references
grep -r "localhost" dist/ 2>/dev/null | grep -v "node_modules" || echo "✓ No localhost references found"

# Upload to Cloud Storage
cd ../../..
gcloud storage rsync -r services/bids/frontend/dist gs://forge-475221-bids --delete-unmatched-destination-objects

# Invalidate CDN cache
gcloud compute url-maps invalidate-cdn-cache forge-lb --path "/*" --async
info

CDN propagation takes 3-5 minutes. Test in an incognito window after this time.

Backend Deployment

Backend services are containerized and deployed to Cloud Run with Cloud SQL integration.

Step 1: Build Docker Image

Cloud Build is used to build Docker images from the repository:

# MUST run from repo root!
gcloud builds submit --config services/bids/backend/cloudbuild.yaml --timeout=20m

This creates gcr.io/forge-475221/bids-backend:latest.

Step 2: Deploy to Cloud Run

# Set secrets first
export DB_PASSWORD='your-database-password'
export GOOGLE_CLIENT_SECRET='your-google-client-secret'
export RESEND_API_KEY='re_xxxxx'
export SUPERTOKENS_URI='https://forge-supertokens-xxxxx.run.app'

# Deploy
gcloud run deploy forge-bids-backend \
--image gcr.io/forge-475221/bids-backend:latest \
--platform managed \
--region us-south1 \
--allow-unauthenticated \
--memory 512Mi \
--cpu 1 \
--min-instances 1 \
--max-instances 10 \
--add-cloudsql-instances forge-475221:us-south1:forge-postgres-prod \
--set-env-vars "DATABASE_URL=postgresql://forgeapp:${DB_PASSWORD}@localhost/bids_db?host=/cloudsql/forge-475221:us-south1:forge-postgres-prod" \
--set-env-vars "SUPERTOKENS_CONNECTION_URI=${SUPERTOKENS_URI}" \
--set-env-vars "API_DOMAIN=https://bids.precisionsiteservices.com" \
--set-env-vars "WEBSITE_DOMAIN=https://forge.precisionsiteservices.com" \
--set-env-vars "GOOGLE_CLIENT_ID=45561947981-6ils22m4mcjlr9q43cn11q8kq2vl6mod.apps.googleusercontent.com" \
--set-env-vars "GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}" \
--set-env-vars "RESEND_API_KEY=${RESEND_API_KEY}" \
--set-env-vars "EMAIL_FROM=Precision Platform <noreply@precisionsiteservices.com>" \
--set-env-vars "NODE_ENV=production"
info

Cloud Run automatically sets PORT=8080. Do not include it in your deployment command.

Step 3: Verify Deployment

# Check health endpoint
curl https://bids.precisionsiteservices.com/api/health

# Expected output: {"status":"ok","timestamp":"...","service":"bids"}

# View Cloud Run logs
gcloud run services logs read forge-bids-backend --region us-south1 --limit 50

SuperTokens Deployment

SuperTokens Core handles authentication sessions. This is a one-time setup.

warning

SuperTokens (Java) cannot use Cloud SQL Auth Proxy Unix sockets. It requires TCP connection to Cloud SQL public IP.

Step 1: Create SuperTokens Database

# Start Cloud SQL Proxy
.\cloud-sql-proxy.exe forge-475221:us-south1:forge-postgres-prod --port=5432

# In another terminal, create database
psql -h 127.0.0.1 -U forgeapp -d postgres -c "CREATE DATABASE supertokens_db;"

Step 2: Get Cloud SQL Public IP

gcloud sql instances describe forge-postgres-prod --format="value(ipAddresses[0].ipAddress)"
# Example output: 34.174.7.92

Step 3: Deploy SuperTokens to Cloud Run

export DB_PASSWORD='your-database-password'
export CLOUD_SQL_IP='34.174.7.92' # From step 2

gcloud run deploy forge-supertokens \
--image docker.io/supertokens/supertokens-postgresql:9.3 \
--platform managed \
--region us-south1 \
--allow-unauthenticated \
--memory 512Mi \
--cpu 1 \
--min-instances 1 \
--port 3567 \
--set-env-vars "POSTGRESQL_HOST=${CLOUD_SQL_IP}" \
--set-env-vars "POSTGRESQL_PORT=5432" \
--set-env-vars "POSTGRESQL_DATABASE_NAME=supertokens_db" \
--set-env-vars "POSTGRESQL_USER=forgeapp" \
--set-env-vars "POSTGRESQL_PASSWORD=${DB_PASSWORD}"

Step 4: Verify SuperTokens

# Note the service URL from deployment output
export SUPERTOKENS_URL='https://forge-supertokens-xxxxx.us-south1.run.app'

# Health check
curl $SUPERTOKENS_URL/
# Expected: Hello

# API version
curl $SUPERTOKENS_URL/apiversion
# Expected: {"versions":["2.0","3.0",...]}

Step 5: Update Backend Environment

Use the SuperTokens URL as SUPERTOKENS_CONNECTION_URI in backend deployments.

info

Current Production URL: https://forge-supertokens-45561947981.us-south1.run.app

Database Schema Updates

When Prisma schema changes, push to production database:

# 1. Start Cloud SQL Proxy
.\cloud-sql-proxy.exe forge-475221:us-south1:forge-postgres-prod --port=5432

# 2. Set DATABASE_URL (separate terminal)
cd services/bids/backend
export DATABASE_URL='postgresql://forgeapp:YOUR_PASSWORD@127.0.0.1:5432/bids_db'

# 3. Push schema
npx prisma db push

# 4. Redeploy backend (see Backend Deployment section)
warning

Always backup the database before schema changes:

gcloud sql backups create --instance=forge-postgres-prod

Google OAuth Configuration

Configure OAuth redirect URIs in GCP Console → APIs & Services → Credentials:

Production URIs:

https://forge-bids-backend-45561947981.us-south1.run.app/auth/callback/google
https://bids.precisionsiteservices.com/api/auth/callback/google

Local Development:

http://localhost:5001/api/auth/callback/google

OAuth Client ID: 45561947981-6ils22m4mcjlr9q43cn11q8kq2vl6mod.apps.googleusercontent.com

Automated Deployment Script

For convenience, use the automated deployment script:

./deploy-to-production.sh

This script:

  1. Verifies GCP authentication
  2. Builds portal and bids frontends
  3. Uploads to Cloud Storage
  4. Builds backend Docker image
  5. Deploys to Cloud Run
  6. Invalidates CDN cache
  7. Runs health checks

Troubleshooting

CDN shows old frontend

Wait 3-5 minutes after cache invalidation. Test in incognito window.

Force refresh: Ctrl+Shift+R (Windows) or Cmd+Shift+R (Mac)

Manual invalidation:

gcloud compute url-maps invalidate-cdn-cache forge-lb --path "/*" --async
Backend changes not appearing

Verify you deployed to the correct service and region:

gcloud run services describe forge-bids-backend --region us-south1

Check the image tag matches:

gcloud run services describe forge-bids-backend --region us-south1 --format="value(spec.template.spec.containers[0].image)"
Database connection failed
  1. Check Cloud SQL Proxy is running
  2. Verify DATABASE_URL format includes /cloudsql/ socket path
  3. Ensure Cloud SQL instance is running:
gcloud sql instances list
OAuth login fails
  1. Verify redirect URIs in GCP Console
  2. Check GOOGLE_CLIENT_ID matches across frontend and backend
  3. Ensure GOOGLE_CLIENT_SECRET is set in Cloud Run
  4. Check API_DOMAIN and WEBSITE_DOMAIN match production URLs
SuperTokens connection fails
  1. Verify SUPERTOKENS_CONNECTION_URI is set correctly
  2. Check SuperTokens service is running:
curl https://forge-supertokens-xxxxx.run.app/
  1. Verify Cloud SQL allows connections from SuperTokens
  2. Check SuperTokens can reach Cloud SQL public IP
Email not sending
  1. Check RESEND_API_KEY is set in Cloud Run
  2. Verify domain is verified in Resend Dashboard
  3. Check Cloud Run logs for Resend API errors
  4. Ensure EMAIL_FROM uses verified domain

Cost Optimization

🖥️

Cloud Run

Min instances: 0 (scale to zero)

Max instances: 10 (prevent runaway costs)

Memory: 512Mi (adequate for most workloads)

🗄️

Cloud SQL

Machine type: db-f1-micro (shared-core)

Storage: Start at 10GB, auto-increase

Backups: Automated daily, 7-day retention

📦

Cloud Storage

Standard class for active files

Nearline class for backups

CDN enabled for fast delivery

🔨

Cloud Build

120 free build-minutes/day

Use --timeout to prevent hung builds

Cache Docker layers for faster builds

Next Steps