Files
LynkedUpPro_CRM/docs/superpowers/2026-05-29-MASTER-PLAN.md
T
2026-05-29 19:26:14 +05:30

63 KiB
Raw Blame History

LynkedUp Pro Roofing — Demo Build: Master Plan, Scope & Rationale

Date: 2026-05-29 · Branch: revamp · App: React 18 + Vite 7 SPA, mock React-context data store, pnpm.

What this document is. The single, authoritative "what we are building and why." It paints the whole picture: the vision, the product as it stands, the canonical company, the current vs. target data model, every phase of work with rationale and acceptance criteria, the state machines, the demo scenarios, and how we execute safely. Detailed step-by-step plans live in docs/superpowers/plans/; the formal design spec in docs/superpowers/specs/2026-05-29-demo-data-coherence-design.md; the subagent rules in docs/superpowers/plans/2026-05-29-execution-protocol.md. When those and this doc disagree, this doc is the intent; the others are the mechanics.


Table of contents

  1. Vision & audiences
  2. Guiding principles
  3. The product at a glance (roles, modules, screens)
  4. The canonical company (roster & org)
  5. Data architecture — current state
  6. Data architecture — target unified model
  7. Status: what's already done (Phase 1)
  8. The phases (28) in depth
  9. The project lifecycle state machine
  10. The subcontractor task state machine
  11. The estimate & inspection models
  12. The 10 demo-case scenarios
  13. Profiles, skills & AI dispatch context
  14. Cross-cutting coherency requirements
  15. Routing map (current → target)
  16. Execution model (subagent-driven, parallel-safe)
  17. Risks & how we mitigate them
  18. Open decisions & deferred work
  19. Glossary
  20. Document index
  • Appendix A — Data dictionary (entity schemas)
  • Appendix B — The 10 scenarios, concrete data
  • Appendix C — Component & file map
  • Appendix D — Demo walkthrough clickstreams (sales + investor)
  • Appendix E — Naming conventions
  • Appendix F — Verification & QA detail
  • Appendix G — Plan-by-plan roadmap (what · why · how)

1. Vision & audiences

Turn this CRM's mock data and screens into one coherent fake roofing company — "LynkedUp Pro Roofing," based in Plano, Texas — convincing enough to carry two very different conversations:

  • The live sales demo. A salesperson sits with a roofing-company prospect and walks the app. Nothing may be empty or obviously fake. Numbers must feel real at a glance. There must be a continuous story: a storm hits, a canvasser knocks a door, a lead is created, an inspector verifies major damage, an insurance-backed estimate is signed, the job runs with subcontractors, invoices are paid, commission is calculated. Every screen the salesperson clicks into must reinforce that story.
  • The investor / stakeholder pitch. Here breadth and sophistication matter: dashboards that summarize a busy pipeline, profit and commission analytics, storm-driven lead attribution, AI-assisted dispatch, gamified field teams. The product should look like a mature, data-rich platform — not a prototype with three rows of sample data.

These two audiences pull in the same direction if — and only if — the underlying data is deeply consistent. A flashy dashboard that contradicts the records behind it is worse than no dashboard. So the whole effort optimizes for end-to-end coherence first, and surface polish second.

2. Guiding principles

  1. Coherence is the wow. The single most impressive thing in a live demo is drilling from a summary number into the exact records that compose it and finding they tie out — dashboard revenue equals the sum of project contract values; a project's budget breakdown sums to its committed and actual costs; the subcontractor working a job sees the same job the owner sees. We engineer for that.
  2. Compute analytics from data, never hardcode. Dashboard KPIs are derived via selectors over the live projects / leads / tasks arrays. This guarantees they can never drift from the detail screens, and every data fix automatically flows into the charts. The only exception is purely-visual long-range trend lines (e.g. a 12-month revenue sparkline) where no daily source data exists — those are clearly illustrative.
  3. One canonical identity per person. Every employee, owner, contractor, and subcontractor has exactly one id, one name, one set of attributes, referenced consistently everywhere. No placeholder names, no parallel id schemes, no "Unknown" labels.
  4. A job is one entity. A lead that is won becomes a project — the same record, not a parallel copy. This is the architectural spine that lets the rich detail UI, lifecycle, estimates, and analytics apply everywhere a job appears.
  5. No empty or broken views. Every tab, list, and modal a demo might open is populated with believable data. Dates are anchored to a fixed DEMO_TODAY (2026-05-29) so nothing goes stale or lands in the future.
  6. Texan realism. Names, addresses, companies, and phone numbers read like a real Plano/DFW roofing operation, not test/asdf/Admin One.

3. The product at a glance

Roles (login types): Customer, Field Agent (canvasser), Admin/Manager, Owner, Contractor, Vendor, Subcontractor. Each lands on a role-specific dashboard after login.

Major modules / screens:

  • Maps / Territory (/…/maps) — pin properties, reverse-geocode, create entries. (Owners can now create entries — fixed.)
  • Pipeline / Kanban (/…/kanban) — leads flow New → Contacted → Appt → Estimate → Signed → In-Progress → Complete, plus Stuck / Follow-up buckets.
  • Leads list (/…/leads) and Lead detail (/…/leads/:id).
  • Projects (owner) — list (/owner/projects) and rich detail (/owner/projects/:id) with 10 tabs (Overview, Budget & Costs, Team, Change Orders, RFIs, Milestones, Invoices, Risk & Issues, Activity, Docs).
  • LynkDispatch (/…/dispatch) — AI-scored rep recommendations for incoming leads.
  • Storm Intel (/…/storm-intel) and Field Storm Zones — hail/storm data, attribution.
  • Leaderboard (/admin/leaderboard) — sales & canvasser rankings (animated podium).
  • ProCanvas (/…/pro-canvas) — gamified canvassing (XP, levels, badges, achievement tiers).
  • Estimates / EstimateBuilder, Owner Snapshot dashboard, Org Settings (roles, permissions, commission), Subcontractor Tasks (owner) and the Subcontractor portal (dashboard, task detail).

Data store: a single large React-context module (src/data/mockStore.jsx, ~7,000 lines) exposing arrays (projects, kanbanLeads, leads, users, personnel, owners, subcontractors, orgMembers, MOCK_SUBCONTRACTOR_TASKS, dispatch data, storm data, estimates/templates) and mutators via useMockStore(). There is no backend and no test framework — everything is in-memory mock data, and verification is by production build + reconciliation checks + running the dev server.

4. The canonical company (roster & org)

LynkedUp Pro Roofing — Plano, TX. Owners run the business; admins manage operations; sales reps close; field agents (canvassers) source storm leads door-to-door; a contractor and several subcontractors execute the work.

Canonical roster (single source of truth — names, ids, employee ids, login):

