Skip to main content

Infrastructure

Last reviewed: 2026-05-13
Maintained by: Engineering

This repo currently uses split hosting for the web app and the API:

  • apps/back-office (Back Office) is deployed to Vercel
  • apps/manager-desk (Manager Desk) is deployed to Vercel
  • apps/api is deployed to Render
  • PostgreSQL runs locally via Docker and uses environment-specific instances in hosted environments

Sentry is environment-configured only:

  • API Sentry runtime vars live on the API host (Render in the current docs standard)
  • Manager Desk Sentry vars live in the Vercel project environment settings
  • Back Office Sentry vars live in the Vercel project environment settings
  • mobile Sentry vars live in Expo / EAS environment settings

Deployment Model

The branch flow is currently:

  • feature branches -> merge into main
  • main does not auto-deploy anywhere
  • deploys to Staging and Production are triggered manually

GitHub Actions handles this through two workflows:

  • .github/workflows/ci.yml: validation on pull_request and push
  • .github/workflows/deploy.yml: manual deployment promotion

What CI Actually Checks

ci.yml has the following main jobs:

1. Install, Typecheck, Lint

This confirms that the repo can:

  • install dependencies with pnpm install --frozen-lockfile
  • pass pnpm run check:api
  • pass pnpm run check:manager-desk
  • pass pnpm run lint

This protects the repo from:

  • broken pnpm-lock.yaml
  • TypeScript regressions
  • lint regressions

2. Build Apps

This confirms that the deployable apps still build cleanly:

  • pnpm run build:api
  • pnpm run build:manager-desk

This protects the repo from:

  • build-only regressions not caught by typecheck
  • deploy-time packaging failures surfacing too late

3. Database Smoke Test

CI spins up a temporary PostgreSQL service and runs:

  • pnpm run db:migrate
  • pnpm run seed:demo
  • pnpm run db:migrate

This confirms that:

  • new migrations work on an empty database
  • the seed script matches the current schema
  • rerunning migrations does not fail after the database is already migrated

4. Tests

This runs workspace tests through:

  • pnpm test

5. Migration Drift Check

This confirms committed migrations still reproduce the checked-in schema snapshot.

Deploy Flow

deploy.yml is manual-only and uses workflow_dispatch.

Staging

When you manually choose target staging:

  • Manager Desk is deployed to the Vercel preview/staging target
  • API is deployed to the Render staging service
  • the workflow uses the GitHub Environment Staging
  • the environment contract is validated before deploy steps run

Production

When you manually choose target production:

  • Manager Desk is deployed to Vercel production
  • API is deployed to the Render production service
  • the workflow uses the GitHub Environment Production
  • the environment contract is validated before deploy steps run

GitHub Environments

The repo expects two active GitHub Environments:

  • Staging
  • Production

Environment-scoped configuration matters because it allows:

  • a different database connection per environment
  • different JWT secrets per environment
  • different WEB_ALLOWED_ORIGINS per environment
  • separate Render and Vercel deployment targets

Mapping Local .env to GitHub

Local development uses root .env.example as the template.

GitHub uses the same contract, split into:

  • vars: non-sensitive runtime values
  • secrets: sensitive values such as DB passwords, JWT secrets, and deploy tokens

Practical rule:

  • if a value is safe to display in the GitHub UI, store it in vars
  • otherwise store it in secrets

Environment validation now happens during manual deploy, not on every CI push.

Required GitHub Variables

Required vars

  • NODE_ENV
  • PORT
  • DB_HOST
  • DB_PORT
  • DB_NAME
  • DB_USER
  • JWT_ACCESS_TTL
  • JWT_REFRESH_TTL_DAYS
  • WEB_ALLOWED_ORIGINS
  • COOKIE_SECURE
  • COOKIE_SAME_SITE
  • COOKIE_DOMAIN optional
  • SENTRY_ENABLED optional
  • SENTRY_ENVIRONMENT optional
  • SENTRY_RELEASE optional
  • SENTRY_TRACES_SAMPLE_RATE optional
  • RAILWAY_PROJECT_ID for deploy environments
  • RAILWAY_ENVIRONMENT_ID for deploy environments
  • RAILWAY_SERVICE_ID_API for deploy environments
  • NEXT_PUBLIC_API_URL for Manager Desk runtime
  • NEXT_PUBLIC_SENTRY_ENABLED optional for Manager Desk runtime
  • NEXT_PUBLIC_SENTRY_DSN optional for Manager Desk runtime
  • NEXT_PUBLIC_SENTRY_ENVIRONMENT optional for Manager Desk runtime
  • NEXT_PUBLIC_SENTRY_RELEASE optional for Manager Desk runtime
  • NEXT_PUBLIC_SENTRY_TRACES_SAMPLE_RATE optional for Manager Desk runtime
  • NEXT_PUBLIC_API_URL for Back Office runtime
  • NEXT_PUBLIC_SENTRY_ENABLED optional for Back Office runtime
  • NEXT_PUBLIC_SENTRY_DSN optional for Back Office runtime
  • NEXT_PUBLIC_SENTRY_ENVIRONMENT optional for Back Office runtime
  • NEXT_PUBLIC_SENTRY_RELEASE optional for Back Office runtime
  • NEXT_PUBLIC_SENTRY_TRACES_SAMPLE_RATE optional for Back Office runtime

Required secrets

  • DB_PASSWORD
  • DATABASE_URL
  • JWT_ACCESS_SECRET
  • JWT_REFRESH_SECRET
  • SENTRY_DSN optional for API runtime
  • VERCEL_TOKEN for deploy environments
  • VERCEL_ORG_ID for deploy environments
  • VERCEL_PROJECT_ID_MANAGER_DESK for deploy environments
  • RAILWAY_TOKEN for deploy environments

Sentry Deployment Notes

  • keep local Sentry disabled unless you are intentionally testing delivery
  • do not hardcode DSNs, org IDs, project IDs, auth tokens, or release secrets in source
  • session replay is intentionally not enabled
  • source map upload is a later deployment task and is not part of the current repo wiring

Preview Strategy

The current setup intentionally uses the simplest preview model:

  • Vercel-generated preview URLs for the web app
  • Render-generated service URLs for the API

Custom subdomains are intentionally deferred until they become an operational requirement.

System Health Alert Retention (Manual)

System Health v1 does not introduce a dedicated scheduler for alert retention. Run manual cleanup during operations maintenance windows:

pnpm run cleanup:system-health-alerts

Default retention is 90 days. Optional override:

pnpm --filter @zgrid/api cleanup:system-health-alerts 120

Source of Truth

When you change the infrastructure setup, keep these files aligned: