import app from './app'; import environment from './config/environment'; import logger from './utils/logger'; import { testConnection, closePool, runMigrations } from './config/database'; import { startAuditCleanupJob, stopAuditCleanupJob } from './jobs/audit-cleanup.job'; import { startNotificationJob, stopNotificationJob } from './jobs/notification-generation.job'; import { startReminderJob, stopReminderJob } from './jobs/reminder.job'; import { startIssueReminderJob, stopIssueReminderJob } from './jobs/issue-reminder.job'; import { startChecklistReminderJob, stopChecklistReminderJob } from './jobs/checklist-reminder.job'; import { permissionService } from './services/permission.service'; const startServer = async (): Promise => { try { // Test database connection logger.info('Testing database connection...'); const dbConnected = await testConnection(); if (!dbConnected) { logger.warn('Database connection failed - server will start but database operations may fail'); } else { // Run pending migrations automatically on startup await runMigrations(); // Load permission cache after migrations await permissionService.loadCache(); } // Start the GDPR IP anonymisation job startAuditCleanupJob(); // Start the notification generation job startNotificationJob(); // Start the order reminder job startReminderJob(); // Start the issue reminder job startIssueReminderJob(); // Start the checklist reminder job startChecklistReminderJob(); // Start the server const server = app.listen(environment.port, () => { logger.info('Server started successfully', { port: environment.port, environment: environment.nodeEnv, database: dbConnected ? 'connected' : 'disconnected', }); // Log integration status so operators can see what's configured logger.info('Integration status', { bookstack: !!environment.bookstack.url, nextcloud: !!environment.nextcloudUrl, vikunja: !!environment.vikunja.url, }); }); // Graceful shutdown handling const gracefulShutdown = async (signal: string) => { logger.info(`${signal} received. Starting graceful shutdown...`); // Stop scheduled jobs first stopAuditCleanupJob(); stopNotificationJob(); stopReminderJob(); stopIssueReminderJob(); stopChecklistReminderJob(); server.close(async () => { logger.info('HTTP server closed'); // Close database connection await closePool(); logger.info('Graceful shutdown completed'); process.exit(0); }); // Force shutdown after 10 seconds setTimeout(() => { logger.error('Forced shutdown after timeout'); process.exit(1); }, 10000); }; process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); process.on('SIGINT', () => gracefulShutdown('SIGINT')); } catch (error) { logger.error('Failed to start server', { error }); process.exit(1); } }; // Handle unhandled promise rejections process.on('unhandledRejection', (reason: Error, _promise: Promise) => { logger.error('Unhandled Promise Rejection', { reason: reason.message, stack: reason.stack, }); }); // Handle uncaught exceptions process.on('uncaughtException', (error: Error) => { logger.error('Uncaught Exception', { message: error.message, stack: error.stack, }); process.exit(1); }); // Start the server startServer();