spurrin-backend/src/app.js
2025-06-09 19:41:17 +05:30

195 lines
6.0 KiB
JavaScript

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');
// 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');
// 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(corsOptions));
// 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);
// 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!");
});
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;