All checks were successful
Build Images and Deploy / Update-PROD-Stack (push) Successful in 36s
114 lines
3.3 KiB
JavaScript
114 lines
3.3 KiB
JavaScript
import express from 'express';
|
||
import cors from 'cors';
|
||
import dotenv from 'dotenv';
|
||
import path from 'path';
|
||
import fs from 'fs';
|
||
import { fileURLToPath } from 'url';
|
||
import { createServer } from 'http';
|
||
import rateLimit from 'express-rate-limit';
|
||
import { initDB } from './db/index.js';
|
||
import { validateConfig, config } from './config.js';
|
||
import { errorHandler } from './middleware/errorHandler.js';
|
||
import { initializeSocket } from './sockets/index.js';
|
||
import authRoutes from './routes/auth.js';
|
||
import challengeRoutes from './routes/challenges.js';
|
||
import predictionRoutes from './routes/predictions.js';
|
||
import friendRoutes from './routes/friends.js';
|
||
import tmdbRoutes from './routes/tmdb.js';
|
||
import leaderboardRoutes from './routes/leaderboard.js';
|
||
|
||
dotenv.config();
|
||
|
||
// Validate environment configuration
|
||
validateConfig();
|
||
|
||
const __filename = fileURLToPath(import.meta.url);
|
||
const __dirname = path.dirname(__filename);
|
||
|
||
const app = express();
|
||
const httpServer = createServer(app);
|
||
|
||
// Initialize Socket.io
|
||
initializeSocket(httpServer);
|
||
|
||
// Rate limiting
|
||
const authLimiter = rateLimit({
|
||
windowMs: 15 * 60 * 1000, // 15 minutes
|
||
max: 5, // 5 requests per window
|
||
message: { error: 'Too many authentication attempts, please try again later.' },
|
||
standardHeaders: true,
|
||
legacyHeaders: false,
|
||
});
|
||
|
||
const apiLimiter = rateLimit({
|
||
windowMs: 15 * 60 * 1000, // 15 minutes
|
||
max: 100, // 100 requests per window
|
||
message: { error: 'Too many requests, please try again later.' },
|
||
standardHeaders: true,
|
||
legacyHeaders: false,
|
||
});
|
||
|
||
const tmdbLimiter = rateLimit({
|
||
windowMs: 60 * 1000, // 1 minute
|
||
max: 20, // 20 requests per minute
|
||
message: { error: 'Too many search requests, please slow down.' },
|
||
standardHeaders: true,
|
||
legacyHeaders: false,
|
||
});
|
||
|
||
// Middleware
|
||
app.use(cors());
|
||
app.use(express.json());
|
||
|
||
// API Routes
|
||
app.use('/api/auth', authLimiter, authRoutes);
|
||
app.use('/api/challenges', apiLimiter, challengeRoutes);
|
||
app.use('/api/predictions', apiLimiter, predictionRoutes);
|
||
app.use('/api/friends', apiLimiter, friendRoutes);
|
||
app.use('/api/tmdb', tmdbLimiter, tmdbRoutes);
|
||
app.use('/api/leaderboard', apiLimiter, leaderboardRoutes);
|
||
|
||
// Health check
|
||
app.get('/api/health', (req, res) => {
|
||
res.json({ status: 'ok', message: "What's The Point API" });
|
||
});
|
||
|
||
// Serve static frontend files (for production)
|
||
const frontendPath = path.join(__dirname, '../../frontend/dist');
|
||
const frontendExists = fs.existsSync(frontendPath);
|
||
|
||
if (frontendExists) {
|
||
app.use(express.static(frontendPath));
|
||
|
||
// Serve index.html for all non-API routes (SPA support)
|
||
app.get('*', (req, res) => {
|
||
res.sendFile(path.join(frontendPath, 'index.html'));
|
||
});
|
||
} else {
|
||
console.log('ℹ️ Frontend dist not found - running in API-only mode (dev)');
|
||
app.get('*', (req, res) => {
|
||
res.json({
|
||
message: "What's The Point API - Frontend running separately",
|
||
frontend: "http://192.168.1.175:5173"
|
||
});
|
||
});
|
||
}
|
||
|
||
// Error handling middleware (must be last)
|
||
app.use(errorHandler);
|
||
|
||
const PORT = config.server.port;
|
||
|
||
// Initialize database and start server
|
||
initDB()
|
||
.then(() => {
|
||
httpServer.listen(PORT, '0.0.0.0', () => {
|
||
console.log(`✅ Server running on port ${PORT}`);
|
||
console.log(`🔌 Socket.io ready for real-time updates`);
|
||
});
|
||
})
|
||
.catch(err => {
|
||
console.error('Failed to start server:', err);
|
||
process.exit(1);
|
||
});
|