Skip to main content

Deployment

Overview

TargetTriggerPipeline
Cloud Run (staging)Push to main.github/workflows/deploy.yml
Cloud Run (production)Manual dispatch with release tag.github/workflows/deploy.yml
Cloudflare PagesPush to main.github/workflows/cloudflare-pages.yml
Kotlin SDK (Maven)GitHub release.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 7 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

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:

SettingStagingProduction
Min instances1 for management, online-txn, and processing; otherwise 01 for warm services; otherwise 0
Max instances5Per-service overrides: auth/management/online-txn 30, card-present/processing 20, merchant-onboarding/status 10
CPU11
Memory2Gi2Gi

Checking Deployment Status

# List Cloud Run revisions (staging; use --project=pinpoint-gateway for prod)
gcloud run revisions list --service=gateway-processing --region=us-east1 --project=peakgateway-staging

# View logs
gcloud logging read 'resource.labels.service_name="gateway-processing"' --project=peakgateway-staging --limit=20 --format='value(jsonPayload.message)'

# Check a public health route. Processing is internal-only and has no public LB route.
curl https://staging-api.peakgateway.co/status/health

Website Deployment

Websites deploy to Cloudflare Pages automatically on push to main:

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

Infrastructure Changes

Terraform manages all GCP infrastructure:

cd infra/tf/gcp
terraform plan # Review changes
terraform apply # Apply (requires approval)

State is stored in Terraform Cloud (org: peaksystems, workspace: gateway).

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

WorkflowTriggerPurpose
ci.ymlPR, push to mainBuild + test all services/libs
deploy.ymlPush to main, release, manualBuild, push, deploy to Cloud Run
cloudflare-pages.ymlPush to mainBuild + deploy all websites
pre-commit.ymlPRLinting, formatting checks
iac-security.ymlinfra/** changesCheckov + Terraform validation
infra-maintenance.ymlHourlyClean old revisions + artifacts
sdk-publish.ymlGitHub releasePublish Kotlin SDK to Maven
sdk-npm-publish.ymlGitHub releasePublish TypeScript SDK to npm