Files

8.9 KiB

Astrolabe — Architecture Playbook

These documents capture the architectural patterns Astrolabe is built on. They are self-contained: everything needed to implement a pattern lives here, in Astrolabe's own domain terms (snippets, datasets, settings, Vega-Lite specs). You do not need any other repository to work from them.

They are the architectural counterpart to docs/spec/: the spec says what the app does (behavior, acceptance points); this playbook says how we build it (state, persistence, modals, routing, rendering, inference, relationships, and the visual + interaction language).

Spec vs playbook: cite, don't restate

The two documents overlap most in §09 (visual) and §10 (interaction), which necessarily talk about user-facing widgets. At that overlap, one rule keeps them from drifting:

  • The spec owns product behavior — what features exist, what surfaces appear when, what the data does. The playbook owns the how — state shape, persistence, ARIA roles, keyboard models, focus, tokens, motion.
  • For product behavior, the spec is the source: cite it (spec §NN), don't restate it, and never contradict it. A playbook bullet may name the behavior in one clause and cite the spec, then spend its words on the how (the role, the keys, the focus move) and the why (the council/canon citation). When a playbook bullet and the spec disagree, the spec wins and the bullet is the bug — both describe the shipped code, so if the spec section is itself stale, rewrite it to match the app, then cite it (the code leads; the spec records). Restatement is the leak: two docs describing the same behavior in their own words drift into contradiction; one cites the other instead.

How to use this playbook

  • Building a feature? Read the relevant spec section first (the what), then the matching playbook doc (the how), then implement core-first per ../IMPLEMENTATION-PLAN.md.
  • Each doc states the pattern, the rationale (what problem it solves, what it prevents), TypeScript sketches in Astrolabe terms, and Do/Don't rules.
  • The sketches are illustrative, not finished code. Adapt them; keep the principles.

The documents

# Doc Covers
01 State & Stores Zustand stores; one source of truth; selector derivations; central useAppStore vs per-feature stores; testable action functions; debounced auto-save.
02 Persistence The infrastructure-adapter boundary; promise-wrapped IndexedDB wrapper; lazy data loading; per-record schema versioning + migration; localStorage prefs with fallback; storage tiers + quota monitoring.
03 Modal System Registry + coordinator + shell; one modal at a time; unsaved-change detection via snapshot; focus trap; backdrop/Escape/close dismissal.
04 Routing & Events URL hash as view-state (restore/sync, Back/Forward); global keyboard routing; Escape priority chain; the single-source isInInteractiveContext() helper (Monaco-aware).
05 Rendering, Theming & Preview vega-embed integration (actions:false, view.finalize()); field-name escaping; theme→config mapping; debounced non-blocking renderer; resilient error display.
06 Type Inference & Profiling Pure, portable column-type inference (number/text/date/boolean) and the dataset profile shape.
07 Naming & Relationships Unique-name enforcement + import auto-suffix; the bidirectional snippet↔dataset name link; rename propagation into specs.
08 vega/editor Techniques Reference brief: borrowable Monaco-schema wiring, vega-embed lifecycle, two-tier validation, and data-flow/debounce techniques distilled from the official Vega-Lite editor — plus where we do better, and our editor-augmentation layer (structural transforms + data-aware hints).
09 Visual Design Language The visual contract: principles inspired by IBM/Carbon, deliberate divergences (square chrome, free color/theming), the token system (Plex type, 8px spacing, role-based color, motion), component conventions, and where to mine the Carbon/IBM source repos for more. Companion: visual-specimen.html.
10 Interaction & Feedback The interaction contract: the feedback-channel decision table, latency/feedback budgets, the non-happy-path triad, the recovery & data-safety contract, the keyboard/focus contract, and the resolved widget patterns (window splitter, toolbar, segmented controls, selectable lists, search, sort, empty states, modals). Cites spec/ for behavior; owns the how.
11 Learning Section The /learn/ deep-dive: a marketing-surface Vite entry reusing core + the landing chart embed; markdown-authored lessons (import.meta.glob) parsed into an ordered block model; the authoring/engine split (pure parser in core; marked only in src/learn).

The non-negotiable layering (every doc assumes this)

  • src/core/ — portable, pure logic. No browser APIs, no React, no Monaco. Spec operations live here and are unit-tested hardest. (Docs 06, 07, parts of 05 land here.)
  • src/app/stores/ — Zustand stores. (Doc 01.)
  • src/app/infrastructure/ — the only place that touches indexedDB, localStorage, or window.location. Everything else goes through these typed adapters. (Docs 02, 04.)
  • src/app/services/ & orchestration/ — coordination that composes stores + infrastructure + core (lifecycle, routing sync, dependency upkeep). (Docs 03, 04, 07.)
  • src/app/components/ — React + CSS Modules. Thin; pushes logic down into stores/core so it stays testable. (Docs 03, 05.)

Why a playbook at all

Patterns written down once, in one place, stop two classes of problem: drift (the same decision re-litigated inconsistently across features) and rediscovery (re-deriving why something is the way it is). When a pattern here proves wrong, change the doc — don't fork the convention silently. This is the same discipline docs/spec/ applies to behavior.