Infrastructure Deployment
Deploy Cal.com self-hosted to GCP Cloud Run with Supabase PostgreSQL, or run locally via Docker Compose.
Mandatory Preflight
Step 1: Check GCP Project Configuration
echo "CALCOM_GCP_PROJECT: ${CALCOM_GCP_PROJECT:-NOT_SET}" echo "CALCOM_GCP_ACCOUNT: ${CALCOM_GCP_ACCOUNT:-NOT_SET}" echo "CALCOM_GCP_REGION: ${CALCOM_GCP_REGION:-us-central1}"
If NOT_SET: These must be configured in .mise.local.toml . Run the setup command.
Step 2: Verify GCP Authentication
gcloud auth list --filter="status=ACTIVE" --format="value(account)" 2>/dev/null
Step 3: Check Supabase Configuration
echo "SUPABASE_PROJECT_REF: ${SUPABASE_PROJECT_REF:-NOT_SET}" echo "SUPABASE_DB_URL_REF: ${SUPABASE_DB_URL_REF:-NOT_SET}"
Step 4: Verify Cal.com Secrets
echo "CALCOM_NEXTAUTH_SECRET_REF: ${CALCOM_NEXTAUTH_SECRET_REF:-NOT_SET}" echo "CALCOM_ENCRYPTION_KEY_REF: ${CALCOM_ENCRYPTION_KEY_REF:-NOT_SET}" echo "CALCOM_CRON_API_KEY_REF: ${CALCOM_CRON_API_KEY_REF:-NOT_SET}"
All 1Password references must be SET. Secrets are stored in Claude Automation vault.
Deploy Target: GCP Cloud Run
Step 1: Verify GCP APIs Enabled
gcloud services list --enabled
--project="$CALCOM_GCP_PROJECT"
--account="$CALCOM_GCP_ACCOUNT" 2>/dev/null | grep -E "run|artifact|build"
Required APIs: Cloud Run, Artifact Registry, Cloud Build.
Step 2: Build Container
From the cal.com fork directory
cd ~/fork-tools/cal.com
Build Docker image
docker build -t calcom-self-hosted .
Step 3: Push to Artifact Registry
Tag for Artifact Registry
docker tag calcom-self-hosted
"${CALCOM_GCP_REGION}-docker.pkg.dev/${CALCOM_GCP_PROJECT}/calcom/calcom:latest"
Push
docker push
"${CALCOM_GCP_REGION}-docker.pkg.dev/${CALCOM_GCP_PROJECT}/calcom/calcom:latest"
Step 4: Deploy to Cloud Run
Resolve secrets from 1Password
NEXTAUTH_SECRET=$(op read "$CALCOM_NEXTAUTH_SECRET_REF") ENCRYPTION_KEY=$(op read "$CALCOM_ENCRYPTION_KEY_REF") CRON_API_KEY=$(op read "$CALCOM_CRON_API_KEY_REF") DATABASE_URL=$(op read "$SUPABASE_DB_URL_REF")
gcloud run deploy calcom
--image="${CALCOM_GCP_REGION}-docker.pkg.dev/${CALCOM_GCP_PROJECT}/calcom/calcom:latest"
--region="$CALCOM_GCP_REGION"
--project="$CALCOM_GCP_PROJECT"
--account="$CALCOM_GCP_ACCOUNT"
--platform=managed
--allow-unauthenticated
--port=3000
--memory=512Mi
--cpu=1
--min-instances=0
--max-instances=2
--set-env-vars="DATABASE_URL=${DATABASE_URL}"
--set-env-vars="NEXTAUTH_SECRET=${NEXTAUTH_SECRET}"
--set-env-vars="CALENDSO_ENCRYPTION_KEY=${ENCRYPTION_KEY}"
--set-env-vars="CRON_API_KEY=${CRON_API_KEY}"
--set-env-vars="NEXT_PUBLIC_WEBAPP_URL=https://calcom-${CALCOM_GCP_PROJECT}.run.app"
--set-env-vars="NEXT_PUBLIC_API_V2_URL=https://calcom-${CALCOM_GCP_PROJECT}.run.app/api/v2"
Deploy Target: Docker Compose (Local Dev)
docker-compose.yml Template
version: "3.9" services: calcom: image: calcom/cal.com:latest restart: unless-stopped ports: - "3000:3000" env_file: - .env depends_on: database: condition: service_healthy
database: image: postgres:15 restart: unless-stopped volumes: - calcom-db:/var/lib/postgresql/data environment: POSTGRES_USER: calcom POSTGRES_PASSWORD: calcom POSTGRES_DB: calcom healthcheck: test: ["CMD-SHELL", "pg_isready -U calcom"] interval: 10s timeout: 5s retries: 5
volumes: calcom-db:
Local .env Template
DATABASE_URL=postgresql://calcom:calcom@database:5432/calcom NEXTAUTH_SECRET=<generate-with-openssl> CALENDSO_ENCRYPTION_KEY=<generate-with-openssl> CRON_API_KEY=<generate-with-openssl> NEXT_PUBLIC_WEBAPP_URL=http://localhost:3000 NEXT_PUBLIC_API_V2_URL=http://localhost:3000/api/v2
Deploy Target: Webhook Relay (Pushover Notifications)
Lightweight Cloud Run service bridging Cal.com webhooks to Pushover emergency alerts. Zero dependencies (Python stdlib only).
Step 1: Verify Pushover Credentials
echo "PUSHOVER_APP_TOKEN: ${PUSHOVER_APP_TOKEN:+SET}" echo "PUSHOVER_USER_KEY: ${PUSHOVER_USER_KEY:+SET}" echo "PUSHOVER_SOUND: ${PUSHOVER_SOUND:-dune}"
All must be SET. See pushover-setup.md for credential setup.
Step 2: Deploy Webhook Relay to Cloud Run
RELAY_SOURCE="$HOME/.claude/plugins/marketplaces/cc-skills/plugins/calcom-commander/scripts/webhook-relay"
gcloud run deploy calcom-pushover-webhook
--source "$RELAY_SOURCE"
--project="$CALCOM_GCP_PROJECT"
--account="$CALCOM_GCP_ACCOUNT"
--region="$CALCOM_GCP_REGION"
--platform managed
--allow-unauthenticated
--set-env-vars="PUSHOVER_TOKEN=$PUSHOVER_APP_TOKEN,PUSHOVER_USER=$PUSHOVER_USER_KEY,PUSHOVER_SOUND=${PUSHOVER_SOUND:-dune}"
--memory=128Mi
--cpu=1
--min-instances=0
--max-instances=1
--timeout=30
--quiet
Note the Service URL from the output. Store in .mise.local.toml as WEBHOOK_RELAY_URL .
Step 3: Verify Health
curl -s "$WEBHOOK_RELAY_URL" | python3 -m json.tool
Expected: {"status": "healthy", "service": "calcom-pushover-webhook"}
Step 4: Register Cal.com Webhook
CALCOM_API_KEY=$(op item get "$CALCOM_OP_UUID" --vault "Claude Automation" --fields password --reveal)
curl -s -X POST "https://api.cal.com/v1/webhooks?apiKey=$CALCOM_API_KEY"
-H "Content-Type: application/json"
-d "{"subscriberUrl":"$WEBHOOK_RELAY_URL","eventTriggers":["BOOKING_CREATED","BOOKING_RESCHEDULED","BOOKING_CANCELLED"],"active":true}"
Step 5: Test with Simulated Booking
curl -s -X POST "$WEBHOOK_RELAY_URL"
-H "Content-Type: application/json"
-d '{"triggerEvent":"BOOKING_CREATED","payload":{"title":"Test Meeting","attendees":[{"name":"Test User"}],"startTime":"2026-01-01T10:00:00Z","endTime":"2026-01-01T10:30:00Z"}}'
Expected: Pushover emergency alert with "dune" sound on your device.
Supabase Database Management
Check Connection
DATABASE_URL=$(op read "$SUPABASE_DB_URL_REF") psql "$DATABASE_URL" -c "SELECT version();"
Run Migrations
cd ~/fork-tools/cal.com DATABASE_URL=$(op read "$SUPABASE_DB_URL_REF") npx prisma migrate deploy
1Password Secret References
All secrets in Claude Automation vault (biometric-free access):
Secret 1Password Reference
NEXTAUTH_SECRET
op://Claude Automation/<item-id>/NEXTAUTH_SECRET
CALENDSO_ENCRYPTION_KEY
op://Claude Automation/<item-id>/CALENDSO_ENCRYPTION_KEY
CRON_API_KEY
op://Claude Automation/<item-id>/CRON_API_KEY
DATABASE_URL
op://Claude Automation/<item-id>/DATABASE_URL
DATABASE_DIRECT_URL
op://Claude Automation/<item-id>/DATABASE_DIRECT_URL
Post-Change Checklist
-
YAML frontmatter valid (no colons in description)
-
Trigger keywords current
-
Path patterns use $HOME not hardcoded paths
-
1Password references are agnostic (no hardcoded UUIDs)