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.

232 lines (228 loc) 13.1 kB
"use strict"; /** * ╔══════════════════════════════════════════════════════════════════════════════════╗ * ║ 🚀 MCP QUIZ SERVER - CLEAN ARCHITECTURE 🚀 ║ * ╠══════════════════════════════════════════════════════════════════════════════════╣ * ║ ║ * ║ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ║ * ║ │ HTTP Routes │◄──►│ Controllers │◄──►│ Use Cases │ ║ * ║ │ (Express) │ │ (Infrastructure)│ │ (Application) │ ║ * ║ └─────────────────┘ └─────────────────┘ └─────────────────┘ ║ * ║ │ │ │ ║ * ║ │ │ │ ║ * ║ ▼ ▼ ▼ ║ * ║ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ║ * ║ │ Route Registry │ │ DI Container │ │ Domain Model │ ║ * ║ │ (Modular) │ │ (Services) │ │ (Entities) │ ║ * ║ └─────────────────┘ └─────────────────┘ └─────────────────┘ ║ * ║ ║ * ║ Clean Architecture Features: ║ * ║ • Interactive setup wizard with Jenkins-style password generation ║ * ║ • DigitalOcean optimized deployment with ASCII animations ║ * ║ • Modular route organization with separate concerns ║ * ║ • Dependency injection and inversion of control ║ * ║ • Clean separation between HTTP, business logic, and data layers ║ * ║ • Comprehensive error handling and audit logging ║ * ║ • Legacy service fallback for gradual migration ║ * ║ • Health checks and monitoring endpoints ║ * ║ ║ * ╚══════════════════════════════════════════════════════════════════════════════════╝ * * @moduleName: MCP Quiz Server - Clean Architecture Implementation * @version: 3.0.0 * @since: 2025-07-31 * @lastUpdated: 2025-07-31 * @projectSummary: Clean architecture HTTP server with modular routes, dependency injection, and comprehensive service organization * @techStack: Express.js, TypeORM, SQLite, TypeScript, Clean Architecture * @dependency: ServerApplication, RouteRegistry, ControllerFactory, DatabaseInitializer * @interModuleDependency: Infrastructure layer components with proper separation of concerns * @requirementsTraceability: * {@link Requirements.REQ_API_001} (Quiz CRUD Operations) * {@link Requirements.REQ_API_002} (RFC 7807 Error Responses) * {@link Requirements.REQ_ARCH_002} (Service Boundary Enforcement) * {@link Requirements.REQ_PERF_001} (Load Performance Standards) * {@link Requirements.REQ_PERF_003} (Resource Usage Limits) * {@link Requirements.REQ_PERF_004} (Database Performance Optimization) * {@link Requirements.REQ_COMPLIANCE_004} (Access Control Logging) * {@link Requirements.REQ_ERROR_004} (Database Error Handling) * @briefDescription: Clean architecture HTTP server with modular route organization, dependency injection, and comprehensive service management * @methods: ServerApplication.initialize(), ServerApplication.start(), graceful shutdown handling * @contributors: Claude Code Agent * @examples: Modular route structure, clean dependency injection, comprehensive error handling * @vulnerabilitiesAssessment: Enhanced security with modular architecture, proper input validation, audit logging, and separation of concerns */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.serverApp = void 0; require("reflect-metadata"); // Required for TypeORM decorators const mvp_config_1 = __importDefault(require("./config/mvp-config")); const ServerApplication_1 = require("./infrastructure/http/ServerApplication"); const error_handler_1 = require("./shared/error-handler"); // Configuration const PORT = parseInt(process.env.PORT || '3000'); const HOST = process.env.HOST || 'localhost'; const ENVIRONMENT = process.env.NODE_ENV || 'development'; // Global server application instance let serverApp; /** * Starts the MCP Quiz Server with Clean Architecture implementation. * * This function performs the following steps: * 1. Validates configuration and feature flags * 2. Creates ServerApplication instance with clean architecture * 3. Initializes all services, controllers, and route modules * 4. Sets up comprehensive error handling and audit logging * 5. Starts the HTTP server with graceful shutdown handling * * The clean architecture implementation provides: * - Modular route organization (QuizRoutes, HealthRoutes, AdminRoutes, etc.) * - Dependency injection with proper service boundaries * - Clean separation between HTTP layer, business logic, and data access * - Legacy service fallback for gradual migration * - Comprehensive health checks and monitoring * * @async * @throws Will exit the process if server startup fails. */ async function startServer() { try { error_handler_1.Logger.info('🚀 Starting MCP Quiz Server with Clean Architecture'); // 🆕 NEW: First-time setup detection and wizard execution // TODO: Fix SetupOrchestrator TypeScript compilation issues /* const { SetupOrchestrator } = await import('./infrastructure/setup/SetupOrchestrator'); const setupOrchestrator = new SetupOrchestrator(); const setupRequired = await setupOrchestrator.isSetupRequired(); if (setupRequired) { Logger.info('🎯 First-time setup required - launching setup wizard'); const setupResult = await setupOrchestrator.runSetup(); if (setupResult.integrationSuccess && setupResult.result) { // Apply setup configuration to existing Config system const setupConfig = SetupOrchestrator.createServerConfig(setupResult.result); // Update environment variables for the current session process.env.PORT = setupConfig.server.port.toString(); process.env.HOST = setupConfig.server.host; process.env.NODE_ENV = setupConfig.server.environment; Logger.info('✅ Setup configuration applied to server'); } else if (!setupResult.integrationSuccess) { throw new Error(`Setup failed: ${setupResult.message}`); } } */ error_handler_1.Logger.info('Configuration validation and feature flag check'); // Validate configuration (this runs automatically on Config import) const config = mvp_config_1.default.getConfig(); error_handler_1.Logger.info(`Environment: ${config.environment}`, { port: PORT, host: HOST, features: Object.entries(config.features) .filter(([_, enabled]) => enabled) .map(([name]) => name), }); // Create server application with simplified OSS configuration const serverConfig = { port: PORT, enableCors: config.environment === 'development', staticPath: 'public', enableSwagger: true, }; error_handler_1.Logger.info('Creating server application with clean architecture'); serverApp = new ServerApplication_1.ServerApplication(serverConfig); // Initialize all services, controllers, and routes error_handler_1.Logger.info('Initializing application components...'); await serverApp.initialize(); // Get application status for logging (simplified for OSS) const appStatus = serverApp.getStatus(); error_handler_1.Logger.info('Application initialization completed', { version: appStatus.version, port: appStatus.port, isRunning: appStatus.isRunning, uptime: appStatus.uptime, }); // Start HTTP server error_handler_1.Logger.info('Starting HTTP server'); await serverApp.start(); // Log successful startup with simplified information error_handler_1.Logger.info('✅ MCP Quiz Server (OSS) started successfully', { port: PORT, environment: ENVIRONMENT, version: appStatus.version, urls: { main: `http://localhost:${PORT}`, health: `http://localhost:${PORT}/health`, api: `http://localhost:${PORT}/quiz/*`, swagger: `http://localhost:${PORT}/api-docs`, }, }); error_handler_1.Logger.info('🎯 OSS Features Active:', { quizManagement: true, mcpIntegration: true, swaggerDocs: true, simplifiedArchitecture: true, }); } catch (error) { error_handler_1.Logger.error('❌ Failed to start MCP Quiz Server:', error instanceof Error ? error : new Error(String(error))); // Attempt graceful cleanup if server app was created if (serverApp) { try { await serverApp.stop(); } catch (shutdownError) { error_handler_1.Logger.error('Error during cleanup:', shutdownError instanceof Error ? shutdownError : new Error(String(shutdownError))); } } process.exit(1); } } /** * Handles graceful shutdown of the server application. * * @description Performs cleanup of database connections, services, and resources * following clean architecture principles. * * @param signal - The shutdown signal received */ async function handleShutdown(signal) { error_handler_1.Logger.info(`🛑 Received ${signal}, shutting down server gracefully...`); try { if (serverApp) { await serverApp.stop(); error_handler_1.Logger.info('✅ Server shutdown completed successfully'); } } catch (error) { error_handler_1.Logger.error('❌ Error during server shutdown:', error instanceof Error ? error : new Error(String(error))); } finally { process.exit(0); } } // Graceful shutdown handlers process.on('SIGINT', () => handleShutdown('SIGINT')); process.on('SIGTERM', () => handleShutdown('SIGTERM')); // Handle uncaught exceptions and unhandled rejections process.on('uncaughtException', error => { error_handler_1.Logger.error('Uncaught Exception:', error instanceof Error ? error : new Error(String(error))); handleShutdown('uncaughtException'); }); process.on('unhandledRejection', (reason, promise) => { error_handler_1.Logger.error('Unhandled Rejection at:', new Error(`Promise: ${promise}, reason: ${reason}`)); handleShutdown('unhandledRejection'); }); // Export the server application for testing (initialized during startup) let exportableServerApp; // Only start the server if not in test environment or being imported if (require.main === module || !process.env.NODE_ENV || process.env.NODE_ENV !== 'test') { startServer() .then(() => { exports.serverApp = exportableServerApp = serverApp; }) .catch(error => { error_handler_1.Logger.error('Failed to start server:', error instanceof Error ? error : new Error(String(error))); process.exit(1); }); } exports.default = exportableServerApp;