From 0488b161f26885044c392c13abb96a2fe5c0aa6b Mon Sep 17 00:00:00 2001 From: Satyam Rastogi Date: Fri, 29 May 2026 20:56:45 +0530 Subject: [PATCH] docs: lead verification design spec (adapted port, grounded data) --- .../2026-05-29-lead-verification-design.md | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-29-lead-verification-design.md diff --git a/docs/superpowers/specs/2026-05-29-lead-verification-design.md b/docs/superpowers/specs/2026-05-29-lead-verification-design.md new file mode 100644 index 0000000..9f967d8 --- /dev/null +++ b/docs/superpowers/specs/2026-05-29-lead-verification-design.md @@ -0,0 +1,87 @@ +# 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.