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.
17 KiB
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, andcargo 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). Themode simple/mode advancedcommand 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/qandmode simple|advancedimplemented; the rest land alongside the features they belong to —saveand friends in track 2,seedin 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 UPDATEreferential actions, indexes,NOT NULL,UNIQUE,CHECK,DEFAULT. (Progress: PK including compound done at create-table time; FK withON DELETE/ON UPDATEactions done (ADR-0013) — declared viaadd 1:n relationship; symmetric outbound + inbound view in the structure renderer; type compatibility validated at declaration viaType::fk_target_type(). Index,NOT NULL,UNIQUE,CHECK,DEFAULTstill 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 viachumsky(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.
- 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)
- B1 SQLite via
rusqlite; all tables createdSTRICT;PRAGMA foreign_keys = ONper connection. (Database accessed through a dedicated worker thread per ADR-0010.) - B2 Schema evolution uses the rebuild-table technique
internally where SQLite
ALTER TABLEcannot. (Progress: rebuild-table primitive landed (ADR-0013) and is used byadd_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)
- 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
shortidgeneration: 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
saveelevates 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
loadopens a picker listing temp projects with timestamps, with the option to browse to an arbitrary location. - P5
playground.dbis 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.yamlwithversionfield carries schema, relationships, and project metadata;data/<table>.csvcarries table data (UTF-8, header row, RFC 4180). - F2 A
.gitignoretemplate (excludingplayground.db) is created in each new project. - F3 Project file format includes a registered-migrator
mechanism so older
versionvalues load cleanly as the format evolves. (Exercised onceversionincrements 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
undorestores the most recent snapshot;redore-applies; both prompt for confirmation showing the snapshot timestamp and a summary of the changes that will be discarded. - U3
history.logrecords every successfully executed command in append-only form. - U4
replayruns commands from ahistory.logor.commandsfile.
Sharing and export (per ADR-0007)
- E1
exportproduces a zip excludingplayground.db; default filenameYYYYMMDD-<projectname>-export-NN.zipwith 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 PLANis 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
hintprovides contextual help for the current input or the most recent error. - H3
helpprovides 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+proptestcovering pure-logic modules (parser, dispatcher, type mapping, project I/O, snapshot ring buffer, replay log). - TT2 Tier 2: Ratatui
TestBackend+instasnapshots 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
shortidtype 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.