Skip to main content

Deployment

Overview

TargetTriggerPipeline
Cloud Run (staging)Push to main.github/workflows/deploy.yml
Cloud Run (production)Published GitHub release tag with production deploy opt-in enabled.github/workflows/deploy.yml
Cloudflare Pages (React applications)Push to main.github/workflows/cloudflare-pages.yml
Cloudflare Pages (Docs and Support Docs)GitHub release or production-enabled manual dispatch.github/workflows/cloudflare-pages.yml
Kotlin SDK (Maven)Every push to main (dev-<commit>) and GitHub releases.github/workflows/sdk-publish.yml
TypeScript SDK (npm)GitHub release.github/workflows/sdk-npm-publish.yml

Cloud Run Deployment Flow

  1. Build: Bazel builds OCI images for all 8 services
  2. Push: Images pushed to Artifact Registry (us-east1-docker.pkg.dev/pinpoint-gateway/gateway/{service}:{tag})
  3. Deploy: gcloud run deploy to Cloud Run with appropriate env vars and secrets

Image Tagging

EnvironmentTagExample
Stagingdevgateway-processing:dev
ProductionRelease taggateway-processing:v0.0.3

CRITICAL: Production must use a pinned immutable release tag. Never use latest or dev for production.

Cloud Run Services

Staging and production use the same service names; the environment is distinguished by GCP project (peakgateway-staging vs pinpoint-gateway), not by a -staging name suffix.

ServiceName (both projects)
authgateway-auth
processinggateway-processing
managementgateway-management
online-txngateway-online-txn
card-presentgateway-card-present
merchant-onboardinggateway-merchant-onboarding
statusgateway-status
mcpgateway-mcp

Region: us-east1. Staging project: peakgateway-staging; production project: pinpoint-gateway. Container images for both environments live in pinpoint-gateway's Artifact Registry (staging pulls cross-project).

Scaling Configuration

Terraform defines Cloud Run scaling in infra/tf/gcp/variables.tf and applies it from infra/tf/gcp/modules/cloud-run/main.tf:

SettingTerraform defaults
Warm servicesProduction: auth, management, merchant-onboarding, online-txn, processing; staging: auth
Warm min instances1
Request-based min instances0
Max instancesauth/management/online-txn 30; card-present/processing 20; merchant-onboarding/status 10; mcp falls back to 10
CPU1
Memory2Gi

Deployment Verification and Rollout Evidence

A merge or push to main, a green validation run, or a successful image build/push proves only that a candidate artifact was produced for the staging path. It is not evidence that production was deployed.

Production requires a published GitHub release tag and the GitHub Actions repository variable PRODUCTION_DEPLOY_ENABLED to be set to true; workflow dispatch alone cannot enter the production deployment job. Treat a rollout as verified only when all of the following are true:

  1. The target Cloud Run revision is Ready and runs the intended immutable image (prefer the image digest, not only a mutable tag).
  2. Service traffic points to that revision. A revision existing or being Ready is not enough.
  3. The appropriate health or surface check passes: use a public route smoke check for a public service, and an authenticated/internal health or surface check for an internal-only service such as processing.

Build, push, and workflow-success indicators are supporting evidence only. Inspect the service traffic and revision image after the rollout, then perform the environment-appropriate check:

# Inspect the revision receiving traffic (staging; use --project=pinpoint-gateway for prod)
gcloud run services describe gateway-processing \
--region=us-east1 \
--project=peakgateway-staging \
--format='yaml(status.latestReadyRevisionName,status.traffic)'

# Inspect the immutable image and readiness of that revision
gcloud run revisions describe REVISION \
--region=us-east1 \
--project=peakgateway-staging \
--format='yaml(spec.containers[0].image,status.conditions)'

# View logs when the health or surface check needs runtime context
gcloud logging read 'resource.labels.service_name="gateway-processing"' --project=peakgateway-staging --limit=20 --format='value(jsonPayload.message)'

For example, the public status route can be checked as follows. Processing is internal-only and has no public load-balancer route:

curl https://staging-api.peakgateway.co/status/health

Website Deployment

React application staging hostnames deploy automatically on pushes to main. Production React hostnames, Docs, and Support Docs deploy only from a GitHub release or a production-enabled manual dispatch. Docs and Support Docs have no staging hostname.

WebsiteProduction URLStaging URL
Portalportal.peakgateway.costaging-portal.peakgateway.co
Checkoutcheckout.peakgateway.costaging-checkout.peakgateway.co
Merchant Portalmerchant.peakgateway.costaging-merchant.peakgateway.co
Marketingpeakgateway.costaging.peakgateway.co
Docsdocs.peakgateway.coN/A
Support Docssupport-docs.peakgateway.coN/A

Cloudflare Pages is a separate deployment surface from Cloud Run. Validate the exact hostname for the intended environment: the staging-* hostnames (and staging.peakgateway.co for Marketing) are distinct from their production hostnames. A green Pages build, or a check against one hostname, does not prove the other environment is deployed or serving the target site. Docs and Support Docs currently have no staging hostname in this table.

Infrastructure Changes

Terraform manages all GCP infrastructure. Remote state and runs use Terrakube (iac-api.peaksuite.dev) with separate gateway production and gateway-staging workspaces. The checked-in backend selectors make local read-only planning explicit:

cd infra/tf/gcp

# Staging
terraform init -reconfigure -backend-config=backend-staging.hcl
terraform plan

# Production (reinitialize before switching environments)
terraform init -reconfigure -backend-config=backend-prod.hcl
terraform plan

Apply through the authorized Terrakube workspace. Do not run a local apply against production.

Maintenance

Cleaning old Cloud Run revisions

# Dry run (default)
./infra/scripts/cleanup-cloud-run-revisions.sh \
--project pinpoint-gateway \
--region us-east1 \
--all-services \
--keep 3

# Apply
./infra/scripts/cleanup-cloud-run-revisions.sh \
--project pinpoint-gateway \
--region us-east1 \
--all-services \
--keep 3 \
--apply

This runs automatically hourly via .github/workflows/infra-maintenance.yml.

CI/CD Pipelines

System / workflowTriggerPurpose
BuildBuddy validation (buildbuddy.yaml)PR, merge queue, push to mainLint, drift, backend, website, SDK, schema, IaC, integration, package, and container validation
BuildBuddy nightlies (buildbuddy.yaml)Daily schedulesManual-tagged integration tests and uncached Android consumer smoke
deploy.ymlPush to main, release, manualBuild, sign, push, and deploy Cloud Run services
cloudflare-pages.ymlPush to main, release, manualBuild and deploy all websites
infra-maintenance.ymlHourlyClean old Cloud Run revisions and expired GitHub artifacts
sdk-publish.ymlPush to main, release, manualPublish Kotlin SDK development or release artifacts to Maven
sdk-npm-publish.ymlRelease, manualPublish or dry-run the TypeScript SDK package
apple-ci.ymlApple SDK changesRun macOS/Xcode validation unavailable to Linux BuildBuddy executors