221 lines
9.5 KiB
TypeScript
221 lines
9.5 KiB
TypeScript
import { QueryInterface, QueryTypes } from 'sequelize';
|
|
import { initializeGoogleSecretManager } from '../services/googleSecretManager.service';
|
|
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/20250123-update-request-number-format';
|
|
import * as m23 from '../migrations/20250126-add-paused-to-enum';
|
|
import * as m24 from '../migrations/20250126-add-paused-to-workflow-status-enum';
|
|
import * as m25 from '../migrations/20250126-add-pause-fields-to-workflow-requests';
|
|
import * as m26 from '../migrations/20250126-add-pause-fields-to-approval-levels';
|
|
import * as m27 from '../migrations/20250127-migrate-in-progress-to-pending';
|
|
// Base branch migrations (m28-m29)
|
|
import * as m28 from '../migrations/20250130-migrate-to-vertex-ai';
|
|
import * as m29 from '../migrations/20251203-add-user-notification-preferences';
|
|
// Dealer claim branch migrations (m30-m39)
|
|
import * as m30 from '../migrations/20251210-add-workflow-type-support';
|
|
import * as m31 from '../migrations/20251210-enhance-workflow-templates';
|
|
import * as m32 from '../migrations/20251210-add-template-id-foreign-key';
|
|
import * as m33 from '../migrations/20251210-create-dealer-claim-tables';
|
|
import * as m34 from '../migrations/20251210-create-proposal-cost-items-table';
|
|
import * as m35 from '../migrations/20251211-create-internal-orders-table';
|
|
import * as m36 from '../migrations/20251211-create-claim-budget-tracking-table';
|
|
import * as m37 from '../migrations/20251213-drop-claim-details-invoice-columns';
|
|
import * as m38 from '../migrations/20251213-create-claim-invoice-credit-note-tables';
|
|
import * as m39 from '../migrations/20251214-create-dealer-completion-expenses';
|
|
import * as m40 from '../migrations/20251218-fix-claim-invoice-credit-note-columns';
|
|
import * as m41 from '../migrations/20250120-create-dealers-table';
|
|
import * as m42 from '../migrations/20250125-create-activity-types';
|
|
import * as m43 from '../migrations/20260113-redesign-dealer-claim-history';
|
|
import * as m44 from '../migrations/20260123-fix-template-id-schema';
|
|
|
|
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: '20250123-update-request-number-format', module: m22 },
|
|
{ name: '20250126-add-paused-to-enum', module: m23 },
|
|
{ name: '20250126-add-paused-to-workflow-status-enum', module: m24 },
|
|
{ name: '20250126-add-pause-fields-to-workflow-requests', module: m25 },
|
|
{ name: '20250126-add-pause-fields-to-approval-levels', module: m26 },
|
|
{ name: '20250127-migrate-in-progress-to-pending', module: m27 },
|
|
// Base branch migrations (m28-m29)
|
|
{ name: '20250130-migrate-to-vertex-ai', module: m28 },
|
|
{ name: '20251203-add-user-notification-preferences', module: m29 },
|
|
// Dealer claim branch migrations (m30-m39)
|
|
{ name: '20251210-add-workflow-type-support', module: m30 },
|
|
{ name: '20251210-enhance-workflow-templates', module: m31 },
|
|
{ name: '20251210-add-template-id-foreign-key', module: m32 },
|
|
{ name: '20251210-create-dealer-claim-tables', module: m33 },
|
|
{ name: '20251210-create-proposal-cost-items-table', module: m34 },
|
|
{ name: '20251211-create-internal-orders-table', module: m35 },
|
|
{ name: '20251211-create-claim-budget-tracking-table', module: m36 },
|
|
{ name: '20251213-drop-claim-details-invoice-columns', module: m37 },
|
|
{ name: '20251213-create-claim-invoice-credit-note-tables', module: m38 },
|
|
{ name: '20251214-create-dealer-completion-expenses', module: m39 },
|
|
{ name: '20251218-fix-claim-invoice-credit-note-columns', module: m40 },
|
|
{ name: '20250120-create-dealers-table', module: m41 },
|
|
{ name: '20250125-create-activity-types', module: m42 },
|
|
{ name: '20260113-redesign-dealer-claim-history', module: m43 },
|
|
{ name: '20260123-fix-template-id-schema', module: m44 },
|
|
];
|
|
|
|
/**
|
|
* Create migrations tracking table if it doesn't exist
|
|
*/
|
|
async function ensureMigrationsTable(queryInterface: QueryInterface): Promise<void> {
|
|
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(sequelize: any): Promise<string[]> {
|
|
try {
|
|
const results = await sequelize.query(
|
|
'SELECT name FROM migrations ORDER BY id',
|
|
{ type: QueryTypes.SELECT }
|
|
) as { name: string }[];
|
|
return results.map(r => r.name);
|
|
} catch (error) {
|
|
// Table might not exist yet
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mark migration as executed
|
|
*/
|
|
async function markMigrationExecuted(sequelize: any, name: string): Promise<void> {
|
|
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 {
|
|
console.log('🔐 Initializing secrets...');
|
|
await initializeGoogleSecretManager();
|
|
|
|
// Dynamically import sequelize after secrets are loaded
|
|
const { sequelize } = require('../config/database');
|
|
|
|
await sequelize.authenticate();
|
|
|
|
const queryInterface = sequelize.getQueryInterface();
|
|
|
|
// Ensure migrations tracking table exists
|
|
await ensureMigrationsTable(queryInterface);
|
|
|
|
// Get already executed migrations
|
|
const executedMigrations = await getExecutedMigrations(sequelize);
|
|
|
|
// 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(sequelize, 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();
|