CentralBackend/server.js
2025-09-07 12:44:01 +02:00

203 lines
7.0 KiB
JavaScript

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();