import express from 'express'; import cors from 'cors'; import helmet from 'helmet'; import morgan from 'morgan'; import rateLimit from 'express-rate-limit'; import { createServer } from 'http'; import { Server } from 'socket.io'; import dotenv from 'dotenv'; dotenv.config(); import { prisma } from './utils/prisma'; import { errorHandler } from './middleware/errorHandler'; import { authRouter } from './routes/auth'; import { userRouter } from './routes/users'; import { walletRouter } from './routes/wallet'; import { transactionsRouter } from './routes/transactions'; import { adminRouter } from './routes/admin'; import { tautulliRouter } from './routes/tautulli'; import { overseerRouter } from './routes/overseer'; import { webhookRouter } from './routes/webhooks'; import { setupSocketHandlers } from './services/socket'; const app = express(); const httpServer = createServer(app); const io = new Server(httpServer, { cors: { origin: process.env.FRONTEND_URL || 'http://localhost:3000', credentials: true } }); // Security middleware app.use(helmet()); app.use(cors({ origin: process.env.FRONTEND_URL || 'http://localhost:3000', credentials: true })); // Rate limiting const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100 // limit each IP to 100 requests per windowMs }); app.use(limiter); // Body parsing app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ extended: true })); // Logging app.use(morgan('combined')); // Health check app.get('/health', (_req, res) => { res.json({ status: 'ok', timestamp: new Date().toISOString() }); }); // API routes app.use('/api/auth', authRouter); app.use('/api/users', userRouter); app.use('/api/wallet', walletRouter); app.use('/api/transactions', transactionsRouter); app.use('/api/admin', adminRouter); app.use('/api/tautulli', tautulliRouter); app.use('/api/overseer', overseerRouter); app.use('/webhooks', webhookRouter); // Error handling app.use(errorHandler); // Setup WebSocket handlers setupSocketHandlers(io); // Start server const PORT = process.env.PORT || 3001; async function startServer() { try { // Connect to database await prisma.$connect(); console.log('✅ Connected to database'); // Ensure default settings exist const settings = await prisma.systemSettings.findFirst(); if (!settings) { await prisma.systemSettings.create({ data: { id: 'default' } }); console.log('✅ Created default system settings'); } httpServer.listen(PORT, () => { console.log(`🚀 Server running on port ${PORT}`); console.log(`📊 API URL: ${process.env.API_URL || `http://localhost:${PORT}`}`); }); } catch (error) { console.error('Failed to start server:', error); process.exit(1); } } // Graceful shutdown process.on('SIGTERM', async () => { console.log('SIGTERM received, shutting down gracefully'); await prisma.$disconnect(); httpServer.close(() => { console.log('Server closed'); process.exit(0); }); }); process.on('SIGINT', async () => { console.log('SIGINT received, shutting down gracefully'); await prisma.$disconnect(); httpServer.close(() => { console.log('Server closed'); process.exit(0); }); }); startServer(); export { io };