Context. surface customer · domain lilith · route /lilith-studio/tara · auth signed-in + role:v1_editorial_producer (default) · source apps/oshun/web/src/app/lilith-studio/tara/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
Purpose#
A single read-only pane on what Tara is currently serving end-users: today's
recommended sit, the course sittings, and the daily ritual. It mirrors live
content for the author's reference — edit/publish actions live behind the studio
shell, not here. Server-rendered by fetching /v1/tara/today,
/v1/tara/sittings, and /v1/tara/ritual in parallel.
Entry points#
- Lilith Studio hub (
/lilith-studio) — verify a Tara surface link /lilith-studio/scenes— verify cross-link- Footer buttons here: "← Studio hub" (→
/lilith-studio), "Scenes" (→/lilith-studio/scenes), "New scene" (→/lilith-studio/scene/new) - Direct URL / bookmark — yes (signed-in + editorial scope)
Layout regions#
/lilith-studio/layout.tsx mounts <ShellLayout active="studio"> and the
editorial gate. This page additionally mounts its own LWebShell with
LCustomerNav active="explore" (see Open questions — likely a double-shell).
Max width 1080, centered.
- Header: studio
ShellLayoutheader + this page'sLCustomerNav(Explore) - Masthead (
LMasthead): left "Lilith Studio · Tara", right "read-only mirror", kicker "What end-users see now", title "Tara, currently live." - Two-column grid (
1.4fr / 1fr):- Left column:
- Today (
LEyebrow): accent-bordered card with mono line "Recommended sit ·· session / · min", serif title, italic "taught by ". Empty → dashed "No recommended sit on the wire for today." - Sittings (course) (
LEyebrow):<ol>of sitting rows (40px 1fr autogrid) — monoindex, seriftitle, and a state·duration chip whose color keys offstate(here=accent, done=green#1f4f3a, else muted). Empty → dashed "No sittings configured for the active path."
- Today (
- Right column:
- Daily ritual (
LEyebrow): rule-bordered card with mono "· · min", serif title, accent "Pattern · ". Empty → dashed "No daily ritual configured."
- Daily ritual (
- Left column:
- Action row (flex, wraps): ghost "← Studio hub", ghost "Scenes", primary "New scene"
States#
- Loading — async server component awaits three
bffGetcalls in parallel; no client skeleton. Verifyloading.tsx - Fully populated — today's sit + sittings list + ritual all present
- No sit today —
today.recommendedSitfalsy → "No recommended sit on the wire for today." - No sittings —
sittings.sittingsempty → "No sittings configured for the active path." - No ritual —
ritualfalsy → "No daily ritual configured." - All empty — every BFF call returns null (network/non-2xx via
bffGet) → all three dashed empty rows - Sitting state variants —
here(accent),done(green),next/queued(muted) - Error (recoverable) —
bffGetswallows errors tonull, so failures render as the empty states — no distinct error UI - Offline — 5s abort → null → empty rows; SW-cached HTML may show last render
- Gated (access denied) — non-editorial scope → layout renders
LilithStudioAccessDenied - Standalone PWA —
data-responsive-page; verify the1.4fr/1frgrid collapses at narrow widths (no explicit responsive rule in code)
Interactions#
This page is a read-only mirror — the only interactive elements are the three footer navigation buttons. The today/sittings/ritual cards are non-interactive display.
- Today card (
<div>) — non-interactive - Sitting row (
<li>) — non-interactive; verify whether a row should link to its sit (none coded) - Ritual card (
<div>) — non-interactive - "← Studio hub" (
LBtn kind="ghost",href="/lilith-studio") - "Scenes" (
LBtn kind="ghost",href="/lilith-studio/scenes")- Function: →
lilith-studio-scenes.md
- Function: →
- "New scene" (
LBtn kind="primary",href="/lilith-studio/scene/new")- Function: →
lilith-studio-scene-new.md - Keyboard: Enter activates; in tab order
- Mobile (≤ 640 px): action row
flexWrap: 'wrap'lets buttons stack
- Function: →
Data & contracts#
- Reads (parallel,
bffGet):GET /v1/tara/today→{ generatedAt, recommendedSit?: { id, title, teacher, durationSeconds, pathLabel, sessionIndex, pathTotal } }GET /v1/tara/sittings→{ generatedAt, sittings: { id, index, title, durationSeconds, state: 'done'|'here'|'next'|'queued' }[] }GET /v1/tara/ritual→{ generatedAt?, ritualId, title, pattern, durationSeconds, recommendedDaypart: 'morning'|'midday'|'evening' }
- Writes: none (read-only mirror)
- Realtime: none
- Caching:
bffGetdefaultrevalidate = 60s; session cookie forwarded - Auth/role check:
/lilith-studio/layout.tsxeditorial gate (admin:* or studio:editorial scope) → elseLilithStudioAccessDenied
Cross-references#
- Studio hub:
lilith-studio.md - Scenes editor:
lilith-studio-scenes.md - New scene:
lilith-studio-scene-new.md - The end-user Tara hub this mirrors:
../03-tara/tara.md - Journey:
../../journeys/lilith-studio-tara-scene-publish.md - Component source:
apps/oshun/web/src/app/lilith-studio/tara/page.tsx(inline page;EmptyRowlocal component) - Feature spec:
V1/features.md - Architecture:
V1/ARCHITECTURE.md
Open questions / known gaps#
- Double shell: the layout mounts
ShellLayoutand this page mountsLWebShelltoo. Confirm whether the page should drop itsLWebShell(the layout's refactor note says pages "return their inner authoring component directly") - Nav
active="explore"vs layoutactive="studio"— two competing active-tab signals - The mirror is read-only by design but offers no link from a sitting row to its underlying sit/source — confirm authors don't need a drill-in here
-
bffGetnull on failure collapses error and empty into one state — no way to tell "no content configured" from "BFF unreachable" - Confirm the three
/v1/tara/*BFF endpoints are the same the end-user/tarahub consumes (so the mirror is truly faithful)