deckhearth/.cursor/rules/no-go-zones.mdc
Randall Stillwell 68bf75f18c feat(infra): adopt node-pg-migrate + backfill initial schema migration
Closes P1 #11 of .convoys/ship-readiness.md (launch sequence step 7) —
"No migration tool — scripts/add-*.js graveyard". Schema changes
post-this-convoy ship as node-pg-migrate migrations under migrations/
at the repo root; the legacy 27 scripts/add-*.js / scripts/fix-*.js /
scripts/seed-*.js jobs remain append-only history per the no-go-zones
rule.

Decisions (full record in .convoys/migration-tool.md § Decisions):

D1 — Tool: node-pg-migrate@^8. Rejected drizzle-kit / prisma migrate /
kysely because each forces broader TypeScript surface than AGENTS.md
Gotcha #9 allows (TS is a devDep only). node-pg-migrate is
JavaScript-native, raw-SQL-friendly via pgm.sql(), and ESM-clean for
the post-bump-next-js "type": "module" repo. Brings pg@^8.21.0 as a
peer dep (dev-only; never loaded in the Next.js bundle).

D2 — Migrations directory: migrations/ at the repo root. Separates
the tool-wrapped artifacts from the historical scripts/migrations/
placeholder folder (which housed the lone pre-tool
2026-05-24-rename-admin-email.js migration and remains preserved for
the audit trail). Matches node-pg-migrate's default flag.

D3 — Tracking table: default pgmigrations (no name collision with
the existing 7-table bootstrap; zero CLI noise).

D4 — Backfill strategy: hand-translate scripts/setup-neon-db.js's
DDL into the initial migration verbatim. Each await sql`...` block
becomes one pgm.sql(`...`) call. Each CREATE uses IF NOT EXISTS, so
the migration is idempotent against fresh AND pre-existing envs —
re-running setup-db on an env that already has the schema is a no-op
DDL-wise (only records the pgmigrations row). Documented assumption:
prod has drifted via the 27 historical add-*.js scripts; reconciling
those into the migration history is the queued
reconcile-historical-add-scripts follow-up convoy.

D5 — Bootstrap reconciliation: split. setup-neon-db.js now (1)
validates ADMIN_INITIAL_PASSWORD + POSTGRES_URL, (2) spawns
`npm run migrate up` via child_process with stdio inherited, (3)
seeds the admin row with ON CONFLICT (email) DO NOTHING. The seven
DDL blocks are deleted from setup-neon-db.js; success/error message
copy is updated to mention the migration step explicitly.

D6 — CI integration: defer. Wiring a CI job that runs migrate up
against a test DB needs either a dedicated Neon branch + secret OR a
Postgres service container; both are real work. Surface as
wire-migrate-into-ci follow-up. Risk acknowledged in
.convoys/migration-tool.md § R3.

D7 — Down-migration on the initial backfill: hard stub. Rolling back
the initial schema would drop every user / card / collection / deck
row in the DB. The stub throws with a long-form error pointing at
the recommended alternative (branch the Neon database + forward-apply).
Future migrations that touch one of the seven bootstrap tables write
their own dated migration with a real down().

Verification (pre-PR):
- npm run lint → 128 problems (baseline preserved, zero regression;
  migration file is lint-clean, no new ignore patterns)
- npm run test:run → 21/21 pass
- node --check on migrations/1779853647564_initial-schema.js + on
  scripts/setup-neon-db.js → exit 0
- Module load + down() throw verified via dynamic import
- npm run migrate -- --help reaches the node-pg-migrate CLI through
  the wrapper

Live verification against a Neon branch is deferred (no throwaway
branch available); the operator's optional post-merge sequence is
documented in .convoys/migration-tool.md § Operator runbook.

See .convoys/migration-tool.md § Follow-ups for the queued
wire-migrate-into-ci / reconcile-historical-add-scripts /
retire-graveyard-scripts-after-audit / audit-node-pg-migrate-transitive-deps
/ add-migration-template follow-up convoys.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 22:55:09 -05:00

37 lines
2.7 KiB
Text

---
description: Files and directories agents must not edit, and should not use as context examples
alwaysApply: true
---
# No-go zones
Do not edit, refactor, or quote as context examples. If you think you need to change one of these, stop and ask.
## Generated / vendored
- `node_modules/` — generated dependency tree
- `.next/` — Next.js build output
- `.vercel/` — Vercel CLI local config + build cache
- `out/`, `build/` — build outputs if present
## Append-only / historical
- `components/Layout.js.backup` — legacy snapshot; delete with a real PR, never edit
- `scripts/add-*.js`, `scripts/fix-*.js`, `scripts/seed-*.js` — historical migration / seed jobs already executed. Write a NEW dated script (or a real migration) for further schema changes; never edit ones that already ran.
## Secrets / credentials
- `.env`, `.env.local`, `.env.development.local`, `.env.test.local`, `.env.production.local`
- Anything matching `.env*.local`
- Never commit `JWT_SECRET`, `POSTGRES_URL`, `RESEND_API_KEY`, `BLOB_READ_WRITE_TOKEN`, `GEMINI_API_KEY`, OpenAI/Anthropic keys.
## Local-only / per-developer
- `.code-review-graph/` — local MCP graph index (only if `user-code-review-graph` is installed)
- `.convoys/.metrics.jsonl` — per-developer convoy analytics (gitignored by default)
## Editing rules of thumb
- **Schema changes:** ship as a `node-pg-migrate` migration under `migrations/` at the repo root (post-`migration-tool` convoy, 2026-05-26). Generate via `npm run migrate create <name> -- -j js`, then edit the generated file. Do NOT edit `scripts/setup-neon-db.js` for any **DDL change** (`CREATE TABLE`, `ALTER`, new columns, constraint changes) — the bootstrap script's DDL was relocated to `migrations/1779853647564_initial-schema.js` and `setup-neon-db.js` now owns only env-var validation, the migration-runner spawn, and the admin-row seed. **Operational changes to `setup-neon-db.js` are still allowed** (env-var gating, error-message hardening, module-system fixes) — the `drop-public-setup` convoy set that precedent. The legacy `scripts/migrations/YYYY-MM-DD-<slug>.js` placeholder is preserved for the lone existing pre-tool migration (`2026-05-24-rename-admin-email.js`) and is **not** used for new work; new migrations go in the repo-root `migrations/` directory and are wrapped by the tool.
- **Auth refactors:** `lib/permission-middleware.js`, `pages/api/auth-utils.js`, `lib/auth-context.js`, `lib/admin-auth.js`, and `lib/use-auth.js` form a deliberately documented mess. Tighten them inside a single convoy; don't cherry-pick.
- **Card-import jobs:** `pages/api/cards/import-*.js` hit external APIs with rate limits. Don't run them ad-hoc against prod data; use staging.