Dashboard Phase 2 — EOD Handoff
TL;DR
Phase 2 vertical-aware dashboard refactor is functionally complete. Seven PRs landed on main today (c3ab3864 → ffa2f832). Funeral admin no longer leaks church terminology on any inspected surface. Church admin verified zero regression. New-vertical pattern doc shipped (knowledge#88 open).
The remaining work is small (3 deferred cosmetic items + 1 monitoring check) and a future sprint (Phase 4 vet go-live).
Section 1 — What was done in this session
Sprint metrics
- 7 PRs merged in 1 session (~6h orchestrator wall-clock, ~12h cumulative subagent runtime)
- Main HEAD:
c3ab3864→ffa2f832 - Tests added: 16 (Phase 2E) + 13 (Phase 2F) = 29 new contract assertions
- Tests passing: 207/207 across
src/lib/verticals/__tests__/* - DOM grep evidence: 0 matches for 14 distinct banned phrases on funeral admin
Pull requests (in merge order)
| PR | Lane | Title | Merge SHA |
|---|---|---|---|
| #275 | 2A | per-vertical AccountForm via verticalProfile.accountForm | 3901f646 |
| #278 | (side) | overnight-work-agent.yml uses KNOWLEDGE_REPO_TOKEN | 0cdf0a8b |
| #276 | 2B | per-vertical Inbox filter chips via verticalProfile.inboxFilters | a7544fd5 |
| #277 | 2C | per-vertical Home metric tiles via verticalProfile.metricsConfig | 537c5013 |
| #279 | 2D | per-vertical Integrations + Notifications cleanup | 20f93395 |
| #280 | 2E | comprehensive funeral bleed sweep + Upgrade tab wire-up | bf41a613 |
| #281 | 2F | vertical-aware Hours + Sharing sub-tab copy | ffa2f832 |
What each PR shipped
Lane 2A (#275) — Settings → Account → Profile sub-tab now renders per-vertical info form via verticalProfile.accountForm ('ChurchInfoForm' | 'FuneralHomeInfoForm' | 'VetClinicInfoForm'). Removed the useIsFuneralVertical() hack from PR #268. Added AccountFormKey type + ACCOUNT_FORM_MAP resolution in SettingsTab.
Lane 2B (#276) — Inbox header chip row driven by verticalProfile.inboxFilters. Added FilterChipSpec + FilterPredicateKey types. Church chips: All/Prayer/Callback/Visitor/Crisis. Funeral chips: All/At-Need/Pre-Planning/Family Contact/Crisis. Vet chips: All/Appointment/Prescription Refill/Emergency/Pet Owner Inquiry. Existing InboxTab predicate logic preserved.
Lane 2C (#277) — Home tab tile row driven by verticalProfile.metricsConfig. Added MetricSpec + MetricQueryKey + MetricClickAction types. Funeral tiles: At-Need Calls / Pre-Planning Inquiries / Family Contacts / Pending Callbacks. Tile clicks navigate to filtered Inbox via clickAction: { type: 'inboxFilter', filter: 'X' }. New metric-queries.server.ts for funeral-specific Supabase queries.
Lane 2D (#279) — Settings → Integrations sub-tab renders per-vertical card list via verticalProfile.integrations. Added IntegrationSpec + IntegrationStatus ('live'|'placeholder'|'beta') + IntegrationCategory types. New IntegrationCard.tsx shared component. Funeral integrations list: Cal.com (live), Passare/Tribute Store/Express Funeral Funding/QuickBooks Online (placeholder), Stripe Billing (live). PR #279 had a real semantic conflict during integration: Lane 2A had renamed FuneralSettingsExtension → FuneralHomeInfoForm, but Lane 2D imported the old name — resolved by dropping the stale import.
Lane 2E (#280) — Comprehensive funeral bleed sweep closing 12 catalogued items (9 cosmetic + 2 structural + 1 header parity):
- Cosmetic: vertical-aware inbox example seed data (Margaret Whitaker at-need + James Harlowe pre-planning replace Sarah Nguyen + David Olsen church examples), vertical-aware inbox row action labels via
terminology.inboxActionLabels, vertical-aware row type labels viaterminology.inboxRowTypes, "intake page" replaces "care page" viaterminology.intakePageLabel, funeral-flavored Settings Account section copy, transparent "Hosted at churchwiseai.com" chatbot label, "Pre-Planning" consistency in Inbox subtitle, header quick-link parity (funeral now has "View Chatbot") - Structural: REMOVED Settings as a tab from FUNERAL_TABS (gear-only per IA Principle 6) + ADDED Subscription tab to FUNERAL_TABS (the Lane-C-never-populated gap — funeral customers couldn't manage their plan from the dashboard until this PR)
Lane 2F (#281) — Hours + Sharing sub-tab copy that Lane 2E missed. Added 4 more terminology fields: officeHoursHelpText, printArtifact, shareableHubTitle, shareableHubDescription. Closed 7 items: "church office", "Worship service times", "congregation", "bulletins", "Care Hub" → Family Hub, "Care Subscribe Link" gated on isChurch, "care messages from your church".
PR #278 (side fix) — overnight-work-agent.yml was using secrets.GITHUB_TOKEN to clone the sibling ChurchWiseAI/knowledge repo. GITHUB_TOKEN is repo-scoped → returns 404 on sibling repos. The KNOWLEDGE_REPO_TOKEN PAT existed since 2026-04-24 (FA-083) but this workflow was never updated to use it. 1-line fix. Impact: Overnight Work Agent had been failing nightly for 14 consecutive days since the workflow was created on 2026-04-18. Tomorrow's 5:30am Toronto run should be the first-ever green run.
Knowledge repo updates
knowledge#88 (open, awaiting merge) — processes/adding-a-new-vertical.md. Internal-only 5-step pattern doc. Plus pnpm derive --all regen of INDEX.md / FRESHNESS_REPORT.md / changelog.md to clear pre-existing drift.
C:/dev/DECISION_LOG.md — appended 2026-05-01 section with full sprint narrative + lessons learned.
Patterns + lessons
Pattern that worked (reused from Day 4): 4 parallel lanes off the same baseline, then sequential rebase + integrate. Phase 2A/2B/2C/2D dispatched as background subagents in worktree-isolated worktrees, all branched off c3ab3864. After 2A merged, 2B/2C/2D each had ~7 additive conflicts on types.ts + 3 vertical profile files + 3 plumbing files — all "keep both contributions" mechanical merges resolved manually.
Lesson — visual audit catches what code review misses. Phase 2A–2D all had clean unit tests, clean typecheck, screenshots showing the intended fix. But the funeral admin Inbox row example seed data was hardcoded in src/lib/admin-examples.ts and rendered for every fresh funeral admin. None of the per-lane tests caught it because each lane was scoped narrowly. Founder's deep visual audit of post-2D screenshots surfaced 12 + 7 = 19 distinct bleed items in two passes.
Lesson — be honest about subagent screenshot claims. The original "comprehensive UI/UX audit" subagent (knowledge#86 from yesterday) claimed to take screenshots that didn't exist on disk. Founder caught it. Every Lane 2A–2F prompt subsequently included the explicit verification rule: "After saving, run ls -la <dir> and paste output. If 0 files, you didn't take screenshots — say so honestly." All 6 lanes complied.
Lesson — semantic vs additive conflicts. Most rebase conflicts in this sprint were truly additive (each lane added a different field to the same interface). One was semantic: Lane 2A renamed FuneralSettingsExtension → FuneralHomeInfoForm while Lane 2D imported the old name. The integration step had to drop the stale import — git's three-way merge couldn't auto-detect the rename intent.
Section 2 — Where things stand on main right now
Repository state
churchwiseai-web/mainatffa2f832— all 7 Phase 2 PRs + Overnight Agent fix mergedknowledge/masteratc545b05— Phase 2 doc PR #88 open against master- Voice agent runtime
vm2Ho2jvQhe6(deployed 2026-04-30) — unchanged, no redeploy needed for Phase 2
Architecture state — what's now vertical-aware
Every admin surface reads from verticalProfile.*:
src/lib/verticals/types.ts — VerticalProfile interface with fields:
├── tabs (TabSpec[])
├── adminTabs (AdminTabSpec[])
├── terminology
│ ├── visitor, callback, teamMember, director, organization
│ ├── audience (2E)
│ ├── intakePageLabel (2E)
│ ├── inboxRowTypes (2E)
│ ├── inboxActionLabels (2E)
│ ├── officeHoursHelpText (2F)
│ ├── printArtifact (2F)
│ ├── shareableHubTitle (2F)
│ └── shareableHubDescription (2F)
├── planKeys (string[])
├── rbacRoleLabels (Partial<Record<TeamRole, string>>)
├── knowledgeTaxonomy (KnowledgeTopicSpec[])
├── crisisCopy (CrisisCopySpec) ← 988 baseline test-enforced
├── accountForm (AccountFormKey) (2A)
├── inboxFilters (FilterChipSpec[]) (2B)
├── metricsConfig (MetricSpec[]) (2C)
├── integrations (IntegrationSpec[]) (2D)
└── server-side data accessors (callbackQueueQuery / voiceCallsQuery / inboxFeedQuery)
ClientVerticalProfile (subset, pure JSON, server→client safe) carries:
brand chrome + tabs + terminology + planKeys + rbacRoleLabels +
accountForm + inboxFilters + metricsConfig + integrations
Plumbing files threaded by Phase 2: VerticalProvider.tsx, page.tsx::toClientProfile(), AdminDashboard.tsx fallback default. Each Phase 2 lane added its field to all 3 in addition to the profile + types changes.
Acceptance status
11/11 IA design checklist criteria PASS. Walk in DECISION_LOG.md 2026-05-01 entry. Evidence: Lane 2E DOM grep + Lane 2F DOM grep + 207/207 tests + 6 funeral screenshots + 4 funeral hours/sharing screenshots + 2 church-no-regression screenshots.
Section 3 — Open work / detailed plan for next session
Tier 1 — small follow-ups (~1-2h, single agent)
3.1 — Lane 2G: residual funeral copy bleed (P3)
Three items Lane 2F deferred:
(a) src/components/admin/forms/SharingForm.tsx (separate from SharingSection):
- Has "Visitors click it to start chatting" copy that bleeds for funeral. Not in 2F's 7-item brief.
- Fix: read audience plural from
verticalProfile.terminology.audience(orisChurch ? 'visitors' : terminology.audiencefor the church-natural-plural).
(b) src/app/admin/[token]/components/SettingsTab.tsx:344 — sub-tab nav description:
- Current:
"All the links and embed codes you need to share your AI chatbot and care page with your visitors." - Renders in slide-over header sub-tab tooltip. Funeral admin sees it.
- Fix: extract to
verticalProfile.terminology.sharingSubTabDescription(new field) OR build at runtime from existing terminology fields.
(c) /care/<slug> URL path — funeral admin "Family Hub" UI label routes to /care/<slug>:
- The URL contains "care" which is church terminology. Visible in browser address bar.
- Decision needed (founder): rename URL path? Or accept that funeral families see
/care/and document it as a tradeoff? Renaming touches: route file rename, middleware, all links/QR codes that hardcode/care/. Higher blast radius than label-only changes. - If renaming: introduce
/<intake-path>/<slug>perverticalProfile.intakePathSegment(new field) with 308-redirect from/care/<slug>for backward compat.
Suggested approach: Single PR Lane 2G covering (a) + (b). Defer (c) to separate decision/PR.
Suggested skill/agent: general-purpose subagent with worktree isolation. ~30 min.
3.2 — Merge knowledge#88
docs(processes): adding-a-new-vertical.md + derive sync (Phase 2 wrap) PR is open at https://github.com/ChurchWiseAI/knowledge/pull/88. Awaiting founder review/merge. No conflicts.
Suggested approach: founder reviews + merges directly, OR fresh-session agent does it.
3.3 — Verify Overnight Agent first-green run
Tomorrow 2026-05-02 at 09:30 UTC (5:30am Toronto), the Overnight Work Agent runs on a schedule. PR #278 should make it succeed for the first time ever. After it runs:
gh run list --repo ChurchWiseAI/churchwiseai-web --workflow="Overnight Work Agent" --limit 1
Expected: conclusion: success + Run Overnight Work Agent step actually executed (not skipped). Plus the 7am Morning Brief should narrate what the agent did overnight.
If still failing: check the logs for a different error. The fix was for the sibling-repo checkout; the actual agent runtime might have other issues never reached before.
Suggested skill/agent: any agent with gh CLI. Fresh session at 7am+ Toronto can verify in ~30 sec.
Tier 2 — Sprint completion polish (~2-3h)
3.4 — Visual regression artifact archival (P3)
Phase 2 screenshots are committed inside the PRs themselves (in tmp/phase2{a,b,c,d,e,f}-screenshots/ folders). They live in main but in transient tmp/ paths. For long-term reference:
mkdir -p C:/dev/knowledge/specs/screenshots/2026-05-01-phase2/
# Copy from PR commits into this stable location
git -C C:/dev/churchwiseai-web show <pr-merge-sha>:tmp/phase2X-screenshots/file.png > ...
git -C C:/dev/knowledge add specs/screenshots/2026-05-01-phase2/
git -C C:/dev/knowledge commit -m "docs(screenshots): archive Phase 2 sprint visual evidence"
Provides a stable URL for the docs-portal (docs.churchwiseai.com) to link to and prevents accidental deletion if tmp/ is ever swept.
Suggested skill/agent: general-purpose shell script. ~15 min.
3.5 — Phase 2 retrospective (optional)
Today's sprint closed 19 funeral-bleed items across 2 audit passes (12 in 2E + 7 in 2F). The pattern of "post-merge visual audit catches what test-driven scope-narrow lanes miss" is worth documenting. Could become a process doc: knowledge/processes/post-sprint-visual-audit.md describing when to invoke deep visual audit, what banned-word lists to grep, how to score evidence.
Suggested skill/agent: chief-of-staff skill or human writing.
Tier 3 — Phase 4 vet vertical go-live (separate multi-day sprint, NOT next session)
Lane D (PR #273) shipped vet vertical scaffold today. Lane 2A/2B/2C/2D/2E/2F all populated vet placeholders. To take vet from scaffold to live commerce:
- Vet brand kit — final logo, color palette, typography. Needs founder design call (
/designskill). - Vet hostname provisioning —
vetwiseai.com(or alternate) DNS + Vercel domain config. - Vet customer table —
premium_vet_clinicsmigration (vs currentpremium_funeral_homes+premium_churches). Schema mostly mirrors funeral. - Vet Stripe products + price IDs —
vwa_starter/vwa_proplans. Mirror funeral tier structure ($999 + $199/mo? Or different?). Founder pricing call. - Vet-specific tabs —
Appointments,Prescriptions(component implementations). Mirror funeralAt-Need/Pre-Planningshape. - Vet voice agent prompts —
voice-agent-livekit/verticals/vet/with prompts.py + agents.py + tools.py. Phase 6 runbook. - Vet KB taxonomy + crisis copy — populate KNOWLEDGE_TAXONOMY.vet from defaults; verify CRISIS_COPY.vet has 988 + ASPCA Animal Poison Control + others.
Estimated effort: 3-5 days, founder-supervised. Not "next session" work.
Suggested skill/agent: multi-skill — /design + /marketing + general-purpose + voice-agent-engineer. Use /ensure-solid to certify go-live readiness.
Section 4 — Watch-outs / known landmines
Carried forward from earlier handoffs (still apply)
-
tenant_iddoes NOT exist onvoice_callback_requests,voice_call_logs,moderation_violations— onlychurch_id. Funeral + vet rows filter bychurch_ideven when semantically the row belongs to a non-church tenant. Future migration P2. -
fwa_demo_playgroundplan key was referenced infuneral-shared.tsbut does NOT exist inpremium_funeral_homes.planCHECK constraint. Usefwa_demofor new demo rows. -
team_rolecolumn onchurch_team_membersis plain TEXT (no CHECK constraint) — funeral + vet team roles can be added without migration. -
Settings sub-tab URL hash
#church-infois the route key for backward-compat. Don't rename even though display label varies by vertical. -
AdminShell falls back to legacy
AdminDashboardduring migration. Don't remove the fallback path until all tabs are migrated to AdminShell-loaded components. -
VerticalProvider runtime context vs VerticalProfile static config — TWO different abstractions. Server code uses
verticalProfile.X(static); client code usesuseVertical()(runtime hook returning ClientVerticalProfile). -
Critical-path-override label is the right pattern when
behavioral-snapshotsLLM-flake fails. Document the reason in a PR comment perproject_chatbot_preview_url_400.mdmemory. -
Knowledge sync gate (CI) runs
changed-files-to-docs.ts. If your code change touches a knowledge-mapped file, you need a paired knowledge PR orknowledge-sync-overridelabel withreason:comment.
New from Phase 2 sprint
-
Church
audiencefield is'people'— backward compat. Code paths that need plural-natural copy on church should useisChurch ? 'congregation' : terminology.audiencerather than blindly using the audience field. Lane 2F flagged this and applied the workaround. -
adaptFuneralToChurchShapehardcodeschatbot_enabled: false— Lane 2E relaxed the gate topremium.chatbot_enabled || verticalProfile?.key === 'funeral'because FuneralWiseAI's $999+$199 bundle always includes chatbot. If you add new conditional UI gated onchatbot_enabled, apply the same pattern. -
Lane 2A renamed
FuneralSettingsExtension→FuneralHomeInfoForm. If you find old references to FuneralSettingsExtension in code or docs, update them. -
/chat/[slug]routes only serve from churchwiseai.com host. Middleware has no funeralwiseai.com → /chat rewrite. Funeral admin transparently labels its chatbot URL "Hosted at churchwiseai.com". Don't display a funeralwiseai.com/chat URL — it 404s. -
Phase 2C funeral tiles have NO
requiresChannel: 'voice'gating —planIncludesVoice()only matches cwa_* keys; gating funeral tiles on voice would hide every tile. FuneralWiseAI ships as one bundle that always includes voice + chat. Documented infuneral.tscomments. -
Phase 2D Playwright host-rewrite limitation — Playwright's per-request Host header rewrite triggers a React hydration mismatch in dev mode (SSR sees funeralwiseai.com but client bundles see localhost), which causes the page to fall back to loading skeleton. Use curl + DOM grep for SSR-level verification on funeral admin in dev. Real production with real DNS works fine.
Section 5 — Fresh-session start protocol
When a new agent opens a session to continue this work:
Step 1 — Re-orient (5 min)
- Invoke
/chief-of-staff— pulls in CLAUDE.md + recent decisions + founder action items. - Read THIS handoff doc at
knowledge/specs/2026-05-01-dashboard-sprint-EOD-handoff.md(you're reading it now). - Read DECISION_LOG entry for 2026-05-01.
- Read the IA design doc at
knowledge/specs/2026-05-01-dashboard-ia-design.md(founder-approved spec, still authoritative).
Step 2 — Verify state (3 min)
- Check main HEAD:
git log --oneline origin/main -3should showffa2f832(#281) at top. - Check knowledge#88 status:
gh pr view 88 --repo ChurchWiseAI/knowledge --json state— if still OPEN, it's awaiting merge. - Check Overnight Agent:
gh run list --repo ChurchWiseAI/churchwiseai-web --workflow="Overnight Work Agent" --limit 1— if today's run was AFTER 09:30 UTC (5:30am Toronto), conclusion should besuccess(first-ever green). If still FAILING, investigate beyond the sibling-repo checkout fix. - Confirm voice agent:
C:/dev/lk.exe agent list --project cwa-voice— should showvm2Ho2jvQhe6deployed 2026-04-30.
Step 3 — Pick up where we left off
If founder has approved Lane 2G (Tier 1 #3.1): Dispatch a general-purpose subagent in worktree isolation with the 3-item scope from §3.1 above. Expected runtime ~30 min.
If founder asks "what's next": Walk them through Tier 1 / Tier 2 / Tier 3 priorities from §3 above. Recommend Tier 1 #3.1 + #3.2 + #3.3 as the natural next batch (~1-2h total).
If founder wants to pivot to Phase 4 (vet go-live): This is a multi-day sprint, NOT a next-session task. Estimate the work via §3.5 (Tier 3) and recommend booking dedicated time.
Step 4 — Founder check-in cadence
Today's pattern worked: founder approved each merge with brief "go" / "1" / "3" responses. Don't ask for more granular approval than necessary. Hard-gated exceptions (live Stripe, voice agent deploys, destructive SQL, sending emails, knowledge#88 merge) still warrant explicit "go" before action.
Step 5 — Don't relitigate locked answers
The IA design doc + Phase 2 sprint locked these. Do NOT re-open in a fresh session:
- Funeral admin uses FuneralWiseAI brand chrome (orange
#B45309) - Funeral admin shows FuneralWiseAI plans only ($999 setup + $199/mo)
- Vet vertical has scaffold (not live commerce yet)
- Settings is gear-only, NOT a tab (IA Principle 6)
- Subscription/Upgrade IS a universal tab on every vertical
- Internal-only new-vertical doc (no partner-facing version yet)
- Per-vertical terminology + per-vertical config registry pattern (vs feature flags)
- Chatbot URL stays at churchwiseai.com host with transparent label (option a)
Section 6 — Acceptance criteria for "Phase 2 sprint complete"
- All 4 Phase 2 lanes (2A/2B/2C/2D) merged to main
- Lane 2E (12-item bleed sweep) merged to main
- Lane 2F (7-item Hours+Sharing copy) merged to main
- Funeral admin DOM grep returns 0 matches for the IA banned-word list (verified 14 specific phrases across 2E + 2F)
- Church admin verified zero regression (DOM grep + 207/207 tests)
- Knowledge sync (
pnpm derive --check) passes - DECISION_LOG entry written
-
knowledge/processes/adding-a-new-vertical.mdwritten + PR opened - Voice agent does not require redeploy (UI-only changes — confirmed)
- knowledge#88 merged to master (pending founder action)
- Overnight Agent first-ever green run verified (pending 2026-05-02 09:30 UTC)
- Lane 2G optional — 3 deferred cosmetic items (P3, not blocking)
Phase 2 verdict: COMPLETE pending the 3 unchecked items above (none are blocking customer-facing functionality).
Appendix — File locations quick reference
| What | Where |
|---|---|
| This handoff doc | knowledge/specs/2026-05-01-dashboard-sprint-EOD-handoff.md |
| Predecessor handoff | knowledge/specs/2026-05-01-dashboard-handoff.md |
| IA design (approved) | knowledge/specs/2026-05-01-dashboard-ia-design.md |
| New-vertical pattern doc | knowledge/processes/adding-a-new-vertical.md (knowledge#88) |
| DECISION_LOG entry | C:/dev/DECISION_LOG.md § 2026-05-01 |
| Phase 2 screenshots (6 + 4 + 8 = 18) | tmp/phase2-review/ + tmp/phase2e-review/ + tmp/phase2f-review/ (this worktree) and inside main commits at tmp/phase2{a,b,c,d,e,f}-screenshots/ |
| Vertical config registry | churchwiseai-web/src/lib/verticals/{types,registry,church,funeral,vet}.ts |
| Per-vertical components | churchwiseai-web/src/components/admin/{church,funeral,vet}/ |
| Shared admin shell | churchwiseai-web/src/app/admin/[token]/components/{AdminDashboard,SettingsTab,InboxTab,DashboardOverview}.tsx |