docs: consolidate CLAUDE.md (merge audit sections, dedupe, fix stale facts); runbooks to docs/release.md
Applied the two-review consolidation: merged the duplicate 2026-06-06/06-09 'Conventions (enforced)' sections into one canonical block (query-invalidation rule stated once instead of three times, Zod-helper 'tracked follow-up' vs 'MANDATORY' contradiction resolved, seed-is-dev-only stated once); removed stale-by-design facts (version pins, test counts, file counts, React 18 typo) and migration-era storytelling; fixed prisma migrate diff flags (--from-url removed in Prisma 7) and documented the non-interactive migration recipe; added the new rules earned this week (@db.Date UTC-truncation, document business rules incl. VAT-only-on-invoices and PO suppliers, document-platform conventions, shared-module reuse list, dashboard invalidation, app_test migrate step). Release/hotfix/drift/baseline runbooks moved to docs/release.md with a pointer (keeps prod details out of every-turn context). Also dropped the db:push npm script - it contradicted the golden rule. CLAUDE.md: 570 -> ~390 lines. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
96
docs/release.md
Normal file
96
docs/release.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# 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>
|
||||
```
|
||||
Reference in New Issue
Block a user