system configuration seed added

This commit is contained in:
laxmanhalaki 2025-11-06 12:33:11 +05:30
parent 31354f2825
commit 53bc624094
20 changed files with 719 additions and 96 deletions

124
CONSOLE_LOGS_CLEANED.md Normal file
View File

@ -0,0 +1,124 @@
# Console Logs Cleanup Summary
## Changes Applied
All verbose, redundant, and confusing console logs have been removed or simplified to keep only essential one-line messages helpful for bug tracking.
## What Was Kept ✅
**Server Startup:**
- `🚀 Server running on port ${PORT} | ${environment}` - Single line server status
**Critical Errors:**
- `❌ Database connection failed`
- `❌ Unable to start server`
- `❌ SSO Callback failed`
- `❌ Get Users failed`
- `❌ Authorization check failed`
- `❌ Admin authorization failed`
- `❌ Migration failed`
- `❌ Configuration seeding error`
- `❌ TAT Error loading working hours/holidays`
**Migration Status:**
- `✅ Migrations up-to-date`
- `🔄 Running ${count} migration(s)...`
- `✅ ${migration-name}` - Per migration success
- `✅ Applied ${count} migration(s)` - Final summary
**Graceful Shutdown:**
- `🛑 SIGTERM signal received: closing HTTP server`
- `🛑 SIGINT signal received: closing HTTP server`
## What Was Removed ❌
### Multi-line Configuration Dumps
- ~~TAT Configuration details (working hours, thresholds, test mode)~~
- ~~System Configuration details (environment, version, features)~~
- ~~Working hours cache loaded messages~~
### Verbose Development Logs
- ~~Database connection established~~
- ~~Database models synchronized~~
- ~~Socket.IO server initialized~~
- ~~Socket.IO client connected with socket.id~~
- ~~Auth routes loaded~~
- ~~Holiday calendar loaded~~
### Migration Details
- ~~Individual table created messages~~
- ~~Individual column added messages~~
- ~~Index created messages~~
- ~~Conversion progress messages~~
### Database Query Logging
- **Disabled SQL query logging** in `database.ts` - previously showed ALL database queries in development mode
## File Changes
### Core Files
1. **src/server.ts** - Simplified to single line startup message
2. **src/app.ts** - Removed database connection messages, kept only errors
3. **src/config/tat.config.ts** - Disabled multi-line TAT config logging
4. **src/config/system.config.ts** - Disabled multi-line system config logging
5. **src/config/database.ts** - **Disabled SQL query logging** (was showing every SELECT/INSERT/UPDATE)
6. **src/realtime/socket.ts** - Removed Socket.IO initialization and connection logs
7. **src/utils/tatTimeUtils.ts** - Removed verbose cache loading messages, kept errors
8. **src/routes/auth.routes.ts** - Removed route loading message
9. **src/middlewares/authorization.middleware.ts** - Improved error messages
### Migration Files (All)
- **2025103000-create-users.ts**
- **2025110501-alter-tat-days-to-generated.ts**
- **20251105-add-skip-fields-to-approval-levels.ts**
- **20251104-create-admin-config.ts**
- **20251104-create-holidays.ts**
- **20251104-create-kpi-views.ts**
All replaced verbose console logs with inline comments.
### Scripts
- **src/scripts/migrate.ts** - Streamlined migration output
- **src/scripts/seed-admin-config.ts** - Simplified seed messages
## New Clean Console Output
### Development Server Start
```
🚀 Server running on port 5000 | development
```
### Running Migrations
```
🔄 Running 2 migration(s)...
✅ 2025103000-create-users
✅ 2025110501-alter-tat-days-to-generated
✅ Applied 2 migration(s)
```
### No More Clutter
- ❌ No SQL query logs
- ❌ No multi-line config dumps
- ❌ No verbose socket connection messages
- ❌ No redundant "table created" messages
## Benefits
1. **Cleaner Logs** - Easy to scan for errors and important events
2. **Better Performance** - No overhead from logging every SQL query
3. **Easier Debugging** - Critical errors stand out with ❌ emoji
4. **Production Ready** - Minimal logging suitable for production environments
## To Enable Debug Logging (If Needed)
To temporarily enable SQL query logging for debugging:
```typescript
// In Re_Backend/src/config/database.ts
logging: console.log // Change from false
```
---
**Summary:** Reduced ~100+ console log statements to ~20 essential one-liners for bug tracking.