id Role Name empId Login type Login id Password
own_001 Owner Justin Johnson LUP-1001 owner justin password
own_002 Owner Diana Reeves LUP-1002 owner diana password
a1 Admin Wade Hollis LUP-1010 employee LUP-1010 password
a2 Admin Darlene Brooks LUP-1011 employee LUP-1011 password
a3 Admin Roy Schaefer LUP-1012 employee LUP-1012 password
p1 Sales Rep Jesus Gonzales LUP-1030 employee LUP-1030 password
p2 Sales Rep Sarah Calloway LUP-1031 employee LUP-1031 password
e1 Field Agent Cody Tatum LUP-1040 employee LUP-1040 password
e2 Field Agent Hannah Reyes LUP-1041 employee LUP-1041 password
e3 Field Agent Travis Boone LUP-1042 employee LUP-1042 password
e4 Field Agent Shelby Greer LUP-1043 employee LUP-1043 password
e5 Field Agent Dalton Pruitt LUP-1044 employee LUP-1044 password
con_001 Contractor Mike Brennan LUP-3001 contractor mike password
sub_001 Subcontractor Carlos Mendoza (Electric Pro Services) LUP-2001 subcontractor carlos password
sub_002 Subcontractor Maya Patel (Skyline Roof Crew) LUP-2002 subcontractor maya password
sub_003 Subcontractor Dwayne Boudreaux (Holland Painting Co.) LUP-2003 subcontractor dwayne password
sub_004 Subcontractor Jennifer Castillo (Wu Plumbing) LUP-2004 subcontractor jennifer password
sub_005 Subcontractor Greg Alston (Alston Window Pros) LUP-2005 subcontractor greg password

Org-role taxonomy used by Org Settings / permissions: OWNER, ADMIN, SALES_REP, CANVASSER, SUBCONTRACTOR. Login identity for employees/admins is the LUP-#### employee id; owners/contractors/subs log in by username; all share the demo password password (the login page's per-role picker auto-fills it).

5. Data architecture — current state

The single most important structural fact (confirmed by code exploration) is that a "job" is currently modeled twice:

  • projects array (proj_001proj_012, now migrating to PRJ-2026-###). Rich schema: budget/approvedBudget, committedCost, actualCost, spent, variancePercent, margin, commissionType/Rate/commission, budgetBreakdown[], changeOrders[], rfis[], riskLog[], issueLog[], paymentSchedule[], activityTimeline[], milestones[], invoices[], documents[], teamMembers[], contractorId, subcontractorIds[], phase, healthScore, completionPercentage. Rendered by OwnerProjectDetail.jsx (2,086 lines, 10 tabs, owner-only) with a full commission/profit engine.
  • KANBAN_LEADS_INITIAL (kl_001kl_044) + KANBAN_PROJECT_DATA (keyed by the 16 won lead ids kl_023kl_038). Thinner schema with different field names (estimatedAmount vs budget, completionPct vs completionPercentage, workTimeline vs activityTimeline, divergent milestone/invoice/RFI/CO shapes) and denormalized contractor strings instead of FKs. Rendered by LeadProjectPage.jsx (1,159 lines, simple/full tab switch).

The two share no join key — no common id, address, or foreign key. They describe overlapping real-world jobs but cannot be cross-referenced. This duplication is the root cause of "lead pages don't match project pages," inconsistent routes, and the maintenance burden of keeping two datasets coherent. Resolving it is Phase 2.

Other key collections: users/personnel/owners/subcontractors (people, now canonical), orgMembers (org roster + roles), MOCK_SUBCONTRACTOR_TASKS + MOCK_NOTIFICATIONS (subcontractor work), DISPATCH_REPS + DISPATCH_RECOMMENDATIONS (LynkDispatch — note: a separate REP-0x namespace), MOCK_ESTIMATES_INITIAL + MASTER_TEMPLATES_INITIAL (estimates, not yet linked to projects), storm/hail data, and ProCanvas gamification state.

6. Data architecture — target unified model

Principle: a won lead and a project are the same entity. After Phase 2:

  • One projects array holds all jobs, keyed by PRJ-2026-###. The 12 existing projects migrate ids (with their inbound FKs from tasks/schedule/subcontractor data). The 16 won kanban leads (kl_023038) are converted into full project records (PRJ-2026-013…028), with KANBAN_PROJECT_DATA field names normalized to the project schema and missing project fields back-filled.
  • Bidirectional link: each converted project carries sourceLeadId: 'kl_0xx'; each won kanban lead carries projectId: 'PRJ-2026-0xx'. The kanban board still shows these leads in Signed/In-Progress/Complete columns, but "More Details" routes to the unified project page.
  • Pre-sale leads (kl_001022, 039044 — New/Contacted/Appt/Estimate + Stuck/Follow-up) remain leads with no project, shown on the lighter LeadProjectPage at /…/leads/:id.
  • One rich detail page (OwnerProjectDetail, made viewable by owner/admin/field-agent) serves every won job at /…/projects/:id. Lead-side extras it currently lacks (pipeline progression bar, stage mover, hail history) are added onto it in Phase 4.

Field normalization map (kanban → project): estimatedAmountbudget/approvedBudget; completionPctcompletionPercentage; workTimelineactivityTimeline; milestone datedueDate; invoice {description,paidDate}{submittedBy,datePaid}; rfi {openedDate,closedDate}{dateOpened,dateClosed}; changeOrder {requestedBy,date}{dateSubmitted}; contractorName/PhonecontractorId. Back-fill: teamMembers, riskLog/issueLog, paymentSchedule, commission*, phase, budgetBreakdown (Plan-1 invariants), computed openRFIs/changeOrderCount/pendingInvoiceCount.

7. Status: what's already done (Phase 1 — Data Foundation)

Complete, independently reviewed APPROVED, 14 commits, build clean. Delivered:

  • Canonical identity — unified id scheme; resolvePerson(id) selector as the single people lookup; orgMembers and subcontractor-task actor ids remapped; no stale ids anywhere.
  • Texan roster + LUP-#### empIds — all placeholder names ("Frank Agent", "Admin One", "Carlos Subcontractor", …) replaced repo-wide; emails reconciled.
  • Financial coherence — all 12 projects' budgetBreakdown columns sum to their totals, committed ≥ actual, spent == actualCost, variance signs correct; paid invoices ≤ actual cost; 6 missing breakdowns added. (106 id/name pairings cross-checked, zero mismatches.)
  • No empty/broken views — Leads list seeded (35 leads); sub_002005 can log in (company/trade aligned to source records); subcontractor tasks address-matched to real projects; On Hold status styled.
  • Pipeline data — every kanban lead has a $ value; Complete-stage leads read finished; 18 storm leads flagged.
  • Login — per-role person picker (expand role → pick person → one-click in); all role paths verified.
  • Earlier fixes — Vite /api/* dev stub (no more @vercel/kv crash); owners can create map entries; animated leaderboard podium (count-up + staggered bottom-up bars); the _Demo_Old feature branch merged in (subcontractor, org-settings, commission features) with conflicts resolved.

8. The phases (28) in depth

Phase 2 — Unify lead↔project + routing/naming (planned; plan written)

  • Current: two data models, two detail pages, two route families, no join key (see §5).
  • Target: one projects model with PRJ-2026-### ids; won leads converted and linked; one rich detail page served under /owner|admin|emp-fa/projects/:id; pre-sale leads stay on the lead page; kanban + project-list links updated (see §6).
  • Why: eliminates the duplication that makes lead pages thinner than project pages and routes inconsistent; once a job is one entity, lifecycle/estimates/analytics/subcontractor-parity all apply everywhere for free.
  • Key decisions: Unify (won = project). PRJ-2026-###. Pre-sale leads = lighter subset of the same page.
  • Obstacles handled in the plan: no join key → generate projectId on conversion + back-link; field-name mismatches → normalization map; missing project fields on won leads → back-fill with Plan-1 invariants; owner-only detail lookup → relax for admin/field-agent; 4 navigation call-sites → conditional links; proj_* FK blast-radius → migrate definitions + FKs together, verified by grep.
  • Acceptance: no proj_### left; 16 new linked projects; all ~28 projects satisfy financial invariants; build clean; won leads route to the rich page for all three roles; pre-sale leads route to the lead page.
  • Demo beat: "Here's the pipeline. This signed job? Click in — full budget, team, change orders, invoices, the same screen the owner manages it on."

Phase 3 — Kanban/pipeline depth + analytics (next plan)

  • Target: (1) realistic pre-sale lead details (customer, address, estimate value, activity notes, real dates — no sequential fake phones); (2) rich per-lead/project data so any job's detail is deep; (3) coherent stage distribution with a working pipeline $ total and conversion funnel; (4) storm attribution on leads, traceable to storm events; the 10 curated demo-case scenarios (see §12); and a computed src/data/selectors.js analytics layer wired into the owner/admin dashboards (pipeline value/funnel/win-rate, revenue/gross/net profit, commission by rep, subcontractor performance, storm attribution).
  • Why: the pipeline must read like a busy real company (investor breadth) and let a salesperson demo any scenario (sales depth); computed analytics guarantee the dashboards never contradict the records.
  • Acceptance: dashboard headline numbers equal the sums of the underlying records; pipeline shows a real $ total; every lead has believable details.

Phase 4 — Project lifecycle + inspections + estimates (plan after 3)

  • Current: OwnerProjectDetail already renders a "PROJECT PROGRESSION" bar (Lead → Inspection Scheduled → Damage Verified → Scope Approved → Project Completed) but it is static and its highlighted stage disagrees with the completion % (e.g. proj_003 shows "Inspection Scheduled" at 42% complete).
  • Target: make it an interactive state machine with progress % correctly tied to the stage (see §9); the inspection model with two touchpoints and an issues/rework loop (see §11); a claimed-vs-verified scope-variance badge; and an estimate-versions section per project (v1 from the customer's claim → v2 verified → signed; each opens the full rendered estimate document).
  • Why: the stage/percent mismatch is a visible defect; interactivity + the inspection loop + scope-variance is the heart of the sales narrative (a professional inspection turns a $200 self-report into an insurance-backed job). Uploads (issue photos/notes) persist for the session; data is seeded.
  • Acceptance: advancing a stage updates progress %; logging an inspection issue (with photo + note) shows on the project and loops to rework then re-inspection; estimate versions list with a Signed badge and full document view.

Phase 5 — Subcontractor task state machine (plan)

  • Target: replace flat task statuses with the stage machine in §10 (Not Assigned → Assigned → Pre-Work Inspection → Work In Progress → On Hold ↔ → Post-Work Review → Pass→Completed / Fail→Rework). Every transition carries an optional note + timestamp + actor; pre/post inspections record who performed them; the owner table gains Task Category + Assigned Date columns; the task modal gets a richer progress timeline + issues list with photos.
  • Why: mirrors the real field workflow and gives the subcontractor an interactive inbox; the review/rework loop is a credible operational story that also feeds owner-side visibility.

Phase 6 — Subcontractor portal data + project parity (plan)

  • Target: the /subcontractor/ pages (dashboard, projects, task detail) get realistic data and, where they show a job, the same project details the owner sees — a permitted subset of the unified project (address, scope, schedule, the subcontractor's slice of budget/payments). Enabled by Phase 2's single project entity.
  • Why: coherence across logins is the demo's credibility test — the same job must look like the same job whether the owner or the subcontractor is viewing it.

Phase 7 — Profiles, skill catalog & AI dispatch context (plan)

  • Target: a two-layer profile per person + a self-service User Details page + an owner Employee/Subcontractor Details view + a shared org skill catalog, all feeding LynkDispatch (see §13).
  • Why: richer structured context yields more believable AI dispatch recommendations (investor wow), and the profile depth is what a prospect expects from a mature CRM.

Phase 8 — ABAC access control + unified routing (plan)

  • Current: the existing framework is effectively RBAC with per-person exceptionsorgPermissions (role × module → actions) + userPermissionOverrides (per-person grant/deny) + usePermissions().can(module, action) + PermissionGate. The routing layer ignores it and is triplicated: feature components are mounted under /owner/…, /admin/…, /emp/fa/… with only <ProtectedRoute allowedRoles={[...]}> and a basePath helper; denied users bounce to /; segments are terse (maps, kanban).
  • Target — ABAC (attribute-based access control) + Option-B unified routes:
    • Policy engine over attributes. Access decisions evaluate policies against attributes of: the subject (user: id, role/orgRole, team, territory/regions, skills, employmentType, seniority), the resource (e.g. project: ownerId, assignedUserIds, subcontractorIds, status, region, sensitivity, value), the action (view/edit/delete/approve/assign/export), and optional context (time). Policies are ordered { effect: 'permit'|'deny', when: <condition over attributes> }; explicit deny wins; default deny.
    • The existing data folds in: role is one subject attribute; each userPermissionOverride becomes a subject.id-scoped policy; the role×module matrix compiles to baseline permit policies. So nothing is thrown away — ABAC is a superset.
    • New API: can(action, resource, ctx?) (resource-aware) replaces the module-only can(module, action); a thin module-level form (can('view', { type: module })) backs route guards. PermissionGate and a new route guard both call it.
    • Expressive rules this enables (examples): sales rep may edit a project only if subject.id ∈ resource.assignedUserIds; a subcontractor may view only projects where subject.id ∈ resource.subcontractorIds (and only their slice); a canvasser may edit leads they sourced and view others in their territory; "all admins except one get feature X" = role-permit + a deny when subject.id == that admin.
    • Unified routes (Option B): one human-readable route per feature, no role prefix — /territory-map, /pipeline, /projects/:id, /leads/:id, /dispatch, /storm-intel, /estimates, /leaderboard, /pro-canvas, /org-settings, /subcontractor-tasks. The route guard evaluates the policy for that route's resource-type + view. Role-specific dashboards/landing stay distinct (/owner, /admin, /agent, /contractor, /vendor, /subcontractor). Removes the 3× triplication and basePath.
    • UX: nav hides what a subject can't view; direct-URL hits to denied routes show a styled Access Restricted page; edit/delete gated inside pages via PermissionGate. No seeded override examples — capability built, configured live in Org Settings (which becomes the policy/attribute editor, ideally keeping the friendly matrix as a front-end that compiles to policies).
  • Why: ABAC is a materially more impressive and realistic enterprise-access story than role gates — it expresses ownership/assignment/territory rules RBAC can't — while still cleanly covering the simple "deny one admin / one agent read-only" asks. Folded with the route cleanup, it also gives one obvious URL per feature.
  • Decisions: ABAC policy engine (attributes + ordered permit/deny policies, deny-wins, default-deny) generalizing the current role/override data; can(action, resource, ctx) API; Option-B unified routes folded in; hide-nav + Access Restricted page; role dashboards kept; no seeded overrides.
  • Acceptance: access decisions consider resource attributes (e.g. a rep blocked from editing a project they're not on; a sub sees only their projects); the route guard blocks denied subjects (Access Restricted) and nav hides denied routes; owner sees all; one route per feature; no basePath/role-prefix duplication; every gated route maps to a resource-type/module.
  • Note on Plan 2: Plan 2 lands the final unified /projects/:id route with a coarse interim allowedRoles guard; Phase 8 swaps that for the ABAC policy guard and consolidates the remaining feature routes (removing the legacy /owner/projects/:id).

9. The project lifecycle state machine

A lifecycleStage field per project drives a state machine; the coarse kanban stage (In-Progress/Complete) derives from it. Each stage maps to a project progress %:

Stage Progress Meaning
Lead 5% Customer's reported claim captured
Damage Inspection Scheduled 10% Inspection booked
Damage Verified 20% Real scope captured (findings + photos)
Scope Approved 30% Customer accepts the verified scope/estimate
Contract Signed 40% Signed estimate; becomes the deal
Work In Progress 4070% Milestone-driven within this band
Work Complete — Awaiting Inspection 80% Build done, pending final inspection
Final Inspection (Scheduled → In Progress) 8590% External examiner reviewing
Rework In Progress regresses If issues found; loops back to Final Inspection
Project Completed 95% Passed inspection
Final Payment Received — Closed 100% Paid in full

Transitions are interactive (owner/admin advance them, each with an optional note + timestamp + actor). (Stage names are the proposed set; minor renames pending from the user.)

10. The subcontractor task state machine

Not Assigned → Assigned → Pre-Work Inspection → Work In Progress → (On Hold ↔) → Post-Work Review → then either Pass → Completed or Fail → Rework Needed (capture what's wrong + note + photo) → back to Work In Progress → re-review. Every transition carries an optional note, timestamp, and who set it. Pre-Work Inspection and Post-Work Review each record who performed them. Surfaced on the owner Subcontractor Tasks page (with Task Category + Assigned Date columns and a rich detail modal) and in the subcontractor's own login.

11. The estimate & inspection models

Estimate versions (per project): estimateVersions[] = { version, date, total, note, status: sent|revised|signed, lineItems/templateRef }. The list shows date/note/total and a Signed badge; clicking a version opens the full rendered estimate document (reusing the existing estimate/template rendering). v1 reflects the customer's claim; later versions reflect the verified scope.

Inspections (two project-level touchpoints, each records who did it):

  • Damage Verification (pre-sale): performed by a field agent or sales rep — inspector recorded per project (name + role) — producing the verified scope, findings, and photos.
  • Final Inspection (post-work): an external examiner brought by the customer — no login/role; we store inspectorName, inspectorContact (phone + email, so they can be re-contacted), inspectionDate, result (pass/fail), feedbackNote, and issues[] (each { description, note, photos[], status: open|fixed }). Re-inspection after rework creates a new round; all rounds remain visible.

Claimed-vs-verified scope variance: the lead stores reportedScope (the customer's claim); Damage Verification produces verifiedScope; when they differ materially, the project carries a scope-variance flag shown as a visible badge (e.g. "Reported ~$200 / 1 day → Verified $15,400 / 5 days"). This feeds the estimate versioning and a decision branch: approved (often via an insurance supplement) or declined (lead lost).

12. The 10 demo-case scenarios

Curated jobs, each threaded end-to-end (lead → project → subcontractor task → invoices → commission) with consistent identities, addresses, and dates, chosen to let a salesperson demonstrate any real-world situation and to show breadth:

  1. Storm-driven win, on track — canvasser sources it, healthy active job.
  2. Insurance-backed up-scope → approved — small self-report; inspection finds major damage; revised estimate; insurance supplement; approved. (The hero discrepancy story.)
  3. Up-scope → customer declines (lost) — sticker shock; lead lost "after inspection."
  4. Smaller/different than claimed — over-stated; inspection down-scopes to a quick job.
  5. Multiple revisions / negotiation — several estimate versions before agreement.
  6. Over-budget / margin loss — scope creep; negative margin (the problem job).
  7. Large commercial, multi-phase — phased payment schedule, multiple subs.
  8. Near-complete, healthy — most milestones done, final invoices pending.
  9. Completed, full lifecycle, all paid — closed-won.
  10. Disputed / on-hold — dispute timeline, paused payments, low health score.

13. Profiles, skills & AI dispatch context

Profile (per employee & subcontractor), two layers:

  • Self section (the person edits on a self-service User Details page; owner can view): preferred name, photo, phone, alt contact, address, emergency contact; optional nickname / pronouns / gender / sex; short bio, years of experience, languages; self-declared specialties + equipment carried (e.g. "tarp, ladder rack, drone"); availability/service areas. Subcontractors also: company name, license #, insurance/COI + expiry, W-9 status.
  • Company section (owner/admin only — private to the company): internal notes ("reliable in storms, keeps a tarp on the truck"), status/tags (preferred/probation/do-not-use), skill scores, pay/commission terms, hire date, manager.
  • Achievements & levels (employees): read-only, pulled from ProCanvas gamification (level, XP, streak, badges, achievement tiers).

Skill catalog (shared, org-level): the owner defines a skill once (name + required description); each person carries a 0100 score or N/A per skill. Comparable across people.

AI dispatch context: LynkDispatch scores reps per lead with factors proximity / driveTime / calendarFit / weather / skillMatch, plus reasons[] chips and a natural-language aiInsight. DISPATCH_REPS map to canonical people; each recommendation is authored to cite real profile facts (equipment + skill scores) — e.g. "Carlos — 92 Emergency Tarp · carries a tarp on the truck" — so "the AI read their profile" is demonstrably true on screen. (Today's recommendations are pre-authored mock; the profile data makes them coherent and explainable.)

14. Cross-cutting coherency requirements

These hold across all phases and are the acceptance backbone:

  • One person, one identity. Same id → same name/role everywhere; no old ids or placeholder names. (Verified by grep gates.)
  • One job, one entity. Lead → project → subcontractor task → invoices → commission all reference the same job and tie out. (Phase 2.)
  • Dashboards reconcile. KPI numbers equal the sums of the records they summarize. (Phase 3 selectors; verified by a reviewer re-summing.)
  • Same job across logins. Owner, pipeline, and subcontractor views of a job agree. (Phases 2 & 6.)
  • Financial invariants. For every project: Σbreakdown.allocated == budget; Σcommitted == committedCost; Σactual == actualCost; committed ≥ actual; spent == actualCost; variancePercent sign correct; paid invoices ≤ actualCost.
  • Profiles cited by dispatch. Equipment/skills referenced in recommendation rationale. (Phase 7.)
  • No future-dated mock; no empty tabs. Anchored to DEMO_TODAY = 2026-05-29.

15. Routing map (current → target)

Current (relevant routes): /owner/projects + /owner/projects/:projectId (OwnerProjectDetail, owner-only); /owner|admin|emp-fa/kanban (KanbanPage); /owner|admin|emp-fa/leads/:leadId (LeadProjectPage); /emp/fa/leads, /emp/fa/leads/new. Kanban cards open a side drawer; the drawer's "More Details" is the only kanban→detail navigation, and it always goes to the lead page.

Plan-2 target: introduce the final unified /projects/:id route (Option B) now, gated by a coarse interim allowedRoles (OWNER/ADMIN/FIELD_AGENT). Won leads' "More Details" routes to /projects/PRJ-2026-###; pre-sale leads keep /…/leads/:id (role-prefixed until Phase 8). Project ids become PRJ-2026-### throughout. The legacy /owner/projects/:id stays until Phase 8 removes the duplicate. (No interim role-prefixed project routes — Plan 2 lands the real URL; Phase 8 only swaps the coarse guard for the ABAC policy guard and consolidates the other feature routes.)

Final target (Phase 8 — Option B, unified): one human-readable route per feature, no role prefix, access decided by the permission guard:

Feature Final route Old (triplicated)
Territory map /territory-map /owner/maps, /admin/maps, /emp/fa/maps
Pipeline (kanban) /pipeline /…/kanban
Project detail /projects/:id /owner/projects/:id (+ interim admin/fa)
Lead detail (pre-sale) /leads/:id /…/leads/:id
LynkDispatch /dispatch /…/dispatch
Storm Intel /storm-intel /…/storm-intel
Estimates /estimates /…/estimates
Leaderboard /leaderboard /admin/leaderboard
ProCanvas /pro-canvas /…/pro-canvas
Org settings /org-settings /owner/settings, /admin/settings
Subcontractor tasks /subcontractor-tasks `/owner
User details / profile /profile (new, Phase 7)

Role-specific dashboards/landing stay distinct: /owner, /admin, /agent (replacing /emp/fa), /contractor, /vendor, /subcontractor. The permission-aware guard (can(module,'view') + per-person overrides) replaces allowedRoles-only checks; nav hides what a person can't view; denied direct-URL hits show a styled Access Restricted page; edit/delete stay gated inside pages via PermissionGate. The basePath triplication helper is removed (links become absolute feature paths).

16. Execution model (subagent-driven, parallel-safe)

  • Controller + fresh subagents. The controller (orchestrating agent) extracts each task's full text and context, dispatches a fresh implementer subagent per task, then runs spec-compliance and code-quality review; the implementer commits per task. Subagents never read the plan file — the controller hands them exactly what they need.
  • Verification gates (no test harness). Each task must end with a green npm run build, its specific grep/reconciliation check, and a committed clean tree. High-value/judgment tasks (e.g. financial reconciliation) also get an independent read-only reviewer; the whole plan ends with a final reviewer.
  • Parallel where lanes are disjoint. Every plan ships a lane/ownership map assigning each task an exclusive file set. Tasks whose lanes don't intersect may run in parallel; tasks that share a file (especially mockStore.jsx) run sequentially. The controller never lets two in-flight agents write the same file, and commits between dependent tasks. (Example: Plan 2's Phase A — id migration then lead→project conversion — is sequential on mockStore.jsx; Phase B — detail-page access, routes, kanban relink, project-list relink — runs as four parallel agents on four different files.)
  • Model tiers. Cheap/fast model for mechanical edits; standard for judgment/integration; most-capable for architecture and final review.
  • Invariants every task preserves: the canonical roster (§4) and the coherency requirements (§14).

17. Risks & how we mitigate them

  • Large shared file (mockStore.jsx). Mitigation: sequential edits with a commit between each; the build gate caught a real duplicate-declaration bug during the original merge and a copy-paste coherence bug during Phase 1.
  • Id migration breaking FKs (Phase 2). proj_* is a foreign key in tasks/schedule/subcontractor data. Mitigation: migrate definitions + FKs together; grep gate (proj_0 → none) proves no dangling references.
  • Lead→project field drift. Mitigation: explicit normalization map + Plan-1 financial-invariant reconciliation on the new projects.
  • Analytics drifting from records. Mitigation: compute from the live arrays (selectors), never hardcode.
  • Demo data going stale. Mitigation: single DEMO_TODAY anchor.
  • Scope sprawl. Mitigation: phased plans, each producing working/verifiable software; this master doc as the stable reference.

18. Open decisions & deferred work

  • Stage-name wording — user said "I'll tweak a few"; proposed names in §9/§10 stand until provided.
  • Full convergence of LeadProjectPage into the unified page — deferred; Phase 4 adds the lead-side extras (stage mover, hail history, progression) onto the project page.
  • Pre-sale leads getting PRJ ids — only on conversion to a project; pre-sale stay kl_*.
  • Per-plan lane maps — authored with each plan to enable safe parallel execution.
  • Distinct per-person passwords — declined for demo simplicity (shared password, auto-filled by the picker).

19. Glossary

  • Lead — a potential job in the pipeline (kanban). Pre-sale leads are not yet projects.
  • Project / Job — a won job with full execution data; after Phase 2, a won lead is a project.
  • Canonical id / roster — the single agreed id + name + empId per person (§4).
  • DEMO_TODAY — fixed demo date (2026-05-29) anchoring all relative dates.
  • resolvePerson(id) — store selector returning a person's {id,name,email,role} from any collection.
  • Lane — the exclusive set of files a task may edit; the basis for safe parallel execution.
  • Scope variance — the gap between a customer's reported claim and the inspection-verified scope.
  • LynkDispatch — the AI rep-recommendation module.
  • ProCanvas — the gamified canvassing module (XP/levels/badges).
  • ABAC — Attribute-Based Access Control: access decided by policies over subject/resource/action/context attributes (Phase 8), generalizing the prior role-based model.
  • Policy — an ordered { effect: permit|deny, when } rule; explicit deny wins, default deny.

20. Document index

  • This master plan: docs/superpowers/2026-05-29-MASTER-PLAN.md
  • Design spec: docs/superpowers/specs/2026-05-29-demo-data-coherence-design.md
  • Execution protocol: docs/superpowers/plans/2026-05-29-execution-protocol.md
  • Plan 1 — Data Foundation (done): docs/superpowers/plans/2026-05-29-demo-data-foundation.md
  • Plan 2 — Unify + Routing (written): docs/superpowers/plans/2026-05-29-plan2-unify-routing.md
  • Plans 38: authored from this master doc as each prior plan lands.

Appendix A — Data dictionary (entity schemas)

Field-level reference for the core entities. "Phase" = where the field is introduced/populated. Types are illustrative (mock data, no DB).

A.1 Project (unified job) — projects[], id PRJ-2026-###

Field Type Notes / Phase
id string PRJ-2026-### (Phase 2)
sourceLeadId string? kl_### if converted from a won lead (Phase 2)
ownerId string → owner (own_001/own_002)
customer object { name, phone, email, address }
address, propertyId string site address
projectType string Roof Replacement, HVAC, Siding, …
status enum active / completed / on_hold / disputed
lifecycleStage enum the §9 state machine (Phase 4)
phase string Structural / MEP / Finishing / Handover
completionPercentage number tied to lifecycleStage (Phase 4)
healthScore number 0100
budget / approvedBudget number contract value
committedCost, actualCost, spent number spent == actualCost; committed ≥ actual
variancePercent number round((actualCostbudget)/budget×100,1)
margin number gross margin
commissionType / commissionRate / commission flat / percent_gross / percent_net / custom
budgetBreakdown[] array { name, category, allocated, committed, actual } — Σ each column ties to totals
milestones[] array { id, name, dueDate, status, assignedTo }
invoices[] array { id, amount, submittedBy, status, dueDate, datePaid } — Σpaid ≤ actualCost
paymentSchedule[] array { id, milestone, amount, dueDate, status }
changeOrders[] array { id, title, amount, status, dateSubmitted, description }
rfis[] array { id, subject, status, submittedBy, dateOpened, dateClosed }
riskLog[] / issueLog[] array risk & issue tracking
activityTimeline[] array { date, action, user, details }
documents[] array { id, name, uploadedBy, uploadedDate, size, notes }
teamMembers[] array { id, userId, name, orgRole, jobRole, status, commissionEnabled, jobCommission }
contractorId, subcontractorIds[] FK → con_001 / sub_###
estimateVersions[] array Phase 4 — { version, date, total, note, status, lineItems/templateRef }
reportedScope / verifiedScope object Phase 4 — claimed vs verified
scopeVariance object? Phase 4 — { reported, verified, flagged }
inspections[] array Phase 4 — see A.5
openRFIs, changeOrderCount, pendingInvoiceCount number computed counts

A.2 Pre-sale lead — kanbanLeads[] (KANBAN_LEADS_INITIAL), id kl_###

{ id, name, address, phone, email, jobType, insuranceType, value, stormSource?, assignedAgentId, assignedAgentName, columnId, bucketId?, projectId?(if won), notes, createdDate, activity[{from,to,by,date,note}] }. Stages via columnId (kc_new…kc_complete) + buckets (kc_stuck/kc_followup).

A.3 Person & Profile — users/personnel/owners/subcontractors; profile (Phase 7)

  • Person (login/identity): { id, name, email, empId(LUP-####), username, password, role, type, companyName?, tradeType?, phone? }.
  • Profile.self (Phase 7): { preferredName, photo, phone, altContact, address, emergencyContact, nickname?, pronouns?, gender?, sex?, bio, yearsExperience, languages[], specialties[], equipment[], availability, serviceAreas[], (sub:) license, insurance{coi,expiry}, w9Status }.
  • Profile.company (owner-only, Phase 7): { internalNotes, statusTags[], skillScores[{skillId,score|'N/A'}], payTerms, hireDate, managerId }.
  • Achievements (employees, read-only): from ProCanvas gamification — { level, xp, streak, badges[], achievementTiers[] }.
  • Skill catalog (org, Phase 7): skillCatalog[] = { id, name, description }.

A.4 Subcontractor task — MOCK_SUBCONTRACTOR_TASKS[], id sct_###

{ id, projectId(→PRJ after Phase 2), subcontractorId, assignedBy, assignedByName, title, category(Phase 5 column), location, description, status(§10 machine), priority, dueDate, assignedDate(Phase 5 column), photos[], statusHistory[], thread[{senderId,senderName,...}], activities[], expenses[], fees[], paymentStatus, paidAt?, stageNotes[](Phase 5) }. Notifications: MOCK_NOTIFICATIONS[] = { id, recipientUserId, taskId, type, message, read, timestamp }.

A.5 Inspection record (Phase 4) — project.inspections[]

{ id, kind: 'damage'|'final', round, inspectorName, inspectorRole?(damage), inspectorContact?{phone,email}(final/external), inspectionDate, result: 'pass'|'fail', feedbackNote, issues[{ id, description, note, photos[], status:'open'|'fixed' }] }.

A.6 Estimate version (Phase 4) — project.estimateVersions[]

{ version, date, total, note, status:'sent'|'revised'|'signed', templateId?, lineItems[] }. Renders via the existing estimate/template view.

A.7 Dispatch (LynkDispatch)

  • DISPATCH_REPS[] (map to canonical people in Phase 7): { id, repId→personId, initials, name, status:'available'|'en_route'|'busy', rating, closeRate, todayAppointments, maxDaily, performanceScore }.
  • DISPATCH_RECOMMENDATIONS[leadId][]: { repId, score, factors{proximity,driveTime,calendarFit,weather,skillMatch}, reasons[], stormReasons[], aiInsight, distanceMi, slotStart, slotEnd, conflictFlag }. Phase 7 authors skillMatch/reasons/aiInsight to cite real profile facts.

A.8 Access control — ABAC (Phase 8)

ABAC = decisions from policies over attributes. The existing RBAC data folds in as inputs.

  • Subject attributes (user): id, role/orgRole, team, territory/regions, skills, employmentType, seniority.
  • Resource attributes (e.g. project): ownerId, assignedUserIds, subcontractorIds, status, region, sensitivity, value, type.
  • Action: view/edit/delete/approve/assign/export. Context (optional): time.
  • Policy: ordered { effect:'permit'|'deny', when:<condition over attributes> }; explicit deny wins; default deny.
  • Engine API: can(action, resource, ctx?) (resource-aware) + module-level form can('view', { type: module }) for route guards.
  • Folded-in legacy data: role → a subject attribute; orgPermissions[module][role] → baseline permit policies; each userPermissionOverrides entry → a subject.id-scoped permit/deny policy. Org Settings becomes the policy/attribute editor (the friendly role×module matrix may remain as a UI that compiles to policies).

Appendix B — The 10 scenarios, concrete data

Each is a full thread (lead → project → subcontractor task → invoices → commission) with consistent roster identities. Addresses are Plano/DFW. (Existing proj_001…012 migrate to PRJ-2026-001…012; converted won-leads become PRJ-2026-013…028 — the table below assigns each scenario a representative id; exact figures are authored to satisfy the financial invariants.)

# Scenario Project Customer / Address Type · Value Owner · Rep · Sub Lifecycle stage The beat
1 Storm-driven win, on track PRJ-2026-001 Marcus & Tara Whitfield · 2604 Dunwick Dr Roof Replacement · $45k Justin Johnson · Jesus Gonzales · Carlos Mendoza Work In Progress (42%) Cody Tatum canvassed after the hail event → signed → Carlos on electrical
2 Insurance-backed up-scope → approved PRJ-2026-013 Brenda Ochoa · 3917 Arizona Pl Roof Replacement · $200→$15.4k Diana Reeves · Sarah Calloway · Maya Patel Contract Signed "Small leak" self-report → inspection finds major hail damage → supplement → approved
3 Up-scope → declined (lost) (lead, lost) Greg Lindfors · 6601 Phoenix Pl Roof · quoted $18k — · Jesus Gonzales · — Lead (lost) Revised estimate too high; lead marked "declined after inspection"
4 Smaller/different than claimed PRJ-2026-014 Nadia Okafor · 2516 Dunwick Dr Gutter Repair · $1.9k Justin Johnson · Sarah Calloway · — Completed Claimed full replacement; inspection down-scopes to a quick repair
5 Multiple revisions / negotiation PRJ-2026-015 The Bauer Trust · 7224 Independence Pkwy Window Replacement · $42k Diana Reeves · Jesus Gonzales · Greg Alston Scope Approved v1→v2→v3 estimate history before agreement
6 Over-budget / margin loss PRJ-2026-004 Hollis Property Group · 2612 Dunwick Dr Interior Reno · $55k (over) Justin Johnson · Sarah Calloway · Carlos Mendoza Work In Progress (78%) Scope-creep change orders push committed > budget; negative margin
7 Large commercial, multi-phase PRJ-2026-007 Custer Rd Retail LLC · 6909 Custer Rd Commercial Roof · $125k Diana Reeves · Jesus Gonzales · Maya Patel + Carlos Work In Progress (32%) Phased payment schedule, multiple subs, big commission
8 Near-complete, healthy PRJ-2026-008 Winslow Family · 2112 Winslow Dr Foundation · $75k Diana Reeves · Sarah Calloway · Jennifer Castillo Work Complete — Awaiting Inspection (88%) Most milestones done; final invoices pending
9 Completed, full lifecycle, paid PRJ-2026-010 Legacy Plaza HOA · 2100 Legacy Dr Parking Lot Resurface · $35k Diana Reeves · Jesus Gonzales · — Final Payment Received (100%) Closed-won; all invoices paid; commission paid out
10 Disputed / on-hold PRJ-2026-011 Cedar Ridge Owners · Legacy Town Center Facade Restoration · $95k Diana Reeves · Sarah Calloway · Dwayne Boudreaux On Hold Dispute timeline, paused payments, health score ~30

Appendix C — Component & file map

File Responsibility
src/data/mockStore.jsx The entire mock data store + mutators + resolvePerson + (Phase 3) selectors hook-ins. ~7,000 lines. The hot file — most data tasks touch it (edit sequentially).
src/data/selectors.js (new, Phase 3) Pure functions deriving analytics (pipeline value/funnel, revenue/profit, commission, sub performance, storm attribution) from the store arrays.
src/App.jsx Route table + ProtectedRoute. Phase 8 rewrites this to unified routes + the permission-aware guard.
src/pages/owner/OwnerProjectDetail.jsx The rich project detail page (10 tabs, commission/profit engine). Becomes the single job page (Phase 2); gains lifecycle/inspection/estimate UI (Phase 4).
src/pages/LeadProjectPage.jsx Pre-sale lead detail (lighter). Won leads stop using it after Phase 2.
src/pages/KanbanPage.jsx + src/components/kanban/KanbanCard.jsx, LeadInfoDrawer.jsx Pipeline board, cards, side drawer. Drawer "More Details" routes won leads → project page (Phase 2).
src/pages/owner/OwnerProjectList.jsx Lists projects + pipeline leads; links both (relinked Phase 2).
src/pages/Maps.jsx Territory map; owners can create entries (fixed).
src/components/Layout.jsx Sidebar/nav; Phase 8 hides items a person can't view.
src/hooks/usePermissions.js, src/components/PermissionGate.jsx, src/utils/permissions.js RBAC core (can, role resolution, component gating). Phase 8 adds the route guard + Access Restricted page.
src/pages/owner/OrgSettings.jsx Edits roles, permissions, per-user overrides, commission.
src/components/dispatch/DispatchRecommendationDrawer.jsx LynkDispatch recommendation UI. Phase 7 wires profile-cited rationale.
src/pages/ProCanvas.jsx + components/ProCanvas/gamification/* Gamified canvassing (XP/levels/badges) — source of profile achievements.
src/pages/Login.jsx, src/context/AuthContext.jsx Per-role login picker (done); auth matching by empId/username.
src/pages/subcontractor/*, src/components/subcontractor/* Subcontractor portal + task modals (Phases 56).

Appendix D — Demo walkthrough clickstreams

Sales demo (the continuous story):

  1. Log in as Justin Johnson (Owner) → Owner dashboard: pipeline value, revenue, profit KPIs.
  2. Storm Intel → a recent Plano hail event; ProCanvas/leaderboard → Cody Tatum's door-knocks that day.
  3. Pipeline → the storm-sourced lead (Scenario 2); open it → reported scope "small leak ~$200".
  4. Project detail → Damage Verified with inspection photos; scope-variance badge ("$200 → $15.4k"); estimate versions (v1 claim → v2 verified, signed); insurance supplement.
  5. Lifecycle advances → Work In Progress; Team tab shows Carlos Mendoza's subcontractor task; open Subcontractor Tasks → his stage timeline.
  6. Invoices/Budget reconcile; commission for Sarah Calloway computed. Close as Scenario 9 (completed, paid).

Investor demo (breadth + sophistication):

  1. Owner dashboard → computed KPIs; drill a KPI into the exact projects that compose it (coherence proof).
  2. LynkDispatch → assign an incoming lead; the AI cites real profile facts ("Carlos — 92 Emergency Tarp · carries a tarp").
  3. Leaderboard → animated podium; ProCanvas → gamification depth.
  4. Org Settings → roles, granular per-person permissions (configure "deny one admin a feature" live); navigate as that admin → Access Restricted.
  5. Profiles / skill catalog → the structured context behind the AI.
  6. Breadth tour: 28 projects across 10 scenario types, storm attribution, subcontractor performance.

Appendix E — Naming conventions

  • Person ids: owners own_00#, admins a#, sales reps/personnel p#, field agents e#, contractor con_00#, subcontractors sub_00#. Employee id (login + display): LUP-#### (1xxx employees/owners, 2xxx subs, 3xxx contractor).
  • Job ids: projects PRJ-2026-###; pre-sale leads kl_###; subcontractor tasks sct_###.
  • Routes: kebab-case feature routes, no role prefix (/territory-map, /pipeline, /projects/:id); role landings /owner, /admin, /agent, /contractor, /vendor, /subcontractor.
  • Dates: all relative to DEMO_TODAY (2026-05-29); never future-dated.
  • Commits: conventional prefixes (feat/fix/chore/docs/refactor); no AI/Claude attribution; author Satyam Rastogi.
  • Files: pages in src/pages/**, shared UI in src/components/**, hooks in src/hooks/**, pure logic in src/utils/**, data/selectors in src/data/**.

Appendix F — Verification & QA detail

No unit-test framework exists, so verification is layered:

  1. Build gate: npm run build must end ✓ built with zero errors after every task — this catches import errors, duplicate declarations, and broken references (it caught both a merge duplicate-declaration bug and a Phase-1 copy-paste bug).
  2. Grep/invariant checks per task: e.g. git grep for stale ids/names returns none; project financial invariants (Appendix A.1) hold; every FK resolves.
  3. Reconciliation review: for data-heavy tasks, an independent read-only reviewer re-sums breakdowns/invoices and confirms dashboard KPIs equal the underlying records.
  4. Cross-login coherence: the same job viewed as owner vs subcontractor agrees (Phase 6); no "Unknown" person labels.
  5. Dev-run spot checks: Leads page non-empty; each role login lands correctly; denied routes show Access Restricted (Phase 8); lifecycle progress % matches stage (Phase 4).
  6. Final whole-implementation review per plan, then superpowers:finishing-a-development-branch.

Appendix G — Plan-by-plan roadmap (what · why · how)

Each plan = one phase, produces working/verifiable software on its own, and is executed via the subagent protocol. "How" lists the approach and the main tasks; full step-by-step lives in each plan file.

Plan 1 — Data Foundation DONE

  • What: canonical identity + resolvePerson; Texan roster + LUP-#### empIds; reconciling project financials + 6 missing breakdowns; seeded Leads page; sub_002005 logins; address-matched subcontractor tasks + On-Hold styling; kanban lead values + storm flags; per-role login picker.
  • Why: nothing else is trustworthy until identities are consistent, money ties out, and no view is empty — this is the bedrock the demo and every later phase stand on.
  • How: 11 sequential subagent tasks on mockStore.jsx (one writer at a time), each with a npm run build gate + grep/reconciliation checks; an independent financial-reconciliation review; final whole-implementation review. (Delivered in 14 commits, APPROVED.)

Plan 2 — Unify Lead↔Project + Routing (written; next to execute)

  • What: migrate proj_###PRJ-2026-### (+ inbound FKs); convert the 16 won kanban leads into full project records (normalize fields, back-fill, link both ways); make the rich detail page viewable by owner/admin/field-agent; introduce the unified /projects/:id route; relink the kanban drawer + project list.
  • Why: a won lead and a project are the same job — collapsing the two parallel data models into one entity + one page is the prerequisite that makes the rich detail, lifecycle, estimates, analytics, and subcontractor parity apply everywhere for free.
  • How: Phase A sequential on mockStore.jsx (T1 id migration → T2 conversion); Phase B parallel across 4 disjoint files (detail-page access, route, kanban relink, list relink); Phase C verify (reviewer re-checks financial invariants + nav). Field-normalization map + back-fill rules in the plan; coarse allowedRoles guard interim (ABAC arrives in Plan 8).

Plan 3 — Kanban/pipeline depth + analytics

  • What: realistic pre-sale lead details (customers, values, notes, real dates — kill the sequential fake phones); the **10 concrete demo-case scenarios** (Appendix B) authored as coherent threads; a working pipeline total + conversion funnel; storm attribution on leads; and src/data/selectors.js deriving dashboard analytics (pipeline value/funnel/win-rate, revenue/gross/net profit, commission by rep, subcontractor performance, storm attribution) wired into the owner/admin dashboards.
  • Why: the pipeline must read like a busy real company (investor breadth) and let a salesperson demo any scenario (sales depth); computed selectors guarantee dashboards never contradict the records a prospect drills into.
  • How: data-authoring subagent tasks on mockStore.jsx (sequential) for lead/scenario data; then a new selectors.js (its own file → parallelizable) of pure functions over the store arrays; then wire dashboards (OwnerSnapshot, admin dashboard) to the selectors (per-dashboard files → parallel). Verify: a reviewer confirms each dashboard KPI equals the sum of the underlying records; pipeline total equals Σ lead values; clicking a pre-sale lead opens its page. (Note: an earlier-suspected App.jsx backslash-route bug turned out to be a Windows grep display artifact — the committed routes are already correct /…/leads/:leadId; no fix needed.) Scope boundary: inspection/estimate-version/on-hold mechanics in scenarios #2/#5/#10 are Phase 4 — Plan 3 authors only their present-tense data.
  • Plan file: docs/superpowers/plans/2026-05-29-plan3-pipeline-depth-analytics.md.

Plan 4 — Project lifecycle + inspections + estimates

  • What: make the existing PROJECT PROGRESSION bar an interactive state machine with progress % tied to the stage (§9); the two-touchpoint inspection model with an issues/rework loop + session photo/note uploads (§11, A.5); the claimed-vs-verified scope-variance badge; and the estimate-versions section (v1 claim → v2 verified → signed; full document view).
  • Why: the static progression bar already disagrees with completion % (a visible defect); interactivity + the inspection loop + scope-variance is the core sales narrative (a professional inspection turns a $200 self-report into an insurance-backed job).
  • How: add the lifecycle/inspection/estimate fields to projects in mockStore.jsx (sequential) per Appendix A; add store mutators (advance stage, add inspection/issue, upload photo→object URL, add estimate version); build the UI in OwnerProjectDetail.jsx (progression control, inspection panel + issues list, scope-variance badge, estimate-versions tab) — these UI pieces in the one file run sequentially, but are independent of the data tasks. A new pure src/data/lifecycle.js (stage set, stage→% map, next/prev helpers) is the one parallel-safe carve-out; everything else is concentrated in mockStore.jsx + OwnerProjectDetail.jsx, so Plan 4 is mostly sequential. Verify: advancing a stage updates %, logging an issue loops to rework then re-inspection, estimate versions render.
  • Plan file: docs/superpowers/plans/2026-05-29-plan4-lifecycle-inspections-estimates.md.

Plan 5 — Subcontractor task state machine

  • What: the §10 stage machine (Not Assigned → Assigned → Pre-Work Inspection → Work In Progress → On Hold ↔ → Post-Work Review → Pass→Completed / Fail→Rework), per-transition notes + actor + timestamp, pre/post-inspection attribution; owner table gains Task Category + Assigned Date; richer task modal (stage timeline + issues with photos).
  • Why: mirrors the real field workflow and gives the subcontractor an interactive inbox; the review/rework loop is a credible operational story feeding owner-side visibility.
  • How: extend MOCK_SUBCONTRACTOR_TASKS + status constants + mutators in mockStore.jsx (sequential); update the owner SubcontractorTasksPage (columns) and the task modal/detail components (parallel — different files). Verify: stages advance with notes in both owner and subcontractor views. (Note: much of the machine already exists — setSubcontractorTaskStatus writes history+activities+notifications for any status, and the subcontractor detail page already has a status picker/history/timeline; Plan 5 mainly adds the §10 stages — Pre-Work Inspection / Post-Work Review / Rework Needed — the owner review gate, the Category/Assigned-Date columns, and the owner modal stage timeline.)
  • Plan file: docs/superpowers/plans/2026-05-29-plan5-subcontractor-state-machine.md.

Plan 6 — Subcontractor portal data + project parity

  • What: realistic data on /subcontractor/*; a subcontractor viewing their task sees the same project the owner sees (permitted subset — address, scope, schedule, their slice of budget/payments).
  • Why: coherence across logins is the demo's credibility test — the same job must look like the same job to owner and subcontractor.
  • How: reuse the unified project entity (Plan 2) + the upcoming ABAC visibility (Plan 8) to render a scoped project view in the subcontractor pages; seed/enrich subcontractor-facing data in mockStore.jsx; build the portal views (component files → parallelizable). Verify: a sub's task links to the real project; the owner and sub views agree.

Plan 7 — Profiles, skill catalog & AI dispatch context

  • What: two-layer profiles (self + company) per person; the self-service User Details page (all roles); the owner Employee/Subcontractor Details view; the org skill catalog; ProCanvas achievements surfaced; DISPATCH_REPS mapped to canonical people; dispatch reasons/aiInsight/skillMatch authored to cite real profile facts.
  • Why: richer structured context yields more believable AI dispatch (investor wow), and profile depth is what a prospect expects from a mature CRM.
  • How: add profile/skillCatalog/skillScores to people + dispatch-rep↔person mapping in mockStore.jsx (sequential); build the User Details page + owner Details view (new component files → parallel); rewrite the pre-authored DISPATCH_RECOMMENDATIONS to reference profile facts. Verify: a recommendation's rationale cites a real skill/equipment value from the cited rep's profile.

Plan 8 — ABAC access control + unified routing

  • What: an attribute-based policy engine (subject/resource/action/context attributes; ordered permit/deny; deny-wins; default-deny) generalizing the role/override data; can(action, resource, ctx) API; a permission-aware route guard; the Option-B unified route scheme (one human-readable route per feature, role landings only); nav hiding + styled Access Restricted page; Org Settings as policy/attribute editor.
  • Why: ABAC expresses ownership/assignment/territory rules RBAC can't (a rep edits only their projects; a sub sees only theirs) while still covering the simple "deny one admin / one agent read-only" asks — a credible enterprise-access story; folded with the route cleanup it also yields one obvious URL per feature.
  • How: define attributes + a policy evaluator in src/utils/permissions.js (+ a policies data source); extend usePermissions to resource-aware can; add a route-guard component; consolidate App.jsx to unified routes and strip basePath across components (the largest cross-file change — sequence carefully, lane-map per file); add the Access Restricted page; make Layout hide denied nav; update Org Settings. Verify: resource-aware decisions (rep blocked from a project they're not on; sub sees only their projects); denied direct-URL → Access Restricted; one route per feature; no basePath left.