Standard operating procedure · SOP-03

Deployment & Release

Version 1.0 · effective 13 July 2026 · owner: Jonny Allum

Trigger: shipping any change to bizos.jonnyai.co.uk. Owner: Jonny Allum. Policy anchors: POL-06, POL-08.

Deployment is currently SSH + fast-forward pull/build/restart on the GCP VM (PM2 + Caddy). The manual GitHub Deploy workflow stays inert until VM secrets are configured — when that lands, this SOP is updated in the same PR.

Pre-deploy (local)

  1. All four gates green: pnpm turbo run typecheck test build and cd apps/shell && pnpm exec tsx audit.mts → PASS. (Sandboxed sessions: NODE_EXTRA_CA_CERTS=/root/.ccr/ca-bundle.crt for the build.)
  2. Sensitive-class change (auth, RLS, billing, public writes, AI actions, cron)? Cooling-off self-review of the diff first (POL-06 §2).
  3. Migrations, if any, are applied to Supabase before the code that needs them (SOP-04) — the app must tolerate the window between.
  4. Everything committed and pushed; the VM only ever pulls, never diverges.

Deploy (VM)

  1. SSH in; git pull --ff-only (if it won't fast-forward, stop — the VM has drifted; fix the branch state first, never merge on the box).
  2. pnpm install (if lockfile changed) → build → pm2 restart the app (and JAIOS only if it changed).
  3. Note the deployed commit hash in the release note (the README "Current state" table records the pattern, e.g. c1d10f5).

Post-deploy smoke test (every deploy, ~5 minutes)

  • Public probes: /, /pricing, a /shop/[slug], a /book/[slug] return 200
  • Login works; dashboard renders for a demo tenant
  • The area you changed, exercised authenticated in the browser
  • One cron endpoint test-fired with BIZOS_CRON_SECRET (if cron touched)
  • Stripe webhook delivery green in the Stripe dashboard (if billing touched)
  • pm2 logs clean of new errors for a few minutes

Rollback

Fix forward with the smallest diff where possible (POL-06 emergency class). If the deploy is unusable: git checkout <last-good-hash> on the VM, build, restart — then repair on a branch locally. Migrations are not rolled back; they are idempotent and forward-only, so the rolled-back app must tolerate the newer schema (this is why migrations are additive — SOP-04).

Release hygiene

  • Deploy when you can watch it for 30 minutes — not last thing at night.
  • One deploy = one intention. Batches of unrelated changes make smoke failures undiagnosable.
  • Update BUILD_PLAN.md RESUME HERE block after any session that changes production state.
← All documents & policiesQuestions? hello@jonnyai.co.uk