Context. surface mobile · domain shell-routing · route /domain/[domainId] · auth anon (entry) | gated per-domain entitlement tier (paywall on lock) · source apps/oshun/mobile/app/domain/[domainId].tsx
Last walked. not yet walked
Purpose#
/domain/[domainId] is the single polymorphic domain screen. It resolves
domainId (tara, veritas, nyx, arete, nisaba, metis), evaluates entitlement
access, and renders a domain-specific entry hero plus the full domain content
(continuity, claims, sky events, check-ins, passages, etc.) inside one
ScrollView. It also handles startup loading, access-locked, offline-cache,
temporarily-unavailable, planned-preview, and deep-link-focus states. At ~14k
lines it is by far the largest mobile screen.
Entry points#
buildDomainRouteHref(domainId, {...})from Home, Explore, Activity, Library, Profile (and inter-domain switches). Params:origin,stack,path,ref,unavailable,reason,offline, plus per-domain hydration query.- Notification routing / deep links resolving to a domain path.
- Stack screen
domain/[domainId](title "Domain", headerBackTitle "Back", gesture-enabled) declared in_layout.tsx.
Layout regions#
- Header: stack header titled "Domain" with Back; gesture back enabled.
- Hero / above-the-fold: domain-specific
DomainEntryHero(eyebrow, title, body, stateLabel, metaItems, primary + secondary actions) — variants per domain (mobile-domain-entry-hero-<domain>). - Main:
mobile-domain-screen-<domain>ScrollView — badge, title, route intro body, route-context chips, planned-preview card (Metis), deep-link-focus card, E2E harnesses (Tara, flagged), then the domain-specific content blocks. - Alternate full-screen states: loading skeleton; access-locked; offline fallback (Tara/Veritas/Nisaba cached lists or generic recovery panel); unavailable recovery panel + domain switcher.
States#
- Loading —
startupLoadingrenders skeleton badge/title/body/cards + "Loadingmodule...". - Empty — per-domain empty handling inside content blocks (e.g. no saved objects); hero still leads with a primary action.
- Populated (short/long) — full domain content; long scroll.
- Error (recoverable) —
domainUnavailable→mobile-domain-unavailable-recovery-panelwith Retry domain launch + "Try another domain" switcher (filtered to allowed/available domains). - Error (unrecoverable) — caught by shell error boundary; unknown
domainIdfalls through tounknowntestIDs. - Offline —
offlineMode(≠ nyx) → cached Tara meditations / Veritas briefings / Nisaba passages+notes lists, each launchable from cache; otherwise genericmobile-domain-offline-<domain>recovery panel. Nyx has its own offline sky-map path. - Permissions-denied — N/A at this screen (capture is on Home).
- Gated —
domainAccess.allowed === false→ "access locked" with current/required tier, reason, Upgrade plan (→ Profile paywall), Back, and an available-domains switcher. - iOS vs Android — Nyx night-mode palette; otherwise dark theme; back
gesture enabled (
fullScreenGestureEnabled).
Interactions#
- Domain entry hero — primary action
(
mobile-domain-entry-primary-<domain>)- Function: per-domain (Tara: launch/resume meditation or course / write reflection; Veritas: resume reading; Nyx: resume observation; Arete: start check-in / view streaks; Nisaba: open passage). Pushes domain path or starts an in-screen session.
- Domain entry hero — secondary actions (
...-secondary-<domain>-*)- Function: open trending brief / top claim / saved brief (Veritas); sky map / highlight / log (Nyx); top goal / journal prompt (Arete); workspace / passage (Nisaba); etc.
- Upgrade plan (access-locked, Pressable)
- Function:
openUpgradeFlow(requiredTier)→ push Profile w/intent=upgrade,domain,requiredTierparams.
- Function:
- Back to
(access-locked / offline / unavailable) - Function:
handleBackInShell→router.replaceprevious domain or origin tab; haptic.
- Function:
- Domain switch chip (
switchChip, access-locked + unavailable states)- Function:
switchDomain(domain)(only allowed + available domains shown).
- Function:
- Retry domain launch (offline/unavailable recovery panels)
- Function:
retryDomainLaunch.
- Function:
- Offline cached card (Tara/Veritas:
ContinuityCard; Nisaba:PassageListItem/NotebookCard)- Function: set offline route path, exit offline mode, launch from cache /
open cached brief/passage/note; haptic + notice. testIDs
<domain>-offline-cache-offline-card/passage/note-<id>.
- Function: set offline route path, exit offline mode, launch from cache /
open cached brief/passage/note; haptic + notice. testIDs
- Deep-link focus CTA (
mobile-domain-deep-link-cta-<domain>)- Function:
handleOpenDeepLinkFocus(opens the resolved deep-link target).
- Function:
- E2E Tara complete session (
tara-e2e-complete-session, flagged)- Function:
handleCompleteTaraSessionForE2E(forces session completion for Maestro). AlsoTaraReflectionCaptureCard(note input, suggestions, save).
- Function:
- Per-domain content controls — extensive: Tara quick-reset/sleep-timer selectors + audio session; Veritas save/follow article+claim, topic follow; Nyx save/remind/night-mode/sky-map; Arete goals/habits/journal/balance/routine; Nisaba annotations (note input, color, visibility, save/edit), compare, grounded evidence. (Each block has its own testIDs; document per-domain in a follow-up pass if needed.)
Data & contracts#
- Reads:
@oshun/domain-registry(getDomainMetadata,isKnownDomain, offline-fallback + launch-permission), per-domain libs (@oshun/domain-tara| veritas|nyx|arete|nisaba,@oshun/shell-routines), BFF client (Nisaba passage/compare/grounded-evidence/manuscript/annotations), offline caches, auth + profile + offline-queue context, runtime config. - Writes: BFF annotation save; library/topic/object follow + save state; Tara reflection records; offline-mode toggles.
- Realtime: shared audio session manager (
getSharedAudioSessionManager). - Caching: per-domain offline caches; in-memory fixtures
(
TARA_CONTINUE_SESSION,VERITAS_*,NYX_*,ARETE_*,NISABA_*). - Auth/role check:
evaluateDomainAccess(domain, entitlements)→ allowed/required tier; Metis surfaces enforce tier before navigation.
Cross-references#
- Entry builders:
@/navigation/routes(buildDomainRouteHref,buildTabRouteHref); context parseparseDomainRouteContext. - Upgrade target: profile.md (
intent=upgradepaywall). - Component sources:
@/components/MobileRecoveryPanel,DomainEntryHero,ContinuityCard,PassageListItem,NotebookCard,TaraReflectionCaptureCard.
Open questions / known gaps#
- Per-domain content blocks are extensive (each domain has dozens of controls) — this file documents the shared scaffold + hero + state machine; a per-domain deep walk should follow.
- Many domain datasets are in-module fixtures alongside live BFF reads (notably Nisaba) — confirm which are live in production.
- Nyx is excluded from the generic offline/unavailable branches (has its own night/offline-sky handling) — verify Nyx offline parity.