Files
Art-gallery/server/migrate.js
T
Danila KhodjaefandCursor 5ddc3fd7f0 Add guided tours and unify left-to-right hall wall hang.
Visitors walk published tours in a 3D hall with stop notes; curators edit drafts via Tour editor. All galleries (artist, movement, tour) place the first work left of the entrance view and the last on the right.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-16 20:27:36 +03:00

79 lines
2.2 KiB
JavaScript

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',
];
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) VALUES ($1, $2)`,
[username, passwordHash]
);
console.log(` bootstrap curator 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));
});