From 1c18d214c137f797d8f406356be284f61077698e Mon Sep 17 00:00:00 2001 From: Randall Stillwell Date: Mon, 25 May 2026 01:58:48 -0500 Subject: [PATCH] feat(brand): infrastructure + email migration for Deck Hearth (B2 of 2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- README.md | 15 +++- TESTING_GUIDE.md | 14 +-- lib/rate-limit.js | 10 +-- package-lock.json | 4 +- package.json | 2 +- pages/login.js | 4 +- scripts/create-test-users.js | 14 +-- .../2026-05-24-rename-admin-email.js | 85 +++++++++++++++++++ scripts/reset-db.js | 4 +- scripts/setup-neon-db.js | 4 +- test/lib/permission-middleware.test.js | 7 ++ 11 files changed, 133 insertions(+), 30 deletions(-) create mode 100644 scripts/migrations/2026-05-24-rename-admin-email.js diff --git a/README.md b/README.md index 8e0ebdc..b43e750 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# TCG Vault +# Deck Hearth A modern trading card game collection manager built with Next.js and Neon Database. @@ -129,7 +129,7 @@ variable is unset or empty. - **CI / Vercel:** set `ADMIN_INITIAL_PASSWORD` as a project secret if setup ever runs from CI. The env var is **only** read by the seed script; runtime auth uses the per-user password stored in the database. -- **Admin email:** the seed creates `admin@tcgvault.com`. Change the password +- **Admin email:** the seed creates `admin@deckhearth.com`. Change the password immediately after first login via the app's profile settings. > **Operators of envs that pre-date this change:** `npm run setup-db` is @@ -140,6 +140,17 @@ variable is unset or empty. > after logging in, or wait for the queued `rotate-default-admin` follow-up > convoy. +> **Operators of envs that pre-date the `pick-a-name` convoy (2026-05-24):** +> the admin row was renamed from `admin@tcgvault.com` to +> `admin@deckhearth.com`. Run +> `node scripts/migrations/2026-05-24-rename-admin-email.js` once after +> deploy to UPDATE any existing `@tcgvault.com` user rows (the admin row, +> plus alice/bob if `npm run create-test-users` was ever run). Re-running +> the migration after the first run is idempotent and prints "Nothing to +> migrate." Verify post-migration with +> `psql $POSTGRES_URL -c "SELECT email FROM users WHERE email LIKE '%@tcgvault.com'"` +> — expect zero rows. + ## šŸ¤ Contributing 1. Fork the repository diff --git a/TESTING_GUIDE.md b/TESTING_GUIDE.md index 1e20a2e..502f45e 100644 --- a/TESTING_GUIDE.md +++ b/TESTING_GUIDE.md @@ -1,12 +1,12 @@ -# šŸŽÆ TCG Vault Collaboration Testing Guide +# šŸŽÆ Deck Hearth Collaboration Testing Guide ## šŸ‘„ Test Accounts | User | Email | Password | Role | |------|-------|----------|------| -| Admin | `admin@tcgvault.com` | `admin123` | Admin | -| Alice | `alice@tcgvault.com` | `alice123` | User | -| Bob | `bob@tcgvault.com` | `bob123` | User | +| Admin | `admin@deckhearth.com` | `admin123` | Admin | +| Alice | `alice@deckhearth.com` | `alice123` | User | +| Bob | `bob@deckhearth.com` | `bob123` | User | ## šŸƒ Sample Cards Available @@ -21,7 +21,7 @@ ### 1. **Login as Alice** ``` -Email: alice@tcgvault.com +Email: alice@deckhearth.com Password: alice123 ``` @@ -43,14 +43,14 @@ Password: alice123 ### 4. **Invite Bob as Collaborator** - Click "Invite Collaborator" button -- Enter: `bob@tcgvault.com` +- Enter: `bob@deckhearth.com` - Role: Collaborator (default) - Message: "Help me build this Pokemon collection!" - Click "Send Invitation" ### 5. **Switch to Bob's Account** - Logout and login as Bob -- Email: `bob@tcgvault.com` +- Email: `bob@deckhearth.com` - Password: `bob123` ### 6. **Accept Invitation (Simulated)** diff --git a/lib/rate-limit.js b/lib/rate-limit.js index 33b9608..ca6500b 100644 --- a/lib/rate-limit.js +++ b/lib/rate-limit.js @@ -7,11 +7,11 @@ import { Redis } from '@upstash/redis'; // classes to match Brief 4's existing algorithm; switching to // `tokenBucket` per-class would be its own convoy. const LIMITER_CONFIG = { - auth: { limit: 5, window: '15 m', prefix: 'tcgvault:auth' }, - search: { limit: 60, window: '1 m', prefix: 'tcgvault:search' }, - upload: { limit: 10, window: '1 h', prefix: 'tcgvault:upload' }, - generate: { limit: 5, window: '1 h', prefix: 'tcgvault:generate' }, - import: { limit: 5, window: '1 h', prefix: 'tcgvault:import' }, + auth: { limit: 5, window: '15 m', prefix: 'deckhearth:auth' }, + search: { limit: 60, window: '1 m', prefix: 'deckhearth:search' }, + upload: { limit: 10, window: '1 h', prefix: 'deckhearth:upload' }, + generate: { limit: 5, window: '1 h', prefix: 'deckhearth:generate' }, + import: { limit: 5, window: '1 h', prefix: 'deckhearth:import' }, }; // Lazy singleton. Module-load init would throw in environments without diff --git a/package-lock.json b/package-lock.json index 8f2f2e7..d70f6db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "tcg-vault", + "name": "deck-hearth", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "tcg-vault", + "name": "deck-hearth", "version": "0.1.0", "dependencies": { "@neondatabase/serverless": "^1.0.1", diff --git a/package.json b/package.json index db16ec0..5069e0a 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "tcg-vault", + "name": "deck-hearth", "version": "0.1.0", "private": true, "type": "module", diff --git a/pages/login.js b/pages/login.js index cb6476f..e82a072 100644 --- a/pages/login.js +++ b/pages/login.js @@ -169,7 +169,7 @@ export default function Login() {