UNPKG

adpa-enterprise-framework-automation

Version:

Modular, standards-compliant Node.js/TypeScript automation framework for enterprise requirements, project, and data management. Provides CLI and API for BABOK v3, PMBOK 7th Edition, and DMBOK 2.0 (in progress). Production-ready Express.js API with TypeSpe

414 lines 16.7 kB
/** * Scope Control Controller * API endpoints for adaptive scope control functionality * * @class ScopeControlController * @description Provides REST API endpoints for scope control operations including * scope change management, monitoring, and PMBOK compliance validation * * @version 1.0.0 * @since 3.2.0 */ import { AdaptiveScopeControlService } from '../../services/AdaptiveScopeControlService.js'; import { Project } from '../../models/Project.js'; import { logger } from '../../utils/logger.js'; export class ScopeControlController { static scopeControlService = new AdaptiveScopeControlService(); /** * Initialize scope control monitoring for a project * POST /api/projects/:projectId/scope-control/initialize */ static async initializeScopeControl(req, res) { try { const { projectId } = req.params; const settings = req.body.settings || {}; // Validate project exists const project = await Project.findById(projectId); if (!project) { res.status(404).json({ success: false, message: 'Project not found', error: `No project found with ID: ${projectId}` }); return; } // Initialize scope control await ScopeControlController.scopeControlService.initializeProjectMonitoring(project, settings); res.status(200).json({ success: true, message: 'Scope control monitoring initialized successfully', data: { projectId, settings: settings, monitoringActive: true } }); } catch (error) { logger.error('Failed to initialize scope control:', error); res.status(500).json({ success: false, message: 'Failed to initialize scope control monitoring', error: (error instanceof Error ? error.message : String(error)) }); } } /** * Submit a scope change request * POST /api/projects/:projectId/scope-control/changes */ static async submitScopeChange(req, res) { try { const { projectId } = req.params; const changeRequest = req.body; // Validate required fields const requiredFields = ['changeType', 'description', 'requestedBy', 'impact']; const missingFields = requiredFields.filter(field => !changeRequest[field]); if (missingFields.length > 0) { res.status(400).json({ success: false, message: 'Missing required fields', error: `Required fields missing: ${missingFields.join(', ')}` }); return; } // Validate project exists const project = await Project.findById(projectId); if (!project) { res.status(404).json({ success: false, message: 'Project not found', error: `No project found with ID: ${projectId}` }); return; } // Submit scope change const scopeChange = await ScopeControlController.scopeControlService.submitScopeChange({ ...changeRequest, projectId, requestDate: new Date() }); res.status(201).json({ success: true, message: 'Scope change request submitted successfully', data: { change: scopeChange, autoApproved: scopeChange.status === 'approved' } }); } catch (error) { logger.error('Failed to submit scope change:', error); res.status(500).json({ success: false, message: 'Failed to submit scope change request', error: (error instanceof Error ? error.message : String(error)) }); } } /** * Approve a scope change * PUT /api/scope-control/changes/:changeId/approve */ static async approveScopeChange(req, res) { try { const { changeId } = req.params; const { approvedBy } = req.body; if (!approvedBy) { res.status(400).json({ success: false, message: 'Approver information required', error: 'approvedBy field is required' }); return; } const approvedChange = await ScopeControlController.scopeControlService.approveScopeChange(changeId, approvedBy); res.status(200).json({ success: true, message: 'Scope change approved successfully', data: { change: approvedChange } }); } catch (error) { logger.error('Failed to approve scope change:', error); if (error instanceof Error && error.message.includes('not found')) { res.status(404).json({ success: false, message: 'Scope change not found', error: error.message }); } else { res.status(500).json({ success: false, message: 'Failed to approve scope change', error: (error instanceof Error ? error.message : String(error)) }); } } } /** * Get scope metrics for a project * GET /api/projects/:projectId/scope-control/metrics */ static async getScopeMetrics(req, res) { try { const { projectId } = req.params; // Validate project exists const project = await Project.findById(projectId); if (!project) { res.status(404).json({ success: false, message: 'Project not found', error: `No project found with ID: ${projectId}` }); return; } const metrics = await ScopeControlController.scopeControlService.getScopeMetrics(projectId); res.status(200).json({ success: true, message: 'Scope metrics retrieved successfully', data: { projectId, metrics, timestamp: new Date() } }); } catch (error) { logger.error('Failed to get scope metrics:', error); res.status(500).json({ success: false, message: 'Failed to retrieve scope metrics', error: (error instanceof Error ? error.message : String(error)) }); } } /** * Get scope alerts for a project * GET /api/projects/:projectId/scope-control/alerts */ static async getScopeAlerts(req, res) { try { const { projectId } = req.params; // Validate project exists const project = await Project.findById(projectId); if (!project) { res.status(404).json({ success: false, message: 'Project not found', error: `No project found with ID: ${projectId}` }); return; } const alerts = await ScopeControlController.scopeControlService.getScopeAlerts(projectId); res.status(200).json({ success: true, message: 'Scope alerts retrieved successfully', data: { projectId, alerts, alertCount: alerts.length, criticalAlerts: alerts.filter(a => a.severity === 'critical').length, timestamp: new Date() } }); } catch (error) { logger.error('Failed to get scope alerts:', error); res.status(500).json({ success: false, message: 'Failed to retrieve scope alerts', error: (error instanceof Error ? error.message : String(error)) }); } } /** * Detect scope creep for a project * POST /api/projects/:projectId/scope-control/detect-creep */ static async detectScopeCreep(req, res) { try { const { projectId } = req.params; // Validate project exists const project = await Project.findById(projectId); if (!project) { res.status(404).json({ success: false, message: 'Project not found', error: `No project found with ID: ${projectId}` }); return; } const scopeCreepDetected = await ScopeControlController.scopeControlService.detectScopeCreep(projectId); const metrics = await ScopeControlController.scopeControlService.getScopeMetrics(projectId); const alerts = scopeCreepDetected ? await ScopeControlController.scopeControlService.getScopeAlerts(projectId) : []; res.status(200).json({ success: true, message: 'Scope creep detection completed', data: { projectId, scopeCreepDetected, metrics, alerts: alerts.filter(a => a.alertType === 'scope_creep'), recommendations: scopeCreepDetected ? [ 'Review recent scope changes for patterns', 'Conduct stakeholder alignment session', 'Reassess project scope baseline', 'Implement stricter change control procedures', 'Consider scope reduction or timeline adjustment' ] : [], timestamp: new Date() } }); } catch (error) { logger.error('Failed to detect scope creep:', error); res.status(500).json({ success: false, message: 'Failed to perform scope creep detection', error: (error instanceof Error ? error.message : String(error)) }); } } /** * Stop scope control monitoring for a project * DELETE /api/projects/:projectId/scope-control/monitoring */ static async stopScopeControlMonitoring(req, res) { try { const { projectId } = req.params; // Validate project exists const project = await Project.findById(projectId); if (!project) { res.status(404).json({ success: false, message: 'Project not found', error: `No project found with ID: ${projectId}` }); return; } ScopeControlController.scopeControlService.stopProjectMonitoring(projectId); res.status(200).json({ success: true, message: 'Scope control monitoring stopped successfully', data: { projectId, monitoringActive: false, timestamp: new Date() } }); } catch (error) { logger.error('Failed to stop scope control monitoring:', error); res.status(500).json({ success: false, message: 'Failed to stop scope control monitoring', error: (error instanceof Error ? error.message : String(error)) }); } } /** * Get scope control dashboard data * GET /api/projects/:projectId/scope-control/dashboard */ static async getScopeControlDashboard(req, res) { try { const { projectId } = req.params; // Validate project exists const project = await Project.findById(projectId); if (!project) { res.status(404).json({ success: false, message: 'Project not found', error: `No project found with ID: ${projectId}` }); return; } // Gather comprehensive dashboard data const [metrics, alerts, scopeCreepDetected] = await Promise.all([ ScopeControlController.scopeControlService.getScopeMetrics(projectId), ScopeControlController.scopeControlService.getScopeAlerts(projectId), ScopeControlController.scopeControlService.detectScopeCreep(projectId) ]); // Calculate dashboard insights const dashboardData = { project: { id: project._id, name: project.name, status: project.status, framework: project.framework }, scopeControl: { metrics, alerts, scopeCreepDetected, healthScore: ScopeControlController.calculateHealthScore(metrics, alerts), riskLevel: ScopeControlController.calculateRiskLevel(metrics, alerts), recommendations: ScopeControlController.generateRecommendations(metrics, alerts, scopeCreepDetected) }, timestamp: new Date() }; res.status(200).json({ success: true, message: 'Scope control dashboard data retrieved successfully', data: dashboardData }); } catch (error) { logger.error('Failed to get scope control dashboard:', error); res.status(500).json({ success: false, message: 'Failed to retrieve scope control dashboard data', error: (error instanceof Error ? error.message : String(error)) }); } } // Helper methods static calculateHealthScore(metrics, alerts) { let score = 100; // Deduct points for various issues score -= metrics.scopeCreepIndex * 20; score -= (100 - metrics.pmbokComplianceScore) * 0.5; score -= alerts.filter(a => a.severity === 'critical').length * 15; score -= alerts.filter(a => a.severity === 'warning').length * 5; return Math.max(0, Math.min(100, score)); } static calculateRiskLevel(metrics, alerts) { const criticalAlerts = alerts.filter(a => a.severity === 'critical').length; const healthScore = ScopeControlController.calculateHealthScore(metrics, alerts); if (criticalAlerts > 0 || healthScore < 50) return 'critical'; if (metrics.scopeCreepIndex > 0.5 || healthScore < 70) return 'high'; if (metrics.scopeCreepIndex > 0.3 || healthScore < 85) return 'medium'; return 'low'; } static generateRecommendations(metrics, alerts, scopeCreepDetected) { const recommendations = []; if (scopeCreepDetected) { recommendations.push('Immediate scope review required - scope creep detected'); recommendations.push('Conduct emergency stakeholder alignment meeting'); } if (metrics.pmbokComplianceScore < 80) { recommendations.push('Improve PMBOK compliance documentation'); recommendations.push('Conduct PMBOK training for project team'); } if (metrics.changeVelocity > 2) { recommendations.push('Implement stricter change control procedures'); recommendations.push('Review change approval thresholds'); } if (alerts.filter(a => a.severity === 'critical').length > 0) { recommendations.push('Address critical scope control alerts immediately'); } if (recommendations.length === 0) { recommendations.push('Scope control is operating within acceptable parameters'); recommendations.push('Continue regular monitoring and maintain current practices'); } return recommendations; } } //# sourceMappingURL=ScopeControlController.js.map