#!/usr/bin/env node /** * Sync production data to development database * * This script copies real data from production to development, filtering out * test records to keep the dev database clean for testing. */ const { execSync } = require('child_process'); const fs = require('fs'); const os = require('os'); const path = require('path'); const PROD_DB_URL = process.env.PROD_DATABASE_URL; const DEV_DB_URL = process.env.DEV_DATABASE_URL; if (!PROD_DB_URL || !DEV_DB_URL) { console.error('โŒ Missing environment variables'); console.error('Please set PROD_DATABASE_URL and DEV_DATABASE_URL'); console.error(''); console.error('Example:'); console.error(' PROD_DATABASE_URL="postgresql://user:pass@host:5432/euchre_camp" \\'); console.error(' DEV_DATABASE_URL="postgresql://user:pass@host:5432/euchre_camp_dev" \\'); console.error(' node scripts/sync-prod-to-dev.js'); process.exit(1); } if (PROD_DB_URL.includes('_dev') || PROD_DB_URL.includes('_ci')) { console.error('โŒ PROD_DATABASE_URL appears to be a non-production database!'); console.error(' This script should only be used with the production database.'); process.exit(1); } const TEST_PATTERNS = { players: [ '%Test%', '%Setup%', '%Home Test%', '%Home Match Player%', '%Admin User%', '%NinePart%', '%Nine Part%', '%Test Player%', '%TestUser%', '%Cucumber%', '%Config Admin%', ], events: [ '%Test%', '%Setup%', '%Recent%', '%Test Tournament%', '%Cucumber%', ], users: [ '%test%', '%setup%', '%cucumber%', '%TestUser%', ] }; function buildLikeClause(patterns) { return patterns.map(p => `name LIKE '${p}'`).join(' OR '); } function buildEmailLikeClause(patterns) { return patterns.map(p => `email LIKE '${p}'`).join(' OR '); } async function main() { console.log('๐Ÿ”„ Syncing production data to development database'); console.log('====================================================\n'); const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); console.log('โš ๏ธ WARNING: This will OVERWRITE the development database!'); console.log(' Production data will be copied, with test records excluded.'); console.log(''); console.log('Source:', PROD_DB_URL.replace(/:[^:@]+@/, ':***@')); console.log('Target:', DEV_DB_URL.replace(/:[^:@]+@/, ':***@')); console.log(''); rl.question('Type "sync" to confirm: ', async (answer) => { if (answer !== 'sync') { console.log('โŒ Cancelled'); rl.close(); process.exit(0); } rl.close(); try { console.log('\n๐Ÿ“ฆ Dumping production data...'); const dumpFile = path.join(os.tmpdir(), `prod_dump_${Date.now()}.sql`); execSync(`pg_dump "${PROD_DB_URL}" -f "${dumpFile}" --no-owner --no-acl`, { stdio: 'inherit' }); console.log('โœ… Dump created'); console.log('\n๐Ÿ—‘๏ธ Clearing development database...'); execSync(`psql "${DEV_DB_URL}" -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"`, { stdio: 'inherit' }); console.log('โœ… Development database cleared'); console.log('\n๐Ÿ“ฅ Restoring to development database...'); execSync(`psql "${DEV_DB_URL}" -f "${dumpFile}"`, { stdio: 'inherit' }); console.log('โœ… Data restored'); console.log('\n๐Ÿงน Cleaning up test records in dev database...'); const playerWhere = buildLikeClause(TEST_PATTERNS.players); const eventWhere = buildLikeClause(TEST_PATTERNS.events); const userWhere = buildEmailLikeClause(TEST_PATTERNS.users); execSync(`psql "${DEV_DB_URL}" -c "DELETE FROM events WHERE (${eventWhere});"`, { stdio: 'inherit' }); console.log(' Deleted test events'); execSync(`psql "${DEV_DB_URL}" -c "DELETE FROM players WHERE (${playerWhere});"`, { stdio: 'inherit' }); console.log(' Deleted test players'); execSync(`psql "${DEV_DB_URL}" -c "DELETE FROM users WHERE (${userWhere}) AND \"playerId\" IS NULL;"`, { stdio: 'inherit' }); console.log(' Deleted test users'); fs.unlinkSync(dumpFile); console.log('\n๐Ÿงน Cleaned up temporary dump file'); console.log('\nโœ… Sync complete!'); console.log('\n๐Ÿ“Š Summary:'); console.log(' - Production data copied to development'); console.log(' - Test records filtered out'); console.log(' - Development database is now a mirror of production (minus test data)'); } catch (error) { console.error('\nโŒ Sync failed:', error.message); process.exit(1); } }); } main();