Files
initiative/specs/006-undo-redo/quickstart.md
Lukas f6766b729d 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>
2026-03-27 11:32:29 +01:00

54 lines
2.5 KiB
Markdown

# 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).