const express = require('express'); const cors = require('cors'); const compression = require('compression'); const path = require('path'); const dotenv = require('dotenv'); const helmet = require('helmet'); const initializeDatabase = require('./config/initDatabase'); const pm2 = require('pm2'); const fs = require('fs'); // Load environment variables dotenv.config(); console.log('Current Working Directory:', process.cwd()); console.log('__dirname:', __dirname); // Import configurations const config = require('./config'); const { securityHeaders, apiLimiter, validateRequest, corsOptions } = require('./middlewares/security'); const { errorHandler } = require('./middlewares/errorHandler'); const logger = require('./utils/logger'); const monitoring = require('./utils/monitoring'); // Import routes const authRoutes = require('./routes/auth'); const hospitalRoutes = require('./routes/hospitals'); const userRoutes = require('./routes/users'); const superAdminRoutes = require('./routes/superAdmins'); const documentRoutes = require('./routes/documents'); const pdfRoutes = require('./routes/pdfRoutes'); const onboardingRoutes = require('./routes/onboarding'); const appUserRoutes = require('./routes/appUsers'); const excelDataRoutes = require('./routes/exceldata'); const feedbackRoute = require('./routes/feedbacks'); const analyticsRoute = require('./routes/analysis'); const appVersionRoutes = require('./routes/appVersioning'); // Import services const { refreshExpiredTokens } = require('./services/cronJobs'); const { repopulateQueueOnStartup } = require('./controllers/documentsController'); require('./services/webSocket'); require('./services/secondaryWebsocket'); // Create Express app const app = express(); // Apply security middleware app.use(helmet()); app.use(securityHeaders); app.use(compression({ level: 6, threshold: 1024, filter: (req, res) => { const contentType = res.getHeader('Content-Type'); return /text|json|javascript|css/.test(contentType); } })); // Apply rate limiting to all API routes app.use('/api/', apiLimiter); // Apply CORS app.use(cors({ origin: true, // Allow all origins credentials: true, methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'], exposedHeaders: ['Content-Range', 'X-Content-Range'], maxAge: 86400 })); // Request validation app.use(validateRequest); // Body parsing middleware app.use(express.json()); app.use(express.urlencoded({ extended: true })); // Static files app.use('/uploads', express.static(path.join(__dirname, '..', 'uploads'))); app.use('/public', express.static(path.join(__dirname, '..', 'public'))); // Request logging middleware app.use((req, res, next) => { const start = Date.now(); res.on('finish', () => { const duration = Date.now() - start; monitoring.trackRequest(req.path, req.method, res.statusCode, duration); logger.info(`${req.method} ${req.path} ${res.statusCode} - ${duration}ms`); }); next(); }); // Initialize database before starting the server async function startServer() { try { // Initialize database await initializeDatabase(); console.log('Database initialized successfully'); // API routes app.use('/api/auth', authRoutes); app.use('/api/hospitals', hospitalRoutes); app.use('/api/users', userRoutes); app.use('/api/superAdmins', superAdminRoutes); app.use('/api/onboarding', onboardingRoutes); app.use('/api/documents', documentRoutes); app.use('/api/pdf', pdfRoutes); app.use('/api/app_users', appUserRoutes); app.use('/api/process_excel', excelDataRoutes); app.use('/api/feedbacks', feedbackRoute); app.use('/api/analytics', analyticsRoute); app.use('/api/app-versioning', appVersionRoutes); // Health check endpoint app.get('/health', (req, res) => { res.json(monitoring.getHealthStatus()); }); // Database sync endpoint (protected by environment check) app.post('/api/sync-database', async (req, res) => { try { // Only allow in development or with proper authentication if (process.env.NODE_ENV === 'development' || req.headers['x-sync-token'] === process.env.DB_SYNC_TOKEN) { await initializeDatabase(); res.json({ message: 'Database synchronized successfully' }); } else { res.status(403).json({ error: 'Unauthorized' }); } } catch (error) { logger.error('Database sync failed:', error); res.status(500).json({ error: 'Database synchronization failed' }); } }); // Root endpoint app.get('/', (req, res) => { res.send("SpurrinAI Backend is running!!!"); }); app.get('/logs', (req, res) => { pm2.connect(err => { if (err) { return res.status(500).send(generateErrorPage('Failed to connect to PM2', err.message)); } pm2.list((err, processes) => { if (err) { return res.status(500).send(generateErrorPage('Failed to list processes', err.message)); } const logs = processes.map(proc => { const logFilePath = path.join(process.env.HOME, '.pm2/logs', `${proc.name}-out.log`); const errorFilePath = path.join(process.env.HOME, '.pm2/logs', `${proc.name}-error.log`); const stdoutSize = fs.existsSync(logFilePath) ? fs.statSync(logFilePath).size : 0; const stderrSize = fs.existsSync(errorFilePath) ? fs.statSync(errorFilePath).size : 0; const maxSize = 10 * 1024 * 1024; // 10MB max size for progress bar return { name: proc.name, logs: { stdout: fs.existsSync(logFilePath) ? fs.readFileSync(logFilePath, 'utf8') : 'No logs available', stderr: fs.existsSync(errorFilePath) ? fs.readFileSync(errorFilePath, 'utf8') : 'No error logs available', stdoutProgress: Math.min((stdoutSize / maxSize) * 100, 100), stderrProgress: Math.min((stderrSize / maxSize) * 100, 100) } }; }); const logsHtml = logs.map(log => `

${log.name}

Standard Output

${log.logs.stdout}

Error Output

${log.logs.stderr}
`).join(''); res.send(` PM2 Logs

PM2 Logs

${logsHtml} `); pm2.disconnect(); }); }); }); function generateErrorPage(title, message) { return ` ${title}

${title}

${message}

`; } console.log('checking automation!'); console.log('checking automation!'); console.log('checking automation!'); console.log('checking automation!'); console.log('checking automation!'); // Error handling middleware app.use(errorHandler); // Start server const PORT = config.server.port; const server = app.listen(PORT, () => { logger.info(`Server is running on http://localhost:${PORT}`); // Initialize background tasks refreshExpiredTokens(); // repopulateQueueOnStartup(); }); // Graceful shutdown const gracefulShutdown = async () => { logger.info('Received shutdown signal'); // Close server server.close(() => { logger.info('HTTP server closed'); }); // Close database connections const db = require('./config/database'); await db.closePool(); // Close WebSocket connections const wss = require('./services/webSocket'); wss.close(() => { logger.info('WebSocket server closed'); }); process.exit(0); }; process.on('SIGTERM', gracefulShutdown); process.on('SIGINT', gracefulShutdown); // Handle uncaught exceptions process.on('uncaughtException', (error) => { logger.error('Uncaught Exception:', error); gracefulShutdown(); }); // Handle unhandled promise rejections process.on('unhandledRejection', (reason, promise) => { logger.error('Unhandled Rejection at:', promise, 'reason:', reason); gracefulShutdown(); }); return server; } catch (error) { console.error('Failed to start server:', error); process.exit(1); } } startServer(); module.exports = app;