# Feature Specification: Persist Encounter **Feature Branch**: `008-persist-encounter` **Created**: 2026-03-05 **Status**: Draft **Input**: User description: "Persist the encounter in browser localStorage so the current encounter survives page reloads." ## User Scenarios & Testing *(mandatory)* ### User Story 1 - Encounter Survives Page Reload (Priority: P1) A user is managing a combat encounter (combatants added, initiative set, turns advanced). They accidentally refresh the page or their browser restarts. When the page reloads, the encounter is restored exactly as it was -- same combatants, same initiative values, same active turn, same round number. **Why this priority**: This is the core value of the feature. Without persistence, all encounter progress is lost on any page navigation or reload, which is the primary pain point. **Independent Test**: Can be fully tested by setting up an encounter, refreshing the page, and verifying all encounter state is preserved. **Acceptance Scenarios**: 1. **Given** an encounter with combatants, initiative values, active turn, and round number, **When** the user reloads the page, **Then** the encounter is restored with all state intact (combatants, initiative, active index, round number). 2. **Given** an encounter that has been modified (combatant added, removed, renamed, or initiative changed), **When** the user reloads the page, **Then** the latest state is reflected. 3. **Given** the user advances the turn multiple times, **When** the user reloads the page, **Then** the active turn and round number are preserved. --- ### User Story 2 - Fresh Start with No Saved Data (Priority: P2) A first-time user opens the application with no previously saved encounter. The application shows the default demo encounter so the user can immediately start exploring. **Why this priority**: Ensures backward compatibility and a smooth first-use experience. **Independent Test**: Can be tested by clearing browser storage and loading the application, verifying the demo encounter appears. **Acceptance Scenarios**: 1. **Given** no saved encounter exists in the browser, **When** the user opens the application, **Then** the default demo encounter is displayed. 2. **Given** saved encounter data has been manually cleared from the browser, **When** the user opens the application, **Then** the default demo encounter is displayed. --- ### User Story 3 - Graceful Handling of Corrupt Data (Priority: P3) Saved data may become invalid (e.g., manually edited in dev tools, schema changes between versions). The application handles this gracefully rather than crashing. **Why this priority**: Protects the user experience from edge cases that would otherwise render the app unusable without manual intervention. **Independent Test**: Can be tested by writing malformed data to the storage key and loading the application. **Acceptance Scenarios**: 1. **Given** the saved encounter data is malformed or unparseable, **When** the user opens the application, **Then** the default demo encounter is displayed and the corrupt data is discarded. 2. **Given** the saved data is missing required fields, **When** the user opens the application, **Then** the default demo encounter is displayed. --- ### Edge Cases - What happens when browser storage quota is exceeded? The application continues to function normally; persistence silently fails without disrupting the user's current session. - What happens when browser storage is unavailable (e.g., private browsing in some browsers)? The application falls back to in-memory-only behavior, functioning identically to the current experience. - What happens when the user has multiple browser tabs open? MVP baseline does not include cross-tab synchronization. Each tab operates independently; the last tab to save wins. ## Requirements *(mandatory)* ### Functional Requirements - **FR-001**: System MUST save the full encounter state (combatants, activeIndex, roundNumber) to browser storage after every state change. - **FR-002**: System MUST restore the saved encounter state when the application loads, if valid saved data exists. - **FR-003**: System MUST fall back to the default demo encounter when no saved data exists or saved data is invalid. - **FR-004**: System MUST NOT crash or show an error to the user when storage is unavailable or data is corrupt. - **FR-005**: System MUST preserve combatant identity (IDs, names, initiative values) across reloads. - **FR-006**: System MUST preserve the active turn position and round number across reloads. ### Key Entities - **Persisted Encounter**: A serialized representation of the Encounter (combatants with IDs, names, and initiative values; activeIndex; roundNumber) stored in the browser. ## Success Criteria *(mandatory)* ### Measurable Outcomes - **SC-001**: Users can reload the page and see their encounter fully restored within 1 second, with zero data loss. - **SC-002**: First-time users see the demo encounter immediately on first visit with no extra steps. - **SC-003**: 100% of corrupt or missing data scenarios result in a usable application (demo encounter displayed), never a crash or blank screen. ## Assumptions - The encounter state is small enough that serialization/deserialization has negligible performance impact. - A single browser storage key is sufficient for the MVP (one encounter at a time). - Cross-tab synchronization is not required for the MVP baseline. - The ID counter for new combatants must also be persisted or derived from existing state so that new combatants added after a reload do not collide with existing IDs.