const express = require('express'); const mongoose = require('mongoose'); const cors = require('cors'); const cookieParser = require('cookie-parser'); const dotenv = require('dotenv'); const path = require('path'); const http = require('http'); // Загрузить переменные окружения из корня проекта const rootEnvPath = path.resolve(__dirname, '../../.env'); dotenv.config({ path: rootEnvPath }); const config = require('../../backend/config'); const { initWebSocket } = require('../../backend/websocket'); // Security middleware const { helmetConfig, sanitizeMongo, xssProtection, hppProtection, ddosProtection } = require('../../backend/middleware/security'); const { sanitizeInput } = require('../../backend/middleware/validator'); const { requestLogger } = require('../../backend/middleware/logger'); const { errorHandler, notFoundHandler } = require('../../backend/middleware/errorHandler'); const { generalLimiter } = require('../../backend/middleware/rateLimiter'); const app = express(); const server = http.createServer(app); // Trust proxy для правильного IP if (config.isProduction()) { app.set('trust proxy', 1); } // Security headers app.use(helmetConfig); // CORS настройки для модераторского сайта const corsOptions = { origin: process.env.MODERATION_CORS_ORIGIN || config.frontendUrl || '*', credentials: true, optionsSuccessStatus: 200, methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization', 'x-telegram-init-data'], maxAge: 86400 }; app.use(cors(corsOptions)); // Cookie parser для JWT токенов в cookies app.use(cookieParser()); // Body parsing app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ extended: true, limit: '10mb' })); // Security middleware app.use(sanitizeMongo); app.use(xssProtection); app.use(hppProtection); // Input sanitization app.use(sanitizeInput); // Request logging app.use(requestLogger); // DDoS protection app.use(ddosProtection); // Rate limiting app.use('/api', generalLimiter); // Health check app.get('/health', (req, res) => { res.json({ status: 'ok', service: 'moderation', timestamp: new Date().toISOString() }); }); // MongoDB подключение (используем ту же БД) mongoose.connect(config.mongoUri) .then(async () => { console.log('✅ MongoDB подключена для модерации'); mongoose.connection.on('error', (err) => { console.error('❌ MongoDB connection error:', err); }); mongoose.connection.on('disconnected', () => { console.warn('⚠️ MongoDB отключена'); }); mongoose.connection.on('reconnected', () => { console.log('✅ MongoDB переподключена'); }); }) .catch(err => { console.error('❌ Не удалось подключиться к MongoDB:', err); process.exit(1); }); // Routes - используем те же роуты из основного бэкенда app.use('/api/mod-app', require('../../backend/routes/modApp')); app.use('/api/moderation-auth', require('../../backend/routes/moderationAuth')); // Базовый роут app.get('/', (req, res) => { res.json({ message: 'Nakama Moderation API' }); }); // 404 handler app.use(notFoundHandler); // Error handler app.use(errorHandler); // Инициализировать WebSocket initWebSocket(server); // Graceful shutdown process.on('SIGTERM', () => { console.log('SIGTERM получен, закрываем сервер модерации...'); server.close(() => { mongoose.connection.close(false, () => { process.exit(0); }); }); }); process.on('SIGINT', () => { console.log('SIGINT получен, закрываем сервер модерации...'); server.close(() => { mongoose.connection.close(false, () => { process.exit(0); }); }); }); const moderationPort = process.env.MODERATION_PORT || 3001; server.listen(moderationPort, '0.0.0.0', () => { console.log('\n' + '='.repeat(60)); console.log('✅ Сервер модерации запущен'); console.log(` 🌐 API: http://0.0.0.0:${moderationPort}/api`); console.log(` 📦 MongoDB: ${config.mongoUri.includes('localhost') ? 'Local' : 'Remote'}`); console.log('='.repeat(60) + '\n'); });