V1 Web PWA · Surface walkthrough

Nyx · Coordinate Tools

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

walked
8sections2 minread

On this page

Context. surface customer · domain nyx · route /domains/nyx/coordinates · auth signed-in · source apps/oshun/web/src/app/domains/nyx/coordinates/page.tsx

Last walked. 2026-05-29 automated runtime walk (Playwright) — hydration fix verified: 0 page/console errors, render+data OK; live SR/touch/offline/telemetry pending manual AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md

Purpose#

Astronomical coordinate-system conversion and timing tools — equatorial ↔ horizontal, galactic conversions, airmass calculation, sidereal time, rise/set times, and coordinate format conversion. Wired via apps/oshun/web/src/app/domains/nyx/coordinates/page.tsx ('use client') which mounts <NyxCoordinateTools onClose={() => router.back()} />.

Entry points#

  • Direct URL / bookmark — yes (signed-in)
  • In-app navigation — verify Nyx domain hub deep-link presence
  • Browser back affordance — in-component back button calls router.back()

Layout regions#

NyxCoordinateTools (apps/oshun/web/src/components/domains/nyx/NyxCoordinateTools.tsx):

  • Header: back button (aria-label="Go back"), title <h1>Coordinate Tools</h1>
  • Tab bar: six tabs from TABSRA/Dec ↔ Alt/Az (converter), Galactic (galactic), Airmass (airmass), Sidereal Time (sidereal), Rise/Set (riseset), Format (format)
  • Content: per-tab calculator with inputs and computed outputs
  • Direction toggle (within converter/galactic): switches conversion direction (eq2hzhz2eq, eq2galgal2eq)

States#

  • Loading — no async data
  • Default tabconverter is initial active tab
  • Computed result — converter shows transformed coordinates with the observer location and time
  • Invalid input — verify behaviour on out-of-range RA / Dec / lat / lng
  • Offline — static client bundle; works offline

Interactions#

  • "Go back" button (icon button, ArrowLeft)
    • Function: onCloserouter.back()
    • Screen reader: "Go back"

Tab bar#

  • RA/Dec ↔ Alt/Az tab — sets direction='converter'
  • Galactic tab — sets direction='galactic'
  • Airmass tab
  • Sidereal Time tab
  • Rise/Set tab
  • Format tab

Converter direction toggle (within converter tab)#

  • eq2hz button (Equatorial → Horizontal) — sets direction='eq2hz'
  • hz2eq button (Horizontal → Equatorial) — sets direction='hz2eq'

Galactic direction toggle (within galactic tab)#

  • eq2gal button (Equatorial → Galactic) — sets direction='eq2gal'
  • gal2eq button (Galactic → Equatorial) — sets direction='gal2eq'

Per-tab input fields#

  • RA / Dec inputs — numeric inputs feeding conversion functions
  • Lat / Lng / time inputs (where applicable) — observer context
  • Computed output rows — read-only display of the transformed coordinates

Data & contracts#

  • Reads: pure client computation — no network reads
  • Writes: none
  • Realtime: none
  • Caching: static client bundle
  • Auth/role check: middleware enforces signed-in for /domains/*

Cross-references#

Open questions / known gaps#

  • Runtime walk (2026-05-29) — defect FIXED & verified: React 418 hydration mismatch resolved (time-derived values now deferred to a post-mount effect via useClientNow/useIsMounted from @/hooks/useClientTime; for /coordinates the missed RiseSetCalculator site was gated). Re-walked against a fresh build: 0 page errors, 0 console errors, HTTP 200. React error #418; visit https://react.dev/errors/418?a. React error 418 is a hydration mismatch — server-rendered HTML differs from the client (this view renders time/position-dependent content, e.g. new Date()/toLocale*, without suppressHydrationWarning). Fix: compute time-dependent values in an effect or gate with suppressHydrationWarning. Status kept drafted until fixed.
  • Document exact per-tab input field labels (lat/lng/RA/Dec format expected)
  • Confirm whether numeric inputs surface ARIA labels and validation messages
  • Verify whether observer location defaults to DEFAULT_OBSERVER or requests user lat/lng