202 lines
6.7 KiB
JavaScript
202 lines
6.7 KiB
JavaScript
require('dotenv').config();
|
|
const express = require('express');
|
|
const cors = require('cors');
|
|
const { createDatabase } = require('./database/createDb');
|
|
const cookieParser = require('cookie-parser');
|
|
const authMiddleware = require('./middleware/authMiddleware');
|
|
const { createRateLimiter } = require('./middleware/rateLimiter');
|
|
// add logger (now with setters/getter)
|
|
const { logger, requestLogger, setLogLevel, setTransportLevel, getLoggerLevels } = require('./middleware/logger');
|
|
|
|
// ADD: import permission initializer and admin-creation script
|
|
const permissionsInit = require('./scripts/initPermissions');
|
|
const createAdminUser = require('./scripts/createAdminUser');
|
|
const createCompanyUser = require('./scripts/createCompanyUser');
|
|
const createPersonalUser = require('./scripts/createPersonalUser');
|
|
|
|
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 });
|
|
});
|
|
|
|
// Import and mount the new verb-specific routers
|
|
const getRoutes = require('./routes/getRoutes');
|
|
const postRoutes = require('./routes/postRoutes');
|
|
const putRoutes = require('./routes/putRoutes');
|
|
const patchRoutes = require('./routes/patchRoutes');
|
|
const deleteRoutes = require('./routes/deleteRoutes'); // added
|
|
|
|
app.use('/api', getRoutes);
|
|
app.use('/api', postRoutes);
|
|
app.use('/api', putRoutes);
|
|
app.use('/api', patchRoutes);
|
|
app.use('/api', deleteRoutes);
|
|
|
|
logger.info('🛣️ Verb-specific 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();
|
|
|
|
// Create company user
|
|
await createCompanyUser();
|
|
|
|
// Create personal user
|
|
await createPersonalUser();
|
|
|
|
// 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(); |