UNPKG

mcp-quiz-server

Version:

🧠 AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.

289 lines (288 loc) • 12.5 kB
"use strict"; /** * @fileoverview Health Routes - Clean Architecture HTTP routes for health checks and system status * @version 1.0.0 * @since 2025-07-31 * @lastUpdated 2025-07-31 * @module HealthRoutes * @description HTTP routes for health checks and system status following clean architecture principles. * Provides endpoints for monitoring application health, database connectivity, and service status. * @contributors Claude Code Agent * @dependencies express, DatabaseInitializer, Config * @requirements REQ_PERF_001, REQ_ERROR_004, REQ_COMPLIANCE_004 * @testCoverage Health check integration tests */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createHealthRoutes = createHealthRoutes; const express = __importStar(require("express")); const packageJson = __importStar(require("../../../../package.json")); const mvp_config_1 = __importDefault(require("../../../config/mvp-config")); /** * Creates health check HTTP routes following clean architecture patterns. * * @description Sets up health check endpoints for monitoring application status, * database connectivity, and overall system health. * * @param config - Configuration object with dependencies * @returns Express router with health routes * * @example * ```typescript * const healthRouter = createHealthRoutes({ * dbInitializer, * environment: 'production' * }); * app.use('/health', healthRouter); * ``` * * @since 2025-07-31 * @author Claude Code Agent * @requirements REQ_PERF_001 (Performance Standards), REQ_ERROR_004 (Error Handling) * @accessibility Public health check endpoints for monitoring */ function createHealthRoutes(config) { const router = express.Router(); const { dbInitializer, environment } = config; /** * GET /health - Basic health check * Public endpoint for basic application health status */ router.get('/', (req, res) => { var _a, _b; try { const dbStatus = (_b = (_a = dbInitializer === null || dbInitializer === void 0 ? void 0 : dbInitializer.getDataSource) === null || _a === void 0 ? void 0 : _a.call(dbInitializer)) === null || _b === void 0 ? void 0 : _b.isInitialized; const appConfig = mvp_config_1.default.getConfig(); // Check authentication status const authenticationStatus = config.authService ? 'enabled' : appConfig.features.userAuth ? 'configured-but-not-injected' : 'disabled'; const healthStatus = { status: 'ok', version: packageJson.version, timestamp: new Date().toISOString(), environment: environment || appConfig.environment || 'unknown', database: dbStatus ? 'connected' : 'disconnected', authentication: authenticationStatus, activeSessions: config.authService ? 0 : 0, // Could query actual sessions if needed features: { cleanArchitecture: true, routeModules: true, legacyFallback: true, }, deployment: appConfig.deployment, }; // Set appropriate HTTP status based on database connectivity const httpStatus = dbStatus ? 200 : 503; res.status(httpStatus).json(healthStatus); } catch (error) { res.status(500).json({ status: 'error', version: packageJson.version, timestamp: new Date().toISOString(), error: 'Health check failed', details: error instanceof Error ? error.message : String(error), }); } }); /** * GET /health/detailed - Detailed health check * Comprehensive health status including system metrics */ router.get('/detailed', (req, res) => { var _a, _b; try { const dbStatus = (_b = (_a = dbInitializer === null || dbInitializer === void 0 ? void 0 : dbInitializer.getDataSource) === null || _a === void 0 ? void 0 : _a.call(dbInitializer)) === null || _b === void 0 ? void 0 : _b.isInitialized; const appConfig = mvp_config_1.default.getConfig(); const detailedHealth = { status: dbStatus ? 'healthy' : 'degraded', version: packageJson.version, timestamp: new Date().toISOString(), environment: environment || appConfig.environment || 'unknown', // Database information database: { status: dbStatus ? 'connected' : 'disconnected', type: appConfig.database.type, path: appConfig.database.path, synchronize: appConfig.database.synchronize, logging: appConfig.database.logging, }, // Feature flags status features: mvp_config_1.default.getClientFeatures(), // System information system: { nodeVersion: process.version, platform: process.platform, uptime: Math.floor(process.uptime()), memoryUsage: process.memoryUsage(), pid: process.pid, }, // Server configuration server: mvp_config_1.default.getServerConfig(), // UI configuration ui: mvp_config_1.default.getUIConfig(), // Deployment information deployment: appConfig.deployment, // Architecture status architecture: { cleanArchitecture: true, routeModules: true, legacyFallback: true, controllerFactory: true, }, }; // Set appropriate HTTP status const httpStatus = dbStatus ? 200 : 503; res.status(httpStatus).json(detailedHealth); } catch (error) { res.status(500).json({ status: 'error', version: packageJson.version, timestamp: new Date().toISOString(), error: 'Detailed health check failed', details: error instanceof Error ? error.message : String(error), }); } }); /** * GET /health/database - Database-specific health check * Focused check on database connectivity and status */ router.get('/database', (req, res) => { var _a, _b, _c, _d, _e; try { const dataSource = (_a = dbInitializer === null || dbInitializer === void 0 ? void 0 : dbInitializer.getDataSource) === null || _a === void 0 ? void 0 : _a.call(dbInitializer); const isConnected = (dataSource === null || dataSource === void 0 ? void 0 : dataSource.isInitialized) || false; const dbHealth = { status: isConnected ? 'connected' : 'disconnected', timestamp: new Date().toISOString(), details: { initialized: isConnected, database: ((_b = dataSource === null || dataSource === void 0 ? void 0 : dataSource.options) === null || _b === void 0 ? void 0 : _b.database) || 'unknown', type: ((_c = dataSource === null || dataSource === void 0 ? void 0 : dataSource.options) === null || _c === void 0 ? void 0 : _c.type) || 'unknown', synchronize: ((_d = dataSource === null || dataSource === void 0 ? void 0 : dataSource.options) === null || _d === void 0 ? void 0 : _d.synchronize) || false, logging: ((_e = dataSource === null || dataSource === void 0 ? void 0 : dataSource.options) === null || _e === void 0 ? void 0 : _e.logging) || false, }, metrics: isConnected ? { // Could add connection pool metrics, query stats, etc. connectionPool: 'N/A for SQLite', } : null, }; const httpStatus = isConnected ? 200 : 503; res.status(httpStatus).json(dbHealth); } catch (error) { res.status(500).json({ status: 'error', timestamp: new Date().toISOString(), error: 'Database health check failed', details: error instanceof Error ? error.message : String(error), }); } }); /** * GET /health/readiness - Kubernetes readiness probe * Endpoint for container orchestration readiness checks */ router.get('/readiness', (req, res) => { var _a, _b; try { const dbStatus = (_b = (_a = dbInitializer === null || dbInitializer === void 0 ? void 0 : dbInitializer.getDataSource) === null || _a === void 0 ? void 0 : _a.call(dbInitializer)) === null || _b === void 0 ? void 0 : _b.isInitialized; if (dbStatus) { res.status(200).json({ status: 'ready', timestamp: new Date().toISOString(), checks: { database: 'pass', configuration: 'pass', services: 'pass', }, }); } else { res.status(503).json({ status: 'not_ready', timestamp: new Date().toISOString(), checks: { database: 'fail', configuration: 'pass', services: 'pass', }, }); } } catch (error) { res.status(503).json({ status: 'not_ready', timestamp: new Date().toISOString(), error: 'Readiness check failed', details: error instanceof Error ? error.message : String(error), }); } }); /** * GET /health/liveness - Kubernetes liveness probe * Endpoint for container orchestration liveness checks */ router.get('/liveness', (req, res) => { try { // Basic liveness check - if we can respond, we're alive res.status(200).json({ status: 'alive', timestamp: new Date().toISOString(), uptime: Math.floor(process.uptime()), pid: process.pid, }); } catch (error) { res.status(500).json({ status: 'unhealthy', timestamp: new Date().toISOString(), error: 'Liveness check failed', details: error instanceof Error ? error.message : String(error), }); } }); return router; }