/** * Clinician Decision Support System * * Provides clinical decision support features: * - Treatment recommendations with explanations * - Override management and documentation * - Tumor board integration * - Evidence summaries * - Risk-benefit visualization * - Alert acknowledgment workflows * * Designed to augment (not replace) clinical judgment. */ import { EventEmitter } from 'events'; // ═══════════════════════════════════════════════════════════════════════════════ // DECISION SUPPORT TYPES // ═══════════════════════════════════════════════════════════════════════════════ export interface ClinicalRecommendation { id: string; patientId: string; generatedAt: Date; validUntil: Date; primaryRecommendation: { regimen: string; drugs: { name: string; dose: string; schedule: string; route: string }[]; setting: 'neoadjuvant' | 'adjuvant' | 'first-line' | 'second-line' | 'third-line-plus' | 'maintenance'; confidenceScore: number; }; alternativeOptions: { regimen: string; drugs: string[]; confidenceScore: number; comparisonToPrimary: string; }[]; supportingEvidence: { type: 'clinical-trial' | 'guideline' | 'real-world' | 'expert-consensus'; source: string; description: string; strength: 'strong' | 'moderate' | 'limited'; url?: string; }[]; biomarkerRationale: { biomarker: string; status: string; impact: string; evidenceLevel: string; }[]; predictions: { responseRate: { value: number; ci95: [number, number] }; medianPFS: { value: number; ci95: [number, number]; unit: 'months' }; medianOS: { value: number; ci95: [number, number]; unit: 'months' }; grade3PlusToxicity: { value: number; topRisks: string[] }; qualityOfLife: { score: number; considerations: string[] }; }; clinicalConsiderations: { category: 'efficacy' | 'safety' | 'practical' | 'cost'; consideration: string; importance: 'critical' | 'important' | 'notable'; }[]; monitoringPlan: { item: string; frequency: string; rationale: string; }[]; clinicalTrialOptions?: { nctId: string; title: string; phase: string; matchingBiomarkers: string[]; distance?: number; }[]; status: 'active' | 'accepted' | 'modified' | 'rejected' | 'expired'; reviewedBy?: string; reviewedAt?: Date; } export interface ClinicianOverride { id: string; recommendationId: string; patientId: string; clinicianId: string; clinicianName: string; clinicianRole: string; timestamp: Date; overrideType: 'full' | 'partial' | 'modification'; originalRecommendation: { regimen: string; drugs: string[]; }; selectedTreatment: { regimen: string; drugs: string[]; doses?: string[]; }; reason: { category: OverrideCategory; freeText: string; clinicalJustification: string; }; riskAcknowledgment?: { acknowledgedRisks: string[]; mitigationPlan?: string; signature: string; timestamp: Date; }; supervisorApproval?: { required: boolean; supervisorId?: string; supervisorName?: string; approved?: boolean; approvalTimestamp?: Date; comments?: string; }; auditStatus: 'pending-review' | 'reviewed' | 'flagged'; } export type OverrideCategory = | 'patient-preference' | 'comorbidity' | 'prior-treatment' | 'access-availability' | 'clinical-trial' | 'contraindication' | 'organ-function' | 'performance-status' | 'cost-coverage' | 'clinical-judgment' | 'other'; export interface TumorBoardCase { id: string; patientId: string; scheduledDate: Date; status: 'scheduled' | 'presented' | 'completed' | 'deferred'; presenter: { id: string; name: string; role: string; department: string; }; attendees: { id: string; name: string; specialty: string; present: boolean; }[]; caseSummary: { diagnosis: string; stage: string; relevantHistory: string; currentStatus: string; questionForBoard: string; }; systemRecommendation?: ClinicalRecommendation; boardDecision?: { recommendation: string; rationale: string; votingResult?: { agree: number; disagree: number; abstain: number }; dissenting_opinions?: string[]; followUpPlan: string; recordedBy: string; timestamp: Date; }; actions?: { action: string; assignedTo: string; dueDate?: Date; completed: boolean; }[]; } export interface AlertAcknowledgment { alertId: string; alertType: string; severity: 'critical' | 'high' | 'moderate' | 'low'; acknowledgedBy: string; acknowledgedAt: Date; action: 'proceed' | 'modify' | 'cancel' | 'defer'; reason?: string; signature: string; } // ═══════════════════════════════════════════════════════════════════════════════ // DECISION SUPPORT SERVICE // ═══════════════════════════════════════════════════════════════════════════════ export class ClinicalDecisionSupportService extends EventEmitter { private recommendations: Map = new Map(); private overrides: Map = new Map(); private tumorBoardCases: Map = new Map(); private alertAcknowledgments: AlertAcknowledgment[] = []; constructor() { super(); } /** * Generate a clinical recommendation */ async generateRecommendation(params: { patientId: string; cancerType: string; stage: string; biomarkers: { name: string; value: string | number; status?: string }[]; genomicAlterations: { gene: string; alteration: string }[]; priorTherapies?: string[]; performanceStatus?: number; comorbidities?: string[]; patientPreferences?: string[]; }): Promise { const id = `REC-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`; const now = new Date(); // Generate recommendation based on inputs // In production, this would call the ML prediction service and knowledge base const recommendation: ClinicalRecommendation = { id, patientId: params.patientId, generatedAt: now, validUntil: new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000), // 7 days primaryRecommendation: this.determinePrimaryRecommendation(params), alternativeOptions: this.determineAlternatives(params), supportingEvidence: this.gatherEvidence(params), biomarkerRationale: this.generateBiomarkerRationale(params.biomarkers, params.genomicAlterations), predictions: this.generatePredictions(params), clinicalConsiderations: this.identifyConsiderations(params), monitoringPlan: this.generateMonitoringPlan(params), clinicalTrialOptions: [], status: 'active' }; this.recommendations.set(id, recommendation); this.emit('recommendation-generated', recommendation); return recommendation; } /** * Get recommendation by ID */ getRecommendation(recommendationId: string): ClinicalRecommendation | undefined { return this.recommendations.get(recommendationId); } /** * Get recommendations for a patient */ getPatientRecommendations(patientId: string): ClinicalRecommendation[] { return Array.from(this.recommendations.values()) .filter(r => r.patientId === patientId) .sort((a, b) => b.generatedAt.getTime() - a.generatedAt.getTime()); } /** * Accept a recommendation */ async acceptRecommendation( recommendationId: string, clinicianId: string, clinicianName: string ): Promise { const rec = this.recommendations.get(recommendationId); if (!rec) throw new Error('Recommendation not found'); rec.status = 'accepted'; rec.reviewedBy = clinicianId; rec.reviewedAt = new Date(); this.emit('recommendation-accepted', { recommendationId, clinicianId, clinicianName, recommendation: rec.primaryRecommendation.regimen }); } /** * Record an override */ async recordOverride(override: Omit): Promise { const id = `OVR-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`; const fullOverride: ClinicianOverride = { ...override, id, timestamp: new Date(), auditStatus: this.requiresSupervisorApproval(override) ? 'pending-review' : 'reviewed' }; // Check if supervisor approval is required if (this.requiresSupervisorApproval(override)) { fullOverride.supervisorApproval = { required: true }; } // Update recommendation status const rec = this.recommendations.get(override.recommendationId); if (rec) { rec.status = override.overrideType === 'full' ? 'rejected' : 'modified'; rec.reviewedBy = override.clinicianId; rec.reviewedAt = new Date(); } // Store override const patientOverrides = this.overrides.get(override.patientId) || []; patientOverrides.push(fullOverride); this.overrides.set(override.patientId, patientOverrides); this.emit('override-recorded', fullOverride); return id; } /** * Check if supervisor approval is required */ private requiresSupervisorApproval(override: Omit): boolean { // Require approval for certain categories const requiresApproval = [ 'clinical-judgment', 'other' ]; if (requiresApproval.includes(override.reason.category)) return true; // Require approval if clinician is a trainee if (['resident', 'fellow', 'np-trainee', 'pa-trainee'].some(r => override.clinicianRole.toLowerCase().includes(r) )) { return true; } return false; } /** * Approve an override */ async approveOverride( overrideId: string, supervisorId: string, supervisorName: string, approved: boolean, comments?: string ): Promise { for (const [patientId, overrides] of this.overrides) { const override = overrides.find(o => o.id === overrideId); if (override && override.supervisorApproval) { override.supervisorApproval.supervisorId = supervisorId; override.supervisorApproval.supervisorName = supervisorName; override.supervisorApproval.approved = approved; override.supervisorApproval.approvalTimestamp = new Date(); override.supervisorApproval.comments = comments; override.auditStatus = approved ? 'reviewed' : 'flagged'; this.emit('override-reviewed', { overrideId, approved, supervisorName }); return; } } throw new Error('Override not found'); } /** * Get overrides for a patient */ getPatientOverrides(patientId: string): ClinicianOverride[] { return this.overrides.get(patientId) || []; } /** * Get pending approvals for a supervisor */ getPendingApprovals(): ClinicianOverride[] { const pending: ClinicianOverride[] = []; for (const overrides of this.overrides.values()) { for (const override of overrides) { if (override.supervisorApproval?.required && !override.supervisorApproval.approved) { pending.push(override); } } } return pending.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()); } /** * Create a tumor board case */ async createTumorBoardCase(caseData: Omit): Promise { const id = `TB-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`; const tumorBoardCase: TumorBoardCase = { ...caseData, id, status: 'scheduled', actions: [] }; // Attach active recommendation if available const recommendations = this.getPatientRecommendations(caseData.patientId); if (recommendations.length > 0 && recommendations[0].status === 'active') { tumorBoardCase.systemRecommendation = recommendations[0]; } this.tumorBoardCases.set(id, tumorBoardCase); this.emit('tumor-board-case-created', { caseId: id, patientId: caseData.patientId }); return id; } /** * Record tumor board decision */ async recordTumorBoardDecision( caseId: string, decision: TumorBoardCase['boardDecision'] ): Promise { const tbCase = this.tumorBoardCases.get(caseId); if (!tbCase) throw new Error('Tumor board case not found'); tbCase.boardDecision = decision; tbCase.status = 'completed'; this.emit('tumor-board-decision-recorded', { caseId, decision }); } /** * Acknowledge an alert */ async acknowledgeAlert(acknowledgment: Omit): Promise { const fullAcknowledgment: AlertAcknowledgment = { ...acknowledgment, acknowledgedAt: new Date() }; this.alertAcknowledgments.push(fullAcknowledgment); this.emit('alert-acknowledged', fullAcknowledgment); } /** * Generate explanation for a recommendation */ generateExplanation(recommendation: ClinicalRecommendation): { summary: string; detailedRationale: string[]; keyFactors: { factor: string; impact: 'positive' | 'negative' | 'neutral'; weight: number }[]; uncertainties: string[]; alternativeConsiderations: string[]; } { const summary = `Based on the patient's ${recommendation.biomarkerRationale.map(b => b.biomarker).join(', ')} status, ` + `${recommendation.primaryRecommendation.regimen} is recommended with ` + `${(recommendation.predictions.responseRate.value * 100).toFixed(0)}% expected response rate.`; const detailedRationale: string[] = []; // Add biomarker rationale for (const br of recommendation.biomarkerRationale) { detailedRationale.push(`${br.biomarker} ${br.status}: ${br.impact}`); } // Add evidence rationale for (const ev of recommendation.supportingEvidence.filter(e => e.strength === 'strong')) { detailedRationale.push(`${ev.source}: ${ev.description}`); } // Key factors const keyFactors = recommendation.biomarkerRationale.map(br => ({ factor: `${br.biomarker} ${br.status}`, impact: this.determineImpact(br.impact), weight: this.determineWeight(br.evidenceLevel) })); // Uncertainties const uncertainties: string[] = []; if (recommendation.predictions.responseRate.ci95[1] - recommendation.predictions.responseRate.ci95[0] > 0.3) { uncertainties.push('Response rate prediction has wide confidence interval'); } if (recommendation.supportingEvidence.every(e => e.strength !== 'strong')) { uncertainties.push('Limited strong evidence available for this combination'); } // Alternative considerations const alternativeConsiderations = recommendation.alternativeOptions.map(alt => `${alt.regimen}: ${alt.comparisonToPrimary}` ); return { summary, detailedRationale, keyFactors, uncertainties, alternativeConsiderations }; } /** * Generate risk-benefit analysis */ generateRiskBenefitAnalysis(recommendation: ClinicalRecommendation): { benefits: { benefit: string; magnitude: 'high' | 'moderate' | 'low'; confidence: number }[]; risks: { risk: string; probability: number; severity: 'severe' | 'moderate' | 'mild'; manageable: boolean }[]; overallAssessment: string; numberNeededToTreat?: number; numberNeededToHarm?: number; } { const benefits = [ { benefit: `${(recommendation.predictions.responseRate.value * 100).toFixed(0)}% objective response rate`, magnitude: recommendation.predictions.responseRate.value > 0.5 ? 'high' as const : recommendation.predictions.responseRate.value > 0.3 ? 'moderate' as const : 'low' as const, confidence: recommendation.primaryRecommendation.confidenceScore }, { benefit: `Median PFS ${recommendation.predictions.medianPFS.value.toFixed(1)} months`, magnitude: recommendation.predictions.medianPFS.value > 12 ? 'high' as const : recommendation.predictions.medianPFS.value > 6 ? 'moderate' as const : 'low' as const, confidence: recommendation.primaryRecommendation.confidenceScore } ]; const risks = recommendation.predictions.grade3PlusToxicity.topRisks.map((risk, i) => ({ risk, probability: recommendation.predictions.grade3PlusToxicity.value * (1 - i * 0.1), severity: 'moderate' as const, manageable: true })); // Calculate NNT (simplified) const baselineResponse = 0.2; // Assumed baseline const treatmentResponse = recommendation.predictions.responseRate.value; const absoluteBenefit = treatmentResponse - baselineResponse; const numberNeededToTreat = absoluteBenefit > 0 ? Math.ceil(1 / absoluteBenefit) : undefined; // Calculate NNH (simplified) const toxicityRate = recommendation.predictions.grade3PlusToxicity.value; const baselineToxicity = 0.1; const absoluteHarm = toxicityRate - baselineToxicity; const numberNeededToHarm = absoluteHarm > 0 ? Math.ceil(1 / absoluteHarm) : undefined; const overallAssessment = this.generateOverallAssessment(benefits, risks, numberNeededToTreat, numberNeededToHarm); return { benefits, risks, overallAssessment, numberNeededToTreat, numberNeededToHarm }; } // ═══════════════════════════════════════════════════════════════════════════════ // HELPER METHODS // ═══════════════════════════════════════════════════════════════════════════════ private determinePrimaryRecommendation(params: any): ClinicalRecommendation['primaryRecommendation'] { // Simplified logic - would use ML service in production let regimen = 'Standard therapy'; let drugs: ClinicalRecommendation['primaryRecommendation']['drugs'] = []; let confidenceScore = 0.75; // Check for biomarker-matched therapy const alterations = params.genomicAlterations || []; // EGFR mutation if (alterations.some((a: any) => a.gene === 'EGFR')) { regimen = 'Osimertinib'; drugs = [{ name: 'Osimertinib', dose: '80mg', schedule: 'Daily', route: 'Oral' }]; confidenceScore = 0.92; } // ALK fusion else if (alterations.some((a: any) => a.gene === 'ALK')) { regimen = 'Alectinib'; drugs = [{ name: 'Alectinib', dose: '600mg', schedule: 'BID', route: 'Oral' }]; confidenceScore = 0.90; } // PD-L1 high else if (params.biomarkers.some((b: any) => b.name.toLowerCase().includes('pd-l1') && parseFloat(b.value) >= 50 )) { regimen = 'Pembrolizumab'; drugs = [{ name: 'Pembrolizumab', dose: '200mg', schedule: 'Q3W', route: 'IV' }]; confidenceScore = 0.85; } // Default chemotherapy else { regimen = 'Carboplatin + Pemetrexed + Pembrolizumab'; drugs = [ { name: 'Carboplatin', dose: 'AUC 5', schedule: 'Q3W', route: 'IV' }, { name: 'Pemetrexed', dose: '500mg/m²', schedule: 'Q3W', route: 'IV' }, { name: 'Pembrolizumab', dose: '200mg', schedule: 'Q3W', route: 'IV' } ]; confidenceScore = 0.78; } return { regimen, drugs, setting: params.priorTherapies?.length > 0 ? 'second-line' : 'first-line', confidenceScore }; } private determineAlternatives(params: any): ClinicalRecommendation['alternativeOptions'] { // Generate 2-3 alternative options return [ { regimen: 'Clinical trial', drugs: ['Investigational agent'], confidenceScore: 0.7, comparisonToPrimary: 'Access to novel therapies; additional monitoring required' }, { regimen: 'Alternative standard therapy', drugs: ['Docetaxel'], confidenceScore: 0.65, comparisonToPrimary: 'Lower efficacy but familiar toxicity profile' } ]; } private gatherEvidence(params: any): ClinicalRecommendation['supportingEvidence'] { const evidence: ClinicalRecommendation['supportingEvidence'] = []; // Add guideline evidence evidence.push({ type: 'guideline', source: 'NCCN Guidelines', description: `Recommended for ${params.cancerType} stage ${params.stage}`, strength: 'strong', url: 'https://www.nccn.org/guidelines' }); // Add clinical trial evidence based on biomarkers if (params.genomicAlterations?.some((a: any) => a.gene === 'EGFR')) { evidence.push({ type: 'clinical-trial', source: 'FLAURA trial', description: 'Osimertinib improved median PFS vs 1st-gen TKI (18.9 vs 10.2 months)', strength: 'strong' }); } if (params.biomarkers?.some((b: any) => b.name.toLowerCase().includes('pd-l1') && parseFloat(b.value) >= 50 )) { evidence.push({ type: 'clinical-trial', source: 'KEYNOTE-024', description: 'Pembrolizumab improved OS vs chemotherapy in PD-L1 ≥50%', strength: 'strong' }); } return evidence; } private generateBiomarkerRationale( biomarkers: { name: string; value: string | number; status?: string }[], alterations: { gene: string; alteration: string }[] ): ClinicalRecommendation['biomarkerRationale'] { const rationale: ClinicalRecommendation['biomarkerRationale'] = []; for (const alt of alterations) { rationale.push({ biomarker: alt.gene, status: alt.alteration, impact: this.getBiomarkerImpact(alt.gene, alt.alteration), evidenceLevel: this.getBiomarkerEvidenceLevel(alt.gene) }); } for (const bm of biomarkers) { if (!rationale.some(r => r.biomarker === bm.name)) { rationale.push({ biomarker: bm.name, status: String(bm.value), impact: this.getBiomarkerImpact(bm.name, String(bm.value)), evidenceLevel: this.getBiomarkerEvidenceLevel(bm.name) }); } } return rationale; } private getBiomarkerImpact(biomarker: string, value: string): string { const impacts: Record = { 'EGFR': 'Sensitive to EGFR TKI therapy', 'ALK': 'Sensitive to ALK TKI therapy', 'BRAF': 'Sensitive to BRAF/MEK inhibitor combination', 'KRAS G12C': 'Sensitive to KRAS G12C inhibitors', 'PD-L1': parseFloat(value) >= 50 ? 'High likelihood of response to immunotherapy' : parseFloat(value) >= 1 ? 'May benefit from immunotherapy' : 'Consider immunotherapy combination', 'MSI-H': 'High likelihood of response to immunotherapy', 'TMB': 'May predict immunotherapy response' }; return impacts[biomarker] || 'Prognostic significance'; } private getBiomarkerEvidenceLevel(biomarker: string): string { const fdaApproved = ['EGFR', 'ALK', 'ROS1', 'BRAF', 'NTRK', 'RET', 'MET', 'KRAS G12C', 'HER2']; if (fdaApproved.includes(biomarker)) return 'FDA-approved'; const nccnRecommended = ['PD-L1', 'MSI-H', 'TMB']; if (nccnRecommended.includes(biomarker)) return 'NCCN-recommended'; return 'Clinical evidence'; } private generatePredictions(params: any): ClinicalRecommendation['predictions'] { // Simplified predictions - would use ML service in production let responseRate = 0.4; let pfs = 8; let os = 18; let toxicityRisk = 0.25; // Adjust based on biomarkers if (params.genomicAlterations?.some((a: any) => ['EGFR', 'ALK', 'ROS1'].includes(a.gene))) { responseRate = 0.75; pfs = 15; os = 30; toxicityRisk = 0.15; } // Adjust based on PD-L1 const pdl1 = params.biomarkers?.find((b: any) => b.name.toLowerCase().includes('pd-l1')); if (pdl1 && parseFloat(pdl1.value) >= 50) { responseRate = Math.max(responseRate, 0.45); } // Adjust based on performance status if (params.performanceStatus && params.performanceStatus >= 2) { responseRate *= 0.8; pfs *= 0.7; os *= 0.7; toxicityRisk *= 1.3; } return { responseRate: { value: responseRate, ci95: [responseRate * 0.8, Math.min(responseRate * 1.2, 0.95)] }, medianPFS: { value: pfs, ci95: [pfs * 0.75, pfs * 1.3], unit: 'months' }, medianOS: { value: os, ci95: [os * 0.7, os * 1.4], unit: 'months' }, grade3PlusToxicity: { value: toxicityRisk, topRisks: ['Neutropenia', 'Fatigue', 'Nausea'] }, qualityOfLife: { score: 0.75, considerations: ['Oral therapy allows home administration', 'Weekly monitoring during first cycle'] } }; } private identifyConsiderations(params: any): ClinicalRecommendation['clinicalConsiderations'] { const considerations: ClinicalRecommendation['clinicalConsiderations'] = []; // Performance status if (params.performanceStatus && params.performanceStatus >= 2) { considerations.push({ category: 'safety', consideration: 'Consider dose reduction due to performance status', importance: 'critical' }); } // Prior therapy if (params.priorTherapies && params.priorTherapies.length > 2) { considerations.push({ category: 'efficacy', consideration: 'Heavily pretreated patient - consider clinical trial', importance: 'important' }); } // Comorbidities if (params.comorbidities?.some((c: string) => c.toLowerCase().includes('renal'))) { considerations.push({ category: 'safety', consideration: 'Dose adjustment may be needed for renal impairment', importance: 'critical' }); } return considerations; } private generateMonitoringPlan(params: any): ClinicalRecommendation['monitoringPlan'] { return [ { item: 'CBC with differential', frequency: 'Before each cycle', rationale: 'Monitor for myelosuppression' }, { item: 'Comprehensive metabolic panel', frequency: 'Before each cycle', rationale: 'Monitor liver/kidney function' }, { item: 'Imaging (CT chest/abdomen)', frequency: 'Every 8-12 weeks', rationale: 'Response assessment (RECIST)' }, { item: 'Clinical assessment', frequency: 'Each visit', rationale: 'Monitor for adverse events' } ]; } private determineImpact(impactText: string): 'positive' | 'negative' | 'neutral' { if (impactText.toLowerCase().includes('sensitive') || impactText.toLowerCase().includes('response') || impactText.toLowerCase().includes('benefit')) { return 'positive'; } if (impactText.toLowerCase().includes('resistant') || impactText.toLowerCase().includes('poor')) { return 'negative'; } return 'neutral'; } private determineWeight(evidenceLevel: string): number { const weights: Record = { 'FDA-approved': 1.0, 'NCCN-recommended': 0.9, 'Clinical evidence': 0.7, 'Preclinical': 0.3 }; return weights[evidenceLevel] || 0.5; } private generateOverallAssessment( benefits: { magnitude: string }[], risks: { severity: string; probability: number }[], nnt?: number, nnh?: number ): string { const highBenefits = benefits.filter(b => b.magnitude === 'high').length; const severeRisks = risks.filter(r => r.severity === 'severe' && r.probability > 0.1).length; if (highBenefits >= 2 && severeRisks === 0) { return 'Favorable risk-benefit profile. Treatment strongly recommended.'; } if (highBenefits >= 1 && severeRisks <= 1) { return 'Acceptable risk-benefit profile. Treatment recommended with appropriate monitoring.'; } if (severeRisks >= 2) { return 'Elevated risk profile. Consider alternatives or enhanced monitoring if proceeding.'; } return 'Moderate risk-benefit profile. Individual patient factors should guide decision.'; } /** * Export decision data for quality review */ exportDecisionData(startDate: Date, endDate: Date): { recommendations: ClinicalRecommendation[]; overrides: ClinicianOverride[]; tumorBoardCases: TumorBoardCase[]; summary: { totalRecommendations: number; acceptanceRate: number; overrideRate: number; commonOverrideReasons: { reason: OverrideCategory; count: number }[]; }; } { const recommendations = Array.from(this.recommendations.values()) .filter(r => r.generatedAt >= startDate && r.generatedAt <= endDate); const allOverrides = Array.from(this.overrides.values()).flat() .filter(o => o.timestamp >= startDate && o.timestamp <= endDate); const cases = Array.from(this.tumorBoardCases.values()) .filter(c => c.scheduledDate >= startDate && c.scheduledDate <= endDate); // Calculate summary statistics const accepted = recommendations.filter(r => r.status === 'accepted').length; const overridden = recommendations.filter(r => r.status === 'modified' || r.status === 'rejected').length; // Count override reasons const reasonCounts = new Map(); for (const override of allOverrides) { const count = reasonCounts.get(override.reason.category) || 0; reasonCounts.set(override.reason.category, count + 1); } const commonOverrideReasons = Array.from(reasonCounts.entries()) .map(([reason, count]) => ({ reason, count })) .sort((a, b) => b.count - a.count); return { recommendations, overrides: allOverrides, tumorBoardCases: cases, summary: { totalRecommendations: recommendations.length, acceptanceRate: recommendations.length > 0 ? accepted / recommendations.length : 0, overrideRate: recommendations.length > 0 ? overridden / recommendations.length : 0, commonOverrideReasons } }; } } export default ClinicalDecisionSupportService;