Skip to main content

Dashboard Phase 2 — EOD Handoff

TL;DR

Phase 2 vertical-aware dashboard refactor is functionally complete. Seven PRs landed on main today (c3ab3864ffa2f832). 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: c3ab3864ffa2f832
  • 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)

PRLaneTitleMerge SHA
#2752Aper-vertical AccountForm via verticalProfile.accountForm3901f646
#278(side)overnight-work-agent.yml uses KNOWLEDGE_REPO_TOKEN0cdf0a8b
#2762Bper-vertical Inbox filter chips via verticalProfile.inboxFiltersa7544fd5
#2772Cper-vertical Home metric tiles via verticalProfile.metricsConfig537c5013
#2792Dper-vertical Integrations + Notifications cleanup20f93395
#2802Ecomprehensive funeral bleed sweep + Upgrade tab wire-upbf41a613
#2812Fvertical-aware Hours + Sharing sub-tab copyffa2f832

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 FuneralSettingsExtensionFuneralHomeInfoForm, 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 via terminology.inboxRowTypes, "intake page" replaces "care page" via terminology.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 FuneralSettingsExtensionFuneralHomeInfoForm 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/main at ffa2f832 — all 7 Phase 2 PRs + Overnight Agent fix merged
  • knowledge/master at c545b05 — 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 (or isChurch ? 'visitors' : terminology.audience for 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> per verticalProfile.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:

  1. Vet brand kit — final logo, color palette, typography. Needs founder design call (/design skill).
  2. Vet hostname provisioningvetwiseai.com (or alternate) DNS + Vercel domain config.
  3. Vet customer tablepremium_vet_clinics migration (vs current premium_funeral_homes + premium_churches). Schema mostly mirrors funeral.
  4. Vet Stripe products + price IDsvwa_starter / vwa_pro plans. Mirror funeral tier structure ($999 + $199/mo? Or different?). Founder pricing call.
  5. Vet-specific tabsAppointments, Prescriptions (component implementations). Mirror funeral At-Need / Pre-Planning shape.
  6. Vet voice agent promptsvoice-agent-livekit/verticals/vet/ with prompts.py + agents.py + tools.py. Phase 6 runbook.
  7. 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)

  1. tenant_id does NOT exist on voice_callback_requests, voice_call_logs, moderation_violations — only church_id. Funeral + vet rows filter by church_id even when semantically the row belongs to a non-church tenant. Future migration P2.

  2. fwa_demo_playground plan key was referenced in funeral-shared.ts but does NOT exist in premium_funeral_homes.plan CHECK constraint. Use fwa_demo for new demo rows.

  3. team_role column on church_team_members is plain TEXT (no CHECK constraint) — funeral + vet team roles can be added without migration.

  4. Settings sub-tab URL hash #church-info is the route key for backward-compat. Don't rename even though display label varies by vertical.

  5. AdminShell falls back to legacy AdminDashboard during migration. Don't remove the fallback path until all tabs are migrated to AdminShell-loaded components.

  6. VerticalProvider runtime context vs VerticalProfile static config — TWO different abstractions. Server code uses verticalProfile.X (static); client code uses useVertical() (runtime hook returning ClientVerticalProfile).

  7. Critical-path-override label is the right pattern when behavioral-snapshots LLM-flake fails. Document the reason in a PR comment per project_chatbot_preview_url_400.md memory.

  8. 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 or knowledge-sync-override label with reason: comment.

New from Phase 2 sprint

  1. Church audience field is 'people' — backward compat. Code paths that need plural-natural copy on church should use isChurch ? 'congregation' : terminology.audience rather than blindly using the audience field. Lane 2F flagged this and applied the workaround.

  2. adaptFuneralToChurchShape hardcodes chatbot_enabled: false — Lane 2E relaxed the gate to premium.chatbot_enabled || verticalProfile?.key === 'funeral' because FuneralWiseAI's $999+$199 bundle always includes chatbot. If you add new conditional UI gated on chatbot_enabled, apply the same pattern.

  3. Lane 2A renamed FuneralSettingsExtensionFuneralHomeInfoForm. If you find old references to FuneralSettingsExtension in code or docs, update them.

  4. /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.

  5. Phase 2C funeral tiles have NO requiresChannel: 'voice' gatingplanIncludesVoice() only matches cwa_* keys; gating funeral tiles on voice would hide every tile. FuneralWiseAI ships as one bundle that always includes voice + chat. Documented in funeral.ts comments.

  6. 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)

  1. Invoke /chief-of-staff — pulls in CLAUDE.md + recent decisions + founder action items.
  2. Read THIS handoff doc at knowledge/specs/2026-05-01-dashboard-sprint-EOD-handoff.md (you're reading it now).
  3. Read DECISION_LOG entry for 2026-05-01.
  4. 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)

  1. Check main HEAD: git log --oneline origin/main -3 should show ffa2f832 (#281) at top.
  2. Check knowledge#88 status: gh pr view 88 --repo ChurchWiseAI/knowledge --json state — if still OPEN, it's awaiting merge.
  3. 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 be success (first-ever green). If still FAILING, investigate beyond the sibling-repo checkout fix.
  4. Confirm voice agent: C:/dev/lk.exe agent list --project cwa-voice — should show vm2Ho2jvQhe6 deployed 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.md written + 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

WhatWhere
This handoff docknowledge/specs/2026-05-01-dashboard-sprint-EOD-handoff.md
Predecessor handoffknowledge/specs/2026-05-01-dashboard-handoff.md
IA design (approved)knowledge/specs/2026-05-01-dashboard-ia-design.md
New-vertical pattern docknowledge/processes/adding-a-new-vertical.md (knowledge#88)
DECISION_LOG entryC:/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 registrychurchwiseai-web/src/lib/verticals/{types,registry,church,funeral,vet}.ts
Per-vertical componentschurchwiseai-web/src/components/admin/{church,funeral,vet}/
Shared admin shellchurchwiseai-web/src/app/admin/[token]/components/{AdminDashboard,SettingsTab,InboxTab,DashboardOverview}.tsx