#!/usr/bin/env node import { sequelize } from '../utils/sequelize.js'; /** * Fix SRS items that were created with next_due_at equal-or-immediately-before created_at * - Detect items created recently whose next_due_at is within a small window of created_at * - Move next_due_at to the next calendar day at 08:00 local (safe default) * * Run on the server after a backup. Prints counts and example rows before/after. */ const DRY_RUN = process.env.DRY_RUN !== 'false'; const run = async () => { try { await sequelize.authenticate(); console.log('✅ DB connection OK'); // Conservative selector: items created in the last 3 days where next_due_at is within 2 minutes of created_at const selector = ` SELECT id, item_key, course_id, stage, next_due_at, created_at FROM community.vocab_srs_item WHERE created_at >= now() - interval '3 days' AND abs(extract(epoch from (next_due_at - created_at))) < 120 ORDER BY created_at ASC LIMIT 500 `; const recent = await sequelize.query(selector, { type: sequelize.QueryTypes.SELECT }); console.log('\nFound items matching heuristic: ', recent.length); console.table(recent.slice(0, 20)); if (recent.length === 0) { console.log('\nNo candidate rows found — nothing to do.'); return; } // Compute update target: next calendar day at 08:00 based on created_at // Use an UPDATE with an expression so each row gets next_due_at = date_trunc('day', created_at + '1 day') + '08:00' const updateQuery = ` UPDATE community.vocab_srs_item SET next_due_at = date_trunc('day', created_at + interval '1 day') + interval '8 hours' WHERE created_at >= now() - interval '3 days' AND abs(extract(epoch from (next_due_at - created_at))) < 120 RETURNING id, item_key, course_id, stage, next_due_at, created_at; `; if (DRY_RUN) { console.log('\nDRY RUN: to apply changes set ENV var DRY_RUN=false'); console.log('Preview of UPDATE SQL:\n', updateQuery); } else { console.log('\nApplying update...'); const updated = await sequelize.query(updateQuery, { type: sequelize.QueryTypes.SELECT }); console.log('\nUpdated rows: ', updated.length); console.table(updated.slice(0, 20)); } console.log('\nRecommendation: rerun `backend/scripts/diag-srs-stats.js` to verify totals afterwards.'); } catch (err) { console.error('Error running fix script:', err); process.exitCode = 2; } finally { try { await sequelize.close(); } catch (_) {} } }; run();