# 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.

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/<name>_migration.tar.gz <timestamp>_<name>/
scp /tmp/<name>_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/<name>_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 <migration_name>
```
