Context. surface customer · domain arete · route /domains/arete/journal · auth signed-in · source apps/oshun/web/src/app/domains/arete/journal/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; content re-verified 2026-06-03 against current source
Purpose#
Internal /domains/arete/* journal-and-reflection workspace. A three-panel
layout: reflection prompts (evening / weekly / open windows) · compose draft ·
continuity inspector (recent reflections, brief, theme-graph links). Wired to
the @oshun/domain-arete library for canonical reflection builders, the Oshun
assistant entry, and a domain-route helper for navigating across Nisaba /
Veritas / Tara / Arete / Nyx.
Entry points#
- Direct URL / bookmark — yes (signed-in)
?entry=<id>query parameter —useBrowserSearchParams().get('entry')is read by the page and passed asinitialEntryId; selects a specific entry on mount- Back navigation — page passes
onBack={() => router.back()} - Theme-graph link from another reflection — the workspace itself can
produce a
targetPathof the form?entry=<id>; navigating to this page with that param setsselectedEntryId - Polished
/areteJournal tab — the polished room'sLSubNavitem carrieshref="/domains/arete/journal"and navigates here
Layout regions#
page.tsx is a 'use client' page using useRouter and
useBrowserSearchParams. Renders
<AreteJournalReflectionWorkspace onBack={() => router.back()} initialEntryId={searchParams.get('entry')} />.
Component at
apps/oshun/web/src/components/domains/arete/AreteJournalReflectionWorkspace.tsx.
- Container (section): cream-paper radial gradient background; column flex; padding 24px (desktop) / 16px
- Header tile: Back button (
aria-label="Go back"), eyebrow + h1 "Keep reflection close enough to shape the next move.", lede paragraph, "Open reflection assistant" CTA (callsdispatchOshunAssistantOpen) - Window selector: row of 3 pill buttons —
evening,weekly,open(data-arete-journal-reflection-period) - Metric strip (3 tiles): Entries this week / Reflection tone / Draft state (Captured / In progress)
- Artifact action panel:
<AreteArtifactActionPanel />with save and export handlers, saved-at timestamp from local artifact store - Three-column grid (desktop) / single column mobile:
- Left: Reflection prompts lane —
data-arete-journal-reflection-prompt-lane. Eyebrow "Reflection mode", reflection-window heading and summary, list of available prompts (filtered byreflectionWindowPromptCategories[window]). Each is a button with category eyebrow + text. - Middle: Compose surface —
data-arete-journal-reflection-compose. Selected-prompt title, instruction body,textareadraft (aria-label="Journal reflection draft"), draft-state label (Captured / In progress), two CTAs: "Capture reflection" and "Send to assistant" (dispatchOshunAssistantOpenwith prompt+draft+continuity context) - Right: Reflection continuity inspector —
data-arete-journal-reflection-inspector. "Recent reflections" section with entry-select buttons. Continuity brief card (MessageSquareQuoteicon) with reflectionSummary text and 2 talking points. "Tags in focus" chips. Theme-graph links: perthemeGraphThreads, an article with theme label, summary, source signals, and per-link buttons that dispatchhandleThemeGraphLink.
- Left: Reflection prompts lane —
States#
- Loading — N/A: client component with sync fixture; saved-at hydrated
via
useEffectagainst localStorage-backedreadSavedAreteArtifact - Initial entry from
?entry=<id>— if the param matches anentries[i].entry.entryId, that entry is pre-selected - Window switched — toggling evening/weekly/open re-derives
availablePromptsand resetsselectedPromptIdto a category-matching prompt - Draft captured —
setDraftCaptured(true)updates thedata-arete-journal-reflection-draft-stateattribute to"captured" - Theme-graph link to a practice — when
link.targetKind === 'practice', the handler parses the?entry=<id>fromlink.targetPath, setsselectedEntryId, and forces window to'open' - Theme-graph link to a non-practice surface —
router.push(buildConceptGraphDomainHref(link))navigates to Nisaba / Veritas / Tara / Arete / Nyx based onlink.targetKind - Desktop vs. mobile layout —
useSemanticViewport+isLaptopUp(viewport)gates the 3-column grid vs. single-column - Saved-at hydrated —
setArtifactSavedAtreads localStorage on mount and onartifactIdchange - Error (recoverable) — relies on app-level error boundary
- Offline — purely client; identical offline (saved artifacts live in localStorage)
- Shell entitlement granted —
/domains/arete?path=/journalis Arete pro-gated; E2E upgrades the seeded account through the real admin bulk-entitlements BFF flow before hydration - Free-tier gated fallback — verify the shell upgrade screen for users without Arete entitlement
- Standalone PWA — no shell chrome around the page
Interactions#
Top bar#
- Back button (
aria-label="Go back")- Function: calls
router.back()viaonBackprop
- Function: calls
- "Open reflection assistant" (button)
- Function: dispatches
dispatchOshunAssistantOpenwith sourcearete-journal-reflection:<window>and a prompt that includes the window label, the selected prompt text, and the selected entry's excerpt - Telemetry: relies on the assistant-entry event for instrumentation
- Function: dispatches
Window selector#
- Evening / Weekly / Open (3 pill buttons)
- Function:
setWindow(option)+ resetselectedPromptIdto a prompt matching the new window's categories - Data attribute:
data-arete-journal-reflection-period={option} - Touch target: 10px+14px padding; E2E verifies ≥ 44 px height on mobile
- Function:
Reflection prompts (per availablePrompts)#
- Prompt card (button,
data-arete-journal-reflection-prompt={prompt.promptId},data-arete-journal-reflection-prompt-selected="true|false")- Function:
setSelectedPromptId(prompt.promptId) - Active style: accent border + tinted background
- Function:
Compose surface#
- Draft textarea (
aria-label="Journal reflection draft",data-arete-journal-reflection-draft)- Function: typing updates
draftTextand resetsdraftCapturedtofalse
- Function: typing updates
- "Capture reflection" (button,
data-arete-journal-reflection-capture)- Function:
setDraftCaptured(true)
- Function:
- "Send to assistant" (button,
data-arete-journal-reflection-assistant-handoff)- Function: dispatches
dispatchOshunAssistantOpenwith sourcearete-journal-reflection:assistant:<promptId>and a multi-line prompt (prompt + draft + continuity cue from selected entry)
- Function: dispatches
Continuity inspector#
- Entry selector (per
entries,data-arete-journal-reflection-entry)- Function:
setSelectedEntryId(item.entry.entryId) - Style: active gets accent border, includes the sentiment tone as a chip
- Function:
- Theme-graph link (per
thread.links,data-arete-journal-theme-graph-action,data-arete-journal-theme-graph-action-kind)- Function:
handleThemeGraphLink(link)— either selects an entry (whenlink.targetKind === 'practice') or routes viabuildConceptGraphDomainHref(link)
- Function:
Artifact actions (AreteArtifactActionPanel)#
- Save —
handleSaveArtifactcallssaveAreteArtifactwith the snapshot JSON (window, promptId, entryId, draftText, draftCaptured) - Export —
handleExportArtifactcallsbuildAreteJournalReflectionExportandtriggerAreteArtifactDownload - Share disabled state —
AreteArtifactActionPanelrenders thejournal_reflectionshare action disabled under the current policy
Data & contracts#
- Reads: imports from
@oshun/domain-arete:buildAreteJournalReflectionExport,buildAreteCoachingSummaryShellModel,buildCanonicalAreteCoachingSummary,buildAreteThemeConceptGraphReflections,buildAreteThemeConceptGraphThreads,getAreteArtifactPolicy. Types:AreteCanonicalCoachingSummary,AreteJournalEntry,AreteJournalPrompt,AreteJournalPromptCategory,AreteThemeConceptGraphLink. In-file fixtureprompts(5 entries) andentries(multipleReflectionEntryModels). - Writes:
saveAreteArtifact(localStorage); no BFF write - Realtime: none
- Caching: client bundle + localStorage for saved artifacts
- Auth/role check: app-level middleware
Cross-references#
- Domain hub:
arete.md - Related polished surfaces:
arete-review.md(weekly review uses similar prompt scaffolding),arete-coaching.md(letter from Lilith) - Sibling internal alternates:
- Cross-domain: theme-graph links route to Nisaba / Veritas / Tara / Arete / Nyx
via
buildConceptGraphDomainHref - Component source:
apps/oshun/web/src/components/domains/arete/AreteJournalReflectionWorkspace.tsx - Library:
libs/domain-arete/*(resolves as@oshun/domain-arete) - Assistant dispatch:
apps/oshun/web/src/navigation/assistant-entry.ts - Artifact support:
apps/oshun/web/src/components/domains/arete/areteArtifactSupport.ts,AreteArtifactActionPanel.tsx
E2E coverage#
apps/oshun/web/e2e/arete-journal-reflection-workspace.spec.tscovers the dedicated route's prompt selection, draft capture, top-bar and compose assistant event payloads, localStorage save, saved-at hydration after reload, entry selection, disabled share control, and Markdown export.- The same spec covers shell hydration through
/domains/arete?origin=home&path=%2Fjournalusing the real admin bulk-entitlements BFF flow to grant pro access before asserting the journal workspace, all three reflection windows, and the shell back button. - Theme-graph coverage includes
?entry=entry-language-fragile, the in-place practice link back to the architecture reflection, and the Tara ritual route generated bybuildConceptGraphDomainHref. - Responsive coverage asserts the desktop three-column lane alignment, mobile stacked order, no horizontal overflow, and minimum touch targets for the window selector.
Open questions / known gaps#
- Direct
/domains/arete/journalstill renders as a bare internal page; shell chrome is covered separately through/domains/arete?path=/journal - Saved artifacts live in localStorage only; no server persistence
-
dispatchOshunAssistantOpenevent payloads are verified; separately verify how the receiving assistant surface (Sophia / Lilith) consumes the seeded prompt - Theme-graph E2E verifies the practice link and Tara ritual route; confirm the remaining Nisaba, Veritas, Arete, and Nyx route mappings against actual route slugs
- In-file
entriesandpromptsarrays are fixtures; no BFF wiring - How does this surface relate to the polished
/arete"Journal" tab (the polished room'sLSubNav"Journal" item carrieshref="/domains/arete/journal"and navigates here)