88 lines
7.8 KiB
Markdown
88 lines
7.8 KiB
Markdown
# Lead Verification — Design Spec
|
||
|
||
**Status:** Approved direction (adapted port from `gitea/bugfix/project-refinement`). Feeds an implementation plan.
|
||
|
||
## Purpose
|
||
|
||
Add the **pre-pipeline lead-verification stage** the CRM is missing. Inbound leads (door-knock, storm canvass, web form, call center, referral) land in a **verification queue** where a verification/call-center team confirms they're real — identity, insurance, reachability — before they enter the sales pipeline. This is a **B2B-first** internal tool (the roofing company's verification desk), not a customer-facing surface.
|
||
|
||
It exists on the old lineage (`gitea/bugfix/project-refinement`, commits `567b29c` "adds lead verification module" + `8a4d577`) as a self-contained module. Our `revamp` branch has diverged heavily (Plans 1–7), so this is an **adapted port** — bring the UI + flow, re-author the data against our canonical model, wire it to our existing `leads` pipeline.
|
||
|
||
## Why it fits (no duplication)
|
||
|
||
`verifyLead(id)` in the source module **auto-converts a verified record into a New Lead** pushed onto the `leads` array. That `leads` array is exactly the one we enriched (Plan 3) and made clickable with a detail page (Plan 6). So the chain becomes:
|
||
|
||
```
|
||
Lead Verification queue → (verify) → New Lead in `leads` → Kanban pipeline → Project (PRJ-2026-###)
|
||
```
|
||
|
||
It sits *upstream* of everything we've built and reuses our pipeline as its output. Nothing we built is duplicated or replaced.
|
||
|
||
## The flow & states
|
||
|
||
Two status axes (both preserved from the source):
|
||
- **Coarse `status`** (drives summary tiles + primary badge): `Pending → Assigned → In Progress → Verified | Unverified`.
|
||
- **Granular `verificationStatus`** (the work detail): `Unassigned`, `Pending Outreach`, `Awaiting Confirmation`, `Verifying Identity`, `Reviewing Insurance`, `Emergency — Awaiting Verifier`, `Failed Contact`, `Verified`.
|
||
|
||
Transitions:
|
||
- A new record is `Pending` / `Unassigned`.
|
||
- **Assign** to a verifier → `Assigned` / `Pending Outreach`.
|
||
- Verifier works it → `In Progress` with a granular `verificationStatus` (Verifying Identity / Reviewing Insurance / etc.).
|
||
- **Verify** → `Verified` (record leaves the active queue) **and a New Lead is pushed to `leads`** (linked back via `verificationId`).
|
||
- **Unverify** (e.g. Failed Contact) → `Unverified` with a reason note.
|
||
- Notes can be added at any point (audit trail).
|
||
|
||
## Data model (into `src/data/mockStore.jsx`)
|
||
|
||
- `MOCK_LEAD_VERIFICATIONS` — ~15 records, re-keyed to our world. Per record (shape from source, adapted): `{ id, leadId, customerName, phone, email, address, source, status, verificationStatus, assigneeId, assigneeName, assignedAt, verifiedAt, urgency, verificationNotes, history:[{ at, by, action }] }`.
|
||
- **Assignees/verifiers** = our canonical **admins** as the verification desk: a1 Wade Hollis, a2 Darlene Brooks, a3 Roy Schaefer (field agents may also appear). No fake names.
|
||
- **Sources** = our real lead sources: Door Knock, Storm Canvass, Web Form, Call Center, Referral.
|
||
- **Customers** = realistic Plano homeowners (varied; not the existing pipeline customers — these are *new* inbound).
|
||
- A spread across all states so the demo shows every status (a couple Verified, a couple Unverified/Failed Contact, several in-progress/assigned/pending, one "Emergency — Awaiting Verifier").
|
||
- `leadVerifications` state + the 6 mutators on the context value:
|
||
- `assignLeadVerification(id, assigneeId, assigneeName)` → Assigned / Pending Outreach.
|
||
- `reassignLeadVerification(id, assigneeId, assigneeName)`.
|
||
- `setLeadVerificationStatus(id, newStatus, note?)`.
|
||
- `verifyLead(id)` → marks Verified + appends history + **pushes a New Lead onto `leads`** using OUR enriched lead schema (firstName/lastName, address/city/state, phones:[{number,type,isPrimary}], emails, leadSource, status:'New', createdByName:'Lead Verification', verificationId).
|
||
- `unverifyLead(id, note)`.
|
||
- `addLeadVerificationNote(id, note)`.
|
||
|
||
## UI (ported components, adapted imports)
|
||
|
||
- `src/components/ui/Select.jsx` — the dark-mode-aware select (reusable; also lets us standardise dropdowns). **New shared component.**
|
||
- `src/components/LeadVerification/` — `statusConfig.js`, `SummaryCards.jsx`, `LeadTableRow.jsx`, `LeadCard.jsx`, `LeadStatusBadge.jsx`, `LeadActionsMenu.jsx`, `AssignLeadModal.jsx`, `LeadDetailsModal.jsx`.
|
||
- `src/pages/LeadVerification/LeadVerificationPage.jsx` — summary tiles (counts per status) + search + filters (status / source / assignee) + a responsive table (desktop) / cards (mobile) + the assign / reassign / verify / unverify / view modals. Uses `usePermissions` (we already have the hook) for action gating.
|
||
|
||
## Routing & nav
|
||
|
||
- Add a **single unified route** `/lead-verification` → `LeadVerificationPage`, gated `allowedRoles={['OWNER','ADMIN','FIELD_AGENT']}` (interim coarse guard; **Plan 8 ABAC** replaces it). (Per our Plan-2 unified-route direction — not the source's three role-prefixed routes.)
|
||
- Add a nav entry ("Lead Verification") for the relevant roles in the sidebar/layout.
|
||
|
||
## Explicitly NOT ported
|
||
|
||
- The source's **access-control-matrix / RBAC** changes (commit `7b485a4`) — our **Plan 8 ABAC** supersedes them. Gate with the existing coarse `ProtectedRoute` for now.
|
||
- Their old-lineage mockStore wholesale — only the verification slice is ported, re-authored against our canonical roster.
|
||
|
||
## Grounding requirements (must be real, coherent data — not placeholders)
|
||
|
||
The source module's `MOCK_LEAD_VERIFICATIONS` is **not** copied verbatim — it is re-authored to our standards:
|
||
- **Real people, no fakes.** Verifiers/assignees are the canonical admins (Wade Hollis / Darlene Brooks / Roy Schaefer); customer names are realistic Plano/DFW homeowners (no "John Smith", "Alice Customer", movie characters, or sequential placeholders). Phones use varied real DFW area codes (972/469/214/945) formatted en-US, never `(972) 555-0NNN` sequences.
|
||
- **Real places & sources.** Addresses are real Plano street/zip combos; sources are the company's actual channels (Door Knock, Storm Canvass, Web Form, Call Center, Referral). Storm-sourced records should reference the same storm-season framing used elsewhere.
|
||
- **Computed, not hardcoded, summaries.** The summary tiles (counts per status) and any totals are derived from the `leadVerifications` array at render — never hardcoded numbers. (Same compute-don't-hardcode rule as the dashboards.)
|
||
- **Coherent dates.** `assignedAt` ≤ `verifiedAt` ≤ DEMO_TODAY (2026-05-29); history timestamps strictly increasing; created dates realistic for an inbound queue.
|
||
- **Verify produces a real, coherent lead.** The New Lead pushed onto `leads` matches our enriched schema so it renders correctly in the Leads list AND opens in the lead detail page (Plan 6) with no empty/broken fields.
|
||
- **Internally consistent.** A record's `status` and `verificationStatus` agree (e.g. `Verified` coarse ↔ `Verified` granular; `In Progress` ↔ a working granular state); an `Assigned`/`In Progress` record has a real assignee; `Unassigned` has none.
|
||
|
||
## Acceptance
|
||
|
||
- Build clean (0 duplicate-key warnings).
|
||
- The page lists 15 verification records with correct per-status summary tiles; filters (status/source/assignee) work; assignees are canonical admins (no fake names).
|
||
- **Verify** a record → it leaves the active queue as Verified AND a matching New Lead appears in the Leads list (`/…/leads`) with `createdByName: 'Lead Verification'`; the new lead opens in the lead detail page (Plan 6).
|
||
- Assign / reassign / set-status / unverify / add-note all persist in session and reflect in the table + badges.
|
||
- `/lead-verification` reachable from nav for OWNER/ADMIN/FIELD_AGENT.
|
||
|
||
## Reuse / dependencies
|
||
- `usePermissions` hook — already present.
|
||
- Our enriched `leads` schema (Plan 3/6) — the verify output target.
|
||
- `components/ui/Select` — newly ported; reusable across the app.
|