Skip to main content

Dashboard View-Mode Toggle — Admin View vs Tech View

Note on table naming. view_mode lives on tenant_team_members; church_team_members is a view that exposes it. Migrations and direct writes target tenant_team_members. Reads through church_team_members continue to work transparently.

Note on naming. DB column values remain 'pastor' | 'tech' for migration stability; user-facing chip label is Admin / Tech so 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 DashboardOverview with 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

VisualModePersistence
👁 Admin chip — stone-100 bg, stone-700 textAdmin 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 textTech Viewview_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. The Train AI tab is HIDDEN from the tab list in Admin View — AdminDashboard filters 'training' out of visibleTabs when viewMode === 'pastor'. The URL /admin/[token]?tab=training still 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.
  • pastorName comes from voiceAgent.pastor_name, falling back to "Pastor".

One actionable number below the greeting:

{N} new prayer requests this morning.

  • N = count of unresolved inbox items where kind === 'prayer' from initialInbox.
  • 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").
  • Click a row → navigates to the Inbox tab via the existing onNavigateTab('inbox'). Item-id anchor highlighting in InboxTab is deferred to Slice 3b.
  • Footer link: See all (N) in Inbox → where N is 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 in PREMIUM_CANONICAL_COLUMNS).
  • Filters events whose ISO date matches today in the church timezone (voiceAgent.church_timezone or default America/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 if premium.pco_enabled).
  • Empty state copy (founder-approved verbatim): "Nothing scheduled today — enjoy the quiet." Triggers when pc_events_cache is 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 AND voiceAgent.twilio_phone_number is set. Shows the E.164 number plus a [Copy] button.
    • Chatbot row — renders only if planIncludesChat(premium) returns true. Shows churchwiseai.com/chat/{slug} plus [Copy].
    • Website row — renders only if planIncludesProWebsite(premium) returns true. Shows {slug}.john316.church plus [Copy] and [View] (opens the live URL in a new tab).
  • Copy buttons use navigator.clipboard.writeText with 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 in src/lib/voice-queries.ts returning { total: number, delta: number }. Computed server-side in page.tsx and passed through AdminShell → AdminDashboard → AdminViewHome.
  • 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 when normalizePlanTier(premium.plan) (from tier-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 > Documents tile.
  • Setup Checklist Rail (the legacy 8-step checklist surface — the wizard at /admin/[token]/welcome replaces 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-sectionAdmin ViewTech 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-tabAdmin ViewTech 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

  1. Given a new customer, when they load /admin/[token], then viewMode === 'pastor' (default) AND the Home tab renders <AdminViewHome> (NOT <DashboardOverview>).
  2. 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 (from voiceAgent.pastor_name, falling back to "Pastor") AND one actionable number (count of unresolved prayer requests today, with the N === 0 empty-state copy when applicable).
  3. Given Admin View with 3+ unread inbox items, when NeedsResponseCard renders, then exactly 3 items are shown with the correct icon per type (Heart / UserPlus / PhoneOutgoing) AND a See all (N) in Inbox → footer link.
  4. Given Admin View with an empty or null pc_events_cache, when TodayCalendarCard renders, then it shows "Nothing scheduled today — enjoy the quiet."
  5. Given Admin View with pc_events_cache containing events whose date matches today in the church timezone, when TodayCalendarCard renders, then up to 3 events show with time + label.
  6. Given Admin View on a cwa_pro_chat plan (chat-only), when YourLinksCard renders, then the Voice row is absent AND the Website row is absent (chat row only).
  7. Given Admin View on a cwa_suite_both plan, when YourLinksCard renders, then all three rows (Voice, Chatbot, Website) are present, each with a [Copy] button (Website also has [View]).
  8. Given Admin View, when ThisWeekCard renders, then it shows the total + delta vs last week (NOT month-over-month). Data comes from getWeeklyDelta(churchId) in voice-queries.ts.
  9. Given Admin View, when the top nav renders, then Train AI is absent from the tab list. The URL /admin/[token]?tab=training still resolves and renders the Train AI page.
  10. Given Admin View, when the user clicks Customize your AI → in the footer, then they navigate to /admin/[token]?tab=training and the Train AI page renders.
  11. 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> AND Train AI reappears in the tab list (without a full page reload).
  12. Given a funeral vertical admin (fwa_* plan), when they load /admin/[token], then Admin View applies AND vertical-aware terminology (funeral_director, families, etc., via useVertical() + 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_team role 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 YourLinksCard for printable bulletin handouts.
  • Item-id anchor highlighting in InboxTab so clicking a row in NeedsResponseCard deep-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-mode as 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 of visibleTabs must 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.