import { sequelize } from '../config/database'; import { QueryInterface, QueryTypes } from 'sequelize'; import * as m0 from '../migrations/2025103000-create-users'; import * as m1 from '../migrations/2025103001-create-workflow-requests'; import * as m2 from '../migrations/2025103002-create-approval-levels'; import * as m3 from '../migrations/2025103003-create-participants'; import * as m4 from '../migrations/2025103004-create-documents'; import * as m5 from '../migrations/20251031_01_create_subscriptions'; import * as m6 from '../migrations/20251031_02_create_activities'; import * as m7 from '../migrations/20251031_03_create_work_notes'; import * as m8 from '../migrations/20251031_04_create_work_note_attachments'; import * as m9 from '../migrations/20251104-add-tat-alert-fields'; import * as m10 from '../migrations/20251104-create-tat-alerts'; import * as m11 from '../migrations/20251104-create-kpi-views'; import * as m12 from '../migrations/20251104-create-holidays'; import * as m13 from '../migrations/20251104-create-admin-config'; import * as m14 from '../migrations/20251105-add-skip-fields-to-approval-levels'; import * as m15 from '../migrations/2025110501-alter-tat-days-to-generated'; import * as m16 from '../migrations/20251111-create-notifications'; import * as m17 from '../migrations/20251111-create-conclusion-remarks'; import * as m18 from '../migrations/20251118-add-breach-reason-to-approval-levels'; import * as m19 from '../migrations/20251121-add-ai-model-configs'; import * as m20 from '../migrations/20250122-create-request-summaries'; import * as m21 from '../migrations/20250122-create-shared-summaries'; import * as m22 from '../migrations/20251210-add-workflow-type-support'; import * as m23 from '../migrations/20251210-enhance-workflow-templates'; import * as m24 from '../migrations/20251210-add-template-id-foreign-key'; import * as m25 from '../migrations/20251210-create-dealer-claim-tables'; import * as m26 from '../migrations/20251210-create-proposal-cost-items-table'; import * as m27 from '../migrations/20251211-create-internal-orders-table'; import * as m28 from '../migrations/20251211-create-claim-budget-tracking-table'; interface Migration { name: string; module: any; } // Define all migrations in order // IMPORTANT: Order matters! Dependencies must be created before tables that reference them const migrations: Migration[] = [ // 1. FIRST: Create base tables with no dependencies { name: '2025103000-create-users', module: m0 }, // ← MUST BE FIRST // 2. Tables that depend on users { name: '2025103001-create-workflow-requests', module: m1 }, { name: '2025103002-create-approval-levels', module: m2 }, { name: '2025103003-create-participants', module: m3 }, { name: '2025103004-create-documents', module: m4 }, { name: '20251031_01_create_subscriptions', module: m5 }, { name: '20251031_02_create_activities', module: m6 }, { name: '20251031_03_create_work_notes', module: m7 }, { name: '20251031_04_create_work_note_attachments', module: m8 }, // 3. Table modifications and additional features { name: '20251104-add-tat-alert-fields', module: m9 }, { name: '20251104-create-tat-alerts', module: m10 }, { name: '20251104-create-kpi-views', module: m11 }, { name: '20251104-create-holidays', module: m12 }, { name: '20251104-create-admin-config', module: m13 }, { name: '20251105-add-skip-fields-to-approval-levels', module: m14 }, { name: '2025110501-alter-tat-days-to-generated', module: m15 }, { name: '20251111-create-notifications', module: m16 }, { name: '20251111-create-conclusion-remarks', module: m17 }, { name: '20251118-add-breach-reason-to-approval-levels', module: m18 }, { name: '20251121-add-ai-model-configs', module: m19 }, { name: '20250122-create-request-summaries', module: m20 }, { name: '20250122-create-shared-summaries', module: m21 }, { name: '20251210-add-workflow-type-support', module: m22 }, { name: '20251210-enhance-workflow-templates', module: m23 }, { name: '20251210-add-template-id-foreign-key', module: m24 }, { name: '20251210-create-dealer-claim-tables', module: m25 }, { name: '20251210-create-proposal-cost-items-table', module: m26 }, { name: '20251211-create-internal-orders-table', module: m27 }, { name: '20251211-create-claim-budget-tracking-table', module: m28 }, ]; /** * Create migrations tracking table if it doesn't exist */ async function ensureMigrationsTable(queryInterface: QueryInterface): Promise { try { const tables = await queryInterface.showAllTables(); if (!tables.includes('migrations')) { await queryInterface.sequelize.query(` CREATE TABLE migrations ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL UNIQUE, executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) `); // Migrations table created } } catch (error) { console.error('Error creating migrations table:', error); throw error; } } /** * Get list of already executed migrations */ async function getExecutedMigrations(): Promise { try { const results = await sequelize.query<{ name: string }>( 'SELECT name FROM migrations ORDER BY id', { type: QueryTypes.SELECT } ); return results.map(r => r.name); } catch (error) { // Table might not exist yet return []; } } /** * Mark migration as executed */ async function markMigrationExecuted(name: string): Promise { await sequelize.query( 'INSERT INTO migrations (name) VALUES (:name) ON CONFLICT (name) DO NOTHING', { replacements: { name }, type: QueryTypes.INSERT } ); } /** * Run all pending migrations */ async function run() { try { await sequelize.authenticate(); const queryInterface = sequelize.getQueryInterface(); // Ensure migrations tracking table exists await ensureMigrationsTable(queryInterface); // Get already executed migrations const executedMigrations = await getExecutedMigrations(); // Find pending migrations const pendingMigrations = migrations.filter( m => !executedMigrations.includes(m.name) ); if (pendingMigrations.length === 0) { console.log('✅ Migrations up-to-date'); process.exit(0); return; } console.log(`🔄 Running ${pendingMigrations.length} migration(s)...`); // Run each pending migration for (const migration of pendingMigrations) { try { await migration.module.up(queryInterface); await markMigrationExecuted(migration.name); console.log(`✅ ${migration.name}`); } catch (error: any) { console.error(`❌ Migration failed: ${migration.name} - ${error.message}`); throw error; } } console.log(`✅ Applied ${pendingMigrations.length} migration(s)`); process.exit(0); } catch (err: any) { console.error('❌ Migration failed:', err.message); process.exit(1); } } run();