import { QueryInterface, DataTypes } from 'sequelize'; /** * Migration to create TAT alerts/reminders table * Stores all TAT-related notifications sent (50%, 75%, 100%) */ export async function up(queryInterface: QueryInterface): Promise { await queryInterface.createTable('tat_alerts', { alert_id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true }, request_id: { type: DataTypes.UUID, allowNull: false, references: { model: 'workflow_requests', key: 'request_id' } }, level_id: { type: DataTypes.UUID, allowNull: false, references: { model: 'approval_levels', key: 'level_id' } }, approver_id: { type: DataTypes.UUID, allowNull: false, references: { model: 'users', key: 'user_id' } }, alert_type: { type: DataTypes.ENUM('TAT_50', 'TAT_75', 'TAT_100'), allowNull: false }, threshold_percentage: { type: DataTypes.INTEGER, allowNull: false, comment: '50, 75, or 100' }, tat_hours_allocated: { type: DataTypes.DECIMAL(10, 2), allowNull: false, comment: 'Total TAT hours for this level' }, tat_hours_elapsed: { type: DataTypes.DECIMAL(10, 2), allowNull: false, comment: 'Hours elapsed when alert was sent' }, tat_hours_remaining: { type: DataTypes.DECIMAL(10, 2), allowNull: false, comment: 'Hours remaining when alert was sent' }, level_start_time: { type: DataTypes.DATE, allowNull: false, comment: 'When the approval level started' }, alert_sent_at: { type: DataTypes.DATE, allowNull: false, defaultValue: DataTypes.NOW, comment: 'When the alert was sent' }, expected_completion_time: { type: DataTypes.DATE, allowNull: false, comment: 'When the level should be completed' }, alert_message: { type: DataTypes.TEXT, allowNull: false, comment: 'The notification message sent' }, notification_sent: { type: DataTypes.BOOLEAN, defaultValue: true, comment: 'Whether notification was successfully sent' }, notification_channels: { type: DataTypes.ARRAY(DataTypes.STRING), defaultValue: [], comment: 'push, email, sms' }, is_breached: { type: DataTypes.BOOLEAN, defaultValue: false, comment: 'Whether this was a breach alert (100%)' }, was_completed_on_time: { type: DataTypes.BOOLEAN, allowNull: true, comment: 'Set when level is completed - was it on time?' }, completion_time: { type: DataTypes.DATE, allowNull: true, comment: 'When the level was actually completed' }, metadata: { type: DataTypes.JSONB, defaultValue: {}, comment: 'Additional context (priority, request title, etc.)' }, created_at: { type: DataTypes.DATE, allowNull: false, defaultValue: DataTypes.NOW } }); // Indexes for performance (with IF NOT EXISTS check) await queryInterface.sequelize.query('CREATE INDEX IF NOT EXISTS "tat_alerts_request_id" ON "tat_alerts" ("request_id");'); await queryInterface.sequelize.query('CREATE INDEX IF NOT EXISTS "tat_alerts_level_id" ON "tat_alerts" ("level_id");'); await queryInterface.sequelize.query('CREATE INDEX IF NOT EXISTS "tat_alerts_approver_id" ON "tat_alerts" ("approver_id");'); await queryInterface.sequelize.query('CREATE INDEX IF NOT EXISTS "tat_alerts_alert_type" ON "tat_alerts" ("alert_type");'); await queryInterface.sequelize.query('CREATE INDEX IF NOT EXISTS "tat_alerts_alert_sent_at" ON "tat_alerts" ("alert_sent_at");'); await queryInterface.sequelize.query('CREATE INDEX IF NOT EXISTS "tat_alerts_is_breached" ON "tat_alerts" ("is_breached");'); await queryInterface.sequelize.query('CREATE INDEX IF NOT EXISTS "tat_alerts_was_completed_on_time" ON "tat_alerts" ("was_completed_on_time");'); } export async function down(queryInterface: QueryInterface): Promise { await queryInterface.dropTable('tat_alerts'); await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_tat_alerts_alert_type";'); }