import express from 'express'; import cors from 'cors'; import helmet from 'helmet'; import rateLimit from 'express-rate-limit'; import dotenv from 'dotenv'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; import { contactRouter } from './routes/contact.js'; import { errorHandler, notFoundHandler } from './middleware/errorHandlers.js'; import { requestLogger } from './middleware/logger.js'; import { initializeEmailService } from './services/emailService.js'; // Get the directory of the current module const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Load environment variables from the backend directory dotenv.config({ path: join(__dirname, '.env') }); async function startServer() { // Initialize email service after environment variables are loaded await initializeEmailService(); const app = express(); const PORT = process.env.PORT || 3001; // Security middleware app.use( helmet({ crossOriginResourcePolicy: { policy: 'cross-origin' }, }) ); // CORS configuration app.use( cors({ origin: process.env.FRONTEND_URL || 'http://localhost:5173', methods: ['GET', 'POST'], allowedHeaders: ['Content-Type', 'Authorization'], 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) || 5, // limit each IP to 5 requests per windowMs message: { error: 'Too many requests from this IP, please try again later.', retryAfter: Math.ceil( (parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 15 * 60 * 1000) / 1000 ), }, standardHeaders: true, legacyHeaders: false, }); app.use('/api/', limiter); // Body parsing middleware app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ extended: true, limit: '10mb' })); // Request logging app.use(requestLogger); // Health check endpoint app.get('/health', (req, res) => { res.json({ status: 'ok', timestamp: new Date().toISOString(), environment: process.env.NODE_ENV || 'development', }); }); // API routes app.use('/api/contact', contactRouter); // Error handling middleware app.use(notFoundHandler); app.use(errorHandler); // Start server app.listen(PORT, () => { console.log(`🚀 Server is running on port ${PORT}`); console.log( `📧 Email service: ${process.env.EMAIL_SERVICE || 'Not configured'}` ); console.log(`🌍 Environment: ${process.env.NODE_ENV || 'development'}`); console.log( `🔗 Frontend URL: ${process.env.FRONTEND_URL || 'http://localhost:5173'}` ); }); // Graceful shutdown process.on('SIGTERM', () => { console.log('SIGTERM signal received: closing HTTP server'); process.exit(0); }); process.on('SIGINT', () => { console.log('SIGINT signal received: closing HTTP server'); process.exit(0); }); } // Start the server startServer().catch((error) => { console.error('Failed to start server:', error); process.exit(1); });