Context. surface customer · domain tara · route /domains/tara/analytics · auth signed-in · source apps/oshun/web/src/app/domains/tara/analytics/page.tsx
Last walked. 2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data (2xx), console/page-errors, expected content, screenshot verified; live screen-reader, touch, offline, and telemetry-delivery checks pending a manual AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; 2026-06-29 targeted Playwright coverage added for real BFF-backed empty and populated analytics states, auth-hydration retry, range switching, CSV export, chart/title semantics, UTC weekday heatmap labels, reduced-motion CSS, scoped axe scans, and route back-stack. Evidence: apps/oshun/web/e2e/tara-analytics.spec.ts
Purpose#
The Tara analytics surface under /domains/tara/*. It renders the member's real
sit-completion analytics from /v1/tara/analytics: minutes, sessions,
completion rate, most-practiced sittings, UTC weekday/hour heatmap, and practice
rhythm calendar, with a CSV export for the active range. It no longer fabricates
seeded-random practice history for members with no data.
Entry points#
- Tara hub — no current source link from
/tarato this route was found in the focused 2026-06-29 pass; treat the hub affordance as an open linkage gap - Direct URL / bookmark — yes
- Domain back-stack —
router.back()is wired into the dashboard'sonBackprop (provided by this page wrapper) - No middleware-specific gating — the page is a
'use client'wrapper with no route-local auth guard; the BFF analytics endpoint is authenticated
Layout regions#
page.tsx is a 'use client' thin wrapper that renders
<TaraAnalyticsDashboard onBack={() => router.back()} />.
Inside TaraAnalyticsDashboard (apps/.../TaraAnalyticsDashboard.tsx):
- Header / back button — back affordance (
onBack) at top-left - Summary stat row — Clock / Target / Flame / TrendingUp lucide icons with numeric headline values
- Meditation minutes bar chart — CSS-driven daily bars derived from the member's real completion rows
- Session completion ring — SVG donut/ring (
stroke-dashoffsetanimated viatara-dash-ring-fillkeyframes) - Most practiced sittings — horizontal CSS bars from
bySitting - Time-of-day heatmap — UTC Sunday-Saturday × 24-hour grid
- Practice rhythm calendar — daily markers across the active window
- CSV export action — downloads the visible window of metrics
States#
- Loaded with real completions — seeded E2E users complete Tara sits via
the real
/v1/tara/sittings/:id/completeBFF route; the dashboard then reads/v1/tara/analyticsand mirrors the same totals, streak, category, heatmap, and daily-point model - Auth-hydration retry — dashboard retries the initial unauthenticated no-token race before settling; authenticated users do not get a false empty dashboard from an early 401
- Empty member —
/v1/tara/analyticsreturnshasData: false; the UI renders "No practice yet" instead of fabricated history - Empty practice day — zero-minute bars and rhythm cells remain in the generated contiguous range; the populated E2E confirms a real practiced day and exported zero rows around it
- Window switcher — This week / This month / All time buttons update
data-time-rangeandaria-pressed - CSV export success — active range downloads
tara-analytics-<range>-<YYYY-MM-DD>.csvwith headerDate,Minutes,Sessions,Completed,Total - Reduced motion —
prefers-reduced-motion: reducecollapses dashboard animations/transitions; E2E verifies bar animation duration is <= 1ms - Auth gate — BFF reads require auth; route-local page guard remains the customer shell/middleware boundary
- BFF/database failure — failed fetch keeps the honest empty model, but there is no explicit user-facing error state
Interactions#
Header / back#
- Back (button)
- Function: calls
router.back()(provided asonBackfrom this page) - Aria-label: "Back to previous page"
- Function: calls
Charts (interactive)#
- Bar / cell hover titles — minute bars and heatmap cells expose native
titletext with date/hour and real minutes/session counts - Window selector — This week / This month / All time segmented buttons update the active range
- CSV export (
Downloadicon button) — triggers a CSV file download of the active window - Keyboard tooltip alternative — chart titles are native hover text, not a focusable disclosure pattern
Data & contracts#
- Reads: BFF
GET /v1/tara/analytics- Source table: real sit completions recorded by
POST /v1/tara/sittings/:id/complete - Model builder:
apps/oshun/bff/src/tara/analytics.ts - UI mapping:
daily,bySitting, andweekdayHour
- Source table: real sit completions recorded by
- Writes: no server writes from the dashboard; CSV export writes a local browser download only
- Realtime: None.
- Caching: BFF replies
cache-control: no-store; page is a client component - Auth/role check: BFF
collectionsAuthGuardplus customer shell/middleware - Telemetry: None observed in this view.
Current E2E evidence#
apps/oshun/web/e2e/tara-analytics.spec.tscreates fresh signed-in users, reads/v1/tara/analyticsdirectly, and verifieshasData: falserenders the empty state with no stat cards.- The same spec records three real sit completions through
/v1/tara/sittings/:id/complete, re-reads/v1/tara/analytics, and proves the browser dashboard matches the returned totals: 27 minutes, 3 sessions, 1-day rhythm, 100% completion, practiced day, per-sitting category rows, and weekday/hour heatmap cell. - It verifies range selection (
This week), CSV download filename and content, reduced-motion animation duration, minute/heatmap title semantics, scoped axe scans for empty and populated states, and route-header back navigation.
Cross-references#
- Sibling Tara routes (this folder):
- Component sources:
apps/oshun/web/src/components/domains/tara/TaraAnalyticsDashboard.tsx
- Feature spec:
V1/features.md#tara
Open questions / known gaps#
- Dashboard reads from real
/v1/tara/analytics; seeded-random dashboard history has been removed. - CSV export contract documented and tested:
Date,Minutes,Sessions,Completed,Total - Confirm the relationship between
/domains/tara/analyticsand the polished/tarasurface — source search found no current hub link - Decide whether BFF/database failures should render an explicit error panel instead of the same honest empty state
- Decide whether chart hover titles need a keyboard-accessible tooltip or data-table alternative