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
JavaScript
;
/**
* @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;
}