Add undo/redo for all encounter actions
Memento-based undo/redo with full encounter snapshots. Undo stack capped at 50 entries, persisted to localStorage. Triggered via buttons in the top bar (inboard of turn navigation) and keyboard shortcuts (Ctrl+Z / Ctrl+Shift+Z, Cmd on Mac, case-insensitive key matching). Clear encounter resets both stacks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
71
specs/037-undo-redo/plan.md
Normal file
71
specs/037-undo-redo/plan.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Implementation Plan: Undo/Redo
|
||||
|
||||
**Branch**: `037-undo-redo` | **Date**: 2026-03-26 | **Spec**: [spec.md](spec.md)
|
||||
**Input**: Feature specification from `/specs/037-undo-redo/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Add undo/redo capability for all encounter state changes using the memento pattern. Before each state transition, the current `Encounter` is pushed to an undo stack (capped at 50 entries). Undo restores the previous snapshot and pushes the current state to a redo stack; any new action clears the redo stack. Stacks are persisted to localStorage. Triggered via UI buttons (disabled when empty) and keyboard shortcuts (Ctrl+Z / Ctrl+Shift+Z, Cmd on Mac), suppressed during text input focus.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: TypeScript 5.8 (strict mode, `verbatimModuleSyntax`)
|
||||
**Primary Dependencies**: React 19, Vite 6, Tailwind CSS v4, Lucide React (icons)
|
||||
**Storage**: localStorage (existing key `"initiative:encounter"`, new keys for undo/redo stacks)
|
||||
**Testing**: Vitest (v8 coverage)
|
||||
**Target Platform**: Web browser (desktop + mobile)
|
||||
**Project Type**: Web application (monorepo: `apps/web` + `packages/domain` + `packages/application`)
|
||||
**Performance Goals**: Undo/redo operations complete in < 1 second (per SC-001)
|
||||
**Constraints**: Undo stack capped at 50 snapshots; localStorage quota is best-effort
|
||||
**Scale/Scope**: Encounters have tens of combatants; 50 snapshots of ~2-5 KB each = ~100-250 KB
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
| Principle | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| I. Deterministic Domain Core | PASS | Stack management (push, pop, cap) is pure logic with no I/O. Domain functions remain unchanged. |
|
||||
| II. Layered Architecture | PASS | Stack operations are pure functions in domain. Persistence is in the adapter layer (localStorage). Hook orchestrates via application pattern. |
|
||||
| II-A. Context-Based State Flow | PASS | Undo/redo state exposed via existing EncounterContext. No new props needed on components beyond the context consumer. |
|
||||
| III. Clarification-First | PASS | No ambiguities remain; issue #16 and spec fully define behavior. |
|
||||
| IV. Escalation Gates | PASS | All requirements come from the spec; no scope expansion. |
|
||||
| V. MVP Baseline Language | PASS | No permanent bans introduced. |
|
||||
| VI. No Gameplay Rules | PASS | Undo/redo is infrastructure, not gameplay. |
|
||||
|
||||
**Result**: All gates pass. No violations to justify.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/037-undo-redo/
|
||||
├── plan.md # This file
|
||||
├── research.md # Phase 0 output
|
||||
├── data-model.md # Phase 1 output
|
||||
├── quickstart.md # Phase 1 output
|
||||
└── tasks.md # Phase 2 output (/speckit.tasks)
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
```text
|
||||
packages/domain/src/
|
||||
├── undo-redo.ts # Pure stack operations (push, pop, cap, clear)
|
||||
├── __tests__/undo-redo.test.ts # Unit tests for stack operations
|
||||
|
||||
packages/application/src/
|
||||
├── undo-use-case.ts # Orchestrates undo via EncounterStore + UndoRedoStore
|
||||
├── redo-use-case.ts # Orchestrates redo via EncounterStore + UndoRedoStore
|
||||
├── ports.ts # Extended with UndoRedoStore port interface
|
||||
|
||||
apps/web/src/
|
||||
├── hooks/use-encounter.ts # Modified: wrap actions with snapshot capture, expose undo/redo
|
||||
├── persistence/undo-redo-storage.ts # localStorage save/load for undo/redo stacks
|
||||
├── contexts/encounter-context.tsx # Modified: expose undo/redo + stack emptiness flags
|
||||
├── components/turn-navigation.tsx # Modified: add undo/redo buttons (inboard of turn step buttons)
|
||||
├── hooks/use-undo-redo-shortcuts.ts # Keyboard shortcut handler (Ctrl+Z, Ctrl+Shift+Z)
|
||||
```
|
||||
|
||||
**Structure Decision**: Follows existing layered architecture. Pure stack operations in domain, use cases in application, persistence and UI in web adapter. No new packages or structural changes needed.
|
||||
Reference in New Issue
Block a user