import { QueryInterface, DataTypes } from 'sequelize'; export const up = async (queryInterface: QueryInterface) => { // 1. Drop and recreate the enum type for snapshot_type to ensure all values are included // This ensures APPROVE is always present when table is recreated // Note: Table should be dropped manually before running this migration try { await queryInterface.sequelize.query(` DO $$ BEGIN -- Drop enum if it exists (cascade will handle any dependencies) IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'enum_dealer_claim_history_snapshot_type') THEN DROP TYPE IF EXISTS enum_dealer_claim_history_snapshot_type CASCADE; END IF; -- Create enum with all values including APPROVE CREATE TYPE enum_dealer_claim_history_snapshot_type AS ENUM ('PROPOSAL', 'COMPLETION', 'INTERNAL_ORDER', 'WORKFLOW', 'APPROVE'); END $$; `); } catch (error) { // If enum creation fails, log error but continue console.error('Enum creation error:', error); throw error; } // 2. Create new simplified level-based dealer_claim_history table await queryInterface.createTable('dealer_claim_history', { history_id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true }, request_id: { type: DataTypes.UUID, allowNull: false, references: { model: 'workflow_requests', key: 'request_id' }, onUpdate: 'CASCADE', onDelete: 'CASCADE' }, approval_level_id: { type: DataTypes.UUID, allowNull: true, // Nullable for workflow-level snapshots references: { model: 'approval_levels', key: 'level_id' }, onUpdate: 'CASCADE', onDelete: 'SET NULL' }, level_number: { type: DataTypes.INTEGER, allowNull: true, // Nullable for workflow-level snapshots comment: 'Level number for easier querying (e.g., 1=Dealer, 3=Dept Lead, 4/5=Completion)' }, level_name: { type: DataTypes.STRING(255), allowNull: true, // Nullable for workflow-level snapshots comment: 'Level name for consistent matching (e.g., "Dealer Proposal Submission", "Department Lead Approval")' }, version: { type: DataTypes.INTEGER, allowNull: false, comment: 'Version number for this specific level (starts at 1 per level)' }, snapshot_type: { type: DataTypes.ENUM('PROPOSAL', 'COMPLETION', 'INTERNAL_ORDER', 'WORKFLOW', 'APPROVE'), allowNull: false, comment: 'Type of snapshot: PROPOSAL (Step 1), COMPLETION (Step 4/5), INTERNAL_ORDER (Step 3), WORKFLOW (general), APPROVE (approver actions with comments)' }, snapshot_data: { type: DataTypes.JSONB, allowNull: false, comment: 'JSON object containing all snapshot data specific to this level and type. Structure varies by snapshot_type.' }, change_reason: { type: DataTypes.TEXT, allowNull: true, comment: 'Reason for this version change (e.g., "Revision Requested: ...")' }, changed_by: { type: DataTypes.UUID, allowNull: false, references: { model: 'users', key: 'user_id' } }, created_at: { type: DataTypes.DATE, allowNull: false, defaultValue: DataTypes.NOW } }); // Add indexes for efficient querying await queryInterface.addIndex('dealer_claim_history', ['request_id', 'level_number', 'version'], { name: 'idx_history_request_level_version' }); await queryInterface.addIndex('dealer_claim_history', ['approval_level_id', 'version'], { name: 'idx_history_level_version' }); await queryInterface.addIndex('dealer_claim_history', ['request_id', 'snapshot_type'], { name: 'idx_history_request_type' }); await queryInterface.addIndex('dealer_claim_history', ['snapshot_type', 'level_number'], { name: 'idx_history_type_level' }); await queryInterface.addIndex('dealer_claim_history', ['request_id', 'level_name'], { name: 'idx_history_request_level_name' }); await queryInterface.addIndex('dealer_claim_history', ['level_name', 'snapshot_type'], { name: 'idx_history_level_name_type' }); // Index for JSONB queries on snapshot_data await queryInterface.addIndex('dealer_claim_history', ['snapshot_type'], { name: 'idx_history_snapshot_type', using: 'BTREE' }); }; export const down = async (queryInterface: QueryInterface) => { // Note: Table should be dropped manually // Drop the enum type try { await queryInterface.sequelize.query(` DROP TYPE IF EXISTS enum_dealer_claim_history_snapshot_type CASCADE; `); } catch (error) { console.warn('Enum drop warning:', error); } };