deckhearth/scripts
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
..
migrations fix(migration): rename-admin-email crashes — neon() returns array, not { rows } 2026-05-25 11:30:09 -05:00
add-card-columns.js Enhanced card detail page with real data and functionality 2025-07-24 15:03:09 -05:00
add-collaboration-features.js 🎉 COMPLETED: Full Collaborative Collections System 2025-07-25 08:34:28 -05:00
add-collection-slugs.js 🔗 Implement Collection Slug URLs 2025-07-26 22:06:52 -05:00
add-favorites-system.js Added Collaborator Facepile to Collection Header 2025-07-25 22:38:03 -05:00
add-image-column.js Enhanced Collections UI with API Integration 2025-07-25 10:06:39 -05:00
add-system-collection-column.js 🔒 Implement 'All My Cards' System Collection 2025-07-27 15:17:51 -05:00
add-updated-at-column.js Created comprehensive admin card editor 2025-07-24 15:16:57 -05:00
add-user-profile-columns.js 🎨 Enhanced Signup with Username & Profile Images 2025-07-28 11:18:58 -05:00
add-user-profile-fields.js 🎯 Build Comprehensive User Profile & Settings System 2025-07-26 18:05:55 -05:00
bulk-import-all.js Fix import issues: Add retry logic and better error handling 2025-07-24 10:30:21 -05:00
create-sample-cards.js 🎯 Complete Testing Workflow Setup 2025-07-25 10:42:00 -05:00
create-sample-collections.js 🔗 Implement Collection Slug URLs 2025-07-26 22:06:52 -05:00
create-test-users.js feat(brand): unify on Deck Hearth across in-repo strings + infra (P1 brand decision) 2026-05-25 02:28:29 -05:00
demote-admin-to-user.js Added comprehensive user management scripts 2025-07-24 20:03:31 -05:00
fix-lorcana-images.js Major Scanner Improvements 2025-07-29 14:19:48 -05:00
fix-user-cards-constraints.js 🔧 Fix System Collections & Database Schema Issues 2025-07-27 19:17:55 -05:00
import-lorcana-simple.js Add real Lorcana import using Lorcast API 2025-07-24 12:27:10 -05:00
import-lorcana.js feat(brand): unify on Deck Hearth across in-repo strings + infra (P1 brand decision) 2026-05-25 02:28:29 -05:00
import-popular-sets.js Major redesign: Enhanced card display with particle effects, improved filters, and search functionality 2025-07-23 21:26:54 -05:00
list-users.js Added comprehensive user management scripts 2025-07-24 20:03:31 -05:00
log-convoy-event.sh bootstrap: agent pipeline v0.5.0 + ship-readiness review 2026-05-23 02:31:26 -05:00
promote-user-to-admin.js Added comprehensive user management scripts 2025-07-24 20:03:31 -05:00
README.md feat(brand): unify on Deck Hearth across in-repo strings + infra (P1 brand decision) 2026-05-25 02:28:29 -05:00
reset-db.js fix(scripts): convert reset-db.js to ESM + require ADMIN_INITIAL_PASSWORD (#25) 2026-05-26 22:08:45 -05:00
seed-collections-alice-bob.js 🎭 Add Collection Seeding Script for Alice & Bob 2025-07-27 12:26:55 -05:00
seed-collections-with-cards.js 🎮 Create Comprehensive Collection Seeding Script 2025-07-27 14:26:35 -05:00
setup-neon-db.js feat(infra): adopt node-pg-migrate + backfill initial schema migration 2026-05-26 22:55:09 -05:00
wt.sh bootstrap: agent pipeline v0.5.0 + ship-readiness review 2026-05-23 02:31:26 -05:00

Deck Hearth Bulk Import Scripts

This directory contains scripts for bulk importing TCG card data into the database.

Available Scripts

Card Import Scripts

Imports the most popular and recent sets from all three TCGs (Magic, Pokemon, Lorcana).

Usage:

npm run import-popular

What it imports:

  • Magic: The Gathering: ~100+ sets from Alpha to recent releases
  • Pokemon: ~100+ sets from Base Set to current Scarlet & Violet
  • Lorcana: All 3 available sets

Estimated time: 2-4 hours (depending on API response times)

2. bulk-import-all.js - Complete Import

Imports ALL available sets from all TCGs (comprehensive import).

Usage:

npm run import-all

What it imports:

  • Magic: The Gathering: 100+ sets (Alpha to current)
  • Pokemon: 100+ sets (Base Set to current)
  • Lorcana: All available sets

Estimated time: 4-8 hours (depending on API response times)

User Management Scripts

3. list-users.js - List All Users

Lists all users in the database with their roles and details.

Usage:

node scripts/list-users.js

Output: Shows user ID, email, role (admin/user), and creation date.

4. promote-user-to-admin.js - Promote User to Admin

Promotes a regular user to admin role.

Usage:

node scripts/promote-user-to-admin.js user@example.com

Requirements: User must be registered first.

5. demote-admin-to-user.js - Demote Admin to User

Demotes an admin back to regular user role.

Usage:

node scripts/demote-admin-to-user.js admin@example.com

Safety: Ensures at least one admin always remains in the system.

Database Management Scripts

6. setup-neon-db.js - Database Setup

Sets up the Neon PostgreSQL database with all required tables and creates the default admin user.

Usage:

node scripts/setup-neon-db.js

7. reset-db.js - Database Reset

Resets the database by dropping and recreating all tables.

Usage:

node scripts/reset-db.js

How It Works

  1. Sequential Import: Scripts import sets one by one to avoid overwhelming the APIs
  2. Error Handling: Failed imports are logged but don't stop the process
  3. Progress Tracking: Real-time console output shows progress
  4. Results Logging: Detailed results are saved to JSON files
  5. Rate Limiting: 1-second delays between imports to be respectful to APIs

Output Files

After running, you'll get timestamped JSON files with detailed results:

  • popular-sets-import-results-[timestamp].json
  • bulk-import-results-[timestamp].json

These files contain:

  • Success/failure status for each set
  • Number of cards imported per set
  • Error messages for failed imports
  • Summary statistics

Prerequisites

  1. Server Running: Make sure your Next.js dev server is running (npm run dev)
  2. Database Setup: Ensure the database is initialized (npm run setup-db)
  3. Dependencies: All required packages are installed

Recommendations

For First-Time Setup

Start with the popular sets import:

npm run import-popular

This will give you a solid foundation with the most relevant cards.

For Complete Database

If you want everything, use the full import:

npm run import-all

For Ongoing Management

After the initial bulk import, use the admin interface at /admin/card-import for:

  • Importing new sets as they release
  • Selective imports of specific sets
  • Monitoring import progress

Troubleshooting

Common Issues

  1. API Rate Limits: If you get rate limit errors, the scripts will continue but log failures
  2. Network Issues: Scripts will retry and continue with the next set
  3. Server Restart: If the server restarts, just restart the import script

Monitoring Progress

Watch the console output for:

  • Successful imports with card counts
  • Failed imports with error messages
  • 📊 Summary statistics at the end

Stopping and Resuming

You can stop the script with Ctrl+C and restart it later. The scripts will start from the beginning, but the database will only store unique cards (no duplicates).

API Endpoints Used

  • POST /api/cards/import-mtg - Magic: The Gathering imports
  • POST /api/cards/import-pokemon - Pokemon imports
  • POST /api/cards/import-lorcana - Lorcana imports

Data Sources

  • Magic: The Gathering: Scryfall API
  • Pokemon: Pokemon TCG API
  • Lorcana: Lorcana API (limited availability)

Performance Notes

  • Each set typically contains 100-400 cards
  • Total database size after full import: ~50,000-100,000 cards
  • Import speed: ~1 set per minute (with delays)
  • Database storage: ~100-200MB after full import