Files
initiative/specs/008-persist-encounter/plan.md

3.6 KiB

Implementation Plan: Persist Encounter

Branch: 008-persist-encounter | Date: 2026-03-05 | Spec: spec.md Input: Feature specification from /specs/008-persist-encounter/spec.md

Summary

Persist the current encounter state to browser localStorage so it survives page reloads. The web adapter layer will serialize encounter state on every change and deserialize on load, falling back to the demo encounter when no valid data exists. The domain and application layers remain unchanged -- persistence is purely an adapter concern.

Technical Context

Language/Version: TypeScript 5.x (strict mode, verbatimModuleSyntax) Primary Dependencies: React 19, Vite 6, Biome 2.0, existing domain/application packages Storage: Browser localStorage (adapter layer only) Testing: Vitest (unit tests for serialization/deserialization logic) Target Platform: Modern browsers (Chrome, Firefox, Safari, Edge) Project Type: Web application (monorepo with domain/application/web layers) Performance Goals: Encounter restore under 1 second (negligible for small JSON payloads) Constraints: No domain or application layer changes; persistence is adapter-only Scale/Scope: Single encounter, single user, single tab (MVP baseline)

Constitution Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

Principle Status Notes
I. Deterministic Domain Core PASS No domain changes. localStorage access is confined to the adapter layer.
II. Layered Architecture PASS Persistence logic lives in the web adapter (apps/web). Domain and application layers are untouched. The existing EncounterStore port is already implemented by the useEncounter hook; persistence wraps around this.
III. Agent Boundary N/A No agent features involved.
IV. Clarification-First PASS Feature is well-scoped; no non-trivial assumptions. Storage key name and serialization format are implementation details within adapter scope.
V. Escalation Gates PASS Implementation stays within spec scope.
VI. MVP Baseline Language PASS Cross-tab sync and multi-encounter support noted as "MVP baseline does not include."
VII. No Gameplay Rules PASS No gameplay mechanics involved.

Gate result: PASS -- no violations.

Project Structure

Documentation (this feature)

specs/008-persist-encounter/
├── 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 (via /speckit.tasks)

Source Code (repository root)

packages/domain/src/
├── types.ts             # Encounter, Combatant, CombatantId (unchanged)
└── index.ts             # Exports (unchanged)

packages/application/src/
├── ports.ts             # EncounterStore interface (unchanged)
└── index.ts             # Exports (unchanged)

apps/web/src/
├── hooks/
│   └── use-encounter.ts # Modified: initialize from localStorage, persist on change
├── persistence/
│   └── encounter-storage.ts  # New: localStorage read/write/validate logic
└── main.tsx             # Unchanged

Structure Decision: All new code goes into apps/web/src/persistence/ as a new adapter module. The useEncounter hook is modified to use this module for initialization and persistence. No new packages or layers are introduced.

Complexity Tracking

No constitution violations to justify.