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>
51 lines
1.5 KiB
JSON
51 lines
1.5 KiB
JSON
{
|
|
"name": "deck-hearth",
|
|
"version": "0.1.0",
|
|
"private": true,
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "next dev",
|
|
"build": "next build",
|
|
"start": "next start",
|
|
"lint": "eslint .",
|
|
"migrate": "node-pg-migrate --database-url-var POSTGRES_URL --envPath .env.local --migrations-dir migrations --verbose",
|
|
"setup-db": "node scripts/setup-neon-db.js",
|
|
"import-popular": "node scripts/import-popular-sets.js",
|
|
"import-all": "node scripts/bulk-import-all.js",
|
|
"test": "vitest",
|
|
"test:run": "vitest run",
|
|
"test:smoke": "playwright test --project=smoke",
|
|
"test:visual": "playwright test --project=visual",
|
|
"test:visual:update": "playwright test --project=visual --update-snapshots"
|
|
},
|
|
"dependencies": {
|
|
"@neondatabase/serverless": "^1.0.1",
|
|
"@upstash/ratelimit": "^2.0.8",
|
|
"@upstash/redis": "^1.38.0",
|
|
"@vercel/blob": "^1.1.1",
|
|
"@vercel/postgres": "^0.10.0",
|
|
"bcryptjs": "^3.0.2",
|
|
"dotenv": "^17.2.1",
|
|
"jsonwebtoken": "^9.0.2",
|
|
"next": "^16.2.6",
|
|
"node-fetch": "^3.3.2",
|
|
"react": "^18.3.1",
|
|
"react-dom": "^18.3.1",
|
|
"resend": "^4.7.0"
|
|
},
|
|
"devDependencies": {
|
|
"@playwright/test": "^1.60.0",
|
|
"@testing-library/dom": "^10.4.1",
|
|
"@testing-library/react": "^16.3.2",
|
|
"autoprefixer": "^10.4.21",
|
|
"eslint": "^9.39.4",
|
|
"eslint-config-next": "^16.2.6",
|
|
"jsdom": "^29.1.1",
|
|
"node-pg-migrate": "^8.0.4",
|
|
"pg": "^8.21.0",
|
|
"postcss": "^8.5.6",
|
|
"tailwindcss": "^3.4.17",
|
|
"typescript": "^5.9.3",
|
|
"vitest": "^3.2.4"
|
|
}
|
|
}
|