'use strict'; // Reshapes completion_requirement_progress.block_progress from // { [blockId]: percentNumber } to { [blockId]: { percent, updatedAt } } so // recordWatchProgress can validate a reported percent against real elapsed // wall-clock time since that block's last sample (anti-skip hardening — // closes the "one API call reports 100%" gaming hole). Applies uniformly to // watch_percent rows too, which start using block_progress as of this change // (previously only watch_video/listen_audio populated it). // // Data-only migration — the column type itself (JSONB) doesn't change, so // this is a plain JS loop + parameterized UPDATE rather than raw jsonb SQL, // consistent with this table's CockroachDB-compatibility precedent (see // 20260715000002, which avoids native ALTER TYPE/enum SQL for the same reason). module.exports = { async up(queryInterface) { const rows = await queryInterface.sequelize.query( `SELECT progress_id, block_progress, "updatedAt" FROM completion_requirement_progress WHERE block_progress IS NOT NULL`, { type: queryInterface.sequelize.QueryTypes.SELECT } ); for (const row of rows) { const bp = row.block_progress ?? {}; const alreadyShaped = Object.values(bp).every((v) => v && typeof v === 'object'); if (alreadyShaped) continue; const reshaped = Object.fromEntries( Object.entries(bp).map(([blockId, percent]) => [ blockId, { percent: Number(percent) || 0, updatedAt: row.updatedAt ?? new Date().toISOString() }, ]) ); await queryInterface.sequelize.query( `UPDATE completion_requirement_progress SET block_progress = :bp WHERE progress_id = :id`, { replacements: { bp: JSON.stringify(reshaped), id: row.progress_id } } ); } }, async down(queryInterface) { const rows = await queryInterface.sequelize.query( `SELECT progress_id, block_progress FROM completion_requirement_progress WHERE block_progress IS NOT NULL`, { type: queryInterface.sequelize.QueryTypes.SELECT } ); for (const row of rows) { const bp = row.block_progress ?? {}; const flattened = Object.fromEntries( Object.entries(bp).map(([blockId, v]) => [blockId, v?.percent ?? v]) ); await queryInterface.sequelize.query( `UPDATE completion_requirement_progress SET block_progress = :bp WHERE progress_id = :id`, { replacements: { bp: JSON.stringify(flattened), id: row.progress_id } } ); } }, };