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
JavaScript
;
/**
* ╔══════════════════════════════════════════════════════════════════════════════════╗
* ║ 🚀 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;