import express from 'express'; import cors from 'cors'; import helmet from 'helmet'; import rateLimit from 'express-rate-limit'; import mongoose from 'mongoose'; import { config } from './config/index.js'; import { logger, requestLogger, errorLogger } from './utils/logger.js'; // Import routes import subscriptionRoutes from './routes/subscriptions.js'; import invoiceRoutes from './routes/invoices.js'; import paymentMethodRoutes from './routes/payment-methods.js'; import transactionRoutes from './routes/transactions.js'; import webhookRoutes from './routes/webhooks.js'; // Create Express app const app = express(); // Security middleware app.use(helmet()); app.use(cors(config.cors)); // Rate limiting const limiter = rateLimit(config.rateLimit); app.use('/api/', limiter); // Body parsing middleware app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ extended: true, limit: '10mb' })); // Webhook routes (before body parsing for raw body) app.use('/webhooks', webhookRoutes); // Request logging app.use(requestLogger); // API routes app.use('/api/subscriptions', subscriptionRoutes); app.use('/api/invoices', invoiceRoutes); app.use('/api/payment-methods', paymentMethodRoutes); app.use('/api/transactions', transactionRoutes); // Health check app.get('/health', (req, res) => { res.json({ status: 'healthy', service: 'billing-service', timestamp: new Date().toISOString(), uptime: process.uptime(), environment: config.env }); }); // Error handling app.use(errorLogger); // 404 handler app.use((req, res) => { res.status(404).json({ success: false, error: 'Route not found' }); }); // Global error handler app.use((err, req, res, next) => { const status = err.status || 500; const message = err.message || 'Internal server error'; res.status(status).json({ success: false, error: message, ...(config.env === 'development' && { stack: err.stack }) }); }); // Database connection export async function connectDB() { try { await mongoose.connect(config.mongodb.uri, { useNewUrlParser: true, useUnifiedTopology: true }); logger.info('MongoDB connected successfully'); } catch (error) { logger.error('MongoDB connection error:', error); process.exit(1); } } // Graceful shutdown export function setupGracefulShutdown(server) { const shutdown = async (signal) => { logger.info(`${signal} received, starting graceful shutdown`); server.close(() => { logger.info('HTTP server closed'); }); try { await mongoose.connection.close(); logger.info('MongoDB connection closed'); process.exit(0); } catch (error) { logger.error('Error during shutdown:', error); process.exit(1); } }; process.on('SIGTERM', () => shutdown('SIGTERM')); process.on('SIGINT', () => shutdown('SIGINT')); } export default app;