Rename spec 037-undo-redo to 006-undo-redo for sequential numbering
Delete merged feature branches (005–037) that inflated the auto-increment counter in create-new-feature.sh, and renumber the undo-redo spec to follow the existing 001–005 sequence. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
53
specs/006-undo-redo/quickstart.md
Normal file
53
specs/006-undo-redo/quickstart.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Quickstart: Undo/Redo
|
||||
|
||||
**Feature**: 006-undo-redo
|
||||
**Date**: 2026-03-26
|
||||
|
||||
## Overview
|
||||
|
||||
This feature adds undo/redo to all encounter state changes using the memento (snapshot) pattern. Each action captures the pre-action encounter state onto an undo stack. Undo restores the previous state; redo re-applies an undone state.
|
||||
|
||||
## Implementation Layers
|
||||
|
||||
### Domain (`packages/domain/src/undo-redo.ts`)
|
||||
|
||||
Pure functions for stack management:
|
||||
- `pushUndo(state, snapshot)` — push snapshot, cap at 50, clear redo
|
||||
- `undo(state, currentEncounter)` — pop undo, push current to redo
|
||||
- `redo(state, currentEncounter)` — pop redo, push current to undo
|
||||
- `clearHistory()` — reset both stacks
|
||||
|
||||
All functions take and return immutable data. No I/O.
|
||||
|
||||
### Application (`packages/application/src/`)
|
||||
|
||||
Use cases that orchestrate domain calls via store ports:
|
||||
- `undoUseCase(encounterStore, undoRedoStore)` — execute undo
|
||||
- `redoUseCase(encounterStore, undoRedoStore)` — execute redo
|
||||
|
||||
New port interface `UndoRedoStore` in `ports.ts`:
|
||||
- `get(): UndoRedoState`
|
||||
- `save(state: UndoRedoState): void`
|
||||
|
||||
### Web Adapter (`apps/web/src/`)
|
||||
|
||||
**Hook (`use-encounter.ts`)**: Wraps every action callback to capture pre-action snapshot. Exposes `undo()`, `redo()`, `canUndo`, `canRedo`.
|
||||
|
||||
**Persistence (`persistence/undo-redo-storage.ts`)**: Save/load undo/redo stacks to localStorage keys `"initiative:encounter:undo"` and `"initiative:encounter:redo"`.
|
||||
|
||||
**UI (`components/turn-navigation.tsx`)**: Undo/Redo buttons in the top bar, inboard of the turn step buttons, disabled when stack is empty.
|
||||
|
||||
**Keyboard (`hooks/use-undo-redo-shortcuts.ts`)**: Global keydown listener for Ctrl+Z / Ctrl+Shift+Z (Cmd on Mac). Suppressed when text input has focus.
|
||||
|
||||
## Key Design Decisions
|
||||
|
||||
1. **Memento over Command**: Full encounter snapshots, not inverse events. Simpler at encounter scale (~2-5 KB per snapshot).
|
||||
2. **Capture in hook, not domain**: Snapshot capture happens in the adapter layer. Domain and application layers are unaware of undo/redo.
|
||||
3. **React state for stacks**: Enables reactive button disabled states without manual re-render triggers.
|
||||
4. **Clear is not undoable**: Both stacks reset on encounter clear (per spec).
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
- **Domain tests**: Pure function tests for stack operations (push, pop, cap, clear, undo/redo roundtrip).
|
||||
- **Application tests**: Use case tests with mock stores.
|
||||
- **Integration**: Spec acceptance scenarios mapped to test cases (undo restores state, redo reapplies, new action clears redo, keyboard suppression during input focus).
|
||||
Reference in New Issue
Block a user