91 lines
5.5 KiB
Markdown
91 lines
5.5 KiB
Markdown
# 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.
|