/** * Seed script to initialize interview configurations * with the existing system-default questions. * * Run: npx tsx scripts/seed-interview-configs.ts */ import 'dotenv/config'; import db from '../src/database/models/index.js'; async function seedInterviewConfigs() { const { sequelize, InterviewConfig, InterviewConfigItem, InterviewConfigItemOption } = db as any; await sequelize.authenticate(); console.log('Database connected.'); // Ensure tables exist await sequelize.sync({ alter: true }); console.log('Tables synced.'); // --- KT Matrix --- const ktMatrixItems = [ { itemKey: 'age', label: 'Age', weight: 5, maxScore: 10, order: 1, options: [ { optionLabel: '20 to 40 years old', optionValue: '20-40', score: 10, order: 1 }, { optionLabel: '40 to 50 years old', optionValue: '40-50', score: 5, order: 2 }, { optionLabel: 'Above 50 years old', optionValue: 'above-50', score: 0, order: 3 }, ]}, { itemKey: 'qualification', label: 'Qualification', weight: 5, maxScore: 10, order: 2, options: [ { optionLabel: 'Post Graduate', optionValue: 'post-graduate', score: 10, order: 1 }, { optionLabel: 'Graduate', optionValue: 'graduate', score: 5, order: 2 }, { optionLabel: 'SSLC', optionValue: 'sslc', score: 0, order: 3 }, ]}, { itemKey: 'localKnowledge', label: 'Local Knowledge and Influence', weight: 5, maxScore: 10, order: 3, options: [ { optionLabel: 'Excellent PR', optionValue: 'excellent', score: 10, order: 1 }, { optionLabel: 'Good PR', optionValue: 'good', score: 5, order: 2 }, { optionLabel: 'Poor PR', optionValue: 'poor', score: 0, order: 3 }, ]}, { itemKey: 'baseLocation', label: 'Base Location vs Applied Location', weight: 10, maxScore: 10, order: 4, options: [ { optionLabel: 'Native of the Applied location', optionValue: 'native', score: 10, order: 1 }, { optionLabel: 'Willing to relocate', optionValue: 'relocate', score: 5, order: 2 }, { optionLabel: 'Will manage remotely with occasional visits', optionValue: 'remote', score: 0, order: 3 }, ]}, { itemKey: 'whyInterested', label: 'Why Interested in Royal Enfield Business?', weight: 10, maxScore: 10, order: 5, options: [ { optionLabel: 'Passion', optionValue: 'passion', score: 10, order: 1 }, { optionLabel: 'Business expansion / Status symbol', optionValue: 'business', score: 5, order: 2 }, ]}, { itemKey: 'passionRe', label: 'Passion for Royal Enfield', weight: 10, maxScore: 10, order: 6, options: [ { optionLabel: 'Currently owns a Royal Enfield', optionValue: 'owns', score: 10, order: 1 }, { optionLabel: 'Owned by Immediate Relative', optionValue: 'relative', score: 5, order: 2 }, { optionLabel: 'Does not own Royal Enfield', optionValue: 'none', score: 0, order: 3 }, ]}, { itemKey: 'passionRides', label: 'Passion For Rides', weight: 10, maxScore: 10, order: 7, options: [ { optionLabel: 'Goes for long rides regularly', optionValue: 'regular', score: 10, order: 1 }, { optionLabel: 'Goes for long rides rarely', optionValue: 'rarely', score: 5, order: 2 }, { optionLabel: "Doesn't go for rides", optionValue: 'never', score: 0, order: 3 }, ]}, { itemKey: 'partnering', label: 'With Whom Partnering?', weight: 5, maxScore: 10, order: 8, options: [ { optionLabel: 'Within family', optionValue: 'family', score: 10, order: 1 }, { optionLabel: 'Outside family', optionValue: 'outside', score: 0, order: 2 }, ]}, { itemKey: 'whoManages', label: 'Who Will Manage the Firm?', weight: 10, maxScore: 10, order: 9, options: [ { optionLabel: 'Owner managed', optionValue: 'owner', score: 10, order: 1 }, { optionLabel: 'Partly owner / partly manager model', optionValue: 'partly', score: 5, order: 2 }, { optionLabel: 'Fully manager model', optionValue: 'manager', score: 0, order: 3 }, ]}, { itemKey: 'businessAcumen', label: 'Business Acumen', weight: 5, maxScore: 10, order: 10, options: [ { optionLabel: 'Has similar automobile experience', optionValue: 'automobile', score: 10, order: 1 }, { optionLabel: 'Has successful business but not automobile', optionValue: 'other-business', score: 5, order: 2 }, { optionLabel: 'No business experience', optionValue: 'no-experience', score: 0, order: 3 }, ]}, { itemKey: 'timeAvailability', label: 'Time Availability', weight: 5, maxScore: 10, order: 11, options: [ { optionLabel: 'Full Time Availability for RE Business', optionValue: 'full-time', score: 10, order: 1 }, { optionLabel: 'Part Time Availability for RE Business', optionValue: 'part-time', score: 5, order: 2 }, { optionLabel: 'Not Available personally, Manager will handle', optionValue: 'manager', score: 0, order: 3 }, ]}, { itemKey: 'propertyOwnership', label: 'Property Ownership', weight: 5, maxScore: 10, order: 12, options: [ { optionLabel: 'Has own property in proposed location', optionValue: 'own', score: 10, order: 1 }, { optionLabel: 'Will rent / lease', optionValue: 'rent', score: 0, order: 2 }, ]}, { itemKey: 'investment', label: 'Investment in the Business', weight: 5, maxScore: 10, order: 13, options: [ { optionLabel: 'Full own funds', optionValue: 'own-funds', score: 10, order: 1 }, { optionLabel: 'Partially from the bank', optionValue: 'partial-bank', score: 5, order: 2 }, { optionLabel: 'Completely bank funded', optionValue: 'full-bank', score: 0, order: 3 }, ]}, { itemKey: 'expandOtherOems', label: 'Will Expand to Other 2W/4W OEMs?', weight: 5, maxScore: 10, order: 14, options: [ { optionLabel: 'No', optionValue: 'no', score: 10, order: 1 }, { optionLabel: 'Yes', optionValue: 'yes', score: 0, order: 2 }, ]}, { itemKey: 'expansionPlans', label: 'Plans of Expansion with RE', weight: 5, maxScore: 10, order: 15, options: [ { optionLabel: 'Immediate blood relation will join & expand', optionValue: 'blood-relation', score: 10, order: 1 }, { optionLabel: 'Wants to expand by himself into more clusters', optionValue: 'self-expand', score: 5, order: 2 }, { optionLabel: 'No plans for expansion', optionValue: 'no-plans', score: 0, order: 3 }, ]}, ]; // --- Level 2 Feedback --- const level2Items = [ { itemKey: 'strategicVision', label: 'Strategic Vision', type: 'textarea' as const, isRequired: true, order: 1 }, { itemKey: 'managementCapabilities', label: 'Management Capabilities', type: 'textarea' as const, isRequired: true, order: 2 }, { itemKey: 'operationalUnderstanding', label: 'Operational Understanding', type: 'textarea' as const, isRequired: true, order: 3 }, { itemKey: 'keyStrengths', label: 'Key Strengths', type: 'textarea' as const, isRequired: true, order: 4 }, { itemKey: 'areasOfConcern', label: 'Areas of Concern', type: 'textarea' as const, isRequired: true, order: 5 }, { itemKey: 'additionalComments', label: 'Additional Comments', type: 'textarea' as const, isRequired: false, order: 6 }, ]; // --- Level 3 Feedback --- const level3Items = [ { itemKey: 'strategicVision', label: 'Business Vision & Strategy', type: 'textarea' as const, isRequired: true, order: 1 }, { itemKey: 'managementCapabilities', label: 'Leadership & Decision Making', type: 'textarea' as const, isRequired: true, order: 2 }, { itemKey: 'operationalUnderstanding', label: 'Operational & Financial Readiness', type: 'textarea' as const, isRequired: true, order: 3 }, { itemKey: 'brandAlignment', label: 'Brand Alignment', type: 'textarea' as const, isRequired: true, order: 4 }, { itemKey: 'keyStrengths', label: 'Key Strengths', type: 'textarea' as const, isRequired: true, order: 5 }, { itemKey: 'areasOfConcern', label: 'Areas of Concern', type: 'textarea' as const, isRequired: true, order: 6 }, { itemKey: 'executiveSummary', label: 'Executive Summary', type: 'textarea' as const, isRequired: true, order: 7 }, { itemKey: 'additionalComments', label: 'Additional Comments', type: 'textarea' as const, isRequired: false, order: 8 }, ]; const transaction = await sequelize.transaction(); try { // Deactivate any existing configs await InterviewConfig.update({ isActive: false }, { where: {}, transaction }); // Create KT Matrix Config const ktConfig = await InterviewConfig.create({ configType: 'KT_MATRIX', name: 'System Default KT Matrix', version: 'v1.0', isActive: true, }, { transaction }); for (const item of ktMatrixItems) { const createdItem = await InterviewConfigItem.create({ configId: ktConfig.id, itemKey: item.itemKey, label: item.label, type: 'select', order: item.order, isRequired: true, weight: item.weight, maxScore: item.maxScore, }, { transaction }); if (item.options) { await InterviewConfigItemOption.bulkCreate( item.options.map((o: any) => ({ itemId: createdItem.id, optionLabel: o.optionLabel, optionValue: o.optionValue, score: o.score, order: o.order, })), { transaction } ); } } // Create Level 2 Config const l2Config = await InterviewConfig.create({ configType: 'LEVEL2_FEEDBACK', name: 'System Default Level 2 Feedback', version: 'v1.0', isActive: true, }, { transaction }); await InterviewConfigItem.bulkCreate( level2Items.map((item) => ({ configId: l2Config.id, itemKey: item.itemKey, label: item.label, type: item.type, order: item.order, isRequired: item.isRequired, weight: null, maxScore: null, })), { transaction } ); // Create Level 3 Config const l3Config = await InterviewConfig.create({ configType: 'LEVEL3_FEEDBACK', name: 'System Default Level 3 Feedback', version: 'v1.0', isActive: true, }, { transaction }); await InterviewConfigItem.bulkCreate( level3Items.map((item) => ({ configId: l3Config.id, itemKey: item.itemKey, label: item.label, type: item.type, order: item.order, isRequired: item.isRequired, weight: null, maxScore: null, })), { transaction } ); await transaction.commit(); console.log('Interview configurations seeded successfully.'); console.log(` - KT Matrix: ${ktMatrixItems.length} criteria`); console.log(` - Level 2 Feedback: ${level2Items.length} fields`); console.log(` - Level 3 Feedback: ${level3Items.length} fields`); } catch (error) { await transaction.rollback(); console.error('Seeding failed:', error); throw error; } finally { await sequelize.close(); } } seedInterviewConfigs().catch((err) => { console.error(err); process.exit(1); });