Escalation — Routing & Team Ownership
Purpose
This page explains how Escalation Routing works in HUPH: the cluster ownership model, when escalations fire, how notifications are routed to the right counselor, and how to reassign clusters. Intended for counselors, marketing staff, and admins managing team allocation.
Prerequisites
- Logged in with the appropriate role (cluster counselor, marketing_staff, marketing_admin, or admin)
- Understand Leads pipeline and Inbox
The 5 Clusters and Counselor Teams
HUPH organizes UPH's programs into 5 academic clusters:
| Cluster Code | Cluster Name |
|---|---|
| CASS | College of Arts & Social Sciences |
| CBT | College of Business & Technology |
| CHS | College of Health Sciences |
| CIST | College of Information Science & Technology |
| CNE | College of Nursing & Education |
Each cluster has counselors with role marketing_counselor and their
own cluster code. Besides per-cluster counselors there are two global
roles: marketing_staff and marketing_admin who receive all
notifications.
Ownership Model (Hybrid-lite)
Every lead has a cluster_id and an owner_source that determines
who "owns" the lead. Three owner sources:
| owner_source | Meaning | Priority |
|---|---|---|
| program_match | Auto — from the program the user mentioned | Weakest (fluid) |
| register_intent | Auto — from a "want_register" intent in chat | Strong (locks) |
| manual | Admin override via UI | Strongest (always wins) |
Truth table:
- New lead arrives → cluster is resolved from
program_interest→owner_source = program_match. If the user switches programs in a later message, the cluster moves automatically. - If a
want_registerintent is detected + contact is captured →owner_sourceupgrades toregister_intent, the cluster is locked (owner_locked_at = NOW()). Futureprogram_matchchanges no longer flip the cluster. - Admin clicks Reassign in the UI →
owner_source = manual+ lock. This is final — only another admin can change it.
When Escalation Fires
There are 3 seeded escalation rules (more can be added at
/admin/settings/escalation-rules):
- Frustrated user → counselor — fires when sentiment = frustrated (priority: high)
- Long conversation no resolution — fires when message count > 15 and stage still inquiry (priority: medium)
- Hot lead notification — fires when lead_score ≥ 80 (notify-only, doesn't escalate)
Rules 1 and 2: action = escalate → conversations.status flips to
escalated, bot pauses, notifications go to the cluster counselor +
global recipients.
Rule 3: action = notify → status does NOT change, only a
notification fires (bot keeps running).
Two Notification Kinds
| Kind | Title | When |
|---|---|---|
| escalation | "Escalation: |
Escalate rule fires |
| notify | "Hot lead: |
Notify rule fires |
Steps
1. See incoming notifications
Notifications appear on the bell icon in the admin header. Click to open the panel showing escalations + hot leads. New rows appear in realtime via Socket.io (without refresh).
┌─────────────────────────────────────────────┐
│ 🔔 3 new │
│ │
│ ⚠ Escalation: Request human help │
│ Cluster CBT • 2 minutes ago │
│ │
│ 🔥 Hot lead: Rudi H. │
│ Score 85 — Informatics • 5m ago │
│ │
│ ⚠ Escalation: Complaint │
│ Cluster CASS • 15m ago │
└─────────────────────────────────────────────┘
2. Notification scope per role
Who gets what?
- marketing_counselor (cluster X) → only escalations for cluster X + hot leads for cluster X
- marketing_staff → all escalations and hot leads (global)
- marketing_admin → all (global)
If cluster_id is NULL (legacy/unresolvable lead), notifications go
only to marketing_staff + marketing_admin.
3. Reassign cluster from lead detail
Sometimes a counselor from cluster A realizes a lead should belong to
cluster B (e.g. user said "interested in Business" but the resolver
mis-matched). From the lead detail page /admin/leads-v2/[id]:
- See the cluster badge + owner_source label in the header ("Auto via program" / "Auto via register" / "Manual by admin")
- Click the Reassign dropdown → pick the new cluster (5 clusters
- "Unassign")
- A ConfirmDialog appears ("Are you sure?") → confirm
owner_sourcebecomesmanual,owner_locked_at=NOW— final lock
The change propagates to conversations.cluster_id via trigger — the
associated conversation immediately moves to the new cluster's
Socket.io room.
4. Filter leads by cluster
In /admin/leads-v2, the first filter chip row shows cluster counts:
CASS(10) CBT(11) CHS(4) CIST(0) CNE(0) unassigned(3). Click one to
filter. Counselors from cluster X see the same badge counts but only
get access to cluster X (after Phase 1.5 RBAC is active).
5. Counselor dashboard view
Each counselor has a /admin/counselor-dashboard page (Phase 1.6)
that shows:
- Only leads from that counselor's cluster
- Pending escalation queue that needs action
- Counselor KPIs: conversion rate, response time, leads contacted
- Shortcut to the inbox filtered by cluster
Example scenarios
User chats "I want to register" — cluster locked. Rudi chats via WhatsApp, initially asks about Animation (CASS), then provides name+phone and says "I want to register". Flow: pre-pass upsert → cluster CASS + program_match. Post-dispatch register_intent detected + contact captured → second upsert → cluster stays CASS but owner_source upgrades to register_intent, locked. If Rudi later mentions a CBT program, the cluster won't flip.
Admin reassigns from CBT to CHS. A marketing admin sees on a lead detail that "Budi Santoso" is in cluster CBT because he mentioned "Business", but his real intent is "Medicine" (CHS). Admin clicks Reassign → CHS → confirm. The lead is now CHS + manual. The CHS counselor gets a new notification in their queue; the CBT counselor no longer has access.
Troubleshooting
Counselor doesn't get a notification even though the lead is in
their cluster. Symptom: CBT lead escalated but the CBT counselor
doesn't see the bell icon update. Cause: conversations.cluster_id
is NULL (propagation trigger didn't run), or the counselor wasn't
logged in when the event fired. Fix: open the lead detail from the
list → verify the cluster badge → if NULL, reassign manually. If
it's correct, refresh the dashboard.
Wrong cluster assignment for a clearly-matched program. Symptom:
user mentions "Informatics" but ends up in CASS (should be CIST).
Cause: incomplete cluster_programs mapping — program name didn't
match exactly or by prefix. Fix: admin reassign manually; report to
the dev team to update the cluster_programs table.
Duplicate notifications from 2 rule fires. Symptom: user frustrated + long conversation → 2 notifications for the same event. Cause: dedup not yet implemented. Fix: ignore the duplicate; dedup is being considered for a later phase.
"Unauthorized" when opening a lead from another cluster. Symptom: CBT counselor clicks a CASS lead link in a notification → 403. Cause: RBAC Phase 1.5 is active — counselors can only access their own cluster. Fix: contact an admin for assignment or reassignment.
See also
- Inbox — Take Over flow that triggers escalation
- Leads pipeline — cluster filter and lead detail
- Troubleshooting — other dashboard issues