Dashboard View-Mode Toggle — Admin View vs Tech View
Note on table naming.
view_modelives ontenant_team_members;church_team_membersis a view that exposes it. Migrations and direct writes targettenant_team_members. Reads throughchurch_team_memberscontinue to work transparently.
Note on naming. DB column values remain
'pastor' | 'tech'for migration stability; user-facing chip label isAdmin / Techso the toggle reads correctly for funeral-director, veterinarian, and local-business-owner admins.
Why this spec exists
Anthony's 2026-05-25 feedback included:
"maybe we have to have 2 areas for our dashboard. a regular user area, and an area for more technical expertise."
Phase 3 Slice 1+2 (PR #604) shipped a header toggle plus four small "hides" inside the existing Home tab. After walking through, the founder said "that hardly makes a dent." Three UX research agents ran the same evening and converged on the same direction: 1 hero + 3-5 attention cards, hide the technical tabs, default Admin View for everyone. The founder approved the full-radical direction on 2026-05-26 — this Slice 3a spec describes a structurally different Home surface, not a few hides on top of the legacy dashboard.
Industry-standard pattern: conditional progressive disclosure (Nielsen, 1995). Stripe Developer mode, Notion Simple/Advanced page settings, Webflow Designer/Editor mode, Gmail Basic HTML view. The dashboard always works the same — a small header toggle reveals or hides the technical surfaces.
Core UX promise
Admin View is the default for everyone. It shows a hero greeting plus 4 attention cards in a single 720px-max column — one hero, 3-5 cards, no analytics donut, no setup checklist rail. Tech View is the opt-in escape hatch (chip in header) that restores the existing
DashboardOverviewwith all the technical surfaces (Integrations sub-tab, Chat Simulator, AnalyticsCard, Documents tile, Setup Checklist Rail).
The toggle
Placement
Top-right of the admin header, between the gear icon and the Upgrade CTA (per admin-ia-2026-04-18.md §1):
🪶 ChurchWiseAI [tabs] [👁 Admin] ⚙️ 🔔 [Upgrade?]
The chip displays the current mode (👁 Admin or 🛠 Tech). Click toggles + persists.
States
| Visual | Mode | Persistence |
|---|---|---|
👁 Admin chip — stone-100 bg, stone-700 text | Admin View (default) | view_mode='pastor' on tenant_team_members (or primary_admin_view_mode on premium_churches for the primary admin) |
🛠 Tech chip — navy-100 bg, navy-800 text | Tech View | view_mode='tech' on the same row |
Behavior
- B1 — Click toggles between modes. Optimistic UI update; persists via
POST /api/admin/view-mode { mode: 'pastor' | 'tech' }. - B2 — Mode is per-member. Pastor and the tech volunteer can each have their own view, scoped by their access token.
- B3 — Mode change does NOT reload — the Home tab branches between
<AdminViewHome>and<DashboardOverview>and the top-nav tab list re-derives in place. - B4 — Default for any new member or pre-migration row:
'pastor'.
What Admin View shows
Admin View renders <AdminViewHome> (new) in the Home tab — a single-column responsive layout, max width 720px centered, stone-50 background, white card surfaces with border border-stone-200 rounded-2xl shadow-sm. Playfair Display for the hero, Inter for body, Lucide icons at 2px stroke.
1. Header
- Tabs visible in Admin View:
Home · Inbox · Website · Upgrade. TheTrain AItab is HIDDEN from the tab list in Admin View —AdminDashboardfilters'training'out ofvisibleTabswhenviewMode === 'pastor'. The URL/admin/[token]?tab=trainingstill resolves and renders the Train AI page; only the nav entry is filtered. - Right side: ViewModeToggle chip (
👁 Admin/🛠 Tech), gear icon → SettingsSlideOver. - Tech View restores all five tabs.
2. Hero Greeting — HeroGreeting.tsx
Single line in Playfair Display. Format:
{Good morning|Good afternoon|Good evening}, {pastorName}.
- Time-of-day is computed client-side from local time: morning <12:00, afternoon <17:00, evening otherwise.
pastorNamecomes fromvoiceAgent.pastor_name, falling back to"Pastor".
One actionable number below the greeting:
{N} new prayer requests this morning.
N= count of unresolved inbox items wherekind === 'prayer'frominitialInbox.- Singular fallback for
N === 1("1 new prayer request this morning."). - If
N === 0:"Quiet morning — no new prayer requests yet."
3. Card 1 — NeedsResponseCard.tsx
- Section heading:
NEEDS YOUR RESPONSE(stone-500 uppercase 11px tracking). - Renders the top 3 unread inbox items from
initialInbox. Each row:- Icon:
Heart(prayer) /UserPlus(visitor) /PhoneOutgoing(callback). - First 80 chars of the body, then name, then relative time ("8m ago", "2h ago").
- Icon:
- Click a row → navigates to the Inbox tab via the existing
onNavigateTab('inbox'). Item-id anchor highlighting inInboxTabis deferred to Slice 3b. - Footer link:
See all (N) in Inbox →whereNis the total inbox count. - Empty state:
"All caught up — nothing waiting on you."
4. Card 2 — TodayCalendarCard.tsx
- Section heading:
TODAY ON YOUR CALENDAR. - Reads
premium.pc_events_cache(JSONB array of Planning Center events — column already present inPREMIUM_CANONICAL_COLUMNS). - Filters events whose ISO date matches today in the church timezone (
voiceAgent.church_timezoneor defaultAmerica/Toronto). - Renders up to 3 events — one per line: time + label (e.g.,
10:00 am Hospital visit — Mrs. Chen). - Footer link:
View week in Planning Center →(links to PCO ifpremium.pco_enabled). - Empty state copy (founder-approved verbatim):
"Nothing scheduled today — enjoy the quiet."Triggers whenpc_events_cacheis null OR an empty array OR contains no events matching today.
5. Card 3 — YourLinksCard.tsx
- Section heading:
YOUR LINKS. - Up to three rows, each conditional on the plan:
- Voice row — renders only if
planIncludesVoice(premium)returns true ANDvoiceAgent.twilio_phone_numberis set. Shows the E.164 number plus a[Copy]button. - Chatbot row — renders only if
planIncludesChat(premium)returns true. Showschurchwiseai.com/chat/{slug}plus[Copy]. - Website row — renders only if
planIncludesProWebsite(premium)returns true. Shows{slug}.john316.churchplus[Copy]and[View](opens the live URL in a new tab).
- Voice row — renders only if
- Copy buttons use
navigator.clipboard.writeTextwith a 1500ms green-checkmark confirmation.
6. Card 4 — ThisWeekCard.tsx
- Section heading:
THIS WEEK. - One big number in Playfair 36px navy = total new pastoral touch points in the last 7 days (prayers + visitors + callbacks + calls).
- Delta line below in stone-600:
+N vs last week/-N vs last week/same as last week. Colored chevron up / down / dash. - Anchor link:
See full activity →→ navigates to the Inbox tab. - Data source: new
getWeeklyDelta(churchId)helper insrc/lib/voice-queries.tsreturning{ total: number, delta: number }. Computed server-side inpage.tsxand passed throughAdminShell → AdminDashboard → AdminViewHome.
7. Footer
- Two text links, low-weight stone-500, separated by
·:Customize your AI →— navigates to/admin/[token]?tab=training. The Train AI tab is hidden from the top nav in Admin View, but the URL still resolves and renders the page. This is the quiet escape hatch for pastors who want to tune the agent without making the tab a permanent fixture in the nav.See Pro features →— only renders whennormalizePlanTier(premium.plan)(fromtier-config.ts) is NOT'suite'. (Suite users have nowhere to upgrade to, so the link is suppressed.)
What Tech View adds on top of Admin View
Tech View renders the existing DashboardOverview.tsx unchanged — donut, setup rail, metric tiles, quick actions, recent activity. All of the Tech-View-only surfaces that Phase 3 Slice 1+2 introduced remain available:
- Integrations sub-tab in the Settings slide-over (DNS verification, Webhook health, Embed snippet, Subscription detail, Recent server events).
- Chat Simulator in Train AI.
AnalyticsCard(donut + breakdown).QuickActionsRow > Documentstile.- Setup Checklist Rail (the legacy 8-step checklist surface — the wizard at
/admin/[token]/welcomereplaces it pre-dashboard, but Tech View customers may still consult it).
Sub-section visibility on the Train AI tab (when reached via direct URL in Admin View, or via the visible tab in Tech View):
| Sub-section | Admin View | Tech View |
|---|---|---|
| Church Knowledge (FAQ + documents) | ✅ | ✅ |
| Theology & Tradition | ✅ — DoctrinalOverrides advanced editor collapsed behind "Show advanced overrides" | ✅ — overrides editor expanded by default |
| Agent Personality | ✅ | ✅ |
| FAQs | ✅ | ✅ |
| Safety Rules | ✅ — same as today (life-safety; pastor needs this) | ✅ |
| Chat Simulator | ❌ HIDDEN | ✅ |
| Pastor Pulse | ✅ (Worship team uses this anyway) | ✅ |
Tech View's Settings sub-tab visibility:
| Sub-tab | Admin View | Tech View |
|---|---|---|
| Account | ✅ | ✅ |
| Team | ✅ | ✅ |
| Notifications | ✅ | ✅ |
| Integrations | ❌ HIDDEN | ✅ — PCO + Cal.com + custom domain DNS panel + Embed snippet + Webhook health |
| Billing (admin/treasurer only) | ✅ | ✅ |
DB schema
Migration 2026-05-26b-team-members-view-mode.sql (already applied via Supabase MCP):
ALTER TABLE tenant_team_members
ADD COLUMN IF NOT EXISTS view_mode text NULL DEFAULT 'pastor';
COMMENT ON COLUMN tenant_team_members.view_mode IS
'Per-member dashboard mode. pastor (default) = streamlined view, tech = full view including DNS, webhooks, raw event logs. See knowledge/acceptance/dashboard-pastor-tech-view.md.';
ALTER TABLE premium_churches
ADD COLUMN IF NOT EXISTS primary_admin_view_mode text NULL DEFAULT 'pastor';
COMMENT ON COLUMN premium_churches.primary_admin_view_mode IS
'View mode for the primary admin (the holder of admin_token who has no tenant_team_members row). Same semantics as tenant_team_members.view_mode.';
-- church_team_members view recreated to expose view_mode
Backfill: existing rows get 'pastor' via the column default. No UPDATE needed.
API
POST /api/admin/view-mode
Body: { token: string, mode: 'pastor' | 'tech' }
Auth: same as /api/admin/onboarding/advance — resolve token via resolveToken. Update tenant_team_members.view_mode (or premium_churches.primary_admin_view_mode if no team-members row).
Response: { ok: true, mode: 'pastor' | 'tech' }.
Acceptance criteria
- Given a new customer, when they load
/admin/[token], thenviewMode === 'pastor'(default) AND the Home tab renders<AdminViewHome>(NOT<DashboardOverview>). - Given Admin View, when the page renders, then the hero greeting shows the correct time-of-day greeting (
Good morning|afternoon|evening) AND the pastor's name (fromvoiceAgent.pastor_name, falling back to"Pastor") AND one actionable number (count of unresolved prayer requests today, with theN === 0empty-state copy when applicable). - Given Admin View with 3+ unread inbox items, when
NeedsResponseCardrenders, then exactly 3 items are shown with the correct icon per type (Heart / UserPlus / PhoneOutgoing) AND aSee all (N) in Inbox →footer link. - Given Admin View with an empty or null
pc_events_cache, whenTodayCalendarCardrenders, then it shows"Nothing scheduled today — enjoy the quiet." - Given Admin View with
pc_events_cachecontaining events whose date matches today in the church timezone, whenTodayCalendarCardrenders, then up to 3 events show with time + label. - Given Admin View on a
cwa_pro_chatplan (chat-only), whenYourLinksCardrenders, then the Voice row is absent AND the Website row is absent (chat row only). - Given Admin View on a
cwa_suite_bothplan, whenYourLinksCardrenders, then all three rows (Voice, Chatbot, Website) are present, each with a[Copy]button (Website also has[View]). - Given Admin View, when
ThisWeekCardrenders, then it shows the total + delta vs last week (NOT month-over-month). Data comes fromgetWeeklyDelta(churchId)invoice-queries.ts. - Given Admin View, when the top nav renders, then
Train AIis absent from the tab list. The URL/admin/[token]?tab=trainingstill resolves and renders the Train AI page. - Given Admin View, when the user clicks
Customize your AI →in the footer, then they navigate to/admin/[token]?tab=trainingand the Train AI page renders. - Given the user clicks the ViewModeToggle chip from Pastor → Tech, then
POST /api/admin/view-mode { mode: 'tech' }is called AND the Home tab re-renders as<DashboardOverview>ANDTrain AIreappears in the tab list (without a full page reload). - Given a funeral vertical admin (
fwa_*plan), when they load/admin/[token], then Admin View applies AND vertical-aware terminology (funeral_director, families, etc., viauseVertical()+wizardCopyForVertical) renders correctly in the cards.
What this spec does NOT cover (deferred)
- A separate "Tech Mode" notification stream (alerts on webhook failures, DNS expiry) — Phase 6 monitoring epic.
- Role-based defaults (e.g.
tech_teamrole auto-defaults to Tech View) — easy extension, but ship the manual toggle first and observe usage. - A "Tech-only" hidden admin dashboard route (
/admin/[token]/tech) — explicitly rejected. The whole point is a single dashboard with progressive disclosure, not a parallel UI. - Pro Website's Website tab redesign — the Admin View tweaks (timestamp pill, hex toggle) ship in this PR; deeper rework belongs in a Website-tab UX pass.
Slice 3b parking lot (richer Admin View content)
- Denominational greeting copy — pull from theology lens to inject "Grace Community is an Evangelical Free church" into the hero.
- Sermon topic / today's verse injection from Pastor Pulse.
- Attendance — "Last Sunday: 347 in attendance" if available.
- Call sentiment summary — "80% grateful, 15% asking for prayer" on Card 4 or a new card.
- QR code preview on
YourLinksCardfor printable bulletin handouts. - Item-id anchor highlighting in
InboxTabso clicking a row inNeedsResponseCarddeep-links to the specific item.
Regression hazards
- Mode persistence race — if the optimistic UI flips before the API call returns, a refresh during the race window might revert. Treat 5xx from
/api/admin/view-modeas a hard failure: revert the UI + show a toast "Couldn't save view preference." - Hidden surfaces in Admin View becoming hard to find — make sure the "Customize your AI" footer link and the Tech View chip are visible enough that a tech volunteer finds them without docs. Same for the "Show advanced overrides" link on the Train AI doctrinal-overrides editor.
- Hero greeting time-of-day relies on browser local time; users at the boundary (12:00, 17:00 local) might see a split state across siblings. Acceptable — the boundary windows are short and the copy is non-actionable.
- Funeral / vet variants share the layout via
useVertical()+wizardCopyForVertical— verify the funeral demo renders all four cards correctly (especially Card 1's "prayer requests" framing, which may need vertical-aware terminology in Slice 3b). - VerticalProvider terminology drift — funeral/vet labels for "Theology & Tradition" already differ; the spec's §"Train AI tab" assumes the church label. Verify the collapse behavior works on funeral + vet variants.
- Top-nav filtering vs URL routing — filtering
'training'out ofvisibleTabsmust NOT remove the route handler. Direct navigation via?tab=training(linked from the footer) must continue to render the page.
End of spec. Ready for founder review of the Slice 3a Admin View aggressive redesign.