View File

@ -21,7 +21,8 @@
"db:migrate:undo": "sequelize-cli db:migrate:undo",
"db:seed": "sequelize-cli db:seed:all",
"clean": "rm -rf dist",
"migrate": "ts-node src/scripts/migrate.ts"
"migrate": "ts-node -r tsconfig-paths/register src/scripts/migrate.ts",
"seed:config": "ts-node -r tsconfig-paths/register src/scripts/seed-admin-config.ts"
},
"dependencies": {
"@google-cloud/storage": "^7.14.0",

View File

@ -21,11 +21,6 @@ const userService = new UserService();
const initializeDatabase = async () => {
try {
await sequelize.authenticate();
console.log('✅ Database connection established successfully');
// Sync models (create tables if they don't exist)
// await sequelize.sync({ force: false });
console.log('✅ Database models synchronized (sync disabled)');
} catch (error) {
console.error('❌ Database connection failed:', error);
}
@ -130,7 +125,7 @@ app.post('/api/v1/auth/sso-callback', async (req: express.Request, res: express.
timestamp: new Date()
});
} catch (error) {
console.error('SSO Callback Error:', error);
console.error('❌ SSO Callback failed:', error);
res.status(500).json({
success: false,
message: 'Internal server error',
@ -169,7 +164,7 @@ app.get('/api/v1/users', async (_req: express.Request, res: express.Response): P
timestamp: new Date()
});
} catch (error) {
console.error('Get Users Error:', error);
console.error('❌ Get Users failed:', error);
res.status(500).json({
success: false,
message: 'Internal server error',

View File

@ -10,7 +10,7 @@ const sequelize = new Sequelize({
username: process.env.DB_USER || 'postgres',
password: process.env.DB_PASSWORD || 'postgres',
dialect: 'postgres',
logging: process.env.NODE_ENV === 'development' ? console.log : false,
logging: false, // Disable SQL query logging for cleaner console output
pool: {
min: parseInt(process.env.DB_POOL_MIN || '2', 10),
max: parseInt(process.env.DB_POOL_MAX || '10', 10),

View File

@ -149,14 +149,7 @@ export function getPublicConfig() {
* Log system configuration on startup
*/
export function logSystemConfig(): void {
console.log('⚙️ System Configuration:');
console.log(` - Environment: ${SYSTEM_CONFIG.APP_ENV}`);
console.log(` - Version: ${SYSTEM_CONFIG.APP_VERSION}`);
console.log(` - Working Hours: ${SYSTEM_CONFIG.WORKING_HOURS.START_HOUR}:00 - ${SYSTEM_CONFIG.WORKING_HOURS.END_HOUR}:00`);
console.log(` - Max File Size: ${SYSTEM_CONFIG.UPLOAD.MAX_FILE_SIZE_MB} MB`);
console.log(` - Max Approval Levels: ${SYSTEM_CONFIG.WORKFLOW.MAX_APPROVAL_LEVELS}`);
console.log(` - AI Conclusion: ${SYSTEM_CONFIG.FEATURES.ENABLE_AI_CONCLUSION ? 'Enabled' : 'Disabled'}`);
console.log(` - TAT Test Mode: ${SYSTEM_CONFIG.TAT.TEST_MODE ? 'ENABLED (1h = 1min)' : 'DISABLED'}`);
// System config logging disabled - use environment variables to verify settings
}
export default SYSTEM_CONFIG;

View File

@ -65,12 +65,7 @@ export function isTestMode(): boolean {
* Log TAT configuration on startup
*/
export function logTatConfig(): void {
console.log('⏰ TAT Configuration:');
console.log(` - Test Mode: ${TAT_CONFIG.TEST_MODE ? 'ENABLED (1 hour = 1 minute)' : 'DISABLED'}`);
console.log(` - Working Hours: ${TAT_CONFIG.WORK_START_HOUR}:00 - ${TAT_CONFIG.WORK_END_HOUR}:00`);
console.log(` - Working Days: Monday - Friday`);
console.log(` - Redis: ${TAT_CONFIG.REDIS_URL}`);
console.log(` - Thresholds: ${TAT_CONFIG.THRESHOLD_50_PERCENT}%, ${TAT_CONFIG.THRESHOLD_75_PERCENT}%, ${TAT_CONFIG.THRESHOLD_100_PERCENT}%`);
// TAT config logging disabled - use environment variables to verify settings
}
export default TAT_CONFIG;

View File

@ -91,7 +91,7 @@ export function requireParticipantTypes(allowed: AllowedType[]) {
return res.status(403).json({ success: false, error: 'Insufficient permissions' });
} catch (err) {
console.error('Authorization check error:', err);
console.error('❌ Authorization check failed:', err);
return res.status(500).json({ success: false, error: 'Authorization check failed' });
}
};
@ -114,7 +114,7 @@ export function requireAdmin(req: Request, res: Response, next: NextFunction): v
next();
} catch (error) {
console.error('Admin authorization check error:', error);
console.error('❌ Admin authorization failed:', error);
res.status(500).json({
success: false,
error: 'Authorization check failed'

View File

@ -105,11 +105,11 @@ export async function up(queryInterface: QueryInterface): Promise<void> {
name: 'users_employee_id_idx'
});
console.log('✅ Created users table with indexes');
// Users table created
}
export async function down(queryInterface: QueryInterface): Promise<void> {
await queryInterface.dropTable('users');
console.log('✅ Dropped users table');
// Users table dropped
}

View File

@ -122,15 +122,13 @@ export async function up(queryInterface: QueryInterface): Promise<void> {
await queryInterface.sequelize.query('CREATE INDEX IF NOT EXISTS "admin_configurations_is_editable" ON "admin_configurations" ("is_editable");');
await queryInterface.sequelize.query('CREATE INDEX IF NOT EXISTS "admin_configurations_sort_order" ON "admin_configurations" ("sort_order");');
console.log('✅ Admin configurations table created successfully');
console.log('Note: Default configurations will be seeded on first server start');
// Admin config table created
}
export async function down(queryInterface: QueryInterface): Promise<void> {
await queryInterface.dropTable('admin_configurations');
await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_admin_configurations_config_category";');
await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_admin_configurations_value_type";');
console.log('✅ Admin configurations table dropped');
// Admin config table dropped
}

View File

@ -95,13 +95,12 @@ export async function up(queryInterface: QueryInterface): Promise<void> {
await queryInterface.sequelize.query('CREATE INDEX IF NOT EXISTS "holidays_holiday_type" ON "holidays" ("holiday_type");');
await queryInterface.sequelize.query('CREATE INDEX IF NOT EXISTS "holidays_created_by" ON "holidays" ("created_by");');
console.log('✅ Holidays table created successfully');
// Holidays table created
}
export async function down(queryInterface: QueryInterface): Promise<void> {
await queryInterface.dropTable('holidays');
await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_holidays_holiday_type";');
console.log('✅ Holidays table dropped successfully');
// Holidays table dropped
}

View File

@ -249,7 +249,7 @@ export async function up(queryInterface: QueryInterface): Promise<void> {
GROUP BY w.request_id, w.request_number, w.title, w.status;
`);
console.log('✅ KPI views created successfully');
// KPI views created
}
export async function down(queryInterface: QueryInterface): Promise<void> {
@ -261,7 +261,6 @@ export async function down(queryInterface: QueryInterface): Promise<void> {
await queryInterface.sequelize.query('DROP VIEW IF EXISTS vw_approver_performance;');
await queryInterface.sequelize.query('DROP VIEW IF EXISTS vw_tat_compliance;');
await queryInterface.sequelize.query('DROP VIEW IF EXISTS vw_request_volume_summary;');
console.log('✅ KPI views dropped successfully');
// KPI views dropped
}

View File

@ -10,7 +10,7 @@ export async function up(queryInterface: QueryInterface): Promise<void> {
// Check if table exists first
const tables = await queryInterface.showAllTables();
if (!tables.includes('approval_levels')) {
console.log('⚠️ approval_levels table does not exist yet, skipping...');
// Table doesn't exist yet, skipping
return;
}
@ -25,7 +25,7 @@ export async function up(queryInterface: QueryInterface): Promise<void> {
defaultValue: false,
comment: 'Indicates if this approver was skipped by initiator'
});
console.log(' ✅ Added is_skipped column');
// Added is_skipped column
}
if (!tableDescription.skipped_at) {
@ -34,7 +34,7 @@ export async function up(queryInterface: QueryInterface): Promise<void> {
allowNull: true,
comment: 'Timestamp when approver was skipped'
});
console.log(' ✅ Added skipped_at column');
// Added skipped_at column
}
if (!tableDescription.skipped_by) {
@ -49,7 +49,7 @@ export async function up(queryInterface: QueryInterface): Promise<void> {
onDelete: 'SET NULL',
comment: 'User ID who skipped this approver'
});
console.log(' ✅ Added skipped_by column');
// Added skipped_by column
}
if (!tableDescription.skip_reason) {
@ -58,7 +58,7 @@ export async function up(queryInterface: QueryInterface): Promise<void> {
allowNull: true,
comment: 'Reason for skipping this approver'
});
console.log(' ✅ Added skip_reason column');
// Added skip_reason column
}
// Check if index exists before creating
@ -73,14 +73,13 @@ export async function up(queryInterface: QueryInterface): Promise<void> {
is_skipped: true
}
});
console.log(' ✅ Added idx_approval_levels_skipped index');
// Index added
}
} catch (error) {
// Index might already exist, which is fine
console.log(' Index already exists or could not be created');
// Index already exists
}
console.log('✅ Skip-related fields migration completed');
// Skip fields added
}
export async function down(queryInterface: QueryInterface): Promise<void> {
@ -93,6 +92,6 @@ export async function down(queryInterface: QueryInterface): Promise<void> {
await queryInterface.removeColumn('approval_levels', 'skipped_at');
await queryInterface.removeColumn('approval_levels', 'is_skipped');
console.log('✅ Removed skip-related fields from approval_levels table');
// Skip fields removed
}

View File

@ -22,11 +22,11 @@ export async function up(queryInterface: QueryInterface): Promise<void> {
const column = result[0] as any;
if (column && column.is_generated === 's') {
console.log('✅ tat_days is already a GENERATED STORED column - skipping migration');
// Already a GENERATED column, skipping
return;
}
console.log('📝 Converting tat_days to GENERATED STORED column...');
// Converting tat_days to GENERATED column
// Step 1: Drop the existing regular column
await queryInterface.sequelize.query(`
@ -41,11 +41,11 @@ export async function up(queryInterface: QueryInterface): Promise<void> {
GENERATED ALWAYS AS (CAST(CEIL(tat_hours / 24.0) AS INTEGER)) STORED;
`);
console.log('✅ tat_days is now a GENERATED STORED column - will auto-calculate from tat_hours');
// tat_days is now auto-calculated
}
export async function down(queryInterface: QueryInterface): Promise<void> {
console.log('⚠️ Rolling back: Converting tat_days from GENERATED to regular column');
// Rolling back to regular column
// Drop the generated column
await queryInterface.sequelize.query(`
@ -71,6 +71,6 @@ export async function down(queryInterface: QueryInterface): Promise<void> {
ALTER COLUMN tat_days SET NOT NULL;
`);
console.log('✅ Rolled back to regular INTEGER column');
// Rolled back successfully
}

View File

@ -15,8 +15,6 @@ export function initSocket(httpServer: any) {
const configured = (process.env.FRONTEND_ORIGIN || '').split(',').map(s => s.trim()).filter(Boolean);
const origins = configured.length ? configured : defaultOrigins;
console.log('🔌 Initializing Socket.IO server with origins:', origins);
io = new Server(httpServer, {
cors: {
origin: origins,
@ -27,10 +25,7 @@ export function initSocket(httpServer: any) {
transports: ['websocket', 'polling']
});
console.log('✅ Socket.IO server initialized');
io.on('connection', (socket: any) => {
console.log('🔗 Client connected:', socket.id);
let currentRequestId: string | null = null;
let currentUserId: string | null = null;

View File

@ -8,8 +8,6 @@ import { asyncHandler } from '../middlewares/errorHandler.middleware';
const router = Router();
const authController = new AuthController();
console.log('✅ Auth routes loaded - token-exchange endpoint registered');
// Token exchange endpoint (no authentication required) - for localhost development
router.post('/token-exchange',
validateBody(tokenExchangeSchema),

View File

@ -63,7 +63,7 @@ async function ensureMigrationsTable(queryInterface: QueryInterface): Promise<vo
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
console.log('✅ Created migrations tracking table');
// Migrations table created
}
} catch (error) {
console.error('Error creating migrations table:', error);
@ -106,7 +106,6 @@ async function markMigrationExecuted(name: string): Promise<void> {
async function run() {
try {
await sequelize.authenticate();
console.log('📦 Database connected');
const queryInterface = sequelize.getQueryInterface();
@ -122,33 +121,29 @@ async function run() {
);
if (pendingMigrations.length === 0) {
console.log('✅ All migrations are up-to-date (no new migrations to run)');
console.log('✅ Migrations up-to-date');
process.exit(0);
return;
}
console.log(`🔄 Running ${pendingMigrations.length} pending migration(s)...\n`);
console.log(`🔄 Running ${pendingMigrations.length} migration(s)...`);
// Run each pending migration
for (const migration of pendingMigrations) {
try {
console.log(`⏳ Running: ${migration.name}`);
await migration.module.up(queryInterface);
await markMigrationExecuted(migration.name);
console.log(`Completed: ${migration.name}\n`);
console.log(`${migration.name}`);
} catch (error: any) {
console.error(`❌ Failed: ${migration.name}`);
console.error('Error:', error.message);
console.error(`❌ Migration failed: ${migration.name} - ${error.message}`);
throw error;
}
}
console.log(`\n✅ Successfully applied ${pendingMigrations.length} migration(s)`);
console.log(`📊 Total migrations: ${executedMigrations.length + pendingMigrations.length}`);
console.log(`✅ Applied ${pendingMigrations.length} migration(s)`);
process.exit(0);
} catch (err: any) {
console.error('\n❌ Migration failed:', err.message);
console.error('\nStack trace:', err.stack);
console.error('❌ Migration failed:', err.message);
process.exit(1);
}
}

View File

@ -0,0 +1,392 @@
/**
* 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',
'WORKING_HOURS',
'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',
'WORKING_HOURS',
'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',
'WORKING_HOURS',
'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',
'WORKING_HOURS',
'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()
)
`);
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;

View File

@ -18,30 +18,19 @@ const startServer = async (): Promise<void> => {
// Seed default configurations if table is empty
try {
await seedDefaultConfigurations();
// console.log('⚙️ System configurations initialized');
} catch (error) {
console.warn('⚠️ Configuration seeding skipped');
console.error('⚠️ Configuration seeding error:', error);
}
// Initialize holidays cache for TAT calculations
try {
await initializeHolidaysCache();
console.log('📅 Holiday calendar loaded for TAT calculations');
} catch (error) {
console.warn('⚠️ Holiday calendar not loaded - TAT will use weekends only');
// Silently fall back to weekends-only TAT calculation
}
server.listen(PORT, () => {
console.log(`🚀 Server running on port ${PORT}`);
console.log(`📊 Environment: ${process.env.NODE_ENV || 'development'}`);
console.log(`🌐 API Base URL: http://localhost:${PORT}`);
console.log(`❤️ Health Check: http://localhost:${PORT}/health`);
console.log(`🔌 Socket.IO path: /socket.io`);
console.log(`⏰ TAT Worker: Initialized and listening`);
console.log('');
logSystemConfig(); // Log centralized system configuration
console.log('');
logTatConfig(); // Log TAT-specific details
console.log(`🚀 Server running on port ${PORT} | ${process.env.NODE_ENV || 'development'}`);
});
} catch (error) {
console.error('❌ Unable to start server:', error);

View File

@ -15,7 +15,7 @@ export async function seedDefaultConfigurations(): Promise<void> {
);
if (count && (count[0] as any).count > 0) {
logger.info('[Config Seed] Configurations already exist. Skipping seed.');
// Table has data, skip seeding silently
return;
}
@ -26,8 +26,8 @@ export async function seedDefaultConfigurations(): Promise<void> {
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
validation_rules, ui_component, options, sort_order, requires_restart,
last_modified_by, last_modified_at, created_at, updated_at
) VALUES
-- TAT Settings
(
@ -43,8 +43,11 @@ export async function seedDefaultConfigurations(): Promise<void> {
false,
'{"min": 1, "max": 168}'::jsonb,
'number',
NULL,
1,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -61,8 +64,11 @@ export async function seedDefaultConfigurations(): Promise<void> {
false,
'{"min": 1, "max": 720}'::jsonb,
'number',
NULL,
2,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -76,9 +82,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Send first gentle reminder when this percentage of TAT is elapsed',
'50',
true,
false,
'{"min": 1, "max": 100}'::jsonb,
'slider',
NULL,
3,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -92,9 +103,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Send escalation warning when this percentage of TAT is elapsed',
'75',
true,
false,
'{"min": 1, "max": 100}'::jsonb,
'slider',
NULL,
4,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -108,9 +124,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Hour when working day starts (24-hour format, 0-23)',
'9',
true,
false,
'{"min": 0, "max": 23}'::jsonb,
'number',
NULL,
5,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -124,9 +145,56 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Hour when working day ends (24-hour format, 0-23)',
'18',
true,
false,
'{"min": 0, "max": 23}'::jsonb,
'number',
NULL,
6,
false,
NULL,
NULL,
NOW(),
NOW()
),
(
gen_random_uuid(),
'WORK_START_DAY',
'TAT_SETTINGS',
'1',
'NUMBER',
'Working Week Start Day',
'Day of week start (1=Monday, 7=Sunday)',
'1',
true,
false,
'{"min": 1, "max": 7}'::jsonb,
'number',
NULL,
7,
false,
NULL,
NULL,
NOW(),
NOW()
),
(
gen_random_uuid(),
'WORK_END_DAY',
'TAT_SETTINGS',
'5',
'NUMBER',
'Working Week End Day',
'Day of week end (1=Monday, 7=Sunday)',
'5',
true,
false,
'{"min": 1, "max": 7}'::jsonb,
'number',
NULL,
8,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -141,9 +209,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Maximum allowed file size for document uploads in megabytes',
'10',
true,
false,
'{"min": 1, "max": 100}'::jsonb,
'number',
NULL,
10,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -157,9 +230,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Comma-separated list of allowed file extensions for uploads',
'pdf,doc,docx,xls,xlsx,ppt,pptx,jpg,jpeg,png,gif',
true,
false,
'{}'::jsonb,
'text',
NULL,
11,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -173,9 +251,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Number of days to retain documents after workflow closure before archival',
'365',
true,
false,
'{"min": 30, "max": 3650}'::jsonb,
'number',
NULL,
12,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -190,9 +273,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Toggle AI-generated conclusion remarks for workflow closures',
'true',
true,
false,
'{}'::jsonb,
'toggle',
NULL,
20,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -206,9 +294,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Maximum character limit for AI-generated conclusion remarks',
'500',
true,
false,
'{"min": 100, "max": 2000}'::jsonb,
'number',
NULL,
21,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -223,9 +316,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Send email notifications for workflow events',
'true',
true,
false,
'{}'::jsonb,
'toggle',
NULL,
30,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -239,9 +337,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Send browser push notifications for real-time events',
'true',
true,
false,
'{}'::jsonb,
'toggle',
NULL,
31,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -255,9 +358,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Delay in milliseconds before sending batched notifications to avoid spam',
'5000',
true,
false,
'{"min": 1000, "max": 30000}'::jsonb,
'number',
NULL,
32,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -272,9 +380,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Display total requests KPI card on dashboard',
'true',
true,
false,
'{}'::jsonb,
'toggle',
NULL,
40,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -288,9 +401,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Display open requests KPI card on dashboard',
'true',
true,
false,
'{}'::jsonb,
'toggle',
NULL,
41,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -304,9 +422,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Display TAT compliance KPI card on dashboard',
'true',
true,
false,
'{}'::jsonb,
'toggle',
NULL,
42,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -320,9 +443,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Display pending actions KPI card on dashboard',
'true',
true,
false,
'{}'::jsonb,
'toggle',
NULL,
43,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -337,9 +465,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Enable users to add spectators to workflow requests',
'true',
true,
false,
'{}'::jsonb,
'toggle',
NULL,
50,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -353,9 +486,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Maximum number of spectators allowed per workflow request',
'20',
true,
false,
'{"min": 1, "max": 100}'::jsonb,
'number',
NULL,
51,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -369,9 +507,14 @@ export async function seedDefaultConfigurations(): Promise<void> {
'Allow sharing workflow links with users outside the organization',
'false',
true,
false,
'{}'::jsonb,
'toggle',
NULL,
52,
false,
NULL,
NULL,
NOW(),
NOW()
),
@ -379,38 +522,48 @@ export async function seedDefaultConfigurations(): Promise<void> {
(
gen_random_uuid(),
'MAX_APPROVAL_LEVELS',
'WORKFLOW_LIMITS',
'SYSTEM_SETTINGS',
'10',
'NUMBER',
'Maximum Approval Levels',
'Maximum number of approval levels allowed per workflow',
'10',
true,
false,
'{"min": 1, "max": 20}'::jsonb,
'number',
NULL,
60,
false,
NULL,
NULL,
NOW(),
NOW()
),
(
gen_random_uuid(),
'MAX_PARTICIPANTS_PER_REQUEST',
'WORKFLOW_LIMITS',
'SYSTEM_SETTINGS',
'50',
'NUMBER',
'Maximum Participants per Request',
'Maximum total participants (approvers + spectators) per workflow',
'50',
true,
false,
'{"min": 2, "max": 200}'::jsonb,
'number',
NULL,
61,
false,
NULL,
NULL,
NOW(),
NOW()
)
`, { type: QueryTypes.INSERT });
logger.info('[Config Seed] ✅ Default configurations seeded successfully (18 settings across 7 categories)');
logger.info('[Config Seed] ✅ Default configurations seeded successfully (20 settings across 7 categories)');
} catch (error) {
logger.error('[Config Seed] Error seeding configurations:', error);
// Don't throw - let server start even if seeding fails

View File

@ -39,9 +39,8 @@ async function loadWorkingHoursCache(): Promise<void> {
};
workingHoursCacheExpiry = dayjs().add(5, 'minute').toDate();
console.log(`[TAT Utils] Loaded working hours: ${hours.startHour}:00-${hours.endHour}:00, Days: ${startDay}-${endDay}`);
} catch (error) {
console.error('[TAT Utils] Error loading working hours cache:', error);
console.error('[TAT] Error loading working hours:', error);
// Fallback to default values from TAT_CONFIG
workingHoursCache = {
startHour: TAT_CONFIG.WORK_START_HOUR,
@ -72,9 +71,8 @@ async function loadHolidaysCache(): Promise<void> {
holidaysCache = new Set(holidays);
holidaysCacheExpiry = dayjs().add(6, 'hour').toDate();
console.log(`[TAT Utils] Loaded ${holidays.length} holidays into cache`);
} catch (error) {
console.error('[TAT Utils] Error loading holidays cache:', error);
console.error('[TAT] Error loading holidays:', error);
// Continue without holidays if loading fails
}
}
@ -226,7 +224,7 @@ export async function initializeHolidaysCache(): Promise<void> {
export function clearWorkingHoursCache(): void {
workingHoursCache = null;
workingHoursCacheExpiry = null;
console.log('[TAT Utils] Working hours cache cleared');
// Cache cleared
}
/**