106 lines
2.8 KiB
TypeScript
106 lines
2.8 KiB
TypeScript
import dotenv from 'dotenv';
|
|
dotenv.config();
|
|
|
|
import express, { Application, Request, Response, NextFunction } from 'express';
|
|
import cors from 'cors';
|
|
import helmet from 'helmet';
|
|
import routes from './routes';
|
|
import logger from './utils/logger';
|
|
import { testConnection } from './config/database';
|
|
import { auditMiddleware } from './middleware/audit.middleware';
|
|
import { scheduleNegativeFlowDetection } from './jobs/negativeFlowDetection';
|
|
|
|
const app: Application = express();
|
|
|
|
const PORT = process.env.PORT || 3000;
|
|
const NODE_ENV = process.env.NODE_ENV || 'development';
|
|
|
|
// Security middleware
|
|
app.use(helmet());
|
|
|
|
// CORS configuration
|
|
const allowedOrigins = (process.env.CORS_ORIGIN || 'http://localhost:5173')
|
|
.split(',')
|
|
.map(origin => origin.trim());
|
|
|
|
app.use(cors({
|
|
origin: (origin, callback) => {
|
|
// Allow requests with no origin (mobile apps, curl, etc.)
|
|
if (!origin) return callback(null, true);
|
|
|
|
if (allowedOrigins.includes(origin)) {
|
|
callback(null, true);
|
|
} else {
|
|
logger.warn(`CORS blocked origin: ${origin}`);
|
|
callback(null, true); // Allow all in development
|
|
}
|
|
},
|
|
credentials: true,
|
|
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
|
allowedHeaders: ['Content-Type', 'Authorization']
|
|
}));
|
|
|
|
// Body parsing middleware
|
|
app.use(express.json({ limit: '10mb' }));
|
|
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
|
|
|
|
// Audit logging middleware (before routes)
|
|
app.use(auditMiddleware);
|
|
|
|
// Health check endpoint
|
|
app.get('/health', (_req: Request, res: Response) => {
|
|
res.status(200).json({
|
|
status: 'ok',
|
|
timestamp: new Date().toISOString(),
|
|
environment: NODE_ENV
|
|
});
|
|
});
|
|
|
|
// Mount all API routes
|
|
app.use('/api', routes);
|
|
|
|
// 404 handler
|
|
app.use((_req: Request, res: Response) => {
|
|
res.status(404).json({
|
|
success: false,
|
|
message: 'Resource not found',
|
|
error: 'NOT_FOUND'
|
|
});
|
|
});
|
|
|
|
// Global error handler
|
|
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
|
|
console.error('Error:', err);
|
|
|
|
res.status(500).json({
|
|
success: false,
|
|
message: NODE_ENV === 'development' ? err.message : 'Internal server error',
|
|
error: 'INTERNAL_ERROR'
|
|
});
|
|
});
|
|
|
|
// Start server
|
|
const startServer = async () => {
|
|
try {
|
|
// Test database connection
|
|
await testConnection();
|
|
logger.info('Database connection established');
|
|
|
|
scheduleNegativeFlowDetection();
|
|
logger.info('Cron jobs initialized');
|
|
|
|
app.listen(PORT, () => {
|
|
logger.info(`Server running on port ${PORT} in ${NODE_ENV} mode`);
|
|
logger.info(`Health check available at http://localhost:${PORT}/health`);
|
|
logger.info(`API available at http://localhost:${PORT}/api`);
|
|
});
|
|
} catch (error) {
|
|
logger.error('Failed to start server:', error);
|
|
process.exit(1);
|
|
}
|
|
};
|
|
|
|
startServer();
|
|
|
|
export default app;
|