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,33 @@
// src/rules-engine/actions/score.action.ts
import type { ActionHandler, ActionResult } from '../types/action.types';
import type { RuleAction, ScoreActionParams } from '../types/rule.types';
import { computeSlaMultiplier } from '../facts/call-facts.provider';
export class ScoreActionHandler implements ActionHandler {
type = 'score';
async execute(action: RuleAction, context: Record<string, any>): Promise<ActionResult> {
const params = action.params as ScoreActionParams;
let score = params.weight;
let slaApplied = false;
let campaignApplied = false;
if (params.slaMultiplier && context['call.slaElapsedPercent'] != null) {
score *= computeSlaMultiplier(context['call.slaElapsedPercent']);
slaApplied = true;
}
if (params.campaignMultiplier) {
const campaignWeight = (context['_campaignWeight'] ?? 5) / 10;
const sourceWeight = (context['_sourceWeight'] ?? 5) / 10;
score *= campaignWeight * sourceWeight;
campaignApplied = true;
}
return {
success: true,
data: { score, weight: params.weight, slaApplied, campaignApplied },
};
}
}