Skip to content

Leads Pipeline — Prospective-Student Prospects

Purpose

This page explains how HUPH's Leads Pipeline works: how prospects are automatically captured from WhatsApp conversations, how their stage is managed, and how to use the /leads-v2 page for follow-up. Intended for counselors and marketing staff whose job is to turn leads into enrolled students.

Prerequisites

  • Logged in as counselor or marketing
  • WhatsApp channel active (Web & Telegram are no longer used as of April 2026)
  • LEAD_CAPTURE_ENABLED=true in env (default, no change needed)

Lead vs Conversation

A lead is NOT the same as a conversation:

  • Conversation = the stream of messages between the user and bot/counselor
  • Lead = a structured record containing the user's contact data (name, phone, email, program interest) extracted from the conversation

One conversation can produce 0 or 1 lead. One lead can have many conversations (if the user WAs in multiple times).

Lead Stages

Real DB enum: incomplete | new | contacted | qualified | enrolled | lost.

Stage Meaning When reached
incomplete Capture not yet complete Only the name detected, phone/email missing
new Basic contact data complete, not yet contacted Name + phone/email present, just formed
contacted Counselor has reached out Counselor clicks "Mark Contacted" on detail page
qualified Serious lead, deserves heavier follow-up Contacted + showing register/visit intent
enrolled Officially enrolled Manual update by admission admin after form submitted
lost Uninterested / unreachable Manual mark by counselor

Steps

1. Open Leads Pipeline

Click Leads in the sidebar, then Leads v2 (URL: /admin/leads-v2). You see the leads list with 30-second polling — data auto-refreshes without reload.

 ┌────────────────────────────────────────────────────┐
 │ Filter: [actionable] [all] [new] [qualified] …     │
 │ Search: [_________]                                │
 │                                                    │
 │ Name          Phone         Stage      Updated     │
 │ ──────────────────────────────────────────────────  │
 │ Budi Santoso  +628123…      new        5m ago      │
 │ Siti Aulia    +628567…      qualified  1h ago      │
 │ Rudi Hartono  +628901…      contacted  3h ago      │
 └────────────────────────────────────────────────────┘

Filter chips: actionable (non-enrolled, non-lost), all, or per-stage (new, qualified, etc). Default is actionable — focus on leads that need action.

Search: type a name, phone, or email → instant filter.

3. Open lead detail

Click a row → the detail page /admin/leads-v2/[id]. Detail shows:

  • Full contact info (name, formatted phone, email, program interest if any)
  • Status actions — Mark Contacted, Mark Qualified, Mark Enrolled, Mark Lost buttons
  • Source conversation — link to the origin conversation
  • Capture metadata — when name/phone/email were first detected and from which message

4. Update stage

Click the appropriate action — e.g. Mark Contacted after you reply to the user via WhatsApp. The stage updates and the polling refreshes the list view too.

5. How capture works behind the scenes

HUPH's contact extractor uses a 4-tier hybrid pipeline:

  1. Regex Layer 1 (always on) — detects Indonesian patterns like "nama saya X", "panggil X", phone format 62xxx
  2. LLM Layer 2 (gated) — Claude Haiku is called when capture is active, or the share_personal_info intent is detected, or the regex hit is weak
  3. State machine for multi-turn slot filling (awaiting_name → awaiting_email → captured), 6-hour TTL
  4. Lead store atomic upsert on (user_id, channel)

Counselors don't need to trigger anything manually — it all runs automatically from the first WhatsApp message.

6. Analytics overview

From the sidebar Leads → Analytics v2 (/admin/analytics-v2), you will see about 13 charts: lead growth, stage distribution, funnel conversion, source breakdown, counselor performance, etc. All charts are near real-time (30s polling).

Example scenarios

Follow up this morning's qualified leads. Open /admin/leads-v2, filter by qualified, see 6 new leads. The counselor opens each one, replies via WhatsApp with an intro template + info-session invitation. After sending, clicks Mark Contacted on the detail page. Within a minute the other counselors' lists are refreshed too.

Monday-morning weekly review. Marketing opens /admin/analytics-v2 → looks at the weekly Lead Growth chart: 127 new leads Mon–Sun, 34 qualified. Exports CSV for the head-of-admission report.

Troubleshooting

Lead stuck at "incomplete" even though the user provided all info. Symptom: the list shows a lead as incomplete even though the user chatted full details like "my name is Rudi, phone 081234, email rudi@..". Cause: the LLM extractor may have failed or timed out. Fix: open the detail → check the capture metadata → if name, phone, and email are all present, manually Advance Stage to new. If it still errors, report to dev team — the feature flag LEAD_CAPTURE_ENABLED may be off.

New lead doesn't appear 5 minutes after user chat. Symptom: user WAs in and provides a name but nothing shows in /leads-v2. Cause: possibly a webhook delay or a stuck state machine. Fix: refresh the page (Ctrl+Shift+R), check the filter (may be hidden by the default actionable), then check Conversations to see if the thread actually exists.

Analytics v2 numbers don't match the list count. Symptom: the list shows 26 leads but Analytics says 28. Cause: 30s polling + aggregate delay — a few seconds of lag between list and chart. Fix: refresh after 1 minute; it usually reconciles.

Cannot "Mark Enrolled". Symptom: the Mark Enrolled button is disabled or missing. Cause: the enrolled stage can only be set by admission admins (role-gated). Fix: escalate to an admin for the update.

See also

  • Inbox — see the source conversation of a lead
  • Follow-up — automated re-engagement for leads
  • Escalation — how cluster ownership affects counselor access to leads