Skip to main content

Deploy & CI/CD

Web app (ka26.shop)

CI/CD pipeline (.github/workflows/deploy.yml)

On every push to main:

  1. Run Testsnpm test (1874 tests, ~1s)
  2. Run Mobile Tests — vitest + Jest in mobile/
  3. Build Imagedocker build → push to Artifact Registry (us-central1-docker.pkg.dev/school-mgmt-saas/ka26)
  4. Deploy to Staginggcloud run deploy ka26-staging
  5. Smoke Tests (Staging)tests/e2e-smoke.test.ts against staging URL
  6. Deploy to Productiongcloud run deploy ka26-marketplace
  7. Verify production is healthy — curl /api/health (10s sleep + retry; if Cold start > sleep window, may falsely fail — re-run via gh run rerun)

Failed at any step → no production deploy.

Manual deploy (don't, unless CI is broken)

gcloud builds submit --tag us-central1-docker.pkg.dev/school-mgmt-saas/ka26/app:manual-$(date +%s)
gcloud run deploy ka26-marketplace --image=... --region=us-central1

Cloud Run service

  • Project: school-mgmt-saas
  • Region: us-central1 (only — never multi-region for cost)
  • Service: ka26-marketplace
  • Service URL: https://ka26-marketplace-4374945524.us-central1.run.app
  • Custom domain: ka26.shop via Global Load Balancer
  • Min instances: 0, max: 10 (default)

Artifact Registry

  • Repo: ka26 in us-central1
  • Auto-cleanup: keep latest 5, delete >7 days old (configured 2026-04-17 to control storage cost)

Landing page (ka-26.com)

Hosted on GitHub Pages (free) — repo sidgk/ka26-website. Deploy is .github/workflows/deploy.yml in that repo, builds Next.js as static export, publishes to Pages. Custom domain CNAME at static/CNAME.

Docs portal (docs.ka-26.com)

This very portal. Hosted on GitHub Pages — repo sidgk/ka26-docs. See GitHub Setup below.

Database

Migrations (Prisma)

Schema lives in prisma/schema.prisma. Generate migration SQL via prisma migrate dev (local) — but for production, write the migration SQL by hand and apply via psql:

PGPASSWORD=Ka26Mkt2026 psql -h 34.123.40.64 -U ka26user -d ka26 -f prisma/migrations/<timestamp>_<name>/migration.sql

Migrations under prisma/migrations/ are idempotent (IF NOT EXISTS, ADD COLUMN IF NOT EXISTS) so re-runs are safe.

Backup strategy

Cloud SQL automated backups should be ON. Verify periodically (see Backups).

Cloud Run env var management

Update a single env var

gcloud run services update ka26-marketplace --region us-central1 \
--update-env-vars NEW_VAR=value

Update multiple

gcloud run services update ka26-marketplace --region us-central1 \
--update-env-vars VAR1=v1,VAR2=v2

Mount a Secret Manager secret

echo -n "secret-value" | gcloud secrets create my-secret --data-file=-
gcloud run services update ka26-marketplace --region us-central1 \
--update-secrets MY_SECRET=my-secret:latest

Cloud Run picks up :latest on every cold-start automatically. To force immediate rotation, deploy a new revision (any change triggers it).

Rollback

# List revisions
gcloud run revisions list --service ka26-marketplace --region us-central1

# Roll all traffic to a known-good revision
gcloud run services update-traffic ka26-marketplace --region us-central1 \
--to-revisions ka26-marketplace-00XXX-yyy=100

Takes ~30s. Note: this doesn't roll back DB migrations — those need a separate forward migration.

GitHub setup

CI runs without seeding

The pipeline doesn't have DB access. Tests are file-shape + smoke tests only — no DB queries during CI.

Required GitHub secrets

  • WIF_PROVIDER — workload identity provider for ka26-deployer@school-mgmt-saas.iam.gserviceaccount.com
  • SMTP_USER, SMTP_PASS — for the hourly health check workflow's email alert
  • ALERT_TO — recipient email for health-cron failures
  • SENTRY_AUTH_TOKEN — optional, for source-map upload
  • SENTRY_ORG, SENTRY_PROJECT — optional

What can break the pipeline

SymptomCauseFix
Build Image: ❌ Type error: Cannot find module 'react-native'Mobile-only file got picked up by Next.js typecheckAdd to tsconfig.json exclude (already done for _archived-mobile, src/_archived)
Deploy to Staging: ❌ Staging health check failed with status 503Cloud Run cold-start race; health check ran before container bootedRe-run the workflow (gh run rerun <id> --failed)
Test failed: 'foo'Code regressionRead the test, fix the code, push again
npm ci fails on node-gypNative module compile issueUsually transient; re-run
Sentry build hook errorsSDK version mismatchCheck next.config.ts — Sentry v10 renamed hideSourceMapssourcemaps.deleteSourcemapsAfterUpload