Files
whats-the-point/backend/src/index.js
Mike Johnston b6527b97cd
All checks were successful
Build Images and Deploy / Update-PROD-Stack (push) Successful in 36s
deploy fixes?
2026-01-30 15:47:42 -05:00

114 lines
3.3 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
});