mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
130 lines
6.6 KiB
Markdown
130 lines
6.6 KiB
Markdown
# Astrolabe Project
|
||
|
||
> **Purpose**: Onboarding document for AI agents (and humans) working on Astrolabe.
|
||
|
||
---
|
||
|
||
## Project Overview
|
||
|
||
**Astrolabe** is a browser-based snippet manager for Vega-Lite visualizations. A user keeps
|
||
a local library of **snippets** (saved Vega-Lite specs), edits each as JSON with live
|
||
validation and a live chart preview, and reuses **datasets** across many snippets. Fully
|
||
local, offline-capable, no account.
|
||
|
||
It is a **spec-driven rebuild** on an architecture adapted from its sibling project Syto.
|
||
The authoritative behavioral contract is **`docs/spec/`** (sections 00–10). Implement _to
|
||
the spec_; do not port legacy code.
|
||
|
||
### Technical Stack
|
||
|
||
| Layer | Technology |
|
||
| ------- | ------------------------------------------------------------------------------------ |
|
||
| Build | Vite, TypeScript, Vitest (happy-dom) |
|
||
| UI | React, Zustand, CSS Modules |
|
||
| Editor | Monaco (JSON + Vega-Lite schema service) |
|
||
| Charts | Vega-Lite + vega-embed |
|
||
| Storage | IndexedDB (snippets, datasets), localStorage (settings/prefs), URL hash (view state) |
|
||
| Offline | `vite-plugin-pwa` (Workbox), `registerType: 'prompt'` |
|
||
|
||
---
|
||
|
||
## Architecture (non-negotiable)
|
||
|
||
- **`src/core/` is portable** — no browser APIs, no React, no Monaco. All spec operations
|
||
live here and are tested hardest.
|
||
- **`src/app/`** — React + Zustand UI. State in Zustand **stores**; browser specifics in
|
||
**`src/app/infrastructure/`** adapters (IndexedDB / localStorage / URL hash). The rest of
|
||
the app never touches `window`/`indexedDB` directly.
|
||
- **Modals** go through a registry + coordinator + shell, not ad-hoc rendering.
|
||
- **CSS Modules + design tokens** (`styles/tokens.css`); themes flip `[data-theme]`.
|
||
- **No shared library with Syto** — patterns are adapted, never imported.
|
||
|
||
See [`docs/architecture/`](docs/architecture/00-overview.md) for the patterns behind each
|
||
layer (state, persistence, modals, routing, rendering, inference, relationships) and
|
||
`docs/IMPLEMENTATION-PLAN.md` for the milestone sequence. Both are **self-contained** — no
|
||
external repo is needed to work from them.
|
||
|
||
---
|
||
|
||
## Directory Structure
|
||
|
||
```
|
||
src/
|
||
├── main.tsx # App entry (font wiring, startup, render)
|
||
├── core/ # Portable spec engine (no browser/React/Monaco)
|
||
├── app/
|
||
│ ├── components/ # React UI (CSS Modules co-located)
|
||
│ ├── hooks/ # Reusable React hooks (e.g. useFocusTrap — shared by overlays)
|
||
│ ├── stores/ # Zustand stores (incl. ConfirmStore — in-app confirm dialogs)
|
||
│ ├── services/ # Business logic
|
||
│ ├── orchestration/ # Startup wiring: store↔adapter subscribers (persistence)
|
||
│ └── infrastructure/ # IndexedDB, localStorage, Monaco, settings adapters
|
||
styles/ # Global CSS (tokens, base)
|
||
docs/
|
||
├── spec/ # Authoritative behavioral specification (00–10) — the WHAT
|
||
├── architecture/ # Architecture playbook (00–09) — the HOW (self-contained)
|
||
│ └── visual-specimen.html # Standalone token sandbox + reusable-primitive catalog
|
||
├── IMPLEMENTATION-PLAN.md # Milestone sequence (M0–M6)
|
||
└── WHY-A-SEPARATE-REBUILD.md
|
||
```
|
||
|
||
---
|
||
|
||
## Development
|
||
|
||
```bash
|
||
npm run dev # Dev server
|
||
npm run build # Typecheck + production build (+ PWA)
|
||
npm run typecheck # tsc --noEmit
|
||
npm test # Vitest (run once)
|
||
npm run test:watch # Vitest watch
|
||
npm run format # Prettier
|
||
```
|
||
|
||
### AI Developer Protocol
|
||
|
||
- **No git on your own initiative** — don't `add`/`commit`/`push` unless explicitly invited.
|
||
- **Verify** — run `npm run typecheck` and `npm test` after changes. A green build and a
|
||
smaller bundle prove nothing about behavior: when a change touches what the user sees or
|
||
does, confirm it by exercising the feature, not by the compiler alone.
|
||
- **Trim content, not capability** — when narrowing a third-party import or build to cut
|
||
size, remove optional _content_, never the library's _features_. The smallest/lowest-level
|
||
entry point is seldom the right one — it often drops capabilities you meant to keep. Prefer
|
||
the entry that excludes the unwanted content while retaining behavior, and validate the
|
||
behavior survived. (This bit us once: importing Monaco's `editor.api` to drop unused
|
||
languages also stripped every editor feature — see `docs/architecture/08`.)
|
||
- The line isn't "content vs. capability" by category — it's **"does any real user path
|
||
depend on this?"** Safe to drop: data no user path exercises (a date formatter's unused
|
||
locale tables, an icon set you never render, themes you don't ship). _Not_ safe, even
|
||
though it looks like "content": **human-language coverage** — font script subsets,
|
||
translatable strings — which is capability the moment the app is meant to be usable in
|
||
that language. Treat dropping it like dropping a feature. (This bit us a second time:
|
||
trimming IBM Plex to the latin subsets dropped Cyrillic — capability for an
|
||
internationally-usable app. We ship every script subset and precache them for offline;
|
||
`unicode-range` means the browser only downloads what a glyph needs anyway.)
|
||
- **Spec is the contract** — when in doubt, read `docs/spec/`. If the spec is wrong or
|
||
silent, raise it; change the spec deliberately rather than drifting from it.
|
||
- **Core-first** — for each feature, build the pure `src/core/` logic with tests before UI.
|
||
|
||
### Project skills
|
||
|
||
Invoke with `/<name>` (defined in `.claude/skills/`):
|
||
|
||
- **`/alignment`** — review uncommitted/staged changes for quality, test coverage, and
|
||
alignment with `docs/spec/` + `docs/architecture/`. Fixes issues directly and leaves
|
||
`// TODO:` breadcrumbs at code sites for out-of-scope observations.
|
||
- **`/doc-update`** — capture session-discovered knowledge gaps into the right doc layer
|
||
(`docs/spec/` for behavior, `docs/architecture/` for patterns).
|
||
- **`/release`** — bump version, update the changelog, prepare a git tag.
|
||
|
||
### Versioning
|
||
|
||
Simplified semver `0.x.y` (pre-1.0): minor for features/behavior, patch for fixes. Single
|
||
source of truth is `version` in `package.json`, injected as `__APP_VERSION__`.
|
||
|
||
### Testing Philosophy
|
||
|
||
High coverage on `src/core/` (parsing, detection, profiling, reference resolution, fit
|
||
transforms, import normalization). Lighter on components. Extract testable logic out of
|
||
components into core/stores where practical.
|