bfdf350ac8
- New docs/handoff/20260507-handoff-1.md captures session state, what's implemented, what's pending (ranked recommendations for next moves), sharp edges, and a smoke-test sequence. - CLAUDE.md updated to reflect current reality: ADRs 0008- 0014 added to the decisions-at-a-glance list, the "repository layout (planned)" placeholder replaced with the actual layout, key invariants spelled out, deferred list rebuilt from current requirements.md.
197 lines
9.3 KiB
Markdown
197 lines
9.3 KiB
Markdown
# RDBMS Playground — project notes for Claude
|
||
|
||
## What this project is
|
||
|
||
A cross-platform TUI application that gives learners a sandbox for
|
||
exploring relational database concepts: tables, columns, primary
|
||
and foreign keys, relationships, indexes, queries, and query
|
||
plans. The audience is students from beginners to those ready for
|
||
raw SQL, and the design accommodates both ends of that spectrum.
|
||
|
||
The application is a teaching tool, not a database administration
|
||
tool. Decisions about the type system, command surface, and
|
||
backend choices are skewed toward pedagogy over breadth.
|
||
|
||
## Authoritative decisions
|
||
|
||
All significant design decisions live in `docs/adr/`. Read
|
||
`docs/adr/README.md` for the index. **Before proposing changes
|
||
that touch a decided area, read the relevant ADR.** Decisions are
|
||
not re-litigated casually — if a decision needs to change, write a
|
||
new ADR that supersedes the old one.
|
||
|
||
Current decisions at a glance (each backed by an ADR):
|
||
|
||
- **Stack:** Rust + Ratatui + Crossterm; `sqlparser-rs` reserved
|
||
for SQL (advanced mode, not yet wired); `chumsky` for the DSL;
|
||
`rusqlite` for the database (ADR-0001).
|
||
- **Backend:** SQLite with `STRICT` tables and FK enforcement on
|
||
(ADR-0002). Database access through a dedicated worker thread
|
||
with mpsc/oneshot request channels (ADR-0010).
|
||
- **Input:** simple mode (DSL only) by default; advanced mode
|
||
(SQL + app-level commands) on toggle; `:` one-shot escape from
|
||
simple to advanced (ADR-0003). No other sigils.
|
||
- **Project format:** `project.yaml` + `data/<table>.csv` +
|
||
`history.log`; `playground.db` is a derived artifact (ADR-0004).
|
||
*(Format defined; track 2 implementation pending.)*
|
||
- **Types:** `text`, `int`, `real`, `decimal`, `bool`, `date`,
|
||
`datetime`, `blob`, `serial`, `shortid`. Compound primary keys
|
||
supported. No real UUIDs (ADR-0005). FK column type
|
||
compatibility via `Type::fk_target_type()` — `serial → int`,
|
||
`shortid → text`, others identity (ADR-0011).
|
||
- **Safety:** auto-snapshot before destructive ops; `:undo`;
|
||
append-only `history.log` for replay and scripting (ADR-0006).
|
||
*(Designed; not yet implemented.)*
|
||
- **Sharing:** `export` command produces a zip without the `.db`;
|
||
no hosted publishing (ADR-0007).
|
||
- **Testing:** four-tier strategy from `cargo test` units up to
|
||
PTY-based end-to-end (ADR-0008). Tiers 1–3 are active; Tier 4
|
||
is wired only for the listed critical flows.
|
||
- **DSL syntax conventions:** required clauses use keyword
|
||
grammar (`with pk`, `to table` optional, `from..to`, `set`,
|
||
`where`); `--` flags are reserved for opt-in choices; one
|
||
sigil only (`:`); keywords case-insensitive, identifiers
|
||
case-preserving (ADR-0009).
|
||
- **Internal metadata tables** (ADR-0012, ADR-0013): the database
|
||
carries `__rdbms_playground_columns` for user-facing column
|
||
types and `__rdbms_playground_relationships` for named FKs.
|
||
These are the source of truth for round-tripping schema info.
|
||
Internal tables follow the `__rdbms_*` naming convention and
|
||
are filtered out of `list_tables`.
|
||
- **FK relationships:** declared via `add 1:n relationship [as
|
||
<name>] from <P>.<col> to <C>.<col> [on delete <action>] [on
|
||
update <action>] [--create-fk]`. Implemented through the
|
||
rebuild-table primitive — the same machinery covers B2's
|
||
pending column drop/rename/type-change use cases (ADR-0013).
|
||
- **Data operations:** `insert / update / delete / show data`
|
||
with required WHERE plus `--all-rows` opt-in for unfiltered
|
||
ops; auto-show after writes shows just the affected rows;
|
||
DELETE reports per-relationship cascade summaries (ADR-0014).
|
||
|
||
## Repository layout
|
||
|
||
```
|
||
.
|
||
├── Cargo.toml # dependencies, lints (nursery)
|
||
├── CLAUDE.md # this file
|
||
├── docs/
|
||
│ ├── adr/ # all decision records (read 0000 first)
|
||
│ ├── handoff/ # session-handover notes
|
||
│ └── requirements.md # the Phase-1 checklist with progress
|
||
├── src/
|
||
│ ├── action.rs # Action enum (Quit / ExecuteDsl)
|
||
│ ├── app.rs # App state + pure update() + Tier-1 tests
|
||
│ ├── cli.rs # CLI args (--theme, --log-file)
|
||
│ ├── db.rs # rusqlite worker, all DDL/DML, metadata tables
|
||
│ ├── dsl/
|
||
│ │ ├── action.rs # ReferentialAction enum + parsing
|
||
│ │ ├── command.rs # Command AST + RelationshipSelector + RowFilter
|
||
│ │ ├── mod.rs # re-exports
|
||
│ │ ├── parser.rs # chumsky grammar (all DSL commands)
|
||
│ │ ├── shortid.rs # base58 generator + validator
|
||
│ │ ├── types.rs # user-facing Type enum + fk_target_type
|
||
│ │ └── value.rs # Value/Bound + per-type validation
|
||
│ ├── event.rs # AppEvent (input + DSL outcomes)
|
||
│ ├── lib.rs # module re-exports for tests
|
||
│ ├── logging.rs # tracing setup, file-backed
|
||
│ ├── main.rs # binary entry; thin
|
||
│ ├── mode.rs # Simple/Advanced mode enum
|
||
│ ├── runtime.rs # Tokio loop, terminal setup, dispatch
|
||
│ ├── snapshots/ # insta snapshots for Tier-2 tests
|
||
│ ├── theme.rs # light/dark themes
|
||
│ └── ui.rs # ratatui rendering
|
||
└── tests/
|
||
└── walking_skeleton.rs # Tier-3 integration tests
|
||
```
|
||
|
||
Key invariants in the code:
|
||
|
||
- **`update()` is pure-sync.** It returns `Vec<Action>` for the
|
||
runtime to enact. Side effects belong in the runtime, not the
|
||
update function — that's what makes Tier 1/3 tests tractable.
|
||
- **Database access goes through the worker thread.** Always.
|
||
No direct `rusqlite::Connection` use outside `db.rs`.
|
||
- **Schema mutations update metadata in the same transaction.**
|
||
See ADR-0012 / ADR-0013. Adding a new DDL operation must keep
|
||
the column- and relationship-metadata tables in sync.
|
||
- **Renderer is pure render of `App` state.** It reports
|
||
viewport metrics back via `note_output_viewport` so subsequent
|
||
scroll input is wrap-aware.
|
||
|
||
## Working style for this project
|
||
|
||
- **Documentation discipline.** Significant decisions get an
|
||
ADR. In-flight discussion stays in conversation or issues
|
||
until it settles. The ADR-0000 index-upkeep rule applies:
|
||
every ADR change updates `docs/adr/README.md` in the same
|
||
edit.
|
||
- **Testing.** Per the user's global standards, tests are
|
||
established before changes, bugs are reproduced with failing
|
||
tests before being fixed, and "all green, no skips" is the
|
||
only acceptable end state. Integration tests exercise full
|
||
flows.
|
||
- **No silent feature loss.** Anything in an ADR is decided. If
|
||
implementation reveals that a decision is wrong or
|
||
impractical, raise it explicitly and update the ADR — do not
|
||
quietly drift.
|
||
- **Pedagogy wins ties.** When a design choice trades clarity
|
||
for raw capability, prefer clarity. Real RDBMS power-user
|
||
features exist; this app is not the place to teach them.
|
||
- **Confirm commits.** Per the user's global rules, every
|
||
`git commit` is preceded by an explicit message proposal
|
||
and user approval. No AI attribution in commit messages.
|
||
|
||
## Things deliberately deferred
|
||
|
||
These are explicitly tracked (mostly in `requirements.md`) but
|
||
not yet implemented:
|
||
|
||
- **Project storage** (track 2 / P-series, F-series): file-
|
||
backed projects, save/load/new/export/import, persistent
|
||
history. Format is fully designed in ADR-0004; the
|
||
metadata-table round-trip lands here.
|
||
- **Complex WHERE expressions** (C5a): AND/OR/comparison/LIKE
|
||
in UPDATE/DELETE/show-data filters. The bridge from DSL
|
||
fluency to real SQL.
|
||
- **SQL handling in advanced mode** (Q1): `sqlparser-rs` parser
|
||
+ a defined SQL subset (Q4 — its own ADR).
|
||
- **Column drops/renames/type changes** (B2 / C2 partial): the
|
||
rebuild-table primitive (ADR-0013) is in place; the grammar
|
||
and dispatch are pending.
|
||
- **Indexes** (C3 partial): `add index`, `drop index`, then
|
||
`EXPLAIN QUERY PLAN` rendering for QA1.
|
||
- **Modify relationship** (C3a): drop+add covers the use case
|
||
today.
|
||
- **m:n convenience** (C4): auto-generates a junction table
|
||
with appropriate FKs — depends on relationships being solid
|
||
(they are).
|
||
- **Friendly error layer** (H1): partial — FK errors are
|
||
enriched both ways; full SQL→English translation pending.
|
||
- **Strong syntax-help in parse errors** (H1a): point users at
|
||
missing keywords/clauses rather than the unexpected
|
||
character.
|
||
- **Snapshot/replay/undo** (U-series): designed in ADR-0006;
|
||
not yet implemented.
|
||
- **Tutorial/lesson system**: acknowledged as in scope for
|
||
design; needs its own ADR.
|
||
- **Session log + Markdown export** (V4): the bigger UX
|
||
project — scrollable session journal, smart structure
|
||
rendering, save-as-markdown.
|
||
- **Readline shortcuts** (I1b): Ctrl-A/Ctrl-E, Ctrl-W/Ctrl-K/
|
||
Ctrl-U.
|
||
- **Multi-line input** (I1): Enter inserts newline,
|
||
Ctrl-Enter submits.
|
||
- **Tab completion** (I3), **syntax highlighting** (I4).
|
||
- **ER diagram export** (V3).
|
||
- **CI** (TT5): test infrastructure exists; CI workflow not
|
||
yet configured.
|
||
|
||
## Handoff notes
|
||
|
||
When taking over a session, read in order:
|
||
|
||
1. `docs/handoff/` — most recent file gives session context.
|
||
2. `CLAUDE.md` (this file).
|
||
3. `docs/requirements.md` — current progress on each item.
|
||
4. `docs/adr/README.md` and any ADR you'll touch.
|