578 lines
13 KiB
TypeScript
578 lines
13 KiB
TypeScript
/**
|
|
* Manual script to seed admin configurations
|
|
* Run this if configurations are not auto-seeding on server startup
|
|
*
|
|
* Usage: npm run seed:config
|
|
*/
|
|
|
|
import { sequelize } from '../config/database';
|
|
import { QueryTypes } from 'sequelize';
|
|
|
|
async function seedAdminConfigurations() {
|
|
try {
|
|
await sequelize.authenticate();
|
|
|
|
// Check if configurations already exist
|
|
const count = await sequelize.query(
|
|
'SELECT COUNT(*) as count FROM admin_configurations',
|
|
{ type: QueryTypes.SELECT }
|
|
);
|
|
|
|
const existingCount = (count[0] as any).count;
|
|
|
|
if (existingCount > 0) {
|
|
console.log(`⚠️ Found ${existingCount} existing configurations. Delete them first or skip this script.`);
|
|
const readline = require('readline').createInterface({
|
|
input: process.stdin,
|
|
output: process.stdout
|
|
});
|
|
|
|
const answer = await new Promise<string>((resolve) => {
|
|
readline.question('Delete existing and re-seed? (yes/no): ', resolve);
|
|
});
|
|
|
|
readline.close();
|
|
|
|
if (answer.toLowerCase() !== 'yes') {
|
|
console.log('❌ Aborted. No changes made.');
|
|
process.exit(0);
|
|
}
|
|
|
|
await sequelize.query('DELETE FROM admin_configurations');
|
|
console.log('✅ Existing configurations deleted');
|
|
}
|
|
|
|
console.log('📝 Seeding admin configurations...');
|
|
|
|
// Insert all default configurations
|
|
await sequelize.query(`
|
|
INSERT INTO admin_configurations (
|
|
config_id, config_key, config_category, config_value, value_type,
|
|
display_name, description, default_value, is_editable, is_sensitive,
|
|
validation_rules, ui_component, sort_order, requires_restart,
|
|
created_at, updated_at
|
|
) VALUES
|
|
-- TAT Settings
|
|
(
|
|
gen_random_uuid(),
|
|
'DEFAULT_TAT_EXPRESS_HOURS',
|
|
'TAT_SETTINGS',
|
|
'24',
|
|
'NUMBER',
|
|
'Default TAT for Express Priority',
|
|
'Default turnaround time in hours for express priority requests (calendar days, 24/7)',
|
|
'24',
|
|
true,
|
|
false,
|
|
'{"min": 1, "max": 168}'::jsonb,
|
|
'number',
|
|
1,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'DEFAULT_TAT_STANDARD_HOURS',
|
|
'TAT_SETTINGS',
|
|
'48',
|
|
'NUMBER',
|
|
'Default TAT for Standard Priority',
|
|
'Default turnaround time in hours for standard priority requests (working hours only)',
|
|
'48',
|
|
true,
|
|
false,
|
|
'{"min": 1, "max": 336}'::jsonb,
|
|
'number',
|
|
2,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'TAT_THRESHOLD_WARNING',
|
|
'TAT_SETTINGS',
|
|
'50',
|
|
'NUMBER',
|
|
'TAT Warning Threshold (%)',
|
|
'Percentage of TAT elapsed when first warning notification is sent',
|
|
'50',
|
|
true,
|
|
false,
|
|
'{"min": 1, "max": 100}'::jsonb,
|
|
'number',
|
|
3,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'TAT_THRESHOLD_CRITICAL',
|
|
'TAT_SETTINGS',
|
|
'75',
|
|
'NUMBER',
|
|
'TAT Critical Threshold (%)',
|
|
'Percentage of TAT elapsed when critical notification is sent',
|
|
'75',
|
|
true,
|
|
false,
|
|
'{"min": 1, "max": 100}'::jsonb,
|
|
'number',
|
|
4,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'TAT_TEST_MODE',
|
|
'TAT_SETTINGS',
|
|
'false',
|
|
'BOOLEAN',
|
|
'TAT Test Mode',
|
|
'Enable test mode where 1 TAT hour = 1 minute (for development/testing only)',
|
|
'false',
|
|
true,
|
|
false,
|
|
'{}'::jsonb,
|
|
'switch',
|
|
5,
|
|
true,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
|
|
-- Working Hours Settings
|
|
(
|
|
gen_random_uuid(),
|
|
'WORK_START_HOUR',
|
|
'TAT_SETTINGS',
|
|
'9',
|
|
'NUMBER',
|
|
'Work Day Start Hour',
|
|
'Hour when work day starts (24-hour format, e.g., 9 for 9:00 AM)',
|
|
'9',
|
|
true,
|
|
false,
|
|
'{"min": 0, "max": 23}'::jsonb,
|
|
'number',
|
|
10,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'WORK_END_HOUR',
|
|
'TAT_SETTINGS',
|
|
'18',
|
|
'NUMBER',
|
|
'Work Day End Hour',
|
|
'Hour when work day ends (24-hour format, e.g., 18 for 6:00 PM)',
|
|
'18',
|
|
true,
|
|
false,
|
|
'{"min": 0, "max": 23}'::jsonb,
|
|
'number',
|
|
11,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'WORK_START_DAY',
|
|
'TAT_SETTINGS',
|
|
'1',
|
|
'NUMBER',
|
|
'Work Week Start Day',
|
|
'Day when work week starts (1 = Monday, 7 = Sunday)',
|
|
'1',
|
|
true,
|
|
false,
|
|
'{"min": 1, "max": 7}'::jsonb,
|
|
'number',
|
|
12,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'WORK_END_DAY',
|
|
'TAT_SETTINGS',
|
|
'5',
|
|
'NUMBER',
|
|
'Work Week End Day',
|
|
'Day when work week ends (1 = Monday, 7 = Sunday)',
|
|
'5',
|
|
true,
|
|
false,
|
|
'{"min": 1, "max": 7}'::jsonb,
|
|
'number',
|
|
13,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'TIMEZONE',
|
|
'WORKING_HOURS',
|
|
'Asia/Kolkata',
|
|
'STRING',
|
|
'System Timezone',
|
|
'Timezone for all TAT calculations and scheduling',
|
|
'Asia/Kolkata',
|
|
true,
|
|
false,
|
|
'{}'::jsonb,
|
|
'select',
|
|
14,
|
|
true,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
|
|
-- Workflow Settings
|
|
(
|
|
gen_random_uuid(),
|
|
'MAX_APPROVAL_LEVELS',
|
|
'WORKFLOW',
|
|
'10',
|
|
'NUMBER',
|
|
'Maximum Approval Levels',
|
|
'Maximum number of approval levels allowed per workflow',
|
|
'10',
|
|
true,
|
|
false,
|
|
'{"min": 1, "max": 20}'::jsonb,
|
|
'number',
|
|
20,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'MAX_PARTICIPANTS',
|
|
'WORKFLOW',
|
|
'50',
|
|
'NUMBER',
|
|
'Maximum Participants',
|
|
'Maximum number of participants (spectators + approvers) per request',
|
|
'50',
|
|
true,
|
|
false,
|
|
'{"min": 1, "max": 100}'::jsonb,
|
|
'number',
|
|
21,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
|
|
-- File Upload Settings
|
|
(
|
|
gen_random_uuid(),
|
|
'MAX_FILE_SIZE_MB',
|
|
'FILE_UPLOAD',
|
|
'10',
|
|
'NUMBER',
|
|
'Maximum File Size (MB)',
|
|
'Maximum size for uploaded files in megabytes',
|
|
'10',
|
|
true,
|
|
false,
|
|
'{"min": 1, "max": 100}'::jsonb,
|
|
'number',
|
|
30,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'ALLOWED_FILE_TYPES',
|
|
'FILE_UPLOAD',
|
|
'pdf,doc,docx,xls,xlsx,ppt,pptx,jpg,jpeg,png,gif,txt',
|
|
'STRING',
|
|
'Allowed File Types',
|
|
'Comma-separated list of allowed file extensions',
|
|
'pdf,doc,docx,xls,xlsx,ppt,pptx,jpg,jpeg,png,gif,txt',
|
|
true,
|
|
false,
|
|
'{}'::jsonb,
|
|
'text',
|
|
31,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
|
|
-- Feature Toggles
|
|
(
|
|
gen_random_uuid(),
|
|
'ENABLE_AI_CONCLUSION',
|
|
'FEATURES',
|
|
'true',
|
|
'BOOLEAN',
|
|
'Enable AI-Generated Conclusions',
|
|
'Allow AI to generate automatic conclusion remarks for approved/rejected requests',
|
|
'true',
|
|
true,
|
|
false,
|
|
'{}'::jsonb,
|
|
'switch',
|
|
40,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'ENABLE_PUSH_NOTIFICATIONS',
|
|
'FEATURES',
|
|
'true',
|
|
'BOOLEAN',
|
|
'Enable Push Notifications',
|
|
'Send browser push notifications for real-time events',
|
|
'true',
|
|
true,
|
|
false,
|
|
'{}'::jsonb,
|
|
'switch',
|
|
41,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'ENABLE_EMAIL_NOTIFICATIONS',
|
|
'FEATURES',
|
|
'true',
|
|
'BOOLEAN',
|
|
'Enable Email Notifications',
|
|
'Send email notifications for workflow events',
|
|
'true',
|
|
true,
|
|
false,
|
|
'{}'::jsonb,
|
|
'switch',
|
|
42,
|
|
true,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
|
|
-- AI Configuration (from migration 20251111-add-ai-provider-configs)
|
|
(
|
|
gen_random_uuid(),
|
|
'AI_PROVIDER',
|
|
'AI_CONFIGURATION',
|
|
'claude',
|
|
'STRING',
|
|
'AI Provider',
|
|
'Active AI provider for conclusion generation (claude, openai, or gemini)',
|
|
'claude',
|
|
true,
|
|
false,
|
|
'{"enum": ["claude", "openai", "gemini"], "required": true}'::jsonb,
|
|
'select',
|
|
100,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'CLAUDE_API_KEY',
|
|
'AI_CONFIGURATION',
|
|
'',
|
|
'STRING',
|
|
'Claude API Key',
|
|
'API key for Claude (Anthropic) - Get from console.anthropic.com',
|
|
'',
|
|
true,
|
|
true,
|
|
'{"pattern": "^sk-ant-", "minLength": 40}'::jsonb,
|
|
'input',
|
|
101,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'OPENAI_API_KEY',
|
|
'AI_CONFIGURATION',
|
|
'',
|
|
'STRING',
|
|
'OpenAI API Key',
|
|
'API key for OpenAI (GPT-4) - Get from platform.openai.com',
|
|
'',
|
|
true,
|
|
true,
|
|
'{"pattern": "^sk-", "minLength": 40}'::jsonb,
|
|
'input',
|
|
102,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'GEMINI_API_KEY',
|
|
'AI_CONFIGURATION',
|
|
'',
|
|
'STRING',
|
|
'Gemini API Key',
|
|
'API key for Gemini (Google) - Get from ai.google.dev',
|
|
'',
|
|
true,
|
|
true,
|
|
'{"minLength": 20}'::jsonb,
|
|
'input',
|
|
103,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'AI_ENABLED',
|
|
'AI_CONFIGURATION',
|
|
'true',
|
|
'BOOLEAN',
|
|
'Enable AI Features',
|
|
'Master toggle to enable/disable all AI-powered features in the system',
|
|
'true',
|
|
true,
|
|
false,
|
|
'{"type": "boolean"}'::jsonb,
|
|
'toggle',
|
|
104,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'CLAUDE_MODEL',
|
|
'AI_CONFIGURATION',
|
|
'claude-sonnet-4-20250514',
|
|
'STRING',
|
|
'Claude Model',
|
|
'Claude (Anthropic) model to use for AI generation',
|
|
'claude-sonnet-4-20250514',
|
|
true,
|
|
false,
|
|
'{}'::jsonb,
|
|
'input',
|
|
105,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'OPENAI_MODEL',
|
|
'AI_CONFIGURATION',
|
|
'gpt-4o',
|
|
'STRING',
|
|
'OpenAI Model',
|
|
'OpenAI model to use for AI generation',
|
|
'gpt-4o',
|
|
true,
|
|
false,
|
|
'{}'::jsonb,
|
|
'input',
|
|
106,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'GEMINI_MODEL',
|
|
'AI_CONFIGURATION',
|
|
'gemini-2.0-flash-lite',
|
|
'STRING',
|
|
'Gemini Model',
|
|
'Gemini (Google) model to use for AI generation',
|
|
'gemini-2.0-flash-lite',
|
|
true,
|
|
false,
|
|
'{}'::jsonb,
|
|
'input',
|
|
107,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'AI_REMARK_GENERATION_ENABLED',
|
|
'AI_CONFIGURATION',
|
|
'true',
|
|
'BOOLEAN',
|
|
'Enable AI Remark Generation',
|
|
'Enable/disable AI-powered conclusion remark generation when requests are approved',
|
|
'true',
|
|
true,
|
|
false,
|
|
'{"type": "boolean"}'::jsonb,
|
|
'toggle',
|
|
108,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
),
|
|
(
|
|
gen_random_uuid(),
|
|
'AI_MAX_REMARK_LENGTH',
|
|
'AI_CONFIGURATION',
|
|
'2000',
|
|
'NUMBER',
|
|
'AI Max Remark Length',
|
|
'Maximum character length for AI-generated conclusion remarks (used as context for AI prompt)',
|
|
'2000',
|
|
true,
|
|
false,
|
|
'{"type": "number", "min": 500, "max": 5000}'::jsonb,
|
|
'number',
|
|
109,
|
|
false,
|
|
NOW(),
|
|
NOW()
|
|
)
|
|
ON CONFLICT (config_key) DO UPDATE SET
|
|
config_value = EXCLUDED.config_value,
|
|
updated_at = NOW()
|
|
`);
|
|
|
|
const finalCount = await sequelize.query(
|
|
'SELECT COUNT(*) as count FROM admin_configurations',
|
|
{ type: QueryTypes.SELECT }
|
|
);
|
|
|
|
console.log(`✅ Seeded ${(finalCount[0] as any).count} admin configurations`);
|
|
|
|
process.exit(0);
|
|
} catch (error) {
|
|
console.error('❌ Error seeding admin configurations:', error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Run if called directly
|
|
if (require.main === module) {
|
|
seedAdminConfigurations();
|
|
}
|
|
|
|
export default seedAdminConfigurations;
|
|
|