Skip to content

ADR-037 — Shared surface-site type, deferred shared <SurfaceMap> component

Status · Accepted (closes RFC-012 OQ-1) Date · 2026-05-09 (back-filled from v0.4.0 implementation) Closes · RFC-012 OQ-1 ("Generic SurfaceMap component, or independent /mars + /moon?") TA anchor · §components/surface-routes Related ADRs · ADR-019 (ajv schema), ADR-038 (per-body 2D projection), ADR-039 (cross-link contract)

Context

PRD-009 specified /mars as a peer of /moon: same panel pattern, same site catalogue shape, same 3D + 2D toggle. RFC-012 OQ-1 asked whether the two routes should share a generic <SurfaceMap> component or stay independent.

Two stages were considered:

  1. Shared TYPE — pull the MarsSite + MoonSite interfaces out into a single SurfaceSite discriminated union with a kind: 'surface' | 'orbiter' field. Both routes alias the type so the JSON schema is shared, validate-data covers both with one ruleset, and panel rendering can share helpers.
  2. Shared COMPONENT — pull the actual 3D scene + 2D map + panel-mount logic into a <SurfaceMap site={…}> component used by both routes.

Decision

Shared TYPE — shipped in v0.4.0

src/types/surface-site.ts defines the canonical SurfaceSite interface plus the kind: 'surface' | 'orbiter' discriminator. src/types/mars-site.ts and src/types/moon-site.ts both export { SurfaceSite as MarsSite } / MoonSite for ergonomic per-route imports. Shared schema in static/data/schemas/surface-site.schema.json validates both mars-sites.json and moon-sites.json.

This gives V1 the data-layer + validation benefits without forcing the routes to share visual code while their 2D projections diverge (see ADR-038).

Shared COMPONENT — deferred to v0.6.0

The shared <SurfaceMap> component refactor is tracked as issue #42 on the v0.6.0 milestone. /mars and /moon currently have independent +page.svelte files that share helpers via src/lib/ (mostly site-state derivations + data fetchers) but not the rendering loop.

Rationale for deferring:

  • The Moon's orthographic-pair 2D projection (near + far disc) and Mars's equirectangular projection (single rectangular map) are visually different enough that a single component would need either two render paths or a per-body adaptor — that's the same complexity as keeping two routes.
  • /mars shipped with rover traverses (RFC-012 OQ-6) which /moon does not have. Adding traverses to a shared component would increase its API surface.
  • The cross-link contract (ADR-039) operates at the data-layer + URL level, not the component level, so it's unaffected by the routing split.

When Apollo / Chandrayaan / Chang'e site overlays land for /moon and the visual pattern stabilises, the shared-component refactor becomes worthwhile. Until then, two +page.svelte files of ~1100 lines each is cheaper than the abstraction.

Rationale

The data-layer abstraction (shared TYPE + schema) gives 80% of the maintenance benefit (one schema, one validator, one set of cross-link helpers) at 20% of the abstraction cost. The component-layer abstraction would force a single rendering path for two routes whose visual designs are still diverging — premature.

Alternatives considered

  • Single shared component for both routes — see "deferred" above. Premature.
  • No shared type — keeps full per-route freedom but duplicates the JSON schema and the cross-link helpers. Rejected because the data-layer cost is real.

Consequences

Positive:

  • One source of truth for surface-site shape across /mars and /moon.
  • One schema validates both sites JSON files; ajv catches drift.
  • Cross-link helpers (/mars/missions, /moon/missions) share a single implementation per ADR-039.
  • Two route files keep visual freedom for as long as projection / overlay design is moving.

Negative:

  • Two +page.svelte files of similar shape — visible duplication that future contributors may try to factor out.
  • The <SurfaceMap> shared component is now an outstanding refactor ticket (#42 on v0.6.0).

Implementation notes

  • src/types/surface-site.ts — canonical SurfaceSite interface + discriminator.
  • src/types/mars-site.ts, src/types/moon-site.ts — re-exports.
  • static/data/schemas/surface-site.schema.json — shared schema.
  • scripts/validate-data.ts validates both mars-sites.json and moon-sites.json against the same schema.
  • src/routes/mars/+page.svelte, src/routes/moon/+page.svelte — independent route files.
  • Component-shared refactor tracked as #42 (v0.6.0 milestone).

Orrery — architecture documentation · MIT · No tracking