docs: ADR-0042 — public website + documentation site plan

Planning artifacts for the first public website, recorded before any
code is written.

- ADR-0042: the decisions — Astro 5 + Starlight + Tailwind v4 (over
  SvelteKit); asciinema .cast demos reusable in docs (scripted-input
  driver, not history.log replay); in-page WASM playground deferred
  behind a stable demo seam, with the portable-core vs native-edge
  boundary recorded for a future ADR; portable static hosting (Vercel
  target); monorepo (website/); website is the canonical docs home;
  full-feature-set docs with "planned" callouts; user-facing copy uses
  no engine name and no "DSL"; install via prebuilt binaries + package
  managers.
- docs/plans/20260604-adr-0042-website.md: implementation plan with the
  grounded documentation inventory and phases A–E.
- website/STYLE.md: living documentation style guide + open-decisions log.
- docs/adr/README.md: index updated for ADR-0042 (numerical order).
This commit is contained in:
claude@clouddev1
2026-06-05 08:13:36 +00:00
parent a8d0138d8b
commit 1fad29c0f9
4 changed files with 397 additions and 0 deletions
@@ -0,0 +1,124 @@
# ADR-0042: Public website and documentation site
## Status
Accepted (2026-06-04). Implementation plan:
[`docs/plans/20260604-adr-0042-website.md`](../plans/20260604-adr-0042-website.md).
## Context
RDBMS Playground is nearing its first public release and needs a public
website that does two jobs: **attract** — a landing page that shows the
playground in action — and **document** — a thorough, canonical reference
for everything the playground can do.
The documentation-heavy surface is already implemented and verified (full
simple- and advanced-mode command set, the ten-type vocabulary,
relationships, constraints, indexes, EXPLAIN, undo/history/replay, projects,
export/import, the teaching echo, clipboard, friendly errors, tab completion
and syntax highlighting; 2151 tests passing at the time of writing). The
site is therefore largely a presentation-and-writing effort, not a
wait-for-features one. A grounded inventory of what is shippable now lives
in the implementation plan.
Several choices here had no canonical default; they were settled during a
planning + `/runda` pass with the user and are recorded below.
## Decision
1. **Stack — Astro 5 + Starlight + Tailwind v4.** Astro's content-first,
zero-JS-by-default model with the Starlight docs theme fits a
marketing-landing-plus-heavy-docs site better than the alternative
considered, SvelteKit + Tailwind (the usual go-to here). Interactive
pieces are added as Astro islands (Svelte or vanilla), so Svelte is still
available where it earns its place. Tailwind v4 is wired via the official
`@tailwindcss/vite` plugin; the `@astrojs/starlight-tailwind` plugin
bridges Tailwind with Starlight's theming.
2. **Demo medium — asciinema.** Showcase sequences are recorded as
asciinema `.cast` files (text-based, small, faithful to the full
alternate-screen render) and embedded with `asciinema-player`. The same
casts are reused inline in the docs — one recording format serves both
the landing page and documentation enrichment. Recordings are produced by
a **scripted-input driver** that types commands into a real PTY with
viewer-friendly pacing; the app's own `history.log` **replay** (ADR-0034)
re-executes commands without typing animation or pacing and is therefore
suitable only for state-deterministic docs snippets, not the hero demo.
3. **In-page WASM playground — deferred** (OOS: **deferred**, not rejected).
A live, type-it-yourself playground compiled from the Rust app to
WebAssembly is desirable but is a multi-week sub-project, so it does not
block the site. The demo section is designed with a stable seam (a single
`Demo` component contract) so a WASM playground island can replace the
asciinema player later with no change to call sites. Recorded boundary
for that future work:
- **Portable core (runs on `wasm32-unknown-unknown` largely as-is):**
`src/dsl/*` (parser, types, grammar, walker), the pure `App::update()`,
`ui.rs`, `theme.rs`, `friendly/*`, output rendering; an in-memory DB
path already exists (`Connection::open_in_memory()`). `rusqlite`
compiles to the browser target via its `ffi-sqlite-wasm-rs` feature.
- **Native edge needing `cfg`-gated browser replacements:** the
multi-thread Tokio runtime + the dedicated DB **worker thread**
(ADR-0010) → current-thread/in-line async; `crossterm` terminal +
event-stream → a browser backend (e.g. Ratzilla's DOM/Canvas) + DOM
events; `arboard`, `zip`, file persistence (ADR-0015), file logging;
and the rusqlite **backup-API** undo (ADR-0006) → a SQL dump/restore.
When taken up, this becomes its own ADR + iteration plan.
4. **Hosting — portable static build; Vercel is the likely target.** Astro 5
builds to static HTML/CSS with no adapter, so the output deploys equally
to Vercel, Cloudflare Pages, Netlify, or GitHub Pages. We avoid coupling
to any one host. **No CI yet** — the site is tested locally (`pnpm dev` /
`pnpm build`) until the repo reaches its public home.
5. **Repo topology — monorepo.** The site lives under `website/` in the
playground repo; the crate stays at the repo root. The repo as a whole
moves to its public home later; site and crate travel together.
6. **Canonical docs home — the website.** User-facing documentation lives on
the site. In-repo `docs/` keeps ADRs, handoffs, and development notes;
`docs/simple-mode-limitations.md` (requirement DOC1) was a development aid
and now *feeds* the site's content rather than competing with it. The
sharing recipes promised by requirement E2 become a docs page.
7. **Documentation scope and conventions.** Document the **full supported
feature set**. Any capability not yet fully implemented (a small minority
— e.g. multi-line input, query cancellation, `seed`, `m:n` convenience,
ER-diagram export, the `show tables`/`relationships`/`indexes` family) is
either omitted or carries a clear **"planned / not yet available"**
callout — never presented as shipped. Two wording rules bind all
user-facing copy:
- **No engine name** (SQLite/STRICT/rusqlite/PRAGMA) — continues the
user-facing posture of ADR-0002; copy says "the database"/"the engine".
- **No "DSL"** — it is internal jargon. The two input modes are **simple
mode** (the playground's keyword command language) and **advanced
mode** (SQL).
8. **Install documentation — two mechanisms.** The install page documents
**prebuilt release binaries** (self-hosted download — not GitHub
Releases, since the repo will move) and **package managers**. Both can be
written now against the planned mechanisms; concrete download URLs slot in
at release. (Distribution items D1D3 in `requirements.md` remain the
tracking home for the release tooling itself.)
## Consequences
- The site can ship on the strength of already-implemented features; it is
gated on writing and recording, not on finishing the app.
- One recording format (asciinema `.cast`) serves both marketing and docs,
and is reusable as the app evolves (re-run the script, re-record).
- The WASM playground is preserved as a real future option without holding
up launch; the demo seam keeps the upgrade cheap.
- A single canonical docs home removes the divergence risk of maintaining
user docs in two places.
- Website build choices (Decisions 1, 2, 4, 5) are recorded here for
traceability but do not, by themselves, warrant further ADRs; only
app-architecture decisions (notably the future WASM port) will.
## Out of scope
- **In-page WASM playground** — *deferred* (see Decision 3); revisit as its
own ADR + iteration plan.
- **Hosted/SaaS playground or a server-backed doc CMS** — *rejected*: a
static site fully satisfies the need, consistent with ADR-0007's
no-hosted-publishing stance. Revisit only if real demand emerges.
+1
View File
@@ -47,3 +47,4 @@ This directory contains the project's ADRs, recorded per
- [ADR-0039 — EXPLAIN over advanced-mode SQL queries](0039-explain-over-advanced-sql.md) — **Accepted** (2026-05-27), **implemented 2026-05-30 (issue #7)**, **supersedes ADR-0030 §13 OOS-2**. Lets `explain` wrap the advanced SQL commands (`Select`/`SqlInsert`/`SqlUpdate`/`SqlDelete`, plus `with`/CTE which builds a `Select`) in addition to the DSL `ShowData`/`Update`/`Delete` it already covers (ADR-0028), running `EXPLAIN QUERY PLAN` over the validated SQL text through the existing ADR-0028 span-styled plan tree (advanced mode only; DSL `explain` unchanged in both modes). Implemented via a second `Advanced` `explain` CommandNode (`EXPLAIN_SQL`) registered under the shared `explain` entry word — reusing the established `insert`/`update`/`delete` shared-word dispatch (`decide`: SQL-first / DSL-fallback), so `explain show data …` and DSL-only `--all-rows` still reach the DSL node; rejected a `DynamicSubgrammar` mode-gate (its resolution cache key omits `mode`). `build_explain_sql` slices the inner SQL off the source (excludes `explain`) and reuses the existing SQL builders; `do_explain_plan` runs the carried text verbatim, no params. Advanced `explain update`/`delete` now route through SQL (identical plan, full SQL syntax); DSL-explain tests pinned to simple mode. Reframed OOS-2 as a *deferred* exclusion (per ADR-0000's out-of-scope discipline), not a rejection. OOS (deferred): EXPLAIN of DDL (no query plan exists)
- [ADR-0040 — A per-command completion marker (✓/✗) replaces the `[ok]` summary line](0040-completion-marker-replaces-ok-summary.md) — **Accepted 2026-05-30 (issue #9)**, amends ADR-0014 / ADR-0028 / ADR-0019 output conventions, builds on ADR-0037's mode-tagged echo. An audit of the whole command surface found the `[ok] <verb> <subject>` summary line duplicates the echo line above it (verb+subject) everywhere; its only unique contribution is the success-vs-error signal (and `explain select` even rendered `[ok] explain` with an empty subject post-ADR-0039). Decision: drop the `[ok]` line and the symmetric `"…" failed:` prefix; the echo line gains a trailing inline **✓** (green, success) / **✗** (red, failure) — `running:` becomes a pending state that resolves to `<input> ✓/✗` on completion (status set via the existing `rfind(Echo)` lookup). Content (row counts, structure, data, plan tree, teaching echo) unchanged. Scoped to the DSL/data/SQL family that has the redundant echo+`[ok]` pair; app-command `[ok]` lines (`rebuild`/`export`/`now editing`) are payload-bearing, have no echo to mark, and stay as-is. `ok.summary` retired; `dsl.failed` reduced to the rendered reason. Broad but mechanical snapshot churn. OOS: app-command `[ok]` lines, the `[WRN]` validity indicator, and the tag colours (issue #10)
- [ADR-0041 — Copy the output panel to the system clipboard](0041-copy-output-to-clipboard.md) — **Accepted 2026-06-02 (issue #11)**, amends ADR-0003's app-command registry (adds **`copy`** / `copy all` / `copy last`). The friction it removes: filing a bug report meant terminal-selecting the output panel and fighting wrapping/borders. New **app-level command** (sigil-free, both modes): `copy` / `copy all` copy the whole panel; `copy last` copies from the most recent echo line to the end. **Mechanism — OSC 52 *and* native (`arboard`), always both**, because OSC 52 acceptance is undetectable (no terminal ack), so a true "fall back when unsupported" can't be built: emit the OSC 52 escape (no new dep — `base64`+`crossterm`; works over SSH; tmux-passthrough-wrapped via `$TMUX`), then a best-effort native write whose failure is ignored (headless host — OSC 52 carried it); the two carry identical content. **Format — plain text verbatim as rendered** (tags, `✓`/`✗`, box-drawing) joined by `\n`, without viewport padding/wrapping; a drift-lock test pins `OutputLine::plain_text` to `render_output_line`. `arboard` added **`--no-default-features`** (drops the `image` crate; X11-only on Linux — `wayland-data-control` deliberately omitted as it ~doubles the dep tree and OSC 52 covers native-Wayland). Security: write-only, scans clean for arboard's tree (cargo audit / osv-scanner / grype), 1Password-maintained, minimal surface. OOS: Markdown export, selection/range, a keybinding, OSC 52 read, `screen` passthrough
- [ADR-0042 — Public website and documentation site](0042-public-website-and-documentation-site.md) — **Accepted 2026-06-04**. The first public website: a marketing landing page plus the **canonical** user docs. Stack **Astro 5 + Starlight + Tailwind v4** (chosen over SvelteKit + Tailwind for a docs-heavy + marketing site; interactive bits as Astro islands). Showcase demos are **asciinema** `.cast` recordings (scripted-input driver for paced, re-recordable sessions — *not* `history.log` replay), reused inline in docs. The **in-page WASM playground is deferred** (OOS: deferred) behind a stable `Demo` seam, with the portable-core (`dsl`/`app`/`ui`, in-memory `rusqlite` via `ffi-sqlite-wasm-rs`) vs native-edge (Tokio/worker-thread/`crossterm`/persistence/backup-API) boundary recorded for a future ADR + iteration plan. Portable **static build** (Vercel target, but host-agnostic); **no CI yet**; **monorepo** (`website/`). Docs cover the **full supported feature set** with "planned" callouts for the unshipped minority; two wording rules bind user-facing copy — **no engine name** (continues ADR-0002) and **no "DSL"** ("simple mode" / "advanced mode"). Install docs cover **prebuilt binaries + package managers** (D1D3 track the release tooling). Plan: `docs/plans/20260604-adr-0042-website.md`
+172
View File
@@ -0,0 +1,172 @@
# Plan: public website and documentation site
**Date:** 2026-06-04 · **Status:** ready to build
Decisions for this work are recorded in
[ADR-0042](../adr/0042-public-website-and-documentation-site.md): Astro 5 +
Starlight + Tailwind v4; asciinema demos reusable in docs; the in-page WASM
playground deferred behind a stable demo seam; portable static hosting
(Vercel target); monorepo (`website/`); website is the canonical docs home;
full-feature-set docs with "planned" callouts; install docs cover prebuilt
binaries + package managers. This plan is the *how*.
## Repository layout
The site lives under `website/` in this repo; the crate stays at the root.
```
website/
├── package.json # pnpm; astro, @astrojs/starlight, tailwind v4
├── astro.config.mjs # Starlight integration + sidebar nav
├── src/
│ ├── pages/index.astro # marketing landing (custom, not Starlight)
│ ├── components/
│ │ ├── Demo.astro # demo SLOT — the WASM-playground seam
│ │ └── Cast.astro # asciinema-player island wrapper
│ ├── content/docs/ # Starlight MDX docs (the bulk of the work)
│ └── styles/ # shared Tailwind + Starlight theme tokens
├── public/casts/ # recorded *.cast asciinema files
├── README.md # local dev + recording recipe
└── STYLE.md # living documentation style guide
```
Root `.gitignore` gains `website/node_modules`, `website/dist`,
`website/.astro`.
## Documentation inventory (grounded — drives Phase D scope)
Built from `docs/handoff/5557`, `docs/adr/*`, the command REGISTRY
(`src/dsl/grammar/mod.rs:603`, which also auto-assembles in-app `help`), the
`Command` enum (`src/dsl/command.rs:149`), and
`src/friendly/strings/en-US.yaml`**not** the coarse `requirements.md`
checkboxes. Test state at survey time: **2151 passing, 0 failing, 1 ignored.**
**SHIPPED — document as-is (the doc core):**
- Input modes: simple, advanced (SQL), `:` one-shot escape, `mode` command,
per-project mode restore (ADR-0003/0015/0037).
- Full simple-mode command surface: create/drop table; add/drop/rename/
change column; add/drop 1:n relationship (named, ON DELETE/UPDATE
CASCADE/SET NULL/RESTRICT, `--create-fk`); add/drop index; insert/update/
delete (required WHERE + `--all-rows`; complex WHERE: AND/OR/NOT, LIKE,
IS NULL, IN, BETWEEN); show table/data (where/limit); add/drop constraint;
explain (ADR-0009/0013/0014/0025/0026/0028/0029).
- Full advanced-mode SQL: CREATE/DROP/ALTER TABLE (cols, constraints, inline
+ table FKs, rename, alter-column-type), CREATE [UNIQUE]/DROP INDEX; SELECT
(joins, GROUP BY/HAVING, ORDER BY, LIMIT/OFFSET, UNION/INTERSECT/EXCEPT,
WITH [RECURSIVE] CTEs); INSERT (multi-row, ON CONFLICT, RETURNING)/UPDATE/
DELETE; full expression grammar incl. CASE, CAST, curated functions;
EXPLAIN over SQL (ADR-00300039).
- Types: all ten, advanced-mode SQL aliases, serial/shortid auto-fill
(ADR-0005/0011/0017/0018). Constraints: PK incl. compound, NOT NULL,
UNIQUE, CHECK, DEFAULT, FK (ADR-0029/0013/0035).
- Undo/redo, history.log journal, replay, `--resume`, `--no-undo`
(ADR-0006/0034). Projects & storage: project.yaml + CSV + history.log,
save/save as/load/new/rebuild, temp projects, `--data-dir`
(ADR-0004/0015). Export/import (zip), clipboard copy/copy all/copy last
(ADR-0007/0041).
- Friendly errors (all five categories) + validity indicator
(ADR-0019/0027), DSL→SQL teaching echo (ADR-0038), EXPLAIN plan tree
(ADR-0028), box-drawing tables (ADR-0016), tab completion + syntax
highlighting + in-line editing (ADR-0022).
**DOCUMENT WITH CAVEAT:** `add unique index` is advanced-only; simple-mode
table rename is intentionally absent (rename is `ALTER TABLE … RENAME TO`);
FK references target single-column PKs only (compound-PK FK refs pending);
`help <command>` detail and richer `hint` (H2/H3) still partial.
**OMIT or MARK "planned":** multi-line input (I1), readline shortcuts (I1b),
in-flight cancellation / query timeout (I5/B3), `seed` (SD1), `m:n` (C4),
one-step modify relationship (C3a), `show tables`/`relationships`/`indexes`
(V5), ER-diagram view/export (V1/V3), session-log + Markdown export (V4).
**Mine verbatim for docs:** `en-US.yaml` `help.app.*`, `help.ddl.*`,
`help.data.*`, `help.types_reference`, `parse.usage.*` (one-line syntax
templates), `hint.*` — keeps docs and in-app help consistent.
## Phases
### A — Scaffold
`pnpm create astro@latest` (Starlight template) in `website/`; `astro add
tailwind` (Tailwind v4 via `@tailwindcss/vite`); add
`@astrojs/starlight-tailwind`. Confirm `pnpm dev` serves and `pnpm build`
emits a static `dist/`. Echo build steps for traceability.
### B — Landing page
Custom `src/pages/index.astro` (Starlight owns `/docs/*`). Hero + value prop
("learn relational databases by doing"), feature highlights from the
inventory, an embedded demo cast above the fold. Use the `frontend-design`
skill to avoid generic AI aesthetics; honour NFR-4/5/7 (distinctive design,
meaningful colour, light/dark).
### C — asciinema recording workflow
Record real `rdbms-playground` sessions to `public/casts/*.cast` using a
**scripted-input driver** (e.g. `asciinema-automation`/autocast, or an
expect/doitlive script) for paced, re-recordable demos. Record at a fixed
sensible cols×rows; provide light + dark player themes. `Cast.astro` wraps
`asciinema-player` as a `client:visible` island; the same component embeds
casts inline in docs. Document the recipe in `website/README.md`.
(`asciinema` 2.4.0 is installed.)
### D — Documentation (the bulk)
Starlight sidebar, scoped from the inventory; built in priority order:
- **Getting started** — install (prebuilt binaries + package managers),
first project, simple vs. advanced mode.
- **Concepts** — projects & storage; undo, history & replay.
- **Simple-mode command reference** — full surface; syntax conventions;
simple-command → SQL teaching echo.
- **Advanced (SQL) mode** — full SQL DDL/DML/SELECT surface.
- **Types**, **Relationships**, **Constraints**, **Indexes**, **Query plans
/ EXPLAIN**.
- **Working with the editor** — completion, highlighting, validity
indicator, in-line editing.
- **Errors explained** — the friendly error layer.
- **Export / import & sharing** (E2 recipes), **clipboard**.
Build order: Tier 1 simple-mode reference + types + constraints + input
modes + mined help/usage strings → Tier 2 advanced SQL + relationships +
project lifecycle + undo/history → Tier 3 teaching echo + EXPLAIN + errors +
completion/highlighting → Tier 4 clipboard + hints + editing.
Conventions live in the **living style guide** `website/STYLE.md` (binding
rules from ADR-0042 §7 — no engine name, **no "DSL"**, "planned" callouts —
plus finer conventions and an open-decisions log for depth/splitting/example
dataset/etc. as they settle). Sources to mine: `src/dsl/command.rs`,
`src/dsl/grammar/*`, the REGISTRY, `en-US.yaml`, `docs/adr/*`,
`docs/simple-mode-limitations.md`.
### E — Hosting & portability
Keep the default static build (no adapter); `dist/` deploys to Vercel or any
static host. `website/README.md` notes the Vercel preset (root dir
`website/`) and the one-line `@astrojs/vercel` switch if SSR is ever needed.
## Demo seam (WASM hook)
`Demo.astro` exposes a stable contract (`{ src, title, height, autoplay }`).
At launch it renders `Cast.astro`; later a `Playground.astro` WASM island
swaps in behind the same props on the landing page and in docs, with zero
call-site changes. Boundary details are in ADR-0042 §3.
## Verification
- `pnpm dev` renders landing + docs; `pnpm build` emits a clean static
`dist/` with no errors/warnings.
- Landing shows at least one playing `.cast`; the same component renders a
cast inline in a docs page (proves reuse).
- Starlight link-check passes (broken internal links fail the build).
- Docs grep clean of forbidden terms: **no "DSL"**, no engine name.
- A `dist/` static deploy works on Vercel (manual import) — confirms
portability. (No CI gate yet, per ADR-0042 §4.)
## Notes / recommendations (non-blocking)
- **Doc drift:** consider generating the command reference from source (the
`help` REGISTRY / `en-US.yaml`) rather than hand-writing all of it.
- **Accessibility/SEO:** pair each hero `.cast` with a text transcript or the
equivalent docs snippet.
- **Branding/domain & analytics** unspecified — assume none until decided;
no third-party trackers without consent.
- Tailwind v4 + Starlight have occasional theme-token friction; the
`@astrojs/starlight-tailwind` plugin is the supported bridge.
- Starlight ships local search (Pagefind) by default.
- No `README.md` exists at the repo root yet — wanted for the destination
repo; out of this plan's core scope but flagged.