Files
initiative/specs/006-undo-redo/plan.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

4.0 KiB

Implementation Plan: Undo/Redo

Branch: 006-undo-redo | Date: 2026-03-26 | Spec: spec.md Input: Feature specification from /specs/006-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)

specs/006-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)

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.