12 KiB
Lead Verification Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: superpowers:subagent-driven-development. Steps use checkbox (
- [ ]). Follow the execution protocol (2026-05-29-execution-protocol.md) — sequential on shared files, parallel only where lanes are disjoint.
Goal: Add a pre-pipeline Lead Verification stage — a verification-team queue (assign → work → verify/unverify) that, on verify, pushes a real New Lead into our existing leads pipeline. Adapted port from gitea/bugfix/project-refinement (commits 567b29c, 8a4d577), re-authored against our canonical data.
Architecture: New leadVerifications data + 6 mutators in mockStore.jsx (verify writes into our enriched leads array); a reusable portaled ui/Select; the ported LeadVerification/ component set + page; a unified /lead-verification route + sidebar nav. Components reuse our existing useMockStore/usePermissions/SpotlightCard/framer-motion/lucide — so the port is mostly verbatim; the real work is grounding the data and wiring.
Tech Stack: React 18, Vite 7, mock React-context store, framer-motion, lucide-react, pnpm. No test harness → verify via npm run build + grep + dev-run.
Spec: docs/superpowers/specs/2026-05-29-lead-verification-design.md. Source branch: gitea/bugfix/project-refinement (already fetched; pull source files with git show gitea/bugfix/project-refinement:<path>).
File structure
| File | Responsibility | New/Mod |
|---|---|---|
src/data/mockStore.jsx |
MOCK_LEAD_VERIFICATIONS (15 grounded records) + leadVerifications state + 6 mutators (verify → leads) |
Modify |
src/components/ui/Select.jsx |
Reusable portaled dark-mode-aware dropdown | Create |
src/components/LeadVerification/statusConfig.js |
Status → visuals/icons map | Create |
src/components/LeadVerification/{SummaryCards,LeadTableRow,LeadCard,LeadStatusBadge,LeadActionsMenu,AssignLeadModal,LeadDetailsModal}.jsx |
Table/cards/badges/menus/modals | Create |
src/pages/LeadVerification/LeadVerificationPage.jsx |
The page: summary tiles + filters + table/cards + modals | Create |
src/App.jsx |
/lead-verification route |
Modify |
src/components/Layout.jsx |
sidebar nav entry | Modify |
Lane / ownership map
| Task | Lane (exclusive files) | Phase |
|---|---|---|
| T1 Data + mutators | src/data/mockStore.jsx |
A |
| T2 ui/Select | new src/components/ui/Select.jsx |
A (parallel — disjoint) |
| T3 Components + page | new src/components/LeadVerification/* + src/pages/LeadVerification/LeadVerificationPage.jsx |
B (after T1+T2) |
| T4 Route + nav | src/App.jsx, src/components/Layout.jsx |
C (after T3) |
| T5 Verify | (read-only) | D |
T1 and T2 are disjoint → parallel. T3 imports both (store mutators + Select). T4 imports the page. T5 last.
Task 1: Lead-verification data + mutators
Files: src/data/mockStore.jsx only.
The source has MOCK_LEAD_VERIFICATIONS + assignLeadVerification/reassignLeadVerification/setLeadVerificationStatus/verifyLead/unverifyLead/addLeadVerificationNote. Read the source for the mutator logic (git show gitea/bugfix/project-refinement:src/data/mockStore.jsx — search leadVerifications/verifyLead ~lines 6700-6810), but re-author the DATA to our grounded standards and adapt verifyLead to OUR leads schema.
- Step 1 — record shape + 15 grounded records. Add
const MOCK_LEAD_VERIFICATIONS = [ ... ]near the other mock arrays. Each record:Grounding (per spec): verifiers = canonical admins a1 Wade Hollis / a2 Darlene Brooks / a3 Roy Schaefer; customers = realistic varied Plano homeowners (NO placeholders/movie names/sequential fakes); phones varied DFW (972/469/214/945), en-US; real Plano addresses+zips; status ↔ verificationStatus internally consistent (Verified↔Verified; In Progress↔a working state; Unassigned↔no assignee); dates{ id: 'lv_001', leadId: 'LD-V-001', customerName: '<realistic Plano homeowner>', phone: '<varied DFW, en-US, NOT (972) 555-0NNN>', email: '<name-derived>', address: '<real Plano street>, Plano, TX <zip>', source: '<Door Knock | Storm Canvass | Web Form | Call Center | Referral>', status: '<Pending | Assigned | In Progress | Verified | Unverified>', verificationStatus: '<Unassigned | Pending Outreach | Awaiting Confirmation | Verifying Identity | Reviewing Insurance | Emergency — Awaiting Verifier | Failed Contact | Verified>', assigneeId: '<a1|a2|a3|null>', assigneeName: '<Wade Hollis|Darlene Brooks|Roy Schaefer|null>', urgency: '<standard|high|emergency>', createdAt: '<ISO>', assignedAt: '<ISO|null>', verifiedAt: '<ISO|null>', verificationNotes: '<short realistic note>', history: [{ at: '<ISO>', by: '<person>', action: '<text>' }], }createdAt ≤ assignedAt ≤ verifiedAt ≤ 2026-05-29. Spread across states: ~2 Verified, ~2 Unverified/Failed Contact, several Assigned/In Progress, a few Pending/Unassigned, 1Emergency — Awaiting Verifier. - Step 2 — state + mutators. Add
const [leadVerifications, setLeadVerifications] = useState(MOCK_LEAD_VERIFICATIONS);. Port the 6 mutators (adapt names/logic from source):assignLeadVerification(id, assigneeId, assigneeName)→ statusAssigned, verificationStatusPending Outreach(if was Unassigned), set assignee +assignedAt, append history.reassignLeadVerification(id, assigneeId, assigneeName)→ swap assignee, append history.setLeadVerificationStatus(id, newStatus, note)→ setstatus(+ derive a sensibleverificationStatus), append history with note.verifyLead(id)→ setstatus:'Verified',verificationStatus:'Verified',verifiedAt, append history"Verified and pushed to New Leads", AND push a New Lead ontoleadsmatching OUR lead schema (readseedLeadsFromAttribution()for the exact shape —{ id:'lead_'+Date.now(), createdAt, status:'New', firstName, lastName, address, city:'Plano', state:'TX', zip, urgency, leadSource, phones:[{number,type:'Mobile',isPrimary:true}], emails:[{email,isPrimary:true}], createdByName:'Lead Verification', verificationId:id }). Derive firstName/lastName by splittingcustomerName.unverifyLead(id, note)→status:'Unverified', append history.addLeadVerificationNote(id, note)→ append tohistory.
- Step 3 — expose
leadVerifications+ the 6 mutators on the contextvalueobject (object-shorthand, matching the existing pattern). - Step 4 (verify):
npm run build→✓ built, 0 duplicate-key warnings.git grep -c "verificationStatus:" -- src/data/mockStore.jsx≥ 15.git grep -nE "\(972\) 555-0[0-9]{3}"shows none introduced. Spot-check 3 records: status↔verificationStatus consistent, assignees are real admins. - Step 5: commit
git commit -am "feat(data): lead-verification queue + mutators (verify pushes a grounded New Lead into the pipeline)".
Task 2: Reusable ui/Select
Files: Create src/components/ui/Select.jsx. Parallel with T1.
- Step 1: Create the file with the source content verbatim (it's framework-only — React + framer-motion + lucide, no app deps):
git show gitea/bugfix/project-refinement:src/components/ui/Select.jsx→ write it tosrc/components/ui/Select.jsx. It's a portaled dropdown (props:value, onChange, options:[{value,label}]|string[], placeholder, id, ariaLabel, className) that renders correctly in dark mode. - Step 2 (verify):
npm run build→✓ built(it's unused until T3, so the bundler tree-shakes it — that's fine; the build just confirms it parses).node -e "..."not needed. - Step 3: commit
git commit -am "feat(ui): add reusable portaled dark-mode-aware Select component"(aftergit add src/components/ui/Select.jsx).
Task 3: LeadVerification components + page
Files: Create src/components/LeadVerification/{statusConfig.js, SummaryCards.jsx, LeadStatusBadge.jsx, LeadActionsMenu.jsx, LeadTableRow.jsx, LeadCard.jsx, AssignLeadModal.jsx, LeadDetailsModal.jsx} and src/pages/LeadVerification/LeadVerificationPage.jsx. After T1 + T2.
- Step 1: For EACH file, pull the source with
git show gitea/bugfix/project-refinement:<path>and create it in our tree. The imports already match our codebase (../../data/mockStore,../../hooks/usePermissions,../../components/SpotlightCard,../ui/Select, framer-motion, lucide) — keep them. - Step 2: Verify the page/components reference the SAME store keys T1 exposed:
leadVerifications,assignLeadVerification,reassignLeadVerification,setLeadVerificationStatus,verifyLead,unverifyLead,addLeadVerificationNote. If any source name differs from T1, reconcile to T1's names (T1 is the source of truth). - Step 3: The
AssignLeadModallists assignees — point it at our canonical admins (a1/a2/a3) from the store (users/personnelfiltered to ADMIN), not any hardcoded source list. The source-filter options derive from the records'sourcevalues; the assignee-filter fromassigneeName. - Step 4 (verify):
npm run build→✓ built, 0 duplicate-key warnings. Grep that the page imports resolve and reference only T1's store keys. - Step 5: commit
git commit -am "feat(leadverification): port verification page + components (table, cards, summary, assign/verify modals)".
Task 4: Route + nav
Files: src/App.jsx, src/components/Layout.jsx. After T3.
- Step 1 (App.jsx): import
LeadVerificationPage(import LeadVerificationPage from './pages/LeadVerification/LeadVerificationPage';). Add ONE unified route:(Unified per our Plan-2 direction; interim coarse guard — Plan 8 ABAC replaces it. Do NOT add the source's three role-prefixed routes.)<Route path="/lead-verification" element={ <ProtectedRoute allowedRoles={['OWNER', 'ADMIN', 'FIELD_AGENT']}> <LeadVerificationPage /> </ProtectedRoute> } /> - Step 2 (Layout.jsx): add a nav entry
{ to: "/lead-verification", icon: ShieldCheck, label: "Lead Verification" }to the OWNER, ADMIN, and FIELD_AGENT nav arrays (after the "Leads" entry). ImportShieldCheckfrom lucide-react if not already imported. - Step 3 (verify):
npm run build→✓ built.git grep -n "/lead-verification" -- src/App.jsx src/components/Layout.jsxshows the route + nav entries. - Step 4: commit
git commit -am "feat(routes): add /lead-verification route + sidebar nav".
Task 5: Verify (read-only)
npm run buildclean, 0 duplicate-key warnings.- 15 verification records; summary tiles' counts equal the per-status record counts (computed, not hardcoded); filters (status/source/assignee) narrow the list.
- No fake names/placeholders in the records (
git grepfor movie names /(972) 555-0NNN→ none); assignees are a1/a2/a3. - The verify→pipeline link (headline): dev-run → open
/lead-verification, verify a record → it leaves the active queue (status Verified) AND a matching New Lead appears in the Leads list (/…/leads) withcreatedByName: 'Lead Verification', and that new lead opens in the lead detail page (Plan 6) with no broken fields. - Assign / reassign / set-status / unverify / add-note persist in session and update the table + badges.
/lead-verificationreachable from the sidebar for OWNER/ADMIN/FIELD_AGENT.
Self-review checklist
- 15 grounded verification records (real admins/customers/addresses/sources; no fakes; status↔verificationStatus consistent; coherent dates).
- 6 mutators exposed;
verifyLeadpushes a schema-correct New Lead intoleads. ui/Select+ allLeadVerification/files + page ported; imports resolve; reference only T1's store keys.- Unified
/lead-verificationroute + nav for the 3 roles; source's RBAC/access-matrix changes NOT ported. - Build clean; verify→New Lead works end-to-end into the existing pipeline.