Files
sena_db_api_layer/app.js
2026-01-19 09:33:35 +07:00

245 lines
5.9 KiB
JavaScript

const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const compression = require('compression');
const morgan = require('morgan');
require('express-async-errors'); // Handle async errors
const config = require('./config/config.json');
// Import configurations
const { initializeDatabase } = require('./config/database');
const { setupRelationships } = require('./models');
const { redisClient } = require('./config/redis');
// Import middleware
const { errorHandler, notFoundHandler } = require('./middleware/errorHandler');
// Import routes
const authRoutes = require('./routes/authRoutes');
const schoolRoutes = require('./routes/schoolRoutes');
const classRoutes = require('./routes/classRoutes');
const academicYearRoutes = require('./routes/academicYearRoutes');
const subjectRoutes = require('./routes/subjectRoutes');
const userRoutes = require('./routes/userRoutes');
const studentRoutes = require('./routes/studentRoutes');
const teacherRoutes = require('./routes/teacherRoutes');
const roomRoutes = require('./routes/roomRoutes');
const attendanceRoutes = require('./routes/attendanceRoutes');
const gradeRoutes = require('./routes/gradeRoutes');
const subscriptionRoutes = require('./routes/subscriptionRoutes');
const trainingRoutes = require('./routes/trainingRoutes');
const parentTaskRoutes = require('./routes/parentTaskRoutes');
const chapterRoutes = require('./routes/chapterRoutes');
const gameRoutes = require('./routes/gameRoutes');
/**
* Initialize Express Application
*/
const app = express();
/**
* Security Middleware
*/
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'"],
fontSrc: ["'self'"],
objectSrc: ["'none'"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"],
},
},
}));
app.use(cors({
origin: config.cors.origin,
credentials: true,
}));
/**
* Body Parsing Middleware
*/
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
/**
* Static Files Middleware
*/
app.use(express.static('public'));
/**
* Compression Middleware
*/
app.use(compression());
/**
* Logging Middleware
*/
if (config.server.env === 'development') {
app.use(morgan('dev'));
} else {
app.use(morgan('combined'));
}
/**
* Health Check Endpoint
*/
app.get('/health', async (req, res) => {
try {
// Check database connection
await require('./config/database').testConnection();
// Check Redis connection
await redisClient.ping();
res.json({
success: true,
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
environment: config.server.env,
services: {
database: 'connected',
redis: 'connected',
},
});
} catch (error) {
res.status(503).json({
success: false,
status: 'unhealthy',
error: error.message,
});
}
});
/**
* API Info Endpoint
*/
app.get('/api', (req, res) => {
res.json({
success: true,
name: 'Sena School Management API',
version: '1.0.0',
description: 'API for managing 200 schools with Redis caching and BullMQ job processing',
enauth: '/api/auth',
dpoints: {
schools: '/api/schools',
classes: '/api/classes',
academicYears: '/api/academic-years',
subjects: '/api/subjects',
users: '/api/users',
students: '/api/students',
teachers: '/api/teachers',
rooms: '/api/rooms',
attendance: '/api/attendance',
grades: '/api/grades',
subscriptions: '/api/subscriptions',
training: '/api/training',
parentTasks: '/api/parent-tasks',
chapters: '/api/chapters',
games: '/api/games',
},
documentation: '/api/docs',
});
});
/**
* API Routes
*/
app.use('/api/auth', authRoutes);
app.use('/api/schools', schoolRoutes);
app.use('/api/classes', classRoutes);
app.use('/api/academic-years', academicYearRoutes);
app.use('/api/subjects', subjectRoutes);
app.use('/api/users', userRoutes);
app.use('/api/students', studentRoutes);
app.use('/api/teachers', teacherRoutes);
app.use('/api/rooms', roomRoutes);
app.use('/api/attendance', attendanceRoutes);
app.use('/api/grades', gradeRoutes);
app.use('/api/subscriptions', subscriptionRoutes);
app.use('/api/training', trainingRoutes);
app.use('/api/parent-tasks', parentTaskRoutes);
app.use('/api/chapters', chapterRoutes);
app.use('/api/games', gameRoutes);
/**
* Queue Status Endpoint
*/
app.get('/api/queues/status', async (req, res) => {
try {
const { getQueueMetrics, QueueNames } = require('./config/bullmq');
const metrics = await Promise.all(
Object.values(QueueNames).map(queueName => getQueueMetrics(queueName))
);
res.json({
success: true,
data: metrics,
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
});
}
});
/**
* Cache Stats Endpoint
*/
app.get('/api/cache/stats', async (req, res) => {
try {
const info = await redisClient.info('stats');
const dbSize = await redisClient.dbsize();
res.json({
success: true,
data: {
dbSize,
stats: info,
},
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
});
}
});
/**
* 404 Handler
*/
app.use(notFoundHandler);
/**
* Global Error Handler
*/
app.use(errorHandler);
/**
* Initialize Application
*/
const initializeApp = async () => {
try {
// Initialize database connection
await initializeDatabase();
// Setup model relationships
setupRelationships();
console.log('✅ Application initialized successfully');
} catch (error) {
console.error('❌ Application initialization failed:', error.message);
throw error;
}
};
module.exports = { app, initializeApp };