feat: rules engine — json-rules-engine integration with worklist scoring

- Self-contained NestJS module: types, storage (Redis+JSON), fact providers, action handlers
- PriorityConfig CRUD (slider values for task weights, campaign weights, source weights)
- Score action handler with SLA multiplier + campaign multiplier formula
- Worklist consumer: scores and ranks items before returning
- Hospital starter template (7 rules)
- REST API: /api/rules/* (CRUD, priority-config, evaluate, templates)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-01 16:59:10 +05:30
parent 7b59543d36
commit b8556cf440
20 changed files with 959 additions and 3 deletions

View File

@@ -0,0 +1,89 @@
{
"priorityConfig": {
"taskWeights": {
"missed_call": { "weight": 9, "slaMinutes": 720, "enabled": true },
"follow_up": { "weight": 8, "slaMinutes": 1440, "enabled": true },
"campaign_lead": { "weight": 7, "slaMinutes": 2880, "enabled": true },
"attempt_2": { "weight": 6, "slaMinutes": 1440, "enabled": true },
"attempt_3": { "weight": 4, "slaMinutes": 2880, "enabled": true }
},
"campaignWeights": {},
"sourceWeights": {
"WHATSAPP": 9, "PHONE": 8, "FACEBOOK_AD": 7, "GOOGLE_AD": 7,
"INSTAGRAM": 5, "WEBSITE": 7, "REFERRAL": 6, "WALK_IN": 5, "OTHER": 5
}
},
"rules": [
{
"ruleType": "priority",
"name": "Missed calls — high urgency",
"description": "Missed calls get highest priority with SLA-based urgency",
"enabled": true,
"priority": 1,
"trigger": { "type": "on_request", "request": "worklist" },
"conditions": { "all": [{ "fact": "call.taskType", "operator": "equal", "value": "missed_call" }] },
"action": { "type": "score", "params": { "weight": 9, "slaMultiplier": true } }
},
{
"ruleType": "priority",
"name": "Scheduled follow-ups",
"description": "Committed callbacks from prior calls",
"enabled": true,
"priority": 2,
"trigger": { "type": "on_request", "request": "worklist" },
"conditions": { "all": [{ "fact": "call.taskType", "operator": "equal", "value": "follow_up" }] },
"action": { "type": "score", "params": { "weight": 8, "slaMultiplier": true } }
},
{
"ruleType": "priority",
"name": "Campaign leads — weighted",
"description": "Outbound campaign calls, weighted by campaign importance",
"enabled": true,
"priority": 3,
"trigger": { "type": "on_request", "request": "worklist" },
"conditions": { "all": [{ "fact": "call.taskType", "operator": "equal", "value": "campaign_lead" }] },
"action": { "type": "score", "params": { "weight": 7, "slaMultiplier": true, "campaignMultiplier": true } }
},
{
"ruleType": "priority",
"name": "2nd attempt — medium urgency",
"description": "First call went unanswered, try again",
"enabled": true,
"priority": 4,
"trigger": { "type": "on_request", "request": "worklist" },
"conditions": { "all": [{ "fact": "call.taskType", "operator": "equal", "value": "attempt_2" }] },
"action": { "type": "score", "params": { "weight": 6, "slaMultiplier": true } }
},
{
"ruleType": "priority",
"name": "3rd attempt — lower urgency",
"description": "Two prior unanswered attempts",
"enabled": true,
"priority": 5,
"trigger": { "type": "on_request", "request": "worklist" },
"conditions": { "all": [{ "fact": "call.taskType", "operator": "equal", "value": "attempt_3" }] },
"action": { "type": "score", "params": { "weight": 4, "slaMultiplier": true } }
},
{
"ruleType": "priority",
"name": "Spam leads — deprioritize",
"description": "High spam score leads get pushed down",
"enabled": true,
"priority": 10,
"trigger": { "type": "on_request", "request": "worklist" },
"conditions": { "all": [{ "fact": "lead.spamScore", "operator": "greaterThan", "value": 60 }] },
"action": { "type": "score", "params": { "weight": -3 } }
},
{
"ruleType": "automation",
"name": "SLA breach — escalate to supervisor",
"description": "Alert supervisor when callback SLA is breached",
"enabled": true,
"priority": 1,
"status": "draft",
"trigger": { "type": "on_schedule", "interval": "5m" },
"conditions": { "all": [{ "fact": "call.slaBreached", "operator": "equal", "value": true }, { "fact": "call.callbackStatus", "operator": "equal", "value": "PENDING_CALLBACK" }] },
"action": { "type": "escalate", "params": { "channel": "notification", "recipients": "supervisor", "message": "SLA breached — no callback attempted", "severity": "critical" } }
}
]
}