127 lines
12 KiB
Markdown
127 lines
12 KiB
Markdown
# 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:
|
|
```js
|
|
{
|
|
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>' }],
|
|
}
|
|
```
|
|
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 `createdAt ≤ assignedAt ≤ verifiedAt ≤ 2026-05-29`. Spread across states: ~2 Verified, ~2 Unverified/Failed Contact, several Assigned/In Progress, a few Pending/Unassigned, 1 `Emergency — 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)` → status `Assigned`, verificationStatus `Pending Outreach` (if was Unassigned), set assignee + `assignedAt`, append history.
|
|
- `reassignLeadVerification(id, assigneeId, assigneeName)` → swap assignee, append history.
|
|
- `setLeadVerificationStatus(id, newStatus, note)` → set `status` (+ derive a sensible `verificationStatus`), append history with note.
|
|
- `verifyLead(id)` → set `status:'Verified'`, `verificationStatus:'Verified'`, `verifiedAt`, append history `"Verified and pushed to New Leads"`, AND **push a New Lead onto `leads`** matching OUR lead schema (read `seedLeadsFromAttribution()` 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 splitting `customerName`.
|
|
- `unverifyLead(id, note)` → `status:'Unverified'`, append history.
|
|
- `addLeadVerificationNote(id, note)` → append to `history`.
|
|
- [ ] **Step 3 — expose** `leadVerifications` + the 6 mutators on the context `value` object (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 to `src/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"` (after `git 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 `AssignLeadModal` lists assignees — point it at our canonical admins (a1/a2/a3) from the store (`users`/`personnel` filtered to ADMIN), not any hardcoded source list. The source-filter options derive from the records' `source` values; the assignee-filter from `assigneeName`.
|
|
- [ ] **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:
|
|
```jsx
|
|
<Route path="/lead-verification" element={
|
|
<ProtectedRoute allowedRoles={['OWNER', 'ADMIN', 'FIELD_AGENT']}>
|
|
<LeadVerificationPage />
|
|
</ProtectedRoute>
|
|
} />
|
|
```
|
|
(Unified per our Plan-2 direction; interim coarse guard — Plan 8 ABAC replaces it. Do NOT add the source's three role-prefixed routes.)
|
|
- [ ] **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). Import `ShieldCheck` from lucide-react if not already imported.
|
|
- [ ] **Step 3 (verify):** `npm run build` → `✓ built`. `git grep -n "/lead-verification" -- src/App.jsx src/components/Layout.jsx` shows 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 build` clean, 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 grep` for 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`) with `createdByName: '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-verification` reachable 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; `verifyLead` pushes a schema-correct New Lead into `leads`.
|
|
- [ ] `ui/Select` + all `LeadVerification/` files + page ported; imports resolve; reference only T1's store keys.
|
|
- [ ] Unified `/lead-verification` route + 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.
|