require('dotenv').config(); const fs = require('fs'); const path = require('path'); const pool = require('./db'); const INCREMENTAL_MIGRATIONS = [ 'migrate-checkup-flags.sql', 'migrate-artist-checkup-flags.sql', 'migrate-influence-sources.sql', 'migrate-painting-annotations.sql', 'migrate-artist-palette.sql', 'migrate-auth.sql', 'migrate-portrait-thumbs.sql', 'migrate-perf-indexes.sql', 'migrate-search.sql', 'migrate-sync-timestamps.sql', 'migrate-i18n.sql', 'migrate-tours.sql', 'migrate-curator-notes.sql', 'migrate-user-roles.sql', ]; const BOOTSTRAP_ADMIN_PERMISSIONS = [ 'images', 'checkup', 'curator_notes', 'translations', 'influences', 'tours', 'users', ]; async function bootstrapCurator() { const { rows } = await pool.query('SELECT COUNT(*)::int AS n FROM users'); if (rows[0].n > 0) { console.log(' curator bootstrap: users table already populated'); return; } const username = (process.env.CURATOR_USERNAME || 'curator').trim(); const password = process.env.CURATOR_PASSWORD; if (!password) { console.warn(' curator bootstrap skipped: set CURATOR_PASSWORD to create the first curator account'); return; } const bcrypt = require('bcryptjs'); const passwordHash = await bcrypt.hash(password, 10); await pool.query( `INSERT INTO users (username, password_hash, role, permissions, is_active) VALUES ($1, $2, 'admin', $3::text[], true)`, [username, passwordHash, BOOTSTRAP_ADMIN_PERMISSIONS] ); console.log(` bootstrap admin account: ${username}`); } async function applySqlFile(label, filePath) { const sql = fs.readFileSync(filePath, 'utf8'); await pool.query(sql); console.log(` ${label}`); } async function migrate() { const dbDir = path.join(__dirname, '..', 'db'); const schemaPath = path.join(dbDir, 'schema.sql'); console.log('Applying db/schema.sql …'); await applySqlFile('schema.sql', schemaPath); console.log('Applying incremental migrations …'); for (const file of INCREMENTAL_MIGRATIONS) { const filePath = path.join(dbDir, file); if (!fs.existsSync(filePath)) { console.warn(` skipped (missing): ${file}`); continue; } await applySqlFile(file, filePath); } console.log('Bootstrapping curator account (if needed) …'); await bootstrapCurator(); console.log('Database migration complete.'); } migrate() .then(() => pool.end()) .catch((err) => { console.error('Migration failed:', err.message); pool.end().finally(() => process.exit(1)); });