require('dotenv').config(); const express = require('express'); const cors = require('cors'); const { createDatabase } = require('./database/createDb'); const getRoutes = require('./routes/getRoutes'); const postRoutes = require('./routes/postRoutes'); const authRoutes = require('./routes/auth'); const cookieParser = require('cookie-parser'); const authMiddleware = require('./middleware/authMiddleware'); const documentsRoutes = require('./routes/documents'); const profileRoutes = require('./routes/profile'); const contractsRoutes = require('./routes/contracts'); const referralRoutes = require('./routes/referral'); const permissionsRoutes = require('./routes/permissions'); const permissionsInit = require('./scripts/initPermissions'); const adminRoutes = require('./routes/admin'); const createAdminUser = require('./scripts/createAdminUser'); const { createRateLimiter } = require('./middleware/rateLimiter'); const documentTemplatesRoutes = require('./routes/documentTemplates'); const companyStampRoutes = require('./routes/companyStamps'); // NEW // add logger (now with setters/getter) const { logger, requestLogger, setLogLevel, setTransportLevel, getLoggerLevels } = require('./middleware/logger'); const app = express(); const PORT = process.env.PORT || 3001; // CORS configuration const ALLOWED_ORIGINS = (process.env.CORS_ALLOWED_ORIGINS) .split(',') .map(o => o.trim()); const corsOptions = { origin: function (origin, callback) { if (!origin) return callback(null, true); // non-browser clients if (ALLOWED_ORIGINS.includes(origin)) { return callback(null, true); } return callback(new Error('Not allowed by CORS')); }, credentials: true, methods: ['GET','POST','PUT','PATCH','DELETE','OPTIONS'], allowedHeaders: ['Content-Type','Authorization'], exposedHeaders: [] }; app.use(cors(corsOptions)); // Middleware app.use(express.json()); app.use(cookieParser()); // -- Replace inline console logging with structured request logger -- app.use(requestLogger); // -- end logging middleware -- // Basic route to handle requests from frontend app.get('/', (req, res) => { res.json({ message: 'Central server is running and ready to receive requests' }); }); // Example API endpoint app.post('/api/data', (req, res) => { logger.debug('Received request from frontend', { requestId: req.id, body: req.body && typeof req.body === 'object' ? '[object]' : req.body }); res.json({ success: true, message: 'Data received successfully', timestamp: new Date().toISOString() }); }); // Test endpoint for frontend app.get('/api/test', (req, res) => { logger.info('Test request received from frontend', { requestId: req.id }); res.json({ success: true, message: 'Backend connection successful!', timestamp: new Date().toISOString(), server: 'Central Server' }); }); // Protected route example app.use('/api/protected', authMiddleware, (req, res) => { res.json({ success: true, message: 'Access granted', user: req.user }); }); // Use getRoutes for URL routing and controller references app.use('/', getRoutes); app.use('/', postRoutes); // <-- Add this line to enable POST /register/personal and /register/company app.use('/api/auth', authRoutes); app.use('/api', documentsRoutes); app.use('/api', profileRoutes); app.use('/api', contractsRoutes); app.use('/api', referralRoutes); app.use('/api', permissionsRoutes); app.use('/api', adminRoutes); app.use('/api', documentTemplatesRoutes); app.use('/api', companyStampRoutes); // NEW logger.info('🛣️ GET routes configured and ready'); // Insert admin endpoint for dynamic log-level control // Requires authenticated user and admin role app.post('/api/admin/log-level', authMiddleware, (req, res) => { // Basic auth + role check (assumes authMiddleware sets req.user) if (!req.user || req.user.role !== 'admin') { logger.warn('admin:forbidden_log_level_change', { requestId: req.id, user: req.user && req.user.id }); return res.status(403).json({ success: false, message: 'Forbidden' }); } const { level, transport } = req.body || {}; const allowedLevels = ['error','warn','info','http','verbose','debug','silly']; if (!level || typeof level !== 'string' || !allowedLevels.includes(level)) { return res.status(400).json({ success: false, message: `Invalid level. Allowed: ${allowedLevels.join(', ')}` }); } let ok = false; if (transport && typeof transport === 'string') { // set specific transport (e.g. 'console' or 'file' or class name) ok = setTransportLevel(transport, level); } else { // set global level (affects logger and all transports) ok = setLogLevel(level); } const current = getLoggerLevels(); if (!ok) { logger.warn('admin:log_level_change_failed', { requestId: req.id, userId: req.user && req.user.id, level, transport }); return res.status(500).json({ success: false, message: 'Failed to apply log level', current }); } logger.info('admin:log_level_changed', { requestId: req.id, userId: req.user && req.user.id, level, transport }); return res.status(200).json({ success: true, message: 'Log level updated', current }); }); // Express error handler (logs structured error and returns safe response) function errorHandler(err, req, res, next) { logger.error('http:error', { message: err && err.message, stack: err && err.stack, requestId: req && req.id, method: req && req.method, url: req && req.originalUrl, user: req && req.user ? { id: req.user.id, email: req.user.email } : undefined }); const status = (err && err.status) || 500; const safeMessage = process.env.NODE_ENV === 'development' ? (err && err.message) : 'Internal Server Error'; res.status(status).json({ success: false, message: safeMessage }); } app.use(errorHandler); // register global error / process handlers process.on('uncaughtException', (err) => { try { logger.error('uncaughtException', { message: err.message, stack: err.stack }); } catch (e) { console.error('Failed to log uncaughtException', e); } // optionally flush and exit for safety setTimeout(() => process.exit(1), 1000); }); process.on('unhandledRejection', (reason) => { try { logger.error('unhandledRejection', { reason: reason && reason.stack ? reason.stack : reason }); } catch (e) { console.error('Failed to log unhandledRejection', e); } // optional: exit or let process continue based on policy }); // Start server with database initialization async function startServer() { try { logger.info('🔄 Initializing server...'); // Initialize database first await createDatabase(); // Initialize permissions await permissionsInit(); // Create admin user await createAdminUser(); // Start the server app.listen(PORT, () => { const host = process.env.HOST || 'localhost'; const url = `http://${host}:${PORT}`; logger.info('🚀 Central server running', { url, port: PORT }); logger.info('📡 Waiting for requests from frontend...'); logger.info('💾 Database initialized and ready'); }); } catch (error) { logger.error('💥 Failed to start server', { message: error.message, stack: error.stack }); process.exit(1); } } // Start everything in order startServer();