← back to Interiordesignershowroom

scripts/fix-dangling-scenes.js

71 lines

#!/usr/bin/env node
// Fix dangling scene_image references — sets scene_image=NULL for rows where
// the file no longer exists on disk. Safe: the server already gracefully falls
// back to product thumbs when scene_image is NULL.
// Run locally: node ids-fix-dangling-scenes.js [--apply]
// Run on prod: SSH to Kamatera, copy this file, run with --apply

const { Pool } = require('pg');
const fs = require('fs');
const path = require('path');

const APPLY = process.argv.includes('--apply');
const PUBLIC_DIR = path.join(__dirname, '..', 'public'); // on prod: /root/Projects/interiordesignershowroom/public

const pool = new Pool({
  connectionString: process.env.DATABASE_URL || 'postgresql://localhost:5432/idshowroom',
});

async function main() {
  const client = await pool.connect();
  try {
    const { rows } = await client.query(
      `SELECT id, slug, scene_image FROM rooms WHERE scene_image IS NOT NULL ORDER BY id`
    );
    console.log(`Found ${rows.length} rooms with scene_image set.`);
    
    const dangling = [];
    for (const row of rows) {
      const imgPath = path.join(PUBLIC_DIR, row.scene_image);
      if (!fs.existsSync(imgPath)) {
        dangling.push(row);
        console.log(`MISSING: /room/${row.slug} → ${row.scene_image}`);
      } else {
        console.log(`OK:      /room/${row.slug} → ${row.scene_image}`);
      }
    }
    
    console.log(`\nTotal dangling: ${dangling.length}/${rows.length}`);
    
    if (dangling.length === 0) {
      console.log('Nothing to fix — all scene_image files exist.');
      return;
    }
    
    if (!APPLY) {
      console.log('\nDRY RUN — pass --apply to NULL out dangling references.');
      console.log('Nulling these would let the server fall back to product thumbs (graceful-degrade).');
      return;
    }
    
    await client.query('BEGIN');
    const ids = dangling.map(r => r.id);
    const { rowCount } = await client.query(
      `UPDATE rooms SET scene_image = NULL WHERE id = ANY($1::int[])`,
      [ids]
    );
    await client.query('COMMIT');
    console.log(`\nApplied: NULLed scene_image on ${rowCount} rows.`);
    console.log('These rooms now show product thumbs as their hero (graceful-degrade is live).');
  } catch (e) {
    await client.query('ROLLBACK').catch(() => {});
    console.error('Error:', e.message);
    process.exit(1);
  } finally {
    client.release();
    await pool.end();
  }
}

main();