docs: website docs structure + first content pages

Phase D foundation. Configures the pragmatic four-section sidebar
(Getting started / Guides / Reference / Concepts) and replaces the
template example pages with grounded content built on the shared
"library" example database (authors/books/members/loans):

- Getting started: installation, first project, simple vs advanced,
  the example library.
- Reference: Types (all ten + serial/shortid + advanced aliases),
  Tables (create/drop, compound PK, advanced CREATE TABLE).
- Concepts: projects & storage (readable files, derived database,
  autosave, temp projects).
- Guides: Build the library (draft, to be refined for teaching).

Command syntax grounded in en-US.yaml usage/help, command.rs, and
types.rs (verified against tests). Records the settled doc decisions
in STYLE.md. Build green (10 pages, Pagefind); content clean of
"DSL"/engine-name.
This commit is contained in:
claude@clouddev1
2026-06-06 07:34:57 +00:00
parent cea99e8b70
commit 0fcb7b1105
13 changed files with 653 additions and 97 deletions
+70 -26
View File
@@ -39,22 +39,63 @@ Status tags used below: **[DECIDED]** (binding or settled) ·
instructions ("Create a table…").
- Prefer short sentences and concrete examples over abstract prose.
## Structure [DECIDED]
Pragmatic, Diátaxis-influenced split (four top-level sidebar sections,
autogenerated per directory under `src/content/docs/`):
- **Getting started** — install, first project, simple vs. advanced, the
example database.
- **Guides** — task-oriented how-tos. *These are the most important didactic
content and will be iterated for teaching quality before publication.*
- **Reference** — the exhaustive command/SQL/type surface. **Page
granularity: one page per topic / command-family** (Tables, Columns,
Relationships, Indexes, Constraints, Inserting & editing data, Querying,
Types, …), each covering the simple-mode and advanced-mode forms where
both apply. Hand-written now (the command surface is settled bar H1a
output); small post-release adjustments are expected and fine.
- **Concepts** — the "why": projects & storage, undo & history, etc.
Ground every reference page in source — `parse.usage.*` and `help.*` in
`src/friendly/strings/en-US.yaml`, `src/dsl/command.rs`, `src/dsl/types.rs`
— never paraphrase grammar from memory.
## "Planned / not yet available" callouts [DECIDED — ADR-0042 §7]
Any capability that is not yet fully implemented is **omitted** or carries a
clear **"planned / not yet available"** callout — never presented as
shipped. Use a Starlight aside (`:::caution` or a custom badge). **[OPEN]**:
exact component + wording (see log).
clear callout — never presented as shipped. Standard form: a Starlight aside
## Examples & code [OPEN]
```md
:::caution[Planned]
This is planned and not yet available.
:::
```
Direction (to confirm in the log):
- A single **standard example schema/dataset** reused across pages so
readers build familiarity (candidate: a small, recognisable domain).
## Examples & code [DECIDED]
- **Shared example database: a small library** — `authors`, `books`,
`members`, `loans` (see the canonical schema below). Reuse it across all
pages so readers build familiarity; it models 1:n (an author has many
books) and m:n (books ↔ members, through loans).
- Where both modes apply, show the **simple-mode** form and its
**advanced-mode (SQL)** equivalent — the in-app teaching echo already
pairs these, so docs can mirror it.
- Code blocks for input/output; reserve casts for motion/flow (see below).
pairs these, so docs mirror it.
- Code blocks for exact input/output; reserve casts for motion/flow.
### Canonical library schema (source of truth for examples)
Use these exact names/types in every example:
| Table | Columns (playground types) |
|-----------|---------------------------------------------------------------------------------------------|
| `authors` | `author_id` serial (pk) · `name` text (not null) · `birth_year` int |
| `books` | `book_id` serial (pk) · `title` text (not null) · `author_id` int (→ authors) · `published` int · `isbn` text (unique) |
| `members` | `member_id` serial (pk) · `name` text (not null) · `joined` date |
| `loans` | `loan_id` serial (pk) · `book_id` int (→ books) · `member_id` int (→ members) · `loaned_on` date · `returned_on` date |
Relationships: `books.author_id → authors.author_id` (1:n); `loans` joins
`books` and `members` (the m:n bridge). Show `shortid` on the Types page via
a small standalone example, not by complicating this schema.
## asciinema casts [DECIDED, details OPEN]
@@ -81,20 +122,23 @@ Direction (to confirm in the log):
Decide these as we write; record the outcome (and escalate to an ADR if
significant).
1. **Depth / organising spine.** Adopt **Diátaxis** (tutorial / how-to /
reference / explanation) as the structure, or a lighter
getting-started + reference + concepts split? Affects the whole sidebar.
2. **Page granularity & splitting.** One page per command, per
command-family, or per task? When does a page split?
3. **Standard example schema/dataset.** What domain + tables do all examples
share?
4. **Simple-vs-advanced pairing.** Always show both forms, or only where
instructive? How to present the pairing visually.
5. **"Planned" callout component & wording.** Exact Starlight component and
standard sentence.
6. **Reference generation vs hand-writing.** Generate the command reference
from source (the `help` REGISTRY / `en-US.yaml`) to avoid drift, or
author by hand? (Flagged in the plan's notes.)
7. **Versioning.** Do docs need version selectors at/after v1, or is
single-version fine for launch?
8. **SEO/meta conventions.** Title/description patterns, Open Graph.
**Resolved (2026-06-05):**
1. ~~Depth / organising spine~~**Pragmatic** four-section split (see
Structure above).
2. ~~Page granularity~~**one page per topic / command-family**, both
modes per page (see Structure).
3. ~~Standard example dataset~~**the library** (schema above).
4. ~~Simple-vs-advanced pairing~~**show both where both apply** (see
Examples).
5. ~~"Planned" callout~~ → standard `:::caution[Planned]` aside (see above).
6. ~~Reference generation vs hand-writing~~**hand-write now** (command
surface is settled bar H1a output; small later adjustments expected).
**Still open:**
7. **Versioning.** Version selectors at/after v1, or single-version for
launch? (Leaning single-version for launch.)
8. **SEO/meta conventions.** Title/description patterns, Open Graph — settle
with Phase B (landing) and the `site` URL.
9. **Cast scripting toolchain.** Confirm the scripted-input driver
(`asciinema-automation`/autocast vs alternative) via a test run; define
the `.cast` script format + storage location. (Execution task, in flight.)
+15 -13
View File
@@ -6,23 +6,25 @@ import tailwindcss from '@tailwindcss/vite';
// https://astro.build/config
export default defineConfig({
// TODO(Phase B/SEO): set `site` to the production URL once the domain is
// known — enables the sitemap and canonical/OG URLs.
integrations: [
starlight({
title: 'My Docs',
social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/withastro/starlight' }],
title: 'RDBMS Playground',
tagline: 'Learn relational databases by doing.',
// TODO(Phase B): point at the real repository once it moves to its
// public home. Omitted for now rather than linking the wrong repo.
// social: [{ icon: 'github', label: 'GitHub', href: '…' }],
customCss: ['./src/styles/global.css'],
// Pragmatic structure (ADR-0042 §7 / website/STYLE.md): Getting
// started, Guides, Reference, Concepts. Autogenerated per directory;
// in-section order is controlled by each page's `sidebar.order`
// frontmatter.
sidebar: [
{
label: 'Guides',
items: [
// Each item here is one entry in the navigation menu.
{ label: 'Example Guide', slug: 'guides/example' },
],
},
{
label: 'Reference',
items: [{ autogenerate: { directory: 'reference' } }],
},
{ label: 'Getting started', items: [{ autogenerate: { directory: 'getting-started' } }] },
{ label: 'Guides', items: [{ autogenerate: { directory: 'guides' } }] },
{ label: 'Reference', items: [{ autogenerate: { directory: 'reference' } }] },
{ label: 'Concepts', items: [{ autogenerate: { directory: 'concepts' } }] },
],
}),
],
@@ -0,0 +1,73 @@
---
title: Projects and storage
description: How the playground stores your work — readable files, a derived database, autosave, and temporary projects.
sidebar:
order: 1
---
Everything you do in the playground lives in a **project** — a folder on
disk. Understanding what is in that folder explains why your work is safe,
shareable, and easy to inspect.
## What a project contains
| File / folder | Role |
|---|---|
| `project.yaml` | The schema: your tables, columns, keys, relationships, and indexes. |
| `data/<table>.csv` | One file per table holding its rows, as plain CSV. |
| `history.log` | An append-only journal of every command you have run. |
| the database file | The working database the playground queries. **Derived** — see below. |
The first three are the **authoritative, human-readable** record of your
project. You can open them in any editor, diff them in version control, and
read them without the playground.
## The database is derived
The database file the playground queries is built *from* `project.yaml` and
the CSV files. Because it is derived, it never needs to be shared or backed
up separately — and if it is ever missing or stale, the `rebuild` command
regenerates it from the readable files:
```text
rebuild
```
## Your work saves itself
There is no "save" step to remember. Every command writes through to the
files as it runs, so a project is always up to date on disk. (The `save`
command exists for a different purpose: giving a temporary project a
permanent name — see below.)
## Temporary vs. named projects
When you start the playground without naming a project, it creates a
**temporary** project with an automatic name. Temporary projects are perfect
for quick experiments. When you want to keep one, give it a name:
```text
save
```
Empty, untouched temporary projects are cleaned up automatically, so casual
experimenting never leaves clutter behind.
## Where projects live
Projects are stored in a standard per-user location for your operating
system. Override it for a single run with `--data-dir <PATH>` — handy for
keeping a course's projects together, or for testing.
## Sharing a project
The `export` command packages a project as a zip you can send to anyone:
```text
export
```
The zip contains the readable files (`project.yaml` and `data/`) but **not**
the derived database or your private `history.log`. The recipient opens it
and the playground rebuilds the database for them. Exporting and
importing has its own reference page.
@@ -0,0 +1,32 @@
---
title: The example library
description: The small library database used throughout these docs.
sidebar:
order: 4
---
Most examples in this documentation use the same small database: a library
with **authors**, **books**, **members**, and **loans**. Keeping one
familiar set of tables makes it easier to focus on the concept each page is
teaching.
## The tables
| Table | Columns |
|---|---|
| `authors` | `author_id` (serial, primary key), `name` (text), `birth_year` (int) |
| `books` | `book_id` (serial, primary key), `title` (text), `author_id` (int → authors), `published` (int), `isbn` (text, unique) |
| `members` | `member_id` (serial, primary key), `name` (text), `joined` (date) |
| `loans` | `loan_id` (serial, primary key), `book_id` (int → books), `member_id` (int → members), `loaned_on` (date), `returned_on` (date) |
## The relationships
- **An author has many books.** `books.author_id` points at
`authors.author_id` — a one-to-many relationship.
- **Members borrow books.** Each row in `loans` ties one book to one member,
so `loans` connects `books` and `members` — a many-to-many relationship
expressed through a bridging table.
You will build these tables and relationships step by step in
[Build the library](/guides/build-the-library/). Individual reference pages
use whichever part of this schema illustrates the command at hand.
@@ -0,0 +1,60 @@
---
title: Your first project
description: Create a table, add a row, and look at it — a two-minute tour of the playground.
sidebar:
order: 2
---
This is the shortest possible tour: create a table, put a row in it, and
look at the result. Everything here is in **simple mode**, which is how the
playground starts.
When you launch `rdbms-playground` with no arguments, it opens a fresh
temporary project for you. Type commands into the input field at the bottom
and press <kbd>Enter</kbd> to run them.
## Create a table
A table needs at least a primary key. The `with pk` clause names the
primary-key column and its type:
```text
create table authors with pk author_id(serial)
```
`serial` is an auto-incrementing number — you will not have to fill it in
yourself.
## Add a couple of columns
In simple mode you create a table with its key, then add the other columns
one at a time:
```text
add column to authors: name (text)
add column to authors: birth_year (int)
```
## Add a row
`insert` adds a row. List the columns you are supplying — the `author_id`
fills itself in because it is a `serial`:
```text
insert into authors (name, birth_year) values ('Ada Lovelace', 1815)
```
The playground shows the row it just inserted, including the generated
`author_id`.
## Look at the data
```text
show data authors
```
That is the whole loop: **create → add columns → insert → show**. From here:
- Build the full example database in [Build the library](/guides/build-the-library/).
- Learn how [simple and advanced modes](/getting-started/modes/) differ.
- Look up any command in the [Reference](/reference/types/).
@@ -0,0 +1,64 @@
---
title: Installation
description: Install RDBMS Playground from a prebuilt binary or a package manager, and run it for the first time.
sidebar:
order: 1
---
RDBMS Playground is a single self-contained program. There is nothing to
configure and no separate database to install — everything it needs is
built in.
## Prebuilt binaries
Download the binary for your platform, make it executable if needed, and
put it somewhere on your `PATH`.
:::note
Download links are published with each release. They are added here when the
first public version ships.
:::
## Package managers
Once published, the playground will be installable through common package
managers:
```sh
# macOS / Linux (Homebrew)
brew install rdbms-playground
# Windows (Scoop)
scoop install rdbms-playground
```
:::note
Package-manager availability lands with the first public release; the exact
names are confirmed here at that time.
:::
## Run it
Start the playground with no arguments and it opens a fresh, automatically
named temporary project so you can start experimenting immediately:
```sh
rdbms-playground
```
To open an existing project, pass its path:
```sh
rdbms-playground path/to/project
```
Useful options (run `rdbms-playground --help` for the full list):
| Option | What it does |
|---|---|
| `--resume` | Reopen the most recently used project. |
| `--data-dir <PATH>` | Use a different location for stored projects. |
| `--theme <light\|dark>` | Force a theme instead of auto-detecting. |
| `--mode <simple\|advanced>` | Start in a specific input mode. |
Next: [create your first project](/getting-started/first-project/).
@@ -0,0 +1,60 @@
---
title: Simple and advanced modes
description: How the playground's two input modes differ, how to switch, and the one-line escape hatch.
sidebar:
order: 3
---
The playground has two input modes. You can do everything a beginner needs
in **simple mode**, and reach for **advanced mode** when you want full SQL.
## Simple mode (the default)
Simple mode is a friendly, keyword-based command language designed for
learning. Commands read close to English:
```text
create table authors with pk author_id(serial)
show data authors
```
Simple mode accepts these learning commands plus the app-level commands
(like `save`, `undo`, and `help`). If you type raw SQL here, the playground
gently points you at advanced mode instead of failing silently.
## Advanced mode (SQL)
Advanced mode accepts standard SQL — `SELECT`, `INSERT`, `CREATE TABLE`, and
more — alongside the same app-level commands:
```sql
select title, published from books where published >= 2000 order by published;
```
Switch modes with the `mode` command:
```text
mode advanced
mode simple
```
The mode you leave a project in is remembered and restored the next time you
open it, so a project set up for SQL practice reopens in advanced mode.
## The one-line escape
When you are in simple mode and want to run a single SQL statement without
switching, prefix the line with a colon:
```text
:select count(*) from books
```
That runs just this one line as SQL; you stay in simple mode afterwards.
## Seeing the SQL behind a command
When you run a simple-mode command in advanced mode, the playground prints
the equivalent SQL beneath your command. It is a built-in way to learn how
the friendly commands map onto real SQL — the same statements you could type
yourself in advanced mode.
@@ -0,0 +1,69 @@
---
title: Build the library
description: Build the example library database step by step — tables, a relationship, and some rows.
sidebar:
order: 1
---
:::note[Draft]
This guide is an early draft. The walkthrough is correct, but the wording
and pacing will be refined for teaching before the docs are published.
:::
This guide builds the [example library](/getting-started/example-library/)
from scratch in simple mode: two tables, a relationship between them, and a
few rows. By the end you will have used the create → add column → relate →
insert → query loop end to end.
## 1. Create the authors table
```text
create table authors with pk author_id(serial)
add column to authors: name (text)
add column to authors: birth_year (int)
```
## 2. Create the books table
```text
create table books with pk book_id(serial)
add column to books: title (text)
add column to books: author_id (int)
add column to books: published (int)
```
## 3. Relate books to authors
An author has many books, so `books.author_id` should point at
`authors.author_id`. Declare that one-to-many relationship:
```text
add 1:n relationship from authors.author_id to books.author_id
```
The relationship reads parent-to-child: **from** the `authors` side **to**
the `books` side.
## 4. Add some rows
`author_id` and `book_id` are `serial`, so they fill themselves in:
```text
insert into authors (name, birth_year) values ('Ada Lovelace', 1815)
insert into authors (name, birth_year) values ('Alan Turing', 1912)
insert into books (title, author_id, published) values ('Notes on the Analytical Engine', 1, 1843)
```
## 5. Look at your data
```text
show data authors
show data books
```
## Where to go next
- Add the `members` and `loans` tables the same way to model borrowing — a
many-to-many relationship through `loans`.
- Try the same steps in advanced mode to see the SQL form of each command.
- Look up any command in detail in the Reference section.
@@ -1,11 +0,0 @@
---
title: Example Guide
description: A guide in my new Starlight docs site.
---
Guides lead a user through a specific task they want to accomplish, often with a sequence of steps.
Writing a good guide requires thinking about what your users are trying to do.
## Further reading
- Read [about how-to guides](https://diataxis.fr/how-to-guides/) in the Diátaxis framework
+36 -26
View File
@@ -1,40 +1,50 @@
---
title: Welcome to Starlight
description: Get started building your docs site with Starlight.
template: splash # Remove or comment out this line to display the site sidebar on this page.
title: RDBMS Playground
description: A terminal playground for learning relational databases — tables, keys, relationships, indexes, queries, and query plans, hands-on.
template: splash
hero:
tagline: Congrats on setting up a new Starlight project!
image:
file: ../../assets/houston.webp
tagline: Learn relational databases by doing — in your terminal.
actions:
- text: Example Guide
link: /guides/example/
- text: Get started
link: /getting-started/installation/
icon: right-arrow
- text: Read the Starlight docs
link: https://starlight.astro.build
icon: external
- text: Browse the reference
link: /reference/types/
variant: minimal
---
import { Card, CardGrid } from '@astrojs/starlight/components';
import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components';
## Next steps
RDBMS Playground is a cross-platform terminal app that gives you a safe
sandbox for exploring relational database concepts: tables, columns,
primary and foreign keys, relationships, indexes, queries, and query
plans. It is built for learning — from your first table to writing raw
SQL.
<CardGrid stagger>
<Card title="Update content" icon="pencil">
Edit `src/content/docs/index.mdx` to see this page change.
<CardGrid>
<Card title="Two ways to work" icon="seti:db">
Start in **simple mode** — a friendly, keyword-based command language —
and switch to **advanced mode** for standard SQL whenever you are ready.
</Card>
<Card title="Change page layout" icon="document">
Delete `template: splash` in `src/content/docs/index.mdx` to display a
sidebar on this page.
<Card title="Learn the SQL underneath" icon="open-book">
Run a simple-mode command in advanced mode and the playground shows you
the equivalent SQL, so the bridge from concepts to SQL is always visible.
</Card>
<Card title="Add new content" icon="add-document">
Add Markdown or MDX files to `src/content/docs` to create new pages.
<Card title="Safe to experiment" icon="approve-check">
Every change can be undone, your work is saved as you go, and you can
rebuild the whole database from plain, readable files.
</Card>
<Card title="Configure your site" icon="setting">
Edit your `sidebar` and other config in `astro.config.mjs`.
</Card>
<Card title="Read the docs" icon="open-book">
Learn more in [the Starlight Docs](https://starlight.astro.build/).
<Card title="See how queries run" icon="rocket">
Ask the playground to explain any query and it renders the database's
plan as an annotated tree — so indexes and scans stop being a mystery.
</Card>
</CardGrid>
## Start here
<CardGrid>
<LinkCard title="Install" href="/getting-started/installation/" description="Get the playground running on your machine." />
<LinkCard title="Your first project" href="/getting-started/first-project/" description="Create a table, add a row, and see it." />
<LinkCard title="The example library" href="/getting-started/example-library/" description="The small database used throughout these docs." />
<LinkCard title="Reference" href="/reference/types/" description="Every command, type, and constraint in detail." />
</CardGrid>
@@ -1,11 +0,0 @@
---
title: Example Reference
description: A reference page in my new Starlight docs site.
---
Reference pages are ideal for outlining how things work in terse and clear terms.
Less concerned with telling a story or addressing a specific use case, they should give a comprehensive outline of what you're documenting.
## Further reading
- Read [about reference](https://diataxis.fr/reference/) in the Diátaxis framework
@@ -0,0 +1,92 @@
---
title: Tables
description: Create and drop tables in simple mode and in advanced-mode SQL, including compound primary keys.
sidebar:
order: 2
---
A table is the core building block. This page covers creating and removing
tables; changing a table's columns after it exists is covered under Columns
in the Reference.
## Create a table (simple mode)
Every table is created with its primary key. The `with pk` clause lists the
primary-key column(s):
```text
create table authors with pk author_id(serial)
```
Other columns are added afterwards with `add column`:
```text
add column to authors: name (text)
add column to authors: birth_year (int)
```
### Compound primary keys
To make the primary key span more than one column, list them, comma
separated:
```text
create table loans with pk book_id(int), member_id(int)
```
**Syntax**
```text
create table <Name> with pk <col>(<type>)[, ...]
```
## Create a table (advanced mode)
In advanced mode you write a full `CREATE TABLE` with every column and
constraint inline:
```sql
create table authors (
author_id serial primary key,
name text not null,
birth_year int
)
```
The advanced form also accepts table-level constraints and inline foreign
keys — see the Constraints and Relationships references.
**Syntax**
```text
create table [if not exists] <Name> (<col> <type> [constraints], ...)
```
## Drop a table
```text
drop table authors
```
In advanced mode you may add `if exists` so removing a table that is not
there succeeds quietly:
```sql
drop table if exists authors
```
:::caution
Dropping a table removes its rows as well. Use `undo` if you drop one by
mistake.
:::
## Renaming a table
Renaming a table is available in advanced mode:
```sql
alter table authors rename to writers
```
There is no simple-mode rename verb — switch to advanced mode (or use the
one-line `:` escape) to rename a table.
@@ -0,0 +1,72 @@
---
title: Types
description: The ten column types, what they store, and the auto-generating serial and shortid types.
sidebar:
order: 1
---
Every column has a type. The playground offers ten, chosen to cover what a
learner needs without the sprawl of a production database.
## The ten types
| Type | Stores |
|---|---|
| `text` | Text of any length. |
| `int` | A whole number (64-bit signed). |
| `real` | A floating-point number. |
| `decimal` | An exact decimal number, kept precise (see note below). |
| `bool` | A truth value, shown as `true` / `false`. |
| `date` | A calendar date, `YYYY-MM-DD`. |
| `datetime` | A date and time, `YYYY-MM-DDTHH:MM:SS`. |
| `blob` | Arbitrary binary data. |
| `serial` | An auto-incrementing whole number — see below. |
| `shortid` | A short random identifier — see below. |
:::note
`decimal`, `date`, and `datetime` are compared as text, so they sort in the
expected order when written in their standard form. Arithmetic on a
`decimal` needs an explicit cast — they are stored exactly rather than as
approximate floating point.
:::
## Auto-generated types: `serial` and `shortid`
Two types fill themselves in when you insert a row, so you never supply them
by hand.
- **`serial`** — the next number in sequence (one more than the current
maximum). It is the natural choice for a primary key. Outside a primary
key, a `serial` column is kept unique.
- **`shortid`** — a short, random, base58 identifier (1012 characters,
avoiding easily-confused characters). Always kept unique. Useful when you
want an identifier that is compact but not guessable or sequential.
```text
create table members with pk member_id(serial)
add column to members: member_code (shortid)
insert into members (name) values ('Grace Hopper')
```
Both the `member_id` and the `member_code` are generated for you.
If you add a `serial` or `shortid` column to a table that already has rows —
or change an existing column to one of these types — the empty cells are
filled with freshly generated values in the same step.
## Keys that point at these types
A foreign key stores a plain looked-up value, not a new generated one. So a
column that references a `serial` primary key is itself an `int`, and one
that references a `shortid` is a `text`. The playground handles this for you
when you declare a relationship; it is worth knowing why the child column's
type differs from the parent key's.
## Type names in advanced mode
In advanced mode you may also use familiar standard-SQL spellings, which map
onto the types above — for example `integer`, `bigint`, and `smallint` are
all `int`; `varchar` and `char` are `text`; `boolean` is `bool`; `timestamp`
is `datetime`; `numeric` is `decimal`; `float` and `double precision` are
`real`. Simple mode uses only the ten names in the table, so it teaches one
clear vocabulary.