V1 Web PWA · Surface walkthrough

Nyx · Event Detail

A per-surface walkthrough of the V1 Web PWA customer surface: layout, states, interactions, data, and cross-references.

walked
9sections6 minread

On this page

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 eventId handoff, 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=%2Fevents and "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 to event.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)
  • 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 with data-nyx-event-detail-missing and a Return link
  • Reminder enabled — full NyxEventReminderControls panel 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#

  • "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
  • "Open in Nyx event lane" linkevent.domainHref
  • "Open focused sky chart" link (data-testid="nyx-event-sky-chart-link", data-nyx-event-sky-chart-link="<eventId>") — href event.skyChartHref

Action row 2#

  • "Save event / Saved event" toggle (data-testid="nyx-event-save-toggle")
    • Function: toggleSaved from useNyxEventActionState
  • "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 selectornyx-event-pages exercises week-before; nyx-event-actions-bff verifies cadence persistence and route reconstruction at the server mirror
  • Channel chipsnyx-event-actions-real-sync exercises and persists push, email, sms, and external-calendar through the real BFF and verifies route labels for mobile-push, email, sms, and calendar-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 NisabaOverlayCardnyx-event-pages verifies the generated cosmology, calendar source-pack, and comparative text targets land in the hydrated Nisaba shell
  • Each VeritasGroundedExplainerCardnyx-event-pages verifies the phenomenon, visibility, and retraction explainer targets land in the hydrated Veritas shell
  • Each TaraRecommendationCardnyx-event-pages verifies the Tara ritual target and the reciprocal Nyx continuity card
  • Each MetisRecommendation cardnyx-event-pages verifies the mini-course, course path, study pack, and tutoring targets land in the hydrated Metis shell preview

Concept graph#

  • Each ConceptGraphThreadCardnyx-event-pages verifies 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 }) from nyxEventPageModels — 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.ts covers 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.ts covers 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-log eventId handoff 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.ts reads the downloaded .ics stream and verifies BEGIN:VCALENDAR, BEGIN:VEVENT, DTSTART, SUMMARY, and event-specific UID:<eventId>@oshun-nyx
  • apps/oshun/web/e2e/nyx-event-actions-bff.spec.ts covers 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.ts covers 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.ts covers the event-detail observation-log link carrying eventId=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 useNyxEventActionState persists save / follow / reminder across reloads (and where) — localStorage primary key oshun:nyx:event-actions:v1 plus BFF mirror /v1/nyx/event-actions; covered by nyx-event-pages and nyx-event-actions-bff
  • Document the assistant explainer panel (buildNyxEventAssistantExplainers result) — rendered as data-testid="nyx-event-assistant-explainers" and covered by nyx-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" target event.domainHref, e.g. /domains/nyx?origin=explore&path=%2Fevents%2Fjupiter-venus-conjunction