From 10450b05de1fb4242c9cabf004a766326d87aaf9 Mon Sep 17 00:00:00 2001 From: Satyam Rastogi Date: Fri, 29 May 2026 02:17:15 +0530 Subject: [PATCH] docs: implementation plan for demo data foundation (phases 1-3) --- .../plans/2026-05-29-demo-data-foundation.md | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 docs/superpowers/plans/2026-05-29-demo-data-foundation.md diff --git a/docs/superpowers/plans/2026-05-29-demo-data-foundation.md b/docs/superpowers/plans/2026-05-29-demo-data-foundation.md new file mode 100644 index 0000000..795ca54 --- /dev/null +++ b/docs/superpowers/plans/2026-05-29-demo-data-foundation.md @@ -0,0 +1,282 @@ +# Demo Data Foundation Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Make the mock data internally coherent — one canonical identity scheme, reconciling financials, and no empty/broken views — as the foundation for the larger demo build. + +**Architecture:** All edits are to `src/data/mockStore.jsx` (a ~6,950-line mock store) plus a few consuming components. Changes are surgical and additive. A new `resolvePerson(id)` selector gives every module one consistent way to look up people. Verification is by `npm run build` + `grep` reconciliation + dev-run, since the project has no unit-test harness. + +**Tech Stack:** React 18, Vite 7, mock React-context store (`useMockStore`), pnpm. + +**Spec:** `docs/superpowers/specs/2026-05-29-demo-data-coherence-design.md` (Phases 1–3). + +**Scope of this plan:** Phase 1 (canonical identity), Phase 2 (financial coherence), Phase 3 (feature-breaking fixes). Phases 4–10 are separate plans. + +--- + +## Canonical ID reference (used throughout) + +The canonical scheme is the `MOCK_USERS` one. Remap everything else to it: + +| Entity | Canonical id | Name | Old ids to replace | +|--------|-------------|------|--------------------| +| Owner 1 | `own_001` | Justin Johnson | `owner_001` | +| Owner 2 | `own_002` | Diana Reeves | `owner_002`, and name "Maria Garcia" | +| Admin 1 | `a1` | Adam Admin | `ADM01`, name "Admin One" | +| Admin 2 | `a2` | Amanda Manager | `ADM02`, name "Admin Two" | +| Admin 3 | `a3` | Arthur Director | `ADM03`, name "Admin Three" | +| Field agent 1 | `e1` | Frank Agent | `FA001` | +| Field agent 2 | `e2` | Fiona Field | `FA002` | +| Field agent 3 | `e3` | Fred Flyer | `FA003` | +| Field agent 4 | `e4` | Felicity Fast | `FA004` | +| Field agent 5 | `e5` | Felix Fixer | `FA005` | +| Justin email | — | `justin@lynkeduppro.com` | `justin@johnsondev.com` (reconcile to one — use lynkeduppro.com everywhere) | + +Org role taxonomy (`orgMembers[].roleKey`: OWNER/ADMIN/SALES_REP/CANVASSER/SUBCONTRACTOR) stays as-is; only the `userId` it points to changes. + +--- + +## File structure + +- **Modify:** `src/data/mockStore.jsx` — identity remap, `resolvePerson`, financial fixes, breakdowns, `leads` seed, sub logins, task↔project fixes, kanban lead values, `DEMO_TODAY`. +- **Modify:** `src/pages/owner/SubcontractorTasksPage.jsx`, `src/components/subcontractor/TaskViewModal.jsx` — add `On Hold` styling. +- **Create:** none in this plan. + +--- + +## Task 1: Add `DEMO_TODAY` constant + +**Files:** +- Modify: `src/data/mockStore.jsx` (near top, after imports) +- Modify: `src/components/kanban/KanbanCard.jsx:14` (replace hardcoded date) + +- [ ] **Step 1: Add the constant** near the top of `mockStore.jsx` (after the import lines): + +```jsx +// Fixed "today" for the demo so seeded dates never go stale or land in the future. +export const DEMO_TODAY = new Date('2026-05-29T12:00:00'); +``` + +- [ ] **Step 2: Use it in KanbanCard.** In `src/components/kanban/KanbanCard.jsx` replace the hardcoded `new Date('2026-04-07')` (line ~14) with an import + use: + +```jsx +import { DEMO_TODAY } from '../../data/mockStore'; +// ... +const NOW = DEMO_TODAY; // was: new Date('2026-04-07') +``` + +- [ ] **Step 3: Verify build.** Run: `npm run build` — Expected: `✓ built` with no errors. +- [ ] **Step 4: Commit.** + +```bash +git add src/data/mockStore.jsx src/components/kanban/KanbanCard.jsx +git commit -m "chore(data): add DEMO_TODAY anchor and use it for kanban day-counter" +``` + +--- + +## Task 2: Add `resolvePerson` selector + +**Files:** +- Modify: `src/data/mockStore.jsx` — add a memoized people index + `resolvePerson` exposed on the store context value. + +- [ ] **Step 1: Build a merged people index** inside the provider (after the people collections are defined, before the `value={{...}}`): + +```jsx +// One lookup for any person across users/personnel/owners/subcontractors. +const peopleIndex = useMemo(() => { + const idx = {}; + const add = (p) => { if (p?.id && !idx[p.id]) idx[p.id] = p; }; + [...(users || []), ...(personnel || []), ...(owners || []), + ...(subcontractors || [])].forEach(add); + return idx; +}, [users, personnel, owners, subcontractors]); + +const resolvePerson = (id) => { + const p = peopleIndex[id]; + if (!p) return { id, name: 'Unknown', email: '', role: '' }; + return { id: p.id, name: p.name || p.fullName || 'Unknown', email: p.email || p.emailAddress || '', role: p.role || '' }; +}; +``` + +- [ ] **Step 2: Expose it** on the context value object (add `resolvePerson,` to the `value={{ ... }}`). +- [ ] **Step 3: Verify build.** Run: `npm run build` — Expected: `✓ built`. +- [ ] **Step 4: Commit.** + +```bash +git add src/data/mockStore.jsx +git commit -m "feat(data): add resolvePerson selector over a merged people index" +``` + +--- + +## Task 3: Remap `orgMembers` to canonical ids + fix names + +**Files:** +- Modify: `src/data/mockStore.jsx` — the `orgMembers` useState array. + +- [ ] **Step 1: Apply the ID + name remap** in `orgMembers` using the Canonical ID reference table: + - `userId: 'owner_001'` → `'own_001'` (name "Justin Johnson", email `justin@lynkeduppro.com`) + - `userId: 'owner_002'` → `'own_002'`, **name "Maria Garcia" → "Diana Reeves"**, email → Diana's canonical email from `MOCK_USERS` + - `userId: 'ADM01'/'ADM02'/'ADM03'` → `'a1'/'a2'/'a3'`, **names "Admin One/Two/Three" → "Adam Admin"/"Amanda Manager"/"Arthur Director"** + - `userId: 'FA001'..'FA005'` → `'e1'..'e5'` (names already match) +- [ ] **Step 2: Verify no stale ids remain.** Run: + +```bash +git grep -nE "owner_00[12]|ADM0[123]|FA00[12345]" -- src/data/mockStore.jsx +``` + +Expected: **no matches in `orgMembers`** (matches may still exist in subcontractor tasks — fixed in Task 4). Confirm none are in the `orgMembers` block. + +- [ ] **Step 3: Verify build.** Run: `npm run build` — Expected: `✓ built`. +- [ ] **Step 4: Commit.** + +```bash +git add src/data/mockStore.jsx +git commit -m "fix(data): remap orgMembers to canonical ids; reconcile Owner #2 + admin names" +``` + +--- + +## Task 4: Remap subcontractor-task person references + +**Files:** +- Modify: `src/data/mockStore.jsx` — `MOCK_SUBCONTRACTOR_TASKS` (and `MOCK_NOTIFICATIONS` actor ids). + +- [ ] **Step 1: Replace ids** in every task's `assignedBy`, `actorId`, `senderId`, and status/thread rows: + - `'owner_001'` → `'own_001'` + - `'ADM01'` → `'a1'` + - Update the denormalized `assignedByName`/`actorName`/`senderName` so "Admin One" → "Adam Admin" and any owner name → "Justin Johnson". +- [ ] **Step 2: Verify no stale ids remain anywhere.** Run: + +```bash +git grep -nE "owner_00[12]|\bADM0[123]\b|FA00[12345]" -- src/data/mockStore.jsx +``` + +Expected: **no matches** (all remapped). + +- [ ] **Step 3: Verify build.** Run: `npm run build` — Expected: `✓ built`. +- [ ] **Step 4: Commit.** + +```bash +git add src/data/mockStore.jsx +git commit -m "fix(data): remap subcontractor task/notification actor ids to canonical scheme" +``` + +--- + +## Task 5: Financial coherence — fix the flagged projects + +**Files:** +- Modify: `src/data/mockStore.jsx` — the `projects` array. + +Reference (from audit): rules = breakdown `allocated`→budget, `committed`→committedCost, `actual`→actualCost; `committed ≥ actual`; `variancePercent = (actualCost − budget)/budget × 100`. + +- [ ] **Step 1: proj_005** — set top-level `committedCost: 28850` (matches the breakdown's committed sum). Leave actualCost 14200 (breakdown actual sum). Recompute `variancePercent = (14200−28000)/28000×100 = -49.3`. +- [ ] **Step 2: proj_008** — reduce paid invoices so the paid total ≤ `actualCost` (44500). Adjust the invoice `amount`s / `status` so `Σ paid ≤ 44500` and `Σ paid ≤ committedCost (52000)`. +- [ ] **Step 3: proj_002 & proj_010** (completed) — reduce paid invoices so `Σ paid ≤ actualCost` (6200 and 23800 respectively). +- [ ] **Step 4: proj_004** — in `budgetBreakdown`, fix the Contingency line so `committed ≥ actual` (raise committed to ≥ 11500, keeping the over-budget total intact). +- [ ] **Step 5: Add `budgetBreakdown`** to proj_006, 008, 009, 010, 011, 012. Each: 4–7 line items where `allocated` sums to the project `budget`, `committed` sums to `committedCost`, `actual` sums to `actualCost`, and `committed ≥ actual` per line. Use realistic vendor/category names matching the project type (e.g. for a roof job: "ABC Supply Co. — Materials", "Texas Roofing Crew A — Labor", "City of Plano — Permits"). +- [ ] **Step 6: Verify variance signs** render correctly — over-budget shows `+`, under shows `−`. (Display logic already does this; just confirm the stored `variancePercent` sign matches `(actualCost−budget)`.) +- [ ] **Step 7: Verify build.** Run: `npm run build` — Expected: `✓ built`. +- [ ] **Step 8: Reconciliation spot-check.** For each project with a `budgetBreakdown`, confirm the three column sums equal `committedCost`/`actualCost` and `allocated`→`budget`. (Manual read or a scratch node script; do not commit the script.) +- [ ] **Step 9: Commit.** + +```bash +git add src/data/mockStore.jsx +git commit -m "fix(data): reconcile project financials and add missing budget breakdowns" +``` + +--- + +## Task 6: Seed the Leads List page + +**Files:** +- Modify: `src/data/mockStore.jsx` — the `leads` useState (currently `useState([])`). + +- [ ] **Step 1: Inspect the shape** the page reads. Open `src/pages/LeadsListPage.jsx` and note the fields used (`firstName`/`lastName`, `phones[]`, `urgency`, `status`, `leadSource`, `canvasserName`, `createdByName`, `createdAt`, `stormSource`, `address`, etc.). +- [ ] **Step 2: Seed ~28–35 records** by initializing `leads` from the existing storm-attribution leads (`MOCK_STORM_ATTRIBUTION_LEADS`), mapped into the LeadsListPage shape. Use canonical `canvasserName`/`createdByName` (Frank Agent, Fiona Field, … — names that exist in `MOCK_USERS`). Spread `createdAt` across recent dates relative to `DEMO_TODAY`; set `stormSource: true` on storm-sourced ones; vary `urgency`/`status`. + +```jsx +const [leads, setLeads] = useState(() => seedLeadsFromAttribution()); +``` + +(Define `seedLeadsFromAttribution()` above the provider; map each SAL-* record to the page shape.) + +- [ ] **Step 3: Verify in dev.** Run dev server, open `/emp/fa/leads` (or owner equivalent). Expected: the list is populated (no "No Leads Yet" empty state). +- [ ] **Step 4: Verify build.** Run: `npm run build` — Expected: `✓ built`. +- [ ] **Step 5: Commit.** + +```bash +git add src/data/mockStore.jsx +git commit -m "fix(data): seed leads list so the Leads page is populated on load" +``` + +--- + +## Task 7: Add subcontractor logins (sub_002–005) + +**Files:** +- Modify: `src/data/mockStore.jsx` — `MOCK_USERS`. + +- [ ] **Step 1: Add four login user records** to `MOCK_USERS` for `sub_002`–`sub_005`, mirroring the `sub_001` (Carlos) record shape (`id`, `name`, `email`, `password: 'password'`, `role: 'SUBCONTRACTOR'`, type `subcontractor`). Use the names already in `MOCK_SUBCONTRACTORS` (Maya Patel, Dwayne …, Jennifer …, Greg Alston) so ids and names match across collections. +- [ ] **Step 2: Verify in dev.** Log in as `sub_002`'s email / `password`. Expected: the subcontractor dashboard loads and shows that sub's tasks/notifications (Maya's rich set is now reachable). +- [ ] **Step 3: Verify build.** Run: `npm run build` — Expected: `✓ built`. +- [ ] **Step 4: Commit.** + +```bash +git add src/data/mockStore.jsx +git commit -m "feat(data): add login records for sub_002-005 so each subcontractor inbox is reachable" +``` + +--- + +## Task 8: Fix task↔project associations + On Hold styling + +**Files:** +- Modify: `src/data/mockStore.jsx` — `MOCK_SUBCONTRACTOR_TASKS` (projectId/location). +- Modify: `src/pages/owner/SubcontractorTasksPage.jsx` — `STATUS_CONFIG`. +- Modify: `src/components/subcontractor/TaskViewModal.jsx` — `STATUS_STYLES`. + +- [ ] **Step 1: Re-point tasks** so each task's `projectId` references a project whose `address` matches the task `location` (residential roofing/electrical tasks → residential projects, not the commercial `proj_011`/`proj_012`). Fix the 6 mismatches the audit flagged (sct_004, _005, _006, _007, _008, _010). +- [ ] **Step 2: Add `On Hold`** to `STATUS_CONFIG` in `SubcontractorTasksPage.jsx` (give it an icon + amber/grey styling, consistent with siblings) and to `STATUS_STYLES` in `TaskViewModal.jsx`. +- [ ] **Step 3: Verify in dev.** Open `/owner/subcontractor-tasks`: On-Hold tasks (sct_005, sct_009) show distinct On-Hold styling (not "Assigned"); the project column shows a sensible, matching project. +- [ ] **Step 4: Verify build.** Run: `npm run build` — Expected: `✓ built`. +- [ ] **Step 5: Commit.** + +```bash +git add src/data/mockStore.jsx src/pages/owner/SubcontractorTasksPage.jsx src/components/subcontractor/TaskViewModal.jsx +git commit -m "fix(data): match subcontractor tasks to real projects; style On Hold status" +``` + +--- + +## Task 9: Add structured `value` to kanban leads + fix Complete-stage data + +**Files:** +- Modify: `src/data/mockStore.jsx` — `KANBAN_LEADS_INITIAL` and `KANBAN_PROJECT_DATA`. + +- [ ] **Step 1: Add a numeric `value`** (estimate $) to **every** `kl_*` lead. For signed+ leads reuse the existing `estimatedAmount` from `KANBAN_PROJECT_DATA`; for earlier-stage leads assign realistic varied amounts ($6k–$42k). +- [ ] **Step 2: Fix Complete-stage leads** (kl_034–038): set their project `completionPct: 100` and a real `actualCost` (≈ their estimate), since they're in the Complete column. +- [ ] **Step 3: Populate `stormSource: true`** on storm-canvassed kanban leads (those whose notes mention storm/hail). +- [ ] **Step 4: Verify in dev.** Open the Kanban board: cards render; storm badges appear on storm leads; Complete column leads show 100%. +- [ ] **Step 5: Verify build.** Run: `npm run build` — Expected: `✓ built`. +- [ ] **Step 6: Commit.** + +```bash +git add src/data/mockStore.jsx +git commit -m "feat(data): add lead values, fix Complete-stage data, populate stormSource on kanban leads" +``` + +--- + +## Self-review checklist (run after all tasks) + +- [ ] `git grep -nE "owner_00[12]|\bADM0[123]\b|FA00[12345]"` returns **no matches** in `src/data/mockStore.jsx`. +- [ ] `own_002` is "Diana Reeves" everywhere (`git grep -n "Maria Garcia"` → no matches). +- [ ] Every project with a `budgetBreakdown` reconciles (column sums == totals). +- [ ] `npm run build` is clean. +- [ ] Dev run: Leads page non-empty; each `sub_00N` login sees its own tasks; On-Hold styled; no "Unknown" person labels on subcontractor tasks. + +## Spec coverage note +This plan covers spec Phases 1–3. Phases 4–6 (threaded scenarios, pipeline breadth, computed analytics) and 7–10 (lifecycle/inspections, sub-task stage machine, profiles) are separate plans authored after this one lands.