# Release & deployment runbook — boha-app-ts Referenced from CLAUDE.md. **Never deploy to production or restart services without explicit user confirmation.** ## Standard release 1. Run the full gates locally: `npx vitest run` (all green), `npx tsc -b --noEmit`, `npm run lint` (0 errors). 2. Bump version: `npm version X.Y.Z --no-git-tag-version` (the user picks the number). 3. `npm run build` 4. Commit and tag: `git tag -a vX.Y.Z` 5. Push to Gitea: `git push origin master && git push origin vX.Y.Z` 6. Create tarball: ```bash tar -czf app-ts-X.Y.Z.tar.gz dist dist-client prisma prisma.config.ts package.json package-lock.json scripts ``` ⚠️ `prisma.config.ts` is REQUIRED — Prisma 7 keeps the datasource URL there; without it, `prisma generate`/`migrate deploy` on prod have no datasource. 7. Deploy via SSH to production (`boha_admin@192.168.50.100`, path `/var/www/app-ts`): ```bash scp app-ts-X.Y.Z.tar.gz boha_admin@192.168.50.100:/tmp/ ssh boha_admin@192.168.50.100 cd /var/www/app-ts rm -rf dist dist-client prisma prisma.config.ts scripts package.json package-lock.json tar -xzf /tmp/app-ts-X.Y.Z.tar.gz npm install --omit=dev npx prisma generate # MANDATORY — see below npx prisma migrate deploy pm2 restart app-ts --update-env ``` **`npx prisma generate` is mandatory.** `npm install` skips client regeneration when dependencies didn't change, leaving a stale client that still selects dropped/renamed columns → P2022 500s in prod (this caused the v2.4.0 incident: every issued-orders query failed until generate ran). 8. Verify: `pm2 list` (status online, correct version, restart counter not climbing), `npx prisma migrate status` ("up to date"), `curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3001/` → 200, and grep logs for errors from the CURRENT pid only (the out log keeps old errors from prior pids). 9. Clean up tarballs locally and in `/tmp/` on the server. **nginx is NOT part of a normal release.** nginx is only a reverse proxy in front of the pm2 app (`proxy_pass` → `127.0.0.1:3001`); a code release changes app code, which `pm2 restart app-ts` picks up — nginx has nothing new to read. Do **not** run `sudo nginx -t && sudo systemctl reload nginx` every deploy. Run it ONLY when you actually edit nginx config (`/etc/nginx/…` — `server_name`, ports, `proxy_pass` upstream, TLS cert paths, locations/redirects/headers, `client_max_body_size`, rate limits, etc.). When you do change it, always `nginx -t` first (validates syntax, changes nothing) THEN `systemctl reload nginx` (graceful re-read, keeps active connections; a bad config on reload is rejected and the old one keeps running). Risky releases (framework jumps, FK/constraint-altering migrations) get a read-only pre-flight first: `prisma migrate status` on prod, verify FK constraint names the migration DROPs, check no data violates new UNIQUE/RESTRICT constraints — and confirm with the user before the irreversible steps. The prod DB is backed up by a cron job (no manual mysqldump needed). ## Hotfixing a migration added after the tarball was built A migration folder created after the release tarball shipped is not on prod, so `prisma migrate deploy` reports "No pending migrations". Ship just the migration folder (still tracked in git — this is NOT raw SQL on prod): ```bash # Local cd prisma/migrations tar -czf /tmp/_migration.tar.gz _/ scp /tmp/_migration.tar.gz boha_admin@192.168.50.100:/tmp/ # On prod ssh boha_admin@192.168.50.100 cd /var/www/app-ts/prisma/migrations tar -xzf /tmp/_migration.tar.gz cd /var/www/app-ts npx prisma migrate deploy pm2 restart app-ts --update-env ``` ## Drift check / preview before deploy ```bash # Preview what SQL would bring the dev DB (per prisma.config.ts) to the local schema npx prisma migrate diff --from-config-datasource --to-schema prisma/schema.prisma --script ``` Empty output = no diff. (Prisma 7 removed `--from-url`; diffs against another DB need its URL in a config/env override.) If drift includes DROPs, investigate before touching production. ## Baselining a database that has no migrations If a database was synced without migration history (no `_prisma_migrations` table): create the initial migration locally, copy `prisma/migrations` to the server, then mark it applied without running SQL: ```bash npx prisma migrate resolve --applied ```