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

357 lines 16.3 kB
import { DocumentReviewIntegration } from '../../services/DocumentReviewIntegration.js'; import { logger } from '../../utils/logger.js'; export class DocumentGenerationController { static integrationService = new DocumentReviewIntegration(); /** * Generate documents with automatic review creation */ static async generateWithReview(req, res, next) { try { const options = { projectId: req.body.projectId, projectName: req.body.projectName, context: req.body.context, enableReview: req.body.enableReview ?? true, reviewPriority: req.body.reviewPriority ?? 'medium', requiredRoles: req.body.requiredRoles, specificReviewers: req.body.specificReviewers, workflowId: req.body.workflowId, autoSubmitForReview: req.body.autoSubmitForReview ?? true, generateAll: req.body.generateAll ?? false, documentKeys: req.body.documentKeys, notifyOnCompletion: req.body.notifyOnCompletion ?? false, notificationRecipients: req.body.notificationRecipients }; // Validate required fields if (!options.projectId || !options.projectName || !options.context) { return res.status(400).json({ error: 'Missing required fields: projectId, projectName, context' }); } if (!options.generateAll && (!options.documentKeys || options.documentKeys.length === 0)) { return res.status(400).json({ error: 'Either generateAll must be true or documentKeys must be provided' }); } logger.info(`Starting document generation with review for project: ${options.projectName}`); const result = await DocumentGenerationController.integrationService.generateDocumentsWithReview(options); res.status(200).json({ success: result.generationResult.success, message: result.generationResult.message, generation: { documentsGenerated: result.summary.documentsGenerated, generatedFiles: result.generationResult.generatedFiles, duration: result.generationResult.duration, errors: result.generationResult.errors }, reviews: { reviewsCreated: result.summary.reviewsCreated, documentsSubmittedForReview: result.summary.documentsSubmittedForReview, documentsSkippedReview: result.summary.documentsSkippedReview, createdReviews: result.reviewsCreated.map(review => ({ id: review.id, documentName: review.documentName, status: review.status, priority: review.priority, dueDate: review.dueDate })) }, summary: result.summary, errors: result.errors }); } catch (error) { logger.error('Error in generate with review:', error); next(error); } } /** * Get project review status */ static async getProjectReviewStatus(req, res, next) { try { const { projectId } = req.params; if (!projectId) { return res.status(400).json({ error: 'Project ID is required' }); } const status = await DocumentGenerationController.integrationService.getProjectReviewStatus(projectId); res.json({ projectId, reviewStatus: status, completionPercentage: status.totalDocuments > 0 ? Math.round((status.completedReviews / status.totalDocuments) * 100) : 0, approvalRate: status.completedReviews > 0 ? Math.round((status.approvedDocuments / status.completedReviews) * 100) : 0 }); } catch (error) { logger.error('Error getting project review status:', error); next(error); } } /** * Regenerate document with feedback */ static async regenerateWithFeedback(req, res, next) { try { const { reviewId } = req.params; const { documentKey, context } = req.body; if (!reviewId || !documentKey || !context) { return res.status(400).json({ error: 'Missing required fields: reviewId (in params), documentKey, context' }); } logger.info(`Regenerating document with feedback for review: ${reviewId}`); const result = await DocumentGenerationController.integrationService.regenerateDocumentWithFeedback(reviewId, documentKey, context); if (result.success) { res.json({ success: true, message: 'Document regenerated successfully', newReviewId: result.newReviewId }); } else { res.status(400).json({ success: false, error: result.error }); } } catch (error) { logger.error('Error regenerating document with feedback:', error); next(error); } } /** * Bulk approve documents */ static async bulkApproveDocuments(req, res, next) { try { const { projectId } = req.params; const { documentIds } = req.body; if (!projectId || !documentIds || !Array.isArray(documentIds)) { return res.status(400).json({ error: 'Missing required fields: projectId (in params), documentIds (array)' }); } logger.info(`Bulk approving ${documentIds.length} documents for project: ${projectId}`); const result = await DocumentGenerationController.integrationService.bulkApproveDocuments(projectId, documentIds); res.json({ success: result.approved.length > 0, message: `Approved ${result.approved.length} documents, ${result.failed.length} failed`, approved: result.approved, failed: result.failed, errors: result.errors, summary: { totalRequested: documentIds.length, approved: result.approved.length, failed: result.failed.length } }); } catch (error) { logger.error('Error in bulk approve documents:', error); next(error); } } /** * Generate documents only (without review) */ static async generateDocumentsOnly(req, res, next) { try { const { context, generateAll, documentKeys } = req.body; if (!context) { return res.status(400).json({ error: 'Context is required' }); } if (!generateAll && (!documentKeys || documentKeys.length === 0)) { return res.status(400).json({ error: 'Either generateAll must be true or documentKeys must be provided' }); } // Use the existing DocumentGenerator directly const { DocumentGenerator } = await import('../../modules/documentGenerator/DocumentGenerator.js'); const generator = new DocumentGenerator(context); let result; if (generateAll) { result = await generator.generateAll(); } else { // Generate specific documents result = { success: true, successCount: 0, failureCount: 0, generatedFiles: [], errors: [], duration: 0, message: '' }; const startTime = Date.now(); for (const documentKey of documentKeys) { const success = await generator.generateOne(documentKey); if (success) { result.successCount++; result.generatedFiles.push(`${documentKey}.md`); } else { result.failureCount++; result.errors.push({ task: documentKey, error: 'Generation failed' }); } } result.duration = Date.now() - startTime; result.success = result.successCount > 0; result.message = `Generated ${result.successCount} documents`; } res.json({ success: result.success, message: result.message, documentsGenerated: result.successCount, documentsFailed: result.failureCount, generatedFiles: result.generatedFiles, duration: result.duration, errors: result.errors }); } catch (error) { logger.error('Error generating documents only:', error); next(error); } } /** * Generate documents with PMBOK validation and review */ static async generateWithValidationAndReview(req, res, next) { try { const options = { projectId: req.body.projectId, projectName: req.body.projectName, context: req.body.context, enableReview: true, // Always enable review for validation workflow reviewPriority: req.body.reviewPriority ?? 'high', // Higher priority for validated documents requiredRoles: req.body.requiredRoles ?? ['compliance_officer', 'subject_matter_expert'], specificReviewers: req.body.specificReviewers, workflowId: req.body.workflowId, autoSubmitForReview: true, generateAll: req.body.generateAll ?? true, documentKeys: req.body.documentKeys, notifyOnCompletion: req.body.notifyOnCompletion ?? true, notificationRecipients: req.body.notificationRecipients }; // Validate required fields if (!options.projectId || !options.projectName || !options.context) { return res.status(400).json({ error: 'Missing required fields: projectId, projectName, context' }); } logger.info(`Starting document generation with PMBOK validation and review for project: ${options.projectName}`); // Step 1: Generate documents with review const result = await DocumentGenerationController.integrationService.generateDocumentsWithReview(options); // Step 2: Run PMBOK validation on generated documents let validationResult = null; if (result.generationResult.success) { try { const { DocumentGenerator } = await import('../../modules/documentGenerator/DocumentGenerator.js'); const generator = new DocumentGenerator(options.context); validationResult = await generator.validatePMBOKCompliance(); } catch (validationError) { logger.error('Error running PMBOK validation:', validationError); result.errors.push(`PMBOK validation failed: ${validationError instanceof Error ? validationError.message : 'Unknown error'}`); } } res.status(200).json({ success: result.generationResult.success, message: result.generationResult.message, generation: { documentsGenerated: result.summary.documentsGenerated, generatedFiles: result.generationResult.generatedFiles, duration: result.generationResult.duration, errors: result.generationResult.errors }, validation: validationResult ? { compliance: validationResult.compliance, consistencyScore: validationResult.consistencyScore, documentQuality: validationResult.documentQuality } : null, reviews: { reviewsCreated: result.summary.reviewsCreated, documentsSubmittedForReview: result.summary.documentsSubmittedForReview, documentsSkippedReview: result.summary.documentsSkippedReview, createdReviews: result.reviewsCreated.map(review => ({ id: review.id, documentName: review.documentName, status: review.status, priority: review.priority, dueDate: review.dueDate, complianceScore: review.metadata?.complianceScore })) }, summary: { ...result.summary, validationCompleted: validationResult !== null, overallCompliance: validationResult?.compliance ?? false }, errors: result.errors }); } catch (error) { logger.error('Error in generate with validation and review:', error); next(error); } } /** * Get workflow status for a project */ static async getWorkflowStatus(req, res, next) { try { const { projectId } = req.params; if (!projectId) { return res.status(400).json({ error: 'Project ID is required' }); } // Get review status const reviewStatus = await DocumentGenerationController.integrationService.getProjectReviewStatus(projectId); // Calculate workflow progress const workflowStatus = { projectId, phase: 'unknown', progress: 0, reviewStatus, nextActions: [], blockers: [] }; // Determine current phase and progress if (reviewStatus.totalDocuments === 0) { workflowStatus.phase = 'generation'; workflowStatus.progress = 0; workflowStatus.nextActions.push('Generate project documents'); } else if (reviewStatus.pendingReviews > 0) { workflowStatus.phase = 'review'; workflowStatus.progress = Math.round((reviewStatus.completedReviews / reviewStatus.totalDocuments) * 100); workflowStatus.nextActions.push(`Complete ${reviewStatus.pendingReviews} pending reviews`); } else if (reviewStatus.completedReviews === reviewStatus.totalDocuments) { workflowStatus.phase = 'completed'; workflowStatus.progress = 100; workflowStatus.nextActions.push('All documents reviewed and approved'); } // Identify blockers if (reviewStatus.rejectedDocuments > 0) { workflowStatus.blockers.push(`${reviewStatus.rejectedDocuments} documents rejected - require revision`); } // Check for overdue reviews (would need additional data) // This is a placeholder - in a real implementation, you'd check due dates if (reviewStatus.pendingReviews > 0) { workflowStatus.blockers.push('Some reviews may be overdue'); } res.json(workflowStatus); } catch (error) { logger.error('Error getting workflow status:', error); next(error); } } } //# sourceMappingURL=DocumentGenerationController.js.map