157 lines
4.5 KiB
JavaScript
157 lines
4.5 KiB
JavaScript
require('dotenv').config();
|
|
const express = require('express');
|
|
const cors = require('cors');
|
|
const helmet = require('helmet');
|
|
const compression = require('compression');
|
|
const rateLimit = require('express-rate-limit');
|
|
const path = require('path');
|
|
|
|
// Import database
|
|
const db = require('./src/database/models');
|
|
|
|
// Import routes (Modular Monolith Structure)
|
|
const authRoutes = require('./src/modules/auth/auth.routes');
|
|
const onboardingRoutes = require('./src/modules/onboarding/onboarding.routes');
|
|
const selfServiceRoutes = require('./src/modules/self-service/self-service.routes');
|
|
const masterRoutes = require('./src/modules/master/master.routes');
|
|
const settlementRoutes = require('./src/modules/settlement/settlement.routes');
|
|
const collaborationRoutes = require('./src/modules/collaboration/collaboration.routes');
|
|
|
|
// Import common middleware & utils
|
|
const errorHandler = require('./src/common/middleware/errorHandler');
|
|
const logger = require('./src/common/utils/logger');
|
|
|
|
// Initialize Express app
|
|
const app = express();
|
|
|
|
// Security middleware
|
|
app.use(helmet());
|
|
app.use(cors({
|
|
origin: process.env.FRONTEND_URL || 'http://localhost:5173',
|
|
credentials: true
|
|
}));
|
|
|
|
// Rate limiting
|
|
const limiter = rateLimit({
|
|
windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 15 * 60 * 1000, // 15 minutes
|
|
max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS) || 100,
|
|
message: 'Too many requests from this IP, please try again later.'
|
|
});
|
|
app.use('/api/', limiter);
|
|
|
|
// Body parsing middleware
|
|
app.use(express.json({ limit: '10mb' }));
|
|
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
|
|
|
|
// Compression
|
|
app.use(compression());
|
|
|
|
// Static files (uploaded documents)
|
|
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
|
|
|
|
// Request logging
|
|
app.use((req, res, next) => {
|
|
logger.info(`${req.method} ${req.path}`, {
|
|
ip: req.ip,
|
|
userAgent: req.get('user-agent')
|
|
});
|
|
next();
|
|
});
|
|
|
|
// Health check endpoint
|
|
app.get('/health', (req, res) => {
|
|
res.json({
|
|
status: 'OK',
|
|
timestamp: new Date().toISOString(),
|
|
uptime: process.uptime(),
|
|
environment: process.env.NODE_ENV
|
|
});
|
|
});
|
|
|
|
// API Routes (Modular)
|
|
app.use('/api/auth', authRoutes);
|
|
app.use('/api/onboarding', onboardingRoutes);
|
|
app.use('/api/self-service', selfServiceRoutes);
|
|
app.use('/api/master', masterRoutes);
|
|
app.use('/api/settlement', settlementRoutes);
|
|
app.use('/api/collaboration', collaborationRoutes);
|
|
|
|
// Backward Compatibility Aliases
|
|
app.use('/api/applications', onboardingRoutes);
|
|
app.use('/api/resignations', require('./src/modules/self-service/resignation.routes'));
|
|
app.use('/api/constitutional', (req, res, next) => {
|
|
// Map /api/constitutional to /api/self-service/constitutional
|
|
req.url = '/constitutional' + req.url;
|
|
next();
|
|
}, selfServiceRoutes);
|
|
app.use('/api/relocations', (req, res, next) => {
|
|
// Map /api/relocations to /api/self-service/relocation
|
|
req.url = '/relocation' + req.url;
|
|
next();
|
|
}, selfServiceRoutes);
|
|
app.use('/api/outlets', require('./src/modules/master/outlet.routes'));
|
|
app.use('/api/finance', settlementRoutes);
|
|
app.use('/api/worknotes', collaborationRoutes);
|
|
|
|
// 404 handler
|
|
app.use((req, res) => {
|
|
res.status(404).json({
|
|
success: false,
|
|
message: 'Route not found'
|
|
});
|
|
});
|
|
|
|
// Global error handler
|
|
app.use(errorHandler);
|
|
|
|
// Database connection and server start
|
|
const PORT = process.env.PORT || 5000;
|
|
|
|
const startServer = async () => {
|
|
try {
|
|
// Test database connection
|
|
await db.sequelize.authenticate();
|
|
logger.info('Database connection established successfully');
|
|
|
|
// Sync database (in development only)
|
|
if (process.env.NODE_ENV === 'development') {
|
|
await db.sequelize.sync({ alter: false });
|
|
logger.info('Database models synchronized');
|
|
}
|
|
|
|
// Start server
|
|
app.listen(PORT, () => {
|
|
logger.info(`🚀 Server running on port ${PORT}`);
|
|
logger.info(`📍 Environment: ${process.env.NODE_ENV}`);
|
|
logger.info(`🔗 API Base URL: http://localhost:${PORT}/api`);
|
|
});
|
|
} catch (error) {
|
|
logger.error('Unable to start server:', error);
|
|
process.exit(1);
|
|
}
|
|
};
|
|
|
|
// Handle unhandled promise rejections
|
|
process.on('unhandledRejection', (err) => {
|
|
logger.error('Unhandled Promise Rejection:', err);
|
|
process.exit(1);
|
|
});
|
|
|
|
// Handle uncaught exceptions
|
|
process.on('uncaughtException', (err) => {
|
|
logger.error('Uncaught Exception:', err);
|
|
process.exit(1);
|
|
});
|
|
|
|
// Graceful shutdown
|
|
process.on('SIGTERM', async () => {
|
|
logger.info('SIGTERM signal received: closing HTTP server');
|
|
await db.sequelize.close();
|
|
process.exit(0);
|
|
});
|
|
|
|
startServer();
|
|
|
|
module.exports = app;
|
|
|