From 53bc624094cd0d6fa2cc8946fb6da1ae72c8ccf3 Mon Sep 17 00:00:00 2001 From: laxmanhalaki Date: Thu, 6 Nov 2025 12:33:11 +0530 Subject: [PATCH] system configuration seed added --- CONSOLE_LOGS_CLEANED.md | 124 ++++++ package.json | 3 +- src/app.ts | 9 +- src/config/database.ts | 2 +- src/config/system.config.ts | 9 +- src/config/tat.config.ts | 7 +- src/middlewares/authorization.middleware.ts | 4 +- src/migrations/2025103000-create-users.ts | 4 +- .../20251104-create-admin-config.ts | 6 +- src/migrations/20251104-create-holidays.ts | 5 +- src/migrations/20251104-create-kpi-views.ts | 5 +- ...1105-add-skip-fields-to-approval-levels.ts | 19 +- .../2025110501-alter-tat-days-to-generated.ts | 10 +- src/realtime/socket.ts | 5 - src/routes/auth.routes.ts | 2 - src/scripts/migrate.ts | 19 +- src/scripts/seed-admin-config.ts | 392 ++++++++++++++++++ src/server.ts | 17 +- src/services/configSeed.service.ts | 165 +++++++- src/utils/tatTimeUtils.ts | 8 +- 20 files changed, 719 insertions(+), 96 deletions(-) create mode 100644 CONSOLE_LOGS_CLEANED.md create mode 100644 src/scripts/seed-admin-config.ts diff --git a/CONSOLE_LOGS_CLEANED.md b/CONSOLE_LOGS_CLEANED.md new file mode 100644 index 0000000..948140d --- /dev/null +++ b/CONSOLE_LOGS_CLEANED.md @@ -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. + diff --git a/package.json b/package.json index b23337f..2532ec9 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/app.ts b/src/app.ts index 1104ddc..6d9b06d 100644 --- a/src/app.ts +++ b/src/app.ts @@ -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', diff --git a/src/config/database.ts b/src/config/database.ts index d0806c8..a00500e 100644 --- a/src/config/database.ts +++ b/src/config/database.ts @@ -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), diff --git a/src/config/system.config.ts b/src/config/system.config.ts index 2045cc2..6742591 100644 --- a/src/config/system.config.ts +++ b/src/config/system.config.ts @@ -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; diff --git a/src/config/tat.config.ts b/src/config/tat.config.ts index c7c9724..54bb373 100644 --- a/src/config/tat.config.ts +++ b/src/config/tat.config.ts @@ -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; diff --git a/src/middlewares/authorization.middleware.ts b/src/middlewares/authorization.middleware.ts index b334f99..bafd6dc 100644 --- a/src/middlewares/authorization.middleware.ts +++ b/src/middlewares/authorization.middleware.ts @@ -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' diff --git a/src/migrations/2025103000-create-users.ts b/src/migrations/2025103000-create-users.ts index 27d138e..20ad787 100644 --- a/src/migrations/2025103000-create-users.ts +++ b/src/migrations/2025103000-create-users.ts @@ -105,11 +105,11 @@ export async function up(queryInterface: QueryInterface): Promise { name: 'users_employee_id_idx' }); - console.log('āœ… Created users table with indexes'); + // Users table created } export async function down(queryInterface: QueryInterface): Promise { await queryInterface.dropTable('users'); - console.log('āœ… Dropped users table'); + // Users table dropped } diff --git a/src/migrations/20251104-create-admin-config.ts b/src/migrations/20251104-create-admin-config.ts index b36b262..50edc87 100644 --- a/src/migrations/20251104-create-admin-config.ts +++ b/src/migrations/20251104-create-admin-config.ts @@ -122,15 +122,13 @@ export async function up(queryInterface: QueryInterface): Promise { 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 { 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 } diff --git a/src/migrations/20251104-create-holidays.ts b/src/migrations/20251104-create-holidays.ts index 73fafb5..af3cda6 100644 --- a/src/migrations/20251104-create-holidays.ts +++ b/src/migrations/20251104-create-holidays.ts @@ -95,13 +95,12 @@ export async function up(queryInterface: QueryInterface): Promise { 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 { 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 } diff --git a/src/migrations/20251104-create-kpi-views.ts b/src/migrations/20251104-create-kpi-views.ts index 6fce8d1..ef1cc97 100644 --- a/src/migrations/20251104-create-kpi-views.ts +++ b/src/migrations/20251104-create-kpi-views.ts @@ -249,7 +249,7 @@ export async function up(queryInterface: QueryInterface): Promise { 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 { @@ -261,7 +261,6 @@ export async function down(queryInterface: QueryInterface): Promise { 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 } diff --git a/src/migrations/20251105-add-skip-fields-to-approval-levels.ts b/src/migrations/20251105-add-skip-fields-to-approval-levels.ts index d8aa992..12a7614 100644 --- a/src/migrations/20251105-add-skip-fields-to-approval-levels.ts +++ b/src/migrations/20251105-add-skip-fields-to-approval-levels.ts @@ -10,7 +10,7 @@ export async function up(queryInterface: QueryInterface): Promise { // 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 { 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 { 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 { 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 { 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 { 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 { @@ -93,6 +92,6 @@ export async function down(queryInterface: QueryInterface): Promise { 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 } diff --git a/src/migrations/2025110501-alter-tat-days-to-generated.ts b/src/migrations/2025110501-alter-tat-days-to-generated.ts index 7b6e66b..0d27b27 100644 --- a/src/migrations/2025110501-alter-tat-days-to-generated.ts +++ b/src/migrations/2025110501-alter-tat-days-to-generated.ts @@ -22,11 +22,11 @@ export async function up(queryInterface: QueryInterface): Promise { 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 { 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 { - 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 { ALTER COLUMN tat_days SET NOT NULL; `); - console.log('āœ… Rolled back to regular INTEGER column'); + // Rolled back successfully } diff --git a/src/realtime/socket.ts b/src/realtime/socket.ts index 2a72b4e..9b354f4 100644 --- a/src/realtime/socket.ts +++ b/src/realtime/socket.ts @@ -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; diff --git a/src/routes/auth.routes.ts b/src/routes/auth.routes.ts index b0bc137..a6c4424 100644 --- a/src/routes/auth.routes.ts +++ b/src/routes/auth.routes.ts @@ -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), diff --git a/src/scripts/migrate.ts b/src/scripts/migrate.ts index 9914368..16b3fdd 100644 --- a/src/scripts/migrate.ts +++ b/src/scripts/migrate.ts @@ -63,7 +63,7 @@ async function ensureMigrationsTable(queryInterface: QueryInterface): Promise { 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); } } diff --git a/src/scripts/seed-admin-config.ts b/src/scripts/seed-admin-config.ts new file mode 100644 index 0000000..c841b21 --- /dev/null +++ b/src/scripts/seed-admin-config.ts @@ -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((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; + diff --git a/src/server.ts b/src/server.ts index f4c3249..e780d3e 100644 --- a/src/server.ts +++ b/src/server.ts @@ -18,30 +18,19 @@ const startServer = async (): Promise => { // 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); diff --git a/src/services/configSeed.service.ts b/src/services/configSeed.service.ts index 486e458..5f93dee 100644 --- a/src/services/configSeed.service.ts +++ b/src/services/configSeed.service.ts @@ -15,7 +15,7 @@ export async function seedDefaultConfigurations(): Promise { ); 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 { 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 { false, '{"min": 1, "max": 168}'::jsonb, 'number', + NULL, 1, false, + NULL, + NULL, NOW(), NOW() ), @@ -61,8 +64,11 @@ export async function seedDefaultConfigurations(): Promise { false, '{"min": 1, "max": 720}'::jsonb, 'number', + NULL, 2, false, + NULL, + NULL, NOW(), NOW() ), @@ -76,9 +82,14 @@ export async function seedDefaultConfigurations(): Promise { '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 { '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 { '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 { '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 { '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 { '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 { '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 { '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 { '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 { '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 { '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 { '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 { '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 { '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 { '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 { '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 { '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 { '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 { '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 { ( 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 diff --git a/src/utils/tatTimeUtils.ts b/src/utils/tatTimeUtils.ts index 85e9917..8ad5e52 100644 --- a/src/utils/tatTimeUtils.ts +++ b/src/utils/tatTimeUtils.ts @@ -39,9 +39,8 @@ async function loadWorkingHoursCache(): Promise { }; 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 { 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 { export function clearWorkingHoursCache(): void { workingHoursCache = null; workingHoursCacheExpiry = null; - console.log('[TAT Utils] Working hours cache cleared'); + // Cache cleared } /**