165068269b
DSL:
- add 1:n relationship [as <name>] from <P>.<col> to <C>.<col>
[on delete <action>] [on update <action>] [--create-fk]
- drop relationship <name> | from <P>.<col> to <C>.<col>
- show table <name> for re-displaying a structure on demand
Database (ADR-0013):
- Rebuild-table primitive following SQLite's
ALTER-via-rebuild recipe (foreign_keys=OFF outside tx,
copy-by-name, foreign_key_check before commit). Reusable for
B2 (column drops/renames/type changes).
- ReferentialAction enum (no action / restrict / set null /
cascade); SET DEFAULT awaits column DEFAULTs.
- __rdbms_playground_relationships metadata table -- names,
auto-generated as <Parent>_<pcol>_to_<Child>_<ccol>.
- Type::fk_target_type() validation at declaration; friendly
errors for type mismatch, non-PK target, missing column,
duplicate name.
- describe_table populates symmetric outbound + inbound
relationship lists. drop_table refuses while inbound
references exist; outbound metadata cleaned up alongside drop.
App / UI:
- In-line cursor editing in the input field: Left, Right,
Home, End, Delete, Backspace honoring UTF-8 boundaries.
- PageUp / PageDown scrolls the output buffer; viewport row
count fed back from the renderer via App::note_output_viewport
so scroll is capped against the actual visible area
(regression-tested) and snaps to the bottom on new output.
- Failure messages quote the command portion ("verb target"
failed: ...) for visual clarity; RelationshipSelector has a
proper Display impl so "no such relationship" reads cleanly.
- Structure rendering shows References / Referenced by sections.
Docs:
- ADR-0013 covers naming, metadata table, symmetric view, and
the rebuild-table strategy.
- requirements.md updates: C3 (FK done), B2 (primitive in),
T3 (compound-PK FK still pending). New entries: I1a (cursor
editing -- landed), I1b (Ctrl-A/E and readline shortcuts --
pending), V4 partial scroll, V5 (show family), C3a (modify
relationship -- deferred).
Tests: 154 passing (140 lib + 14 integration), 0 skipped.
Clippy clean with nursery enabled.
399 lines
17 KiB
Markdown
399 lines
17 KiB
Markdown
# RDBMS Playground — Requirements (Phase 1)
|
||
|
||
This document is the **consolidated Phase 1 requirements
|
||
checklist** for RDBMS Playground. It captures everything the
|
||
project has committed to so far, derived from the design
|
||
conversation and the ADRs in `docs/adr/`.
|
||
|
||
**Purpose.** Phase 5 verification at every milestone measures
|
||
delivered work against this checklist. An item not on this list
|
||
was not promised; an item silently dropped without confirmation
|
||
is a process failure.
|
||
|
||
**Scope.** The list is intentionally coarse — each item is a
|
||
unit of "satisfied / not satisfied" judgement. When an item is
|
||
taken up for implementation, it is decomposed further in a
|
||
backlog (initially in this repo, later in GitHub issues once the
|
||
repo is pushed).
|
||
|
||
## Status legend
|
||
|
||
- `[ ]` — open, not yet implemented
|
||
- `[x]` — satisfied (implemented + tested)
|
||
- `[~]` — deferred, awaiting an ADR or further design before any
|
||
implementation
|
||
- `[-]` — explicitly out of scope (rationale at the bottom)
|
||
|
||
## Test baseline
|
||
|
||
No test suite exists yet — the repo currently contains only
|
||
docs. The baseline is therefore "0 passing, 0 failing, 0
|
||
skipped." Subsequent phases establish the suite and measure
|
||
against it.
|
||
|
||
---
|
||
|
||
## Distribution and install
|
||
|
||
- [ ] **D1** Cross-platform binaries: Linux, macOS, Windows on
|
||
x86_64 and aarch64.
|
||
- [ ] **D2** Single static binary, no runtime dependencies.
|
||
- [ ] **D3** Released via prebuilt binaries plus Homebrew, Scoop,
|
||
`winget`, and `cargo binstall`.
|
||
|
||
## TUI shell
|
||
|
||
- [ ] **S1** Three-region layout: items list (left), output
|
||
panel (right), input field (bottom).
|
||
- [ ] **S2** Items list shows tables and per-table indexes;
|
||
designed to extend to additional element kinds (relations,
|
||
views, etc.) without restructuring.
|
||
*(Progress: tables are listed live from the database; indexes
|
||
pending alongside C3 index support.)*
|
||
- [ ] **S3** Output panel renders a visualization of the
|
||
currently selected item and supports multiple tabs.
|
||
- [ ] **S4** Hint area below the input field; keyboard-toggleable
|
||
for inspecting hints about the current input or last error.
|
||
- [ ] **S5** Mode label and distinct border style on the input
|
||
field communicate the current input mode at all times.
|
||
|
||
## Input field
|
||
|
||
- [ ] **I1** Multi-line entry that auto-expands; Ctrl-Enter (or
|
||
equivalent) submits, plain Enter inserts a newline.
|
||
- [ ] **I1a** In-line cursor editing in the input field: Left /
|
||
Right arrows move the cursor by character (UTF-8 boundaries
|
||
honoured), Home / End jump to the extremes, Delete removes the
|
||
character at the cursor, Backspace removes the character
|
||
before. Insertion happens at the cursor position. *(Implemented;
|
||
multi-line editing per I1 still pending.)*
|
||
- [ ] **I1b** Readline-style cursor shortcuts: Ctrl-A / Ctrl-E
|
||
as aliases for Home / End for users on keyboards without those
|
||
keys (and for ergonomics in command-driven workflows). Likely
|
||
followed by Ctrl-W (delete previous word), Ctrl-K (delete to
|
||
end), Ctrl-U (delete to start). Pending.
|
||
- [ ] **I2** Persistent navigable input history (project-scoped,
|
||
with a global rolling history also available).
|
||
*(Progress: in-memory navigable history (Up/Down arrows, draft
|
||
preservation, dedup of consecutive duplicates) is implemented;
|
||
persistence across sessions arrives with track 2's project
|
||
storage.)*
|
||
- [ ] **I3** Tab completion for app commands, DSL keywords, table
|
||
names, column names, and SQL keywords.
|
||
- [ ] **I4** Syntax highlighting for both the DSL and SQL.
|
||
- [ ] **I5** In-flight query/command cancellation (Ctrl-C in the
|
||
output area or input field).
|
||
|
||
## Input modes (per ADR-0003)
|
||
|
||
- [ ] **M1** Simple mode is the default. It accepts DSL data
|
||
commands and the canonical app-level commands; raw SQL is
|
||
rejected with a friendly hint.
|
||
- [ ] **M2** Advanced mode accepts SQL plus the canonical
|
||
app-level commands without any sigil.
|
||
- [ ] **M3** Prefixing a single line with `:` in simple mode is a
|
||
one-shot advanced escape (with the prompt label updated). The
|
||
`mode simple` / `mode advanced` command switches modes
|
||
persistently.
|
||
|
||
## App-level commands (per ADR-0003)
|
||
|
||
- [ ] **A1** All canonical app-level commands implemented and
|
||
available in both modes: `save`, `save as`, `load`, `new`,
|
||
`export`, `import`, `seed`, `replay`, `undo`, `redo`, `mode`,
|
||
`help`, `hint`, `quit`.
|
||
*(Progress: `quit`/`q` and `mode simple|advanced` implemented;
|
||
the rest land alongside the features they belong to — `save`
|
||
and friends in track 2, `seed` in the seeding iteration, etc.)*
|
||
|
||
## DSL data commands
|
||
|
||
- [ ] **C1** Table operations: create / drop / rename.
|
||
*(Progress: create + drop done; rename pending.)*
|
||
- [ ] **C2** Column operations: add / drop / rename / change
|
||
type, including the rebuild-table dance behind the scenes
|
||
where SQLite ALTER cannot do it directly.
|
||
*(Progress: add done; drop/rename/change-type pending — the
|
||
rebuild-table dance is the gating piece, B2.)*
|
||
- [ ] **C3** Schema constraints: primary key (single and
|
||
compound), foreign key with `ON DELETE` / `ON UPDATE` referential
|
||
actions, indexes, `NOT NULL`, `UNIQUE`, `CHECK`, `DEFAULT`.
|
||
*(Progress: PK including compound done at create-table time;
|
||
FK with `ON DELETE` / `ON UPDATE` actions done (ADR-0013) —
|
||
declared via `add 1:n relationship`; symmetric outbound +
|
||
inbound view in the structure renderer; type compatibility
|
||
validated at declaration via `Type::fk_target_type()`. Index,
|
||
`NOT NULL`, `UNIQUE`, `CHECK`, `DEFAULT` still pending.)*
|
||
- [~] **C3a** Modify relationship: `modify relationship <name>
|
||
[on delete <action>] [on update <action>]`. Users can achieve
|
||
the same via drop + add today; one-step modify is a small
|
||
follow-up using the existing rebuild-table machinery. ADR
|
||
pending.
|
||
- [ ] **C4** Convenience: `create m:n relationship from <T1> to
|
||
<T2>` produces an auto-named junction table the user can rename;
|
||
pulls primary keys and FK definitions automatically.
|
||
- [ ] **C5** Data operations: insert / update / delete via DSL.
|
||
|
||
## SQL handling
|
||
|
||
- [ ] **Q1** SQL parsed via `sqlparser-rs`; supported subset is
|
||
defined (specifics deferred to a future ADR).
|
||
*(Progress: DSL is parsed via `chumsky` (ADR-0009); SQL
|
||
handling in advanced mode is still a placeholder echo.)*
|
||
- [ ] **Q2** Non-standard syntax rejected with a clear message
|
||
pointing at the supported subset.
|
||
- [x] **Q3** User-facing simplified types map transparently to
|
||
SQLite STRICT types in generated DDL. *(All ten types implemented
|
||
and tested.)*
|
||
- [~] **Q4** Supported SQL subset specification — design and ADR
|
||
pending. Q1 cannot be marked satisfied without it.
|
||
|
||
## Database backend (per ADR-0002)
|
||
|
||
- [x] **B1** SQLite via `rusqlite`; all tables created `STRICT`;
|
||
`PRAGMA foreign_keys = ON` per connection. *(Database accessed
|
||
through a dedicated worker thread per ADR-0010.)*
|
||
- [ ] **B2** Schema evolution uses the rebuild-table technique
|
||
internally where SQLite `ALTER TABLE` cannot.
|
||
*(Progress: rebuild-table primitive landed (ADR-0013) and is
|
||
used by `add_relationship` / `drop_relationship`. Reuse for
|
||
column drops/renames/type changes pending; the primitive is
|
||
designed to support those without further architectural work.)*
|
||
- [ ] **B3** Query timeout and cancellation supported (no
|
||
cartesian-join-of-doom can hang the app).
|
||
*(Progress: the worker-thread architecture is in place; the
|
||
cancellation/timeout protocol on top of it is pending.)*
|
||
|
||
## Type system (per ADR-0005)
|
||
|
||
- [x] **T1** All ten user-facing types implemented: `text`,
|
||
`int`, `real`, `decimal`, `bool`, `date`, `datetime`, `blob`,
|
||
`serial`, `shortid`. *(Mapping to SQLite STRICT covered by
|
||
ADR-0005; FK target type rule by ADR-0011.)*
|
||
- [ ] **T2** `shortid` generation: base58, 10–12 characters,
|
||
omits ambiguous characters; generated client-side at insert.
|
||
*(Type exists; insert-time generation arrives with the data
|
||
insertion path.)*
|
||
- [ ] **T3** Compound primary keys handled end-to-end (DSL,
|
||
storage, display, FK reference).
|
||
*(Progress: DSL grammar (`with pk a:int,b:int`), storage, and
|
||
table-info description are all present; the FK iteration
|
||
references single-column PKs only — compound-key FK references
|
||
remain pending.)*
|
||
|
||
## Visualizations
|
||
|
||
- [ ] **V1** Single-element views render in the output pane: a
|
||
selected table as its structure (columns, types, keys,
|
||
constraints); a selected relationship as two tables joined by
|
||
a line.
|
||
*(Progress: a basic structure view (column rows with SQLite
|
||
type names) is rendered after each successful DDL; pretty
|
||
rendering, selection nav, and relationship line-art pending —
|
||
see V4 for the broader direction.)*
|
||
- [ ] **V2** SQL query results render as a dynamic table view in
|
||
the output pane, with multiple result tabs supported.
|
||
- [~] **V3** Full ER-diagram export (whole-database graph, viewed
|
||
outside the TUI) — low priority; design and ADR pending.
|
||
- [~] **V4** Output panel as a *scrollable per-session log* with
|
||
inline rich rendering. Direction agreed in conversation: the
|
||
output area is a chronological journal of operations and
|
||
selections (e.g. a "selected table X" entry with the rendered
|
||
structure underneath); structure renderings choose between a
|
||
compact ASCII-table form and a vertical line-per-column form
|
||
based on dimensions; the log is exportable to Markdown so
|
||
learners can keep a record of their session. Design and ADR
|
||
pending before any implementation.
|
||
*(Partial: PageUp / PageDown scrolling of the existing line
|
||
buffer is in, with new output snapping the view to the most
|
||
recent. The full V4 scope — smart structure rendering, log
|
||
styling, Markdown export, scroll indicator — remains pending.)*
|
||
- [ ] **V5** `show <kind> [<name>]` family of commands for
|
||
redisplaying schema info on demand. *(Progress: `show table
|
||
<name>` implemented and reuses the structure-render pipeline;
|
||
`show tables`, `show relationships`, etc. pending.)*
|
||
|
||
## Project lifecycle (per ADR-0004)
|
||
|
||
- [ ] **P1** An auto-named temporary project is created on
|
||
startup unless a project is specified, and stored in a
|
||
platform-standard path
|
||
(e.g. `~/.rdbms-playground/projects/temp-<name>`).
|
||
- [ ] **P2** `save` elevates a temp project to a named project at
|
||
a chosen location.
|
||
- [ ] **P3** Project is always saved as changes occur — there is
|
||
no manual dirty state.
|
||
- [ ] **P4** `load` opens a picker listing temp projects with
|
||
timestamps, with the option to browse to an arbitrary location.
|
||
- [ ] **P5** `playground.db` is a derived artifact: rebuilt
|
||
silently when missing, rebuilt with confirmation and a change
|
||
summary when present (per ADR-0004).
|
||
|
||
## Project file format (per ADR-0004)
|
||
|
||
- [ ] **F1** `project.yaml` with `version` field carries schema,
|
||
relationships, and project metadata; `data/<table>.csv` carries
|
||
table data (UTF-8, header row, RFC 4180).
|
||
- [ ] **F2** A `.gitignore` template (excluding `playground.db`)
|
||
is created in each new project.
|
||
- [ ] **F3** Project file format includes a registered-migrator
|
||
mechanism so older `version` values load cleanly as the format
|
||
evolves. (Exercised once `version` increments past 1; the
|
||
mechanism itself is built in v1.)
|
||
|
||
## Undo and replay (per ADR-0006)
|
||
|
||
- [ ] **U1** Auto-snapshot before destructive operations into a
|
||
ring buffer (initial size N=10, tunable).
|
||
- [ ] **U2** `undo` restores the most recent snapshot; `redo`
|
||
re-applies; both prompt for confirmation showing the snapshot
|
||
timestamp and a summary of the changes that will be discarded.
|
||
- [ ] **U3** `history.log` records every successfully executed
|
||
command in append-only form.
|
||
- [ ] **U4** `replay` runs commands from a `history.log` or
|
||
`.commands` file.
|
||
|
||
## Sharing and export (per ADR-0007)
|
||
|
||
- [ ] **E1** `export` produces a zip excluding `playground.db`;
|
||
default filename `YYYYMMDD-<projectname>-export-NN.zip` with a
|
||
non-clobbering two-digit sequence.
|
||
- [ ] **E2** User documentation includes sharing recipes for
|
||
git, email, and direct file transfer.
|
||
|
||
## Sample data / seeding
|
||
|
||
- [ ] **SD1** `seed <table> [count]` generates plausible fake
|
||
data; junction tables are seeded with valid foreign-key
|
||
references drawn from existing parent rows.
|
||
- [~] **SD2** Detailed seeding rules (per-type generators,
|
||
locale, determinism, override hooks) — design and ADR pending.
|
||
|
||
## Query analysis
|
||
|
||
- [ ] **QA1** `EXPLAIN QUERY PLAN` is run on demand for queries;
|
||
output is rendered as an annotated tree highlighting full
|
||
scans, index use, and join order.
|
||
- [~] **QA2** Plan rendering specifics (tree layout, annotation
|
||
taxonomy, colour scheme) — design and ADR pending.
|
||
|
||
## Hints, help, errors
|
||
|
||
- [ ] **H1** Friendly error-rewriting layer translates SQLite
|
||
error messages into learner-friendly equivalents.
|
||
- [ ] **H2** `hint` provides contextual help for the current
|
||
input or the most recent error.
|
||
- [ ] **H3** `help` provides general reference and per-command
|
||
help.
|
||
|
||
## CLI
|
||
|
||
- [ ] **L1** Load a project via a positional CLI argument.
|
||
- [~] **L2** Submit a command alongside project load — deferred,
|
||
not v1.
|
||
|
||
## Tutorials and lessons
|
||
|
||
- [~] **TU1** Tutorial / lesson system — design and ADR pending
|
||
before any implementation. Out of v1 unless an ADR is written.
|
||
|
||
## Testing (per ADR-0008)
|
||
|
||
- [ ] **TT1** Tier 1: `cargo test` + `proptest` covering
|
||
pure-logic modules (parser, dispatcher, type mapping, project
|
||
I/O, snapshot ring buffer, replay log).
|
||
- [ ] **TT2** Tier 2: Ratatui `TestBackend` + `insta` snapshots
|
||
for representative views.
|
||
- [ ] **TT3** Tier 3: synthetic event-loop integration tests
|
||
covering the user-facing flows in this checklist.
|
||
- [ ] **TT4** Tier 4: PTY-based end-to-end for the four critical
|
||
flows named in ADR-0008 (cold launch → DDL → quit; save →
|
||
reopen; export → import → rebuild; undo after DROP).
|
||
- [ ] **TT5** CI runs all tiers on Linux, macOS, and Windows on
|
||
stable Rust.
|
||
|
||
## Cross-cutting
|
||
|
||
- [ ] **X1** Comprehensive logging via the project's logging
|
||
infrastructure per `CLAUDE.md` (decision points, parameter
|
||
values, fallback paths).
|
||
- [~] **X2** Language: English-only for v1; multi-language is an
|
||
open question to revisit later.
|
||
- [~] **X3** Accessibility: TUI screen-reader support is
|
||
best-effort and not a v1 commitment; revisit if user need
|
||
emerges.
|
||
|
||
---
|
||
|
||
## Non-functional requirements
|
||
|
||
NFRs are quality bars rather than discrete features. Where a
|
||
target is measurable, it is stated numerically; where it is
|
||
necessarily qualitative, the criterion is named and the bar is
|
||
"reviewer judgement against the criterion."
|
||
|
||
- [ ] **NFR-1 Performance — startup.** Cold launch to first
|
||
rendered frame under 500ms on commodity hardware (developer
|
||
laptop, mid-range desktop). Measured in CI on the Linux runner
|
||
as a regression gate.
|
||
- [ ] **NFR-2 Performance — input latency.** Keystroke-to-render
|
||
latency under 16ms during normal editing; long-running queries
|
||
must execute off the UI thread so the interface remains
|
||
responsive (typing, scrolling, mode switching) while a query is
|
||
running.
|
||
- [ ] **NFR-3 Performance — resource footprint.** Idle memory
|
||
under 50MB on the smallest target platform; no busy-loops; CPU
|
||
near zero when waiting for input.
|
||
- [ ] **NFR-4 Visual quality — distinctive design.** Colour
|
||
palette and typography are deliberate and consistent across
|
||
views; layout uses Unicode box-drawing and symbols where they
|
||
add clarity; rendering avoids the generic flat-default look
|
||
that ships with most TUI frameworks. Criterion: a reviewer can
|
||
identify the app from a screenshot of any view.
|
||
- [ ] **NFR-5 Visual quality — colour use.** Colour conveys
|
||
information rather than decoration: mode indication, query
|
||
result types (numeric vs text vs null), error severity,
|
||
syntax highlighting categories. Foreground/background
|
||
combinations meet WCAG-AA contrast (4.5:1 for normal text)
|
||
even though we have not committed to broader accessibility.
|
||
- [ ] **NFR-6 Cross-platform parity.** Behaviour and visual
|
||
quality are equivalent across Linux, macOS, and Windows on
|
||
crossterm-supported terminals. Platform-specific divergence
|
||
(e.g. font fallbacks) is documented, not silently tolerated.
|
||
- [ ] **NFR-7 Light and dark background support.** The colour
|
||
scheme remains legible and visually coherent on both light and
|
||
dark terminal backgrounds. The mechanism (auto-detect via
|
||
terminal query, explicit user setting, or both) is an
|
||
implementation choice, but the outcome is non-negotiable: no
|
||
dark-on-dark or light-on-light readability failures on either
|
||
background.
|
||
|
||
---
|
||
|
||
## Explicitly out of scope
|
||
|
||
- [-] **N1** Hosted publishing platform — per ADR-0007. Sharing
|
||
is local-artifact based.
|
||
- [-] **N2** Real UUID column type — per ADR-0005. The `shortid`
|
||
type covers the pedagogical need at TUI-friendly width.
|
||
- [-] **N3** Cross-emulator visual regression coverage — per
|
||
ADR-0008. Crossterm abstracts terminals adequately; we revisit
|
||
only if a real regression surfaces.
|
||
|
||
---
|
||
|
||
## Maintenance
|
||
|
||
This document is updated whenever:
|
||
|
||
- A new requirement is committed to (added as a new item with the
|
||
next free ID in its section).
|
||
- A deferred item is taken up (status moves from `[~]` to `[ ]`).
|
||
- An item is satisfied (status moves to `[x]`, with a reference
|
||
to the commit, PR, or test that demonstrates it).
|
||
- An item moves out of scope (status moves to `[-]` with a
|
||
rationale and a link to the decision).
|
||
|
||
IDs are stable: once assigned, they are not reused. Removing a
|
||
requirement leaves a "withdrawn" entry referencing the decision.
|