deckhearth/scripts/reset-db.js
varutasu 9abbab6c21
feat(brand): unify on Deck Hearth across in-repo strings + infra (P1 brand decision)
Resolves the launch-blocking 'TCG Vault vs Deck Hearth' inconsistency called out in AGENTS.md line 5 since project setup. Operator gate-0 decision: Deck Hearth wins. Two briefs applied serially. B1 (mechanical): 7-file display + comment sweep. B2 (infrastructure): Redis prefix rename in lib/rate-limit.js (5 prefixes, accept one-time counter reset), package.json + lockfile regen (STOP-on-churn confirmed only name lines changed), admin/alice/bob email rename in seed scripts + login pre-fill + NEW idempotent migration script scripts/migrations/2026-05-24-rename-admin-email.js. Risk 4 PRESERVE applied: test/lib/permission-middleware.test.js retains admin@tcgvault.com literal with 7-line architect-authored why comment (documents pre-fix-auth-bypass bug shape; preserves historical truth per project's gotcha-documentation convention). All 5 D-decisions ratified at gate-1 (Deck Hearth / deck-hearth / deckhearth / admin@deckhearth.com / full deckhearth Redis prefix). Local: lint 128 baseline (B1 + B2), vitest 21/21 (B1 + B2). CI all green: Playwright smoke 3/3 against rebranded preview in 1m4s, forbidden-cors-headers pass, forbidden-endpoints pass, Screenshot diff pass, Vercel deployment complete. Cross-validation lineage: 4th convoy where the same 3-test smoke spec defends auth surface through sweeping change (after PR #15 Layout default-user, PR #19 CORS, PR #20 rate-limit, now this PR #21 brand rename). OPERATOR POST-MERGE ACTION REQUIRED: run 'node scripts/migrations/2026-05-24-rename-admin-email.js' against prod Neon DB before next admin login (ordering: migration FIRST, then any subsequent setup-db invocation). Migration is ESM, idempotent, UNIQUE-collision-safe. PR #21 architect-commit 50ce9ab, B1 ac8c998, B2 1c18d21.
2026-05-25 02:28:29 -05:00

164 lines
No EOL
5.1 KiB
JavaScript

#!/usr/bin/env node
/**
* Reset Database Script
*
* This script drops and recreates all tables in your Neon database.
*/
// Load environment variables from .env.local
require('dotenv').config({ path: '.env.local' });
const { neon } = require('@neondatabase/serverless');
async function resetDatabase() {
const sql = neon(process.env.POSTGRES_URL);
try {
console.log('✅ Connecting to Neon database...');
// Drop all tables in correct order (due to foreign key constraints)
console.log('🗑️ Dropping existing tables...');
await sql`DROP TABLE IF EXISTS deck_cards CASCADE`;
await sql`DROP TABLE IF EXISTS decks CASCADE`;
await sql`DROP TABLE IF EXISTS collection_cards CASCADE`;
await sql`DROP TABLE IF EXISTS collections CASCADE`;
await sql`DROP TABLE IF EXISTS user_cards CASCADE`;
await sql`DROP TABLE IF EXISTS cards CASCADE`;
await sql`DROP TABLE IF EXISTS users CASCADE`;
console.log('✅ Dropped all tables');
// Create tables
await sql`
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
role VARCHAR(50) DEFAULT 'user',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`;
console.log('✅ Created users table');
await sql`
CREATE TABLE cards (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
set_name VARCHAR(255),
set_code VARCHAR(50),
card_number VARCHAR(50),
rarity VARCHAR(50),
game VARCHAR(50) NOT NULL,
mana_cost VARCHAR(50),
cmc INTEGER,
card_type VARCHAR(255),
colors JSONB,
oracle_text TEXT,
power VARCHAR(10),
toughness VARCHAR(10),
image_url TEXT,
stock_image_url TEXT,
current_price DECIMAL(10,2),
market_price DECIMAL(10,2),
scryfall_id VARCHAR(255) UNIQUE,
verified BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`;
console.log('✅ Created cards table');
await sql`
CREATE TABLE user_cards (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
card_id INTEGER REFERENCES cards(id) ON DELETE CASCADE,
quantity INTEGER DEFAULT 1,
condition VARCHAR(50) DEFAULT 'NM',
is_foil BOOLEAN DEFAULT false,
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, card_id, is_foil)
)
`;
console.log('✅ Created user_cards table');
await sql`
CREATE TABLE collections (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
description TEXT,
is_public BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`;
console.log('✅ Created collections table');
await sql`
CREATE TABLE collection_cards (
id SERIAL PRIMARY KEY,
collection_id INTEGER REFERENCES collections(id) ON DELETE CASCADE,
card_id INTEGER REFERENCES cards(id) ON DELETE CASCADE,
quantity INTEGER DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(collection_id, card_id)
)
`;
console.log('✅ Created collection_cards table');
await sql`
CREATE TABLE decks (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
description TEXT,
game VARCHAR(50),
is_public BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`;
console.log('✅ Created decks table');
await sql`
CREATE TABLE deck_cards (
id SERIAL PRIMARY KEY,
deck_id INTEGER REFERENCES decks(id) ON DELETE CASCADE,
card_id INTEGER REFERENCES cards(id) ON DELETE CASCADE,
quantity INTEGER DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(deck_id, card_id)
)
`;
console.log('✅ Created deck_cards table');
// Create admin user
const bcrypt = require('bcryptjs');
const hashedPassword = await bcrypt.hash('admin123', 12);
await sql`
INSERT INTO users (email, password, role)
VALUES (${'admin@deckhearth.com'}, ${hashedPassword}, ${'admin'})
`;
console.log('✅ Created admin user');
console.log('🎉 Database reset completed successfully!');
console.log('');
console.log('📋 Database Details:');
console.log(' Database: Neon PostgreSQL');
console.log(' Admin User: admin@deckhearth.com');
console.log(' Admin Password: admin123');
} catch (error) {
console.error('❌ Database reset failed:', error.message);
process.exit(1);
}
}
resetDatabase();