infra-deploy
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseInfrastructure Deployment
基础设施部署
Deploy Cal.com self-hosted to GCP Cloud Run with Supabase PostgreSQL, or run locally via Docker Compose.
将自托管Cal.com部署到搭载Supabase PostgreSQL的GCP Cloud Run,也可通过Docker Compose在本地运行。
Mandatory Preflight
必备前置检查
Step 1: Check GCP Project Configuration
步骤1:检查GCP项目配置
bash
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 . Run the setup command.
.mise.local.tomlbash
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}"如果显示NOT_SET:这些变量必须在中配置,请运行设置命令。
.mise.local.tomlStep 2: Verify GCP Authentication
步骤2:验证GCP身份认证
bash
gcloud auth list --filter="status=ACTIVE" --format="value(account)" 2>/dev/nullbash
gcloud auth list --filter="status=ACTIVE" --format="value(account)" 2>/dev/nullStep 3: Check Supabase Configuration
步骤3:检查Supabase配置
bash
echo "SUPABASE_PROJECT_REF: ${SUPABASE_PROJECT_REF:-NOT_SET}"
echo "SUPABASE_DB_URL_REF: ${SUPABASE_DB_URL_REF:-NOT_SET}"bash
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
步骤4:验证Cal.com密钥
bash
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.
bash
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}"所有1Password引用必须已配置,密钥存储在Claude Automation保管库中。
Deploy Target: GCP Cloud Run
部署目标:GCP Cloud Run
Step 1: Verify GCP APIs Enabled
步骤1:确认GCP API已启用
bash
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.
bash
gcloud services list --enabled \
--project="$CALCOM_GCP_PROJECT" \
--account="$CALCOM_GCP_ACCOUNT" 2>/dev/null | grep -E "run|artifact|build"所需API:Cloud Run、Artifact Registry、Cloud Build。
Step 2: Build Container
步骤2:构建容器
bash
undefinedbash
undefinedFrom the cal.com fork directory
从cal.com fork目录执行
cd ~/fork-tools/cal.com
cd ~/fork-tools/cal.com
Build Docker image
构建Docker镜像
docker build -t calcom-self-hosted .
undefineddocker build -t calcom-self-hosted .
undefinedStep 3: Push to Artifact Registry
步骤3:推送到Artifact Registry
bash
undefinedbash
undefinedTag for Artifact Registry
为Artifact Registry打标签
docker tag calcom-self-hosted
"${CALCOM_GCP_REGION}-docker.pkg.dev/${CALCOM_GCP_PROJECT}/calcom/calcom:latest"
"${CALCOM_GCP_REGION}-docker.pkg.dev/${CALCOM_GCP_PROJECT}/calcom/calcom:latest"
docker tag calcom-self-hosted
"${CALCOM_GCP_REGION}-docker.pkg.dev/${CALCOM_GCP_PROJECT}/calcom/calcom:latest"
"${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"
"${CALCOM_GCP_REGION}-docker.pkg.dev/${CALCOM_GCP_PROJECT}/calcom/calcom:latest"
undefineddocker push
"${CALCOM_GCP_REGION}-docker.pkg.dev/${CALCOM_GCP_PROJECT}/calcom/calcom:latest"
"${CALCOM_GCP_REGION}-docker.pkg.dev/${CALCOM_GCP_PROJECT}/calcom/calcom:latest"
undefinedStep 4: Deploy to Cloud Run
步骤4:部署到Cloud Run
bash
undefinedbash
undefinedResolve secrets from 1Password
从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"
--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"
---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"
--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(本地开发)
docker-compose.yml Template
docker-compose.yml 模板
yaml
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:yaml
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
本地 .env 模板
bash
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/v2bash
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/v2Deploy Target: Webhook Relay (Pushover Notifications)
部署目标:Webhook中继(Pushover通知)
Lightweight Cloud Run service bridging Cal.com webhooks to Pushover emergency alerts. Zero dependencies (Python stdlib only).
轻量级Cloud Run服务,用于将Cal.com webhook桥接到Pushover紧急告警,无额外依赖(仅使用Python标准库)。
Step 1: Verify Pushover Credentials
步骤1:验证Pushover凭证
bash
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.
bash
echo "PUSHOVER_APP_TOKEN: ${PUSHOVER_APP_TOKEN:+SET}"
echo "PUSHOVER_USER_KEY: ${PUSHOVER_USER_KEY:+SET}"
echo "PUSHOVER_SOUND: ${PUSHOVER_SOUND:-dune}"所有变量必须已配置,凭证配置方法请查看pushover-setup.md。
Step 2: Deploy Webhook Relay to Cloud Run
步骤2:将Webhook中继部署到Cloud Run
bash
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 \
--quietNote the Service URL from the output. Store in as .
.mise.local.tomlWEBHOOK_RELAY_URLbash
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请记录输出中的服务URL,将其作为存储在中。
WEBHOOK_RELAY_URL.mise.local.tomlStep 3: Verify Health
步骤3:验证健康状态
bash
curl -s "$WEBHOOK_RELAY_URL" | python3 -m json.toolbash
curl -s "$WEBHOOK_RELAY_URL" | python3 -m json.toolExpected: {"status": "healthy", "service": "calcom-pushover-webhook"}
预期输出:{"status": "healthy", "service": "calcom-pushover-webhook"}
undefinedundefinedStep 4: Register Cal.com Webhook
步骤4:注册Cal.com Webhook
bash
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}"bash
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
步骤5:模拟预约测试
bash
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.
bash
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"}}'预期结果:你的设备将收到带有「dune」提示音的Pushover紧急告警。
Supabase Database Management
Supabase数据库管理
Check Connection
检查连接
bash
DATABASE_URL=$(op read "$SUPABASE_DB_URL_REF")
psql "$DATABASE_URL" -c "SELECT version();"bash
DATABASE_URL=$(op read "$SUPABASE_DB_URL_REF")
psql "$DATABASE_URL" -c "SELECT version();"Run Migrations
执行迁移
bash
cd ~/fork-tools/cal.com
DATABASE_URL=$(op read "$SUPABASE_DB_URL_REF") npx prisma migrate deploybash
cd ~/fork-tools/cal.com
DATABASE_URL=$(op read "$SUPABASE_DB_URL_REF") npx prisma migrate deploy1Password Secret References
1Password密钥引用
All secrets in Claude Automation vault (biometric-free access):
| Secret | 1Password Reference |
|---|---|
| |
| |
| |
| |
| |
所有密钥存储在Claude Automation保管库中(支持无生物识别访问):
| 密钥名称 | 1Password 引用路径 |
|---|---|
| |
| |
| |
| |
| |
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)
- YAML前置元数据有效(描述中无冒号)
- 触发关键词为最新版本
- 路径模式使用$HOME而非硬编码路径
- 1Password引用是通用格式(无硬编码UUID)