mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage-server
synced 2026-05-18 20:08:19 +00:00
feat: suggestion rules engine + caller context evaluation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
152
src/rules-engine/suggestion-rules.ts
Normal file
152
src/rules-engine/suggestion-rules.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
export type SuggestionType = 'upsell' | 'crosssell' | 'retention' | 'operational';
|
||||
export type SuggestionPriority = 'high' | 'medium' | 'low';
|
||||
|
||||
export type SuggestionTrigger = {
|
||||
type: SuggestionType;
|
||||
title: string;
|
||||
reason: string;
|
||||
priority: SuggestionPriority;
|
||||
};
|
||||
|
||||
type CallerFacts = {
|
||||
isNew: boolean;
|
||||
interestedService: string | null;
|
||||
leadStatus: string | null;
|
||||
contactAttempts: number;
|
||||
appointments: Array<{ status: string; department: string; doctorName: string; scheduledAt: string }>;
|
||||
calls: Array<{ direction: string; disposition: string | null; startedAt: string }>;
|
||||
utmCampaign: string | null;
|
||||
leadSource: string | null;
|
||||
};
|
||||
|
||||
const DEPARTMENT_PACKAGES: Record<string, { package: string; description: string }> = {
|
||||
CARDIOLOGY: { package: 'Cardiac Wellness Package', description: 'ECG, stress test, lipid panel' },
|
||||
ORTHOPEDICS: { package: 'Joint Care Package', description: 'X-ray, physiotherapy assessment, bone density' },
|
||||
GENERAL_MEDICINE: { package: 'Full Body Checkup', description: 'Complete health screening with blood work' },
|
||||
NEUROLOGY: { package: 'Neuro Wellness Package', description: 'EEG, nerve conduction, cognitive assessment' },
|
||||
GYNECOLOGY: { package: 'Women\'s Health Package', description: 'Pap smear, mammogram, hormone panel' },
|
||||
};
|
||||
|
||||
const CROSS_SELL_MAP: Record<string, { department: string; reason: string }> = {
|
||||
ORTHOPEDICS: { department: 'Physiotherapy', reason: 'complement orthopedic treatment' },
|
||||
CARDIOLOGY: { department: 'Dietician', reason: 'dietary guidance for heart health' },
|
||||
GENERAL_MEDICINE: { department: 'Ophthalmology', reason: 'routine eye screening' },
|
||||
};
|
||||
|
||||
export const evaluateSuggestionRules = (facts: CallerFacts): SuggestionTrigger[] => {
|
||||
const triggers: SuggestionTrigger[] = [];
|
||||
|
||||
// Rule 1: Package upsell by department
|
||||
for (const appt of facts.appointments) {
|
||||
const dept = (appt.department ?? '').toUpperCase().replace(/\s+/g, '_');
|
||||
const pkg = DEPARTMENT_PACKAGES[dept];
|
||||
if (pkg && appt.status === 'SCHEDULED') {
|
||||
triggers.push({
|
||||
type: 'upsell',
|
||||
title: pkg.package,
|
||||
reason: `Patient has ${appt.department} appointment with ${appt.doctorName}, offer ${pkg.description}`,
|
||||
priority: 'high',
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Rule 2: Reschedule missed/cancelled appointments
|
||||
const needsReschedule = facts.appointments.find(a =>
|
||||
a.status === 'CANCELLED' || a.status === 'RESCHEDULED' || a.status === 'NO_SHOW'
|
||||
);
|
||||
if (needsReschedule) {
|
||||
triggers.push({
|
||||
type: 'retention',
|
||||
title: 'Reschedule appointment',
|
||||
reason: `Last ${needsReschedule.department} appointment was ${needsReschedule.status.toLowerCase()}, offer to rebook with ${needsReschedule.doctorName}`,
|
||||
priority: 'medium',
|
||||
});
|
||||
}
|
||||
|
||||
// Rule 3: Cross-sell related department
|
||||
for (const appt of facts.appointments) {
|
||||
const dept = (appt.department ?? '').toUpperCase().replace(/\s+/g, '_');
|
||||
const cross = CROSS_SELL_MAP[dept];
|
||||
if (cross && appt.status === 'SCHEDULED') {
|
||||
triggers.push({
|
||||
type: 'crosssell',
|
||||
title: `${cross.department} consultation`,
|
||||
reason: `${cross.reason} — patient already seeing ${appt.department}`,
|
||||
priority: 'low',
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Rule 4: First-visit patient — health checkup
|
||||
if (facts.isNew || facts.contactAttempts === 0) {
|
||||
triggers.push({
|
||||
type: 'upsell',
|
||||
title: 'Welcome Health Checkup',
|
||||
reason: 'First-time patient, offer introductory health screening package',
|
||||
priority: 'medium',
|
||||
});
|
||||
}
|
||||
|
||||
// Rule 5: Returning patient with no recent appointment
|
||||
if (!facts.isNew && facts.appointments.length === 0 && facts.contactAttempts > 2) {
|
||||
triggers.push({
|
||||
type: 'retention',
|
||||
title: 'Re-engagement',
|
||||
reason: `Returning patient with ${facts.contactAttempts} prior contacts but no active appointments`,
|
||||
priority: 'high',
|
||||
});
|
||||
}
|
||||
|
||||
return triggers.slice(0, 4);
|
||||
};
|
||||
|
||||
// For display in Settings > Automations (read-only cards)
|
||||
export const SUGGESTION_RULE_DEFINITIONS = [
|
||||
{
|
||||
name: 'Package Upsell by Department',
|
||||
category: 'upsell' as const,
|
||||
description: 'Suggest department wellness package when patient has a scheduled appointment.',
|
||||
trigger: 'On call connect',
|
||||
condition: 'Scheduled appointment exists',
|
||||
action: 'Suggest department package',
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
name: 'Reschedule Missed Appointment',
|
||||
category: 'retention' as const,
|
||||
description: 'Offer to rebook when patient has a cancelled or rescheduled appointment.',
|
||||
trigger: 'On call connect',
|
||||
condition: 'Cancelled/Rescheduled/No-show appointment exists',
|
||||
action: 'Suggest rebooking',
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
name: 'Cross-sell Related Department',
|
||||
category: 'crosssell' as const,
|
||||
description: 'Suggest complementary department service based on current appointment.',
|
||||
trigger: 'On call connect',
|
||||
condition: 'Scheduled appointment in mapped department',
|
||||
action: 'Suggest related service',
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
name: 'First Visit Health Checkup',
|
||||
category: 'upsell' as const,
|
||||
description: 'Suggest introductory health screening for first-time patients.',
|
||||
trigger: 'On call connect',
|
||||
condition: 'New patient or zero contact attempts',
|
||||
action: 'Suggest health checkup package',
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
name: 'Returning Patient Re-engagement',
|
||||
category: 'retention' as const,
|
||||
description: 'Prompt re-engagement for returning patients with no active appointments.',
|
||||
trigger: 'On call connect',
|
||||
condition: 'Returning patient, no appointments, 3+ contacts',
|
||||
action: 'Suggest booking',
|
||||
enabled: true,
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user