6.5 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).
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. |
| 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. |
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 touchesindexedDB,localStorage, orwindow.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.