Context. surface customer · domain nyx · route /domains/nyx/events/[eventId] · auth signed-in · source apps/oshun/web/src/app/domains/nyx/events/[eventId]/page.tsx
Last walked. 2026-06-27 documentation reconciliation against existing automated coverage — standalone and shell event detail render, missing state, event-lane entry, sky-chart handoff, cross-domain overlays, concept graph, ICS download content, action-state persistence, reminder BFF mirror, service-worker notification routing, and observation-log eventId back-reference verified by Nyx E2E specs.
Purpose#
Canonical Nyx event page — full detail for a single celestial event including
observation plan, what-to-notice list, sky-chart handoff, and cross-domain
bridges into Nisaba (cosmology overlays), Veritas (grounded explainers), Tara
(perspective recommendations) and Metis (study recommendations). Page is a
'use client' shell
(apps/oshun/web/src/app/domains/nyx/events/[eventId]/page.tsx) that mounts
<NyxEventDetailWorkspace eventId={params.eventId} origin="explore" onClose={() => router.back()} variant="page" />.
Entry points#
- Calendar overlay row (
/domains/nyx/events) — "View event page" link (data-testid="nyx-event-open-<eventId>") →event.domainHref - Direct URL / bookmark — yes (signed-in)
- Other Nyx surfaces — yes: event lane rows, the focused sky-chart handoff,
observation-log
eventIdhandoff, and notification service-worker deep links are covered by Nyx E2E specs
Layout regions#
NyxEventDetailWorkspace
(apps/oshun/web/src/components/domains/nyx/NyxEventDetailWorkspace.tsx,
variant="page") renders:
- Top breadcrumb row: "Back to Nyx events" link →
/domains/nyx?origin=explore&path=%2Feventsand "Open inside the Nyx domain" link →event.domainHref - Hero card: chip strip (event type / importance / visibility / state
label + summary badges), kicker "Nyx event page",
<h1 data-testid="nyx-event-detail-title">{event.title}</h1>, summary paragraph - Meta panels grid:
Starts/Window/Countdown/Equipment - Action row 1: "Add to calendar" button (
data-nyx-event-download-ics), "Open in Nyx event lane" link → domain href, "Open focused sky chart" link →event.skyChartHref - Action row 2 (
data-testid="nyx-event-action-bar"): Save / Follow / Remind toggle buttons (useNyxEventActionState) NyxEventReminderControls(full size, when reminder enabled)- Two-column section:
- Article (left): "Why this event matters" (description + seasonal
context), "Observation plan" (headline + numbered steps cards with
data-testid="nyx-event-observation-plan"), "What to notice" bulleted list, "Concept graph links" panel (data-testid="nyx-event-concept-graph", when threads present) - Sidebar (right) — overlay/recommendation cards:
- Sky chart handoff panel (
data-testid="nyx-event-sky-chart-panel") — focus summary, object chips, mode chip ("Event tracking" / "Guided sky"), "Continue into chart" link toevent.skyChartHref - Nisaba overlays (
data-testid="nyx-event-nisaba-overlays", conditional) - Veritas grounded explainers
(
data-testid="nyx-event-veritas-explainers", conditional) - Tara perspective recommendation
(
data-testid="nyx-event-tara-recommendations", conditional) - Metis recommendations
(
data-testid="nyx-event-metis-recommendations", conditional)
- Sky chart handoff panel (
- Article (left): "Why this event matters" (description + seasonal
context), "Observation plan" (headline + numbered steps cards with
- Missing-event state: if
getNyxEventDetailModel(eventId)returns null, renders the "Event not found" card with a "Return to Nyx events" link (data-nyx-event-detail-missing)
States#
- Loading — model lookup is synchronous (
getNyxEventDetailModel); no async fetch or loading spinner is coded - Populated — canonical seeded events render the page shell, hero,
observation plan, action bar, reminder controls, and cross-domain sections
they have data for (
nyx-event-pages) - No event (unknown
eventId) — "Event not found" card withdata-nyx-event-detail-missingand a Return link - Reminder enabled — full
NyxEventReminderControlspanel expands; week-before + external-calendar selection persists across standalone and shell detail routes - No cross-domain overlays — conditional sections (Nisaba / Veritas / Tara / Metis) omitted
- Offline — static client model; renders offline once cached
- Standalone PWA — verify safe-area insets at top breadcrumb row
Interactions#
Breadcrumb / nav row#
- "Back to Nyx events" link — href
/domains/nyx?origin=explore&path=%2Fevents - "Open inside the Nyx domain" link — href
event.domainHref
Hero card#
- Chip strip — read-only badges for event type, importance, visibility, state, and any summary badges
Action row 1#
- "Add to calendar" button (
data-nyx-event-download-ics)- Function:
downloadNyxEventICalFile(event.eventId)— triggers ICS download
- Function:
- "Open in Nyx event lane" link —
event.domainHref - "Open focused sky chart" link
(
data-testid="nyx-event-sky-chart-link",data-nyx-event-sky-chart-link="<eventId>") — hrefevent.skyChartHref
Action row 2#
- "Save event / Saved event" toggle
(
data-testid="nyx-event-save-toggle")- Function:
toggleSavedfromuseNyxEventActionState
- Function:
- "Follow event / Following updates" toggle
(
data-testid="nyx-event-follow-toggle") - "Remind me / Reminder set" toggle
(
data-testid="nyx-event-reminder-toggle")
Reminder controls (when reminder enabled)#
- Cadence selector —
nyx-event-pagesexercisesweek-before;nyx-event-actions-bffverifies cadence persistence and route reconstruction at the server mirror - Channel chips —
nyx-event-actions-real-syncexercises and persistspush,email,sms, andexternal-calendarthrough the real BFF and verifies route labels formobile-push,email,sms, andcalendar-sync
Observation plan#
- Each step card — read-only with
Step N, title, detail
Sky chart handoff#
- Focus object chips — read-only badges (each from
event.skyChartFocusObjects) - Mode chip — "Event tracking" or "Guided sky"
- "Continue into chart" link — href
event.skyChartHref
Cross-domain overlay cards#
- Each
NisabaOverlayCard—nyx-event-pagesverifies the generated cosmology, calendar source-pack, and comparative text targets land in the hydrated Nisaba shell - Each
VeritasGroundedExplainerCard—nyx-event-pagesverifies the phenomenon, visibility, and retraction explainer targets land in the hydrated Veritas shell - Each
TaraRecommendationCard—nyx-event-pagesverifies the Tara ritual target and the reciprocal Nyx continuity card - Each
MetisRecommendationcard —nyx-event-pagesverifies the mini-course, course path, study pack, and tutoring targets land in the hydrated Metis shell preview
Concept graph#
- Each
ConceptGraphThreadCard—nyx-event-pagesverifies the seasonal-threshold event, Nisaba passage, Arete practice, and anchor-chain links, including live click-through to Nisaba and Arete
Missing state#
- "Return to Nyx events" link — href
/domains/nyx?origin=explore&path=%2Fevents
Data & contracts#
- Reads:
getNyxEventDetailModel(eventId, { origin, stack })fromnyxEventPageModels— bundled detail data - Writes: ICS file download; save / follow / reminder state via
useNyxEventActionState - Realtime: none
- Caching: static client bundle
- Auth/role check: middleware enforces signed-in for
/domains/*
Automated coverage#
-
apps/oshun/web/e2e/nyx-event-pages.spec.tscovers standalone/events/<id>and shell/domains/nyx/events/<id>render, event-lane entry, missing-event recovery, back link, sky-chart handoff, cross-domain Nisaba/Veritas/Tara/Metis cards, assistant explainers, concept graph links, ICS filename, and save/follow/reminder action-state persistence across standalone and shell routes -
apps/oshun/web/e2e/nyx-event-actions-real-sync.spec.tscovers the standalone event detail route against the real BFF action-state mirror: title and meta panels, "Open inside the Nyx domain" and "Open in Nyx event lane" canonical shell hrefs, observation-logeventIdhandoff href, save/follow/reminder writes, all cadence/channel controls, all reminder route labels, remote read-back after localStorage clearing, and shell event-lane re-entry with persisted controls -
apps/oshun/web/e2e/nyx-event-ics.spec.tsreads the downloaded.icsstream and verifiesBEGIN:VCALENDAR,BEGIN:VEVENT,DTSTART,SUMMARY, and event-specificUID:<eventId>@oshun-nyx -
apps/oshun/web/e2e/nyx-event-actions-bff.spec.tscovers the real BFF action-state mirror: auth/scope gates, PUT→GET cadence + channel persistence, delivery-route reconstruction, and invalid-write fail-closed branches -
apps/oshun/web/e2e/nyx-service-worker-notification.spec.tscovers the shipped service worker's Nyx reminder push payload and notification-click cold/open-window and existing-window focus behavior -
apps/oshun/web/e2e/nyx-tonight-observation.spec.tscovers the event-detail observation-log link carryingeventId=jupiter-venus-conjunction, observation POST body, BFF read-back, and Home rail/KPI rehydration
Cross-references#
- Calendar list:
domains-nyx-events.md - Sky chart:
domains-nyx-star-chart.md - Domain hub:
nyx.md - Component source:
apps/oshun/web/src/components/domains/nyx/NyxEventDetailWorkspace.tsx - Model source:
apps/oshun/web/src/components/domains/nyx/nyxEventPageModels.ts
Open questions / known gaps#
- Confirm whether
useNyxEventActionStatepersists save / follow / reminder across reloads (and where) — localStorage primary keyoshun:nyx:event-actions:v1plus BFF mirror/v1/nyx/event-actions; covered bynyx-event-pagesandnyx-event-actions-bff - Document the assistant explainer panel (
buildNyxEventAssistantExplainersresult) — rendered asdata-testid="nyx-event-assistant-explainers"and covered bynyx-event-pages - Confirm what the "Open inside the Nyx domain" link goes to versus the
breadcrumb back-link — the breadcrumb targets
/domains/nyx?origin=explore&path=%2Fevents; both "Open inside the Nyx domain" and "Open in Nyx event lane" targetevent.domainHref, e.g./domains/nyx?origin=explore&path=%2Fevents%2Fjupiter-venus-conjunction