Commit graph

4 commits

Author SHA1 Message Date
Randall Stillwell
1c18d214c1 feat(brand): infrastructure + email migration for Deck Hearth (B2 of 2)
Closes the pick-a-name convoy. Applies D1-D5 + Risk 4 PRESERVE per
operator gate-1 ratification.

Infrastructure renames:
- lib/rate-limit.js: 5 Redis key prefixes tcgvault:* → deckhearth:* (D5).
  One-time per-15-min / per-1-hour counter reset accepted; no user impact
  because counter windows are short anyway. Existing rate-limit state in
  Upstash will accumulate at the new prefix on first request.
- package.json: name field tcg-vault → deck-hearth (D2)
- package-lock.json: regenerated for the name change; STOP-on-churn
  protocol confirmed only the two name lines changed (no dep churn)
- All three test users (admin/alice/bob) renamed to @deckhearth.com (D4)
- One-off migration script scripts/migrations/2026-05-24-rename-admin-
  email.js (NEW): ESM, idempotent, UNIQUE-collision-safe. Per the
  no-go-zones rule for new migrations. Operator MUST run post-deploy.
- README.md + TESTING_GUIDE.md operator-caveat blockquotes flagged
- pages/login.js demo-credential pre-fill updated

PRESERVED per Risk 4:
- test/lib/permission-middleware.test.js literal admin@tcgvault.com
  with 7-line architect-authored "why" comment block. This is the
  documented pre-fix-auth-bypass bug shape; the regression-lock
  literal stays as historical truth.

Verification:
- npm run lint: 128 problems (baseline preserved)
- npm run test:run: 21/21 pass (preserved literal keeps green)
- Grep across full repo: 0 hits for TCG Vault / tcgvault / tcg-vault
  except the explicit preserve in the test file + .convoys/ historical
- lib/rate-limit.js: 5 deckhearth: prefixes, 0 tcgvault: prefixes
- node --check on the new migration script: exit 0
- git diff package-lock.json: only the 2 "name": lines changed (no churn)

Operator post-merge action:
- Run `node scripts/migrations/2026-05-24-rename-admin-email.js` against
  the production Neon DB. Order matters: migration FIRST, then any
  subsequent `npm run setup-db` invocation. Migration script will refuse
  to run if collision detected (means setup-db already ran post-rename).

Architect brief: .convoys/pick-a-name/brief-2-infrastructure-and-email-migration.md
Architect commit: 50ce9ab
Operator gate-1: D1-D5 + Risk 4 PRESERVE ratified.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 01:58:48 -05:00
Randall Stillwell
b63b5090cc fix(seed): convert scripts/setup-neon-db.js from CJS to ESM (Node 22.x compat)
Brief 2 of drop-public-setup. Closes Decision D — pure module-system
conversion of scripts/setup-neon-db.js so `npm run setup-db` actually
runs on Node 22.x where package.json has "type": "module" (added by
bump-next-js for ESLint v9 flat-config support).

Before this commit, `npm run setup-db` threw:
  ReferenceError: require is not defined in ES module scope

After this commit, brief 1's ADMIN_INITIAL_PASSWORD env-var gate actually
fires as documented.

Changes (all in scripts/setup-neon-db.js):
  - require('dotenv').config(...) → import dotenv + dotenv.config(...)
  - require('@neondatabase/serverless') → import { neon }
  - inline require('bcryptjs') hoisted to top-of-file import bcrypt
  - no functional changes; same DDL, same env-var gate, same console.logs

Smoke verification: see PR description.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-23 17:02:44 -05:00
Randall Stillwell
ff80753fe4 feat(seed): require ADMIN_INITIAL_PASSWORD env var; strip admin123 from README
Closes P0 #3 from .convoys/ship-readiness.md.

scripts/setup-neon-db.js:
  - Read ADMIN_INITIAL_PASSWORD env var at the top of setupNeonDatabase()
    before any DB connection. Fail loudly (process.exit(1)) with an
    actionable message if unset or empty.
  - Replace bcrypt.hash('admin123', 12) with bcrypt.hash(adminPassword, 12).
  - Delete the two console.log lines that echoed admin user + password to
    stdout (R3 - stdout leak into CI logs).
  - Keep ON CONFLICT (email) DO NOTHING unchanged. Re-running setup-db
    on an env with the admin row already present is a no-op for the
    password (R4 - silent rotation prevention). Rotation of existing
    weak-hash admin rows is out of scope (Decision A - queued for the
    rotate-default-admin follow-up convoy).

README.md:
  - Add ADMIN_INITIAL_PASSWORD to the install-step env-example block
    with a CI-secret note (and add KV_REST_API_URL/KV_REST_API_TOKEN
    for completeness; they're optional for local dev).
  - Replace the "Default Admin Account" section with "First-time
    admin setup", documenting the env var, openssl rand suggestion,
    and the operator rotation note for envs that predate this change.
  - Zero occurrences of 'admin123' remain in README.md (the operator
    rotation note refers to "the prior weak default" instead of naming
    the literal string, so grep verification A2 holds).

Decisions A1 (going-forward only), B (operational change allowed),
C1 (no vitest coverage - manual smoke in PR description) per
.convoys/drop-public-setup.md section Decisions.

Smoke output: see PR description.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-23 17:02:44 -05:00
Randall Stillwell
e75a4a6649 Major redesign: Enhanced card display with particle effects, improved filters, and search functionality
- Redesigned card display with 2.5:3.5 aspect ratio and image-only view
- Added infinite scroll to replace pagination
- Implemented authentic card back placeholders for MTG, Pokemon, and Lorcana
- Added rarity-based particle effects with tiered intensity (mythic/enchanted/rare/uncommon)
- Enhanced hover details panel with structured card information
- Fixed search functionality with debouncing and Enter key support
- Improved filter system with working TCG, rarity, set, and price filters
- Added favorite system for cards in both hover and detail views
- Updated card detail page with comprehensive metadata and actions
- Fixed API filtering with proper Vercel Postgres implementation
- Added particle animations and rarity glow effects
- Improved overall UX with better visual hierarchy and interactions
2025-07-23 21:26:54 -05:00