roadmap: add Phase 1.5 — undo & redo (snapshot-based)

- effort S (~0.5-1 day): rides on Phase 1 machinery (serde snapshots,
  replace_state, the store.track() autosave trigger) — no component
  changes needed, page-agnostic
- coalesced snapshots (one per ~1 s window), capped stacks, Ctrl+Z /
  Ctrl+Shift+Z with focus guard for text fields
- sequencing note: lands before the edit-heavy Phases 2-7 so their edits
  are undoable from day one; nothing depends on it
- Phase 8 e2e item: drop the persistence round trip (already covered by
  persistence.spec.ts), add undo shortcuts
- ARCHITECTURE gaps list: note the missing undo/redo
This commit is contained in:
yaroslav k 2026-08-16 11:57:31 +03:00
parent cc57da0d83
commit 42b106c793
2 changed files with 29 additions and 3 deletions

View File

@ -157,6 +157,8 @@ currently mounted on any page.
## Current gaps ## Current gaps
- Quests, notes, contacts: models and mock data only - Quests, notes, contacts: models and mock data only
- No undo/redo (planned as Phase 1.5; snapshot-based, rides on the
persist machinery)
- `Character` and `Wiki` pages render placeholders - `Character` and `Wiki` pages render placeholders
- Prepared spells list is empty; `Spell` is a name-only stub; attunements - Prepared spells list is empty; `Spell` is a name-only stub; attunements
have no UI; `Settings` has only `version` have no UI; `Settings` has only `version`

View File

@ -98,6 +98,28 @@ export/import round trip). Notes:
- Version check is the migration hook: `parse_dashboard` returns - Version check is the migration hook: `parse_dashboard` returns
`ImportError::{Parse, NewerVersion, OldVersion}` (RU messages). `ImportError::{Parse, NewerVersion, OldVersion}` (RU messages).
## Phase 1.5 — Undo & redo (S, ~0.5-1 day)
Snapshot-based undo rides on the Phase 1 machinery: serialize → push →
`replace_state`. It is page-agnostic: the `store.track()` trigger already
fires on any mutation, so no component changes are needed and every later
phase's edits are undoable from day one.
- [ ] `state::undo.rs` (hydrate-gated): undo/redo stacks of serialized
`Dashboard`, capped (e.g. 100); push coalesced on the store trigger
(one snapshot per ~1 s window → one undo step = one edit burst)
- [ ] a new edit after undo clears the redo stack; Clear and import push a
snapshot first, so they are undoable too
- [ ] `undo()` / `redo()` call `replace_state`; expose stack depths as
`RwSignal<usize>` for button disabled states
- [ ] header buttons: ↩ Отменить / Вернуть (disabled when empty)
- [ ] shortcuts: Ctrl+Z, Ctrl+Shift+Z (Ctrl+Y); ignore when focus is in an
input/textarea/select, so typing never triggers undo
- [ ] unit tests for stack semantics; e2e: edit → undo → redo; reload keeps
the undone state (undo writes through autosave)
- **Acceptance:** every edit since the last window is reversible with a
keystroke; undo survives a reload.
## Phase 2 — Character page (M, ~1-2 days) ## Phase 2 — Character page (M, ~1-2 days)
`/` currently renders the literal string "character". `/` currently renders the literal string "character".
@ -167,8 +189,8 @@ New route `/contacts`. Model and mock data exist; zero UI.
## Phase 8 — Polish, tests, release (L, ~2-4 days) ## Phase 8 — Polish, tests, release (L, ~2-4 days)
- [ ] responsive SCSS pass (sidebar and header on mobile widths) - [ ] responsive SCSS pass (sidebar and header on mobile widths)
- [ ] Playwright e2e: persistence round-trip, add item from search, quest CRUD, - Playwright e2e: add item from search, quest CRUD, notes filter, undo
notes filter shortcuts (persistence round trip is covered by `persistence.spec.ts`)
- [ ] rewrite README: usage, dev workflow, deploy - [ ] rewrite README: usage, dev workflow, deploy
- [ ] release build via cargo-leptos; verify SSR + hydration; pick a deploy target - [ ] release build via cargo-leptos; verify SSR + hydration; pick a deploy target
- **Acceptance:** fresh clone → `cargo leptos build` → app runs; e2e green. - **Acceptance:** fresh clone → `cargo leptos build` → app runs; e2e green.
@ -179,7 +201,9 @@ New route `/contacts`. Model and mock data exist; zero UI.
- Phase 1 before Phases 2-7: every new page must persist. Building pages first - Phase 1 before Phases 2-7: every new page must persist. Building pages first
against mock data and persisting later costs a data-migration pass instead. against mock data and persisting later costs a data-migration pass instead.
- Phases 2 and 3 can run in parallel after Phase 1 (different components). - Phases 2 and 3 can run in parallel after Phase 1.5 (different components).
- Phase 1.5 (undo) is page-agnostic: it must land before the edit-heavy
phases so their edits are undoable; nothing in Phases 2-7 depends on it.
- Phases 4-6 are independent of each other and share one CRUD-list pattern — - Phases 4-6 are independent of each other and share one CRUD-list pattern —
build the pattern once (e.g. a generic list editor) and reuse it. build the pattern once (e.g. a generic list editor) and reuse it.
- Phase 7 reuses the Phase 3 add-to-inventory path; keep that path shared. - Phase 7 reuses the Phase 3 add-to-inventory path; keep that path shared.