---
path: /domains/nyx/events/[eventId]
surface: customer
domain: nyx
auth: signed-in
source: apps/oshun/web/src/app/domains/nyx/events/[eventId]/page.tsx
status: walked
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.'
---

# Nyx · Event Detail

## 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

- [x] **Loading** — model lookup is synchronous (`getNyxEventDetailModel`); no
      async fetch or loading spinner is coded
- [x] **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`)
- [x] **No event** (unknown `eventId`) — "Event not found" card with
      `data-nyx-event-detail-missing` and a Return link
- [x] **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

### Breadcrumb / nav row

- [x] **"Back to Nyx events" link** — href
      `/domains/nyx?origin=explore&path=%2Fevents`
- [x] **"Open inside the Nyx domain" link** — href `event.domainHref`

### Hero card

- [x] **Chip strip** — read-only badges for event type, importance, visibility,
      state, and any summary badges

### Action row 1

- [x] **"Add to calendar" button** (`data-nyx-event-download-ics`)
  - Function: `downloadNyxEventICalFile(event.eventId)` — triggers ICS download
- [x] **"Open in Nyx event lane" link** — `event.domainHref`
- [x] **"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

- [x] **"Save event / Saved event" toggle**
      (`data-testid="nyx-event-save-toggle"`)
  - Function: `toggleSaved` from `useNyxEventActionState`
- [x] **"Follow event / Following updates" toggle**
      (`data-testid="nyx-event-follow-toggle"`)
- [x] **"Remind me / Reminder set" toggle**
      (`data-testid="nyx-event-reminder-toggle"`)

### Reminder controls (when reminder enabled)

- [x] **Cadence selector** — `nyx-event-pages` exercises `week-before`;
      `nyx-event-actions-bff` verifies cadence persistence and route
      reconstruction at the server mirror
- [x] **Channel chips** — `nyx-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

- [x] **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

- [x] **Each `NisabaOverlayCard`** — `nyx-event-pages` verifies the generated
      cosmology, calendar source-pack, and comparative text targets land in the
      hydrated Nisaba shell
- [x] **Each `VeritasGroundedExplainerCard`** — `nyx-event-pages` verifies the
      phenomenon, visibility, and retraction explainer targets land in the
      hydrated Veritas shell
- [x] **Each `TaraRecommendationCard`** — `nyx-event-pages` verifies the Tara
      ritual target and the reciprocal Nyx continuity card
- [x] **Each `MetisRecommendation` card** — `nyx-event-pages` verifies the
      mini-course, course path, study pack, and tutoring targets land in the
      hydrated Metis shell preview

### Concept graph

- [x] **Each `ConceptGraphThreadCard`** — `nyx-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

- [x] **"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

- [x] `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
- [x] `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
- [x] `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`
- [x] `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
- [x] `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
- [x] `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`](./domains-nyx-events.md)
- Sky chart: [`domains-nyx-star-chart.md`](./domains-nyx-star-chart.md)
- Domain hub: [`nyx.md`](./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

- [x] 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`
- [x] Document the assistant explainer panel (`buildNyxEventAssistantExplainers`
      result) — rendered as `data-testid="nyx-event-assistant-explainers"` and
      covered by `nyx-event-pages`
- [x] 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`
