Add optional filename field to export dialog with automatic .json extension handling. Extract resolveFilename() for testability. Add tests for includeHistory flag, bundleToJson, and filename resolution. Add export format compatibility note to CLAUDE.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
107 lines
8.6 KiB
Markdown
107 lines
8.6 KiB
Markdown
# Feature Specification: JSON Import/Export
|
|
|
|
**Feature Branch**: `007-json-import-export`
|
|
**Created**: 2026-03-27
|
|
**Status**: Draft
|
|
**Input**: Gitea issue #17 — JSON import/export for full encounter state
|
|
|
|
## User Scenarios & Testing *(mandatory)*
|
|
|
|
### Story IE-1 — Export encounter to file (Priority: P1)
|
|
|
|
A DM has set up an encounter (combatants, HP, initiative, conditions) and wants to save or share it. They click an export button, choose whether to include undo/redo history, and either download a `.json` file or copy the JSON to their clipboard.
|
|
|
|
**Why this priority**: Export is the foundation — without it, import has nothing to work with. It also delivers standalone value as a backup mechanism.
|
|
|
|
**Independent Test**: Can be fully tested by creating an encounter, exporting (via download or clipboard), and verifying the output contains all encounter data and player character templates.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** the user clicks the export action, **Then** a dialog appears with an option to include undo/redo history (off by default) and two export methods: download file and copy to clipboard.
|
|
2. **Given** an encounter with combatants (some with HP, AC, conditions, initiative), **When** the user exports, **Then** the output contains the encounter state, player character templates, and optionally undo/redo stacks.
|
|
3. **Given** an empty encounter with no combatants, **When** the user exports, **Then** the output contains the empty encounter state and any existing player character templates.
|
|
4. **Given** an encounter with player character combatants (color, icon, linked template), **When** the user exports, **Then** the exported data preserves all player character visual properties and template links.
|
|
5. **Given** the user chooses "Copy to clipboard", **When** the export completes, **Then** the JSON is copied and a visual confirmation is shown.
|
|
|
|
---
|
|
|
|
### Story IE-2 — Import encounter from file (Priority: P1)
|
|
|
|
A DM receives a `.json` file from another DM (or from their own earlier export) and wants to load it. They click an import button, choose an import method (file upload or clipboard paste), and the application replaces the current state with the imported data.
|
|
|
|
**Why this priority**: Import completes the core value proposition — without it, export is just a read-only backup. Both are needed for the feature to be useful.
|
|
|
|
**Independent Test**: Can be tested by importing a valid `.json` file (or pasting valid JSON from the clipboard) and verifying the encounter, undo/redo history, and player characters are replaced with the imported data.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** the user clicks the import action, **Then** a dialog appears offering two import methods: file upload and clipboard paste.
|
|
2. **Given** the current encounter is empty, **When** the user imports valid encounter data (via file or clipboard), **Then** the application loads the imported encounter, undo/redo history, and player characters without any confirmation prompt.
|
|
3. **Given** the current encounter has combatants, **When** the user imports valid encounter data, **Then** a confirmation dialog appears warning that the current encounter will be replaced.
|
|
4. **Given** the confirmation dialog is shown, **When** the user confirms, **Then** the current encounter, undo/redo history, and player characters are replaced with the imported data.
|
|
5. **Given** the confirmation dialog is shown, **When** the user cancels, **Then** the current state remains unchanged.
|
|
|
|
---
|
|
|
|
### Story IE-3 — Reject invalid import files (Priority: P2)
|
|
|
|
A DM accidentally selects a wrong file (a non-JSON file, a corrupted export, or a JSON file with the wrong structure). The application rejects it and shows a clear error message without losing the current state.
|
|
|
|
**Why this priority**: Error handling is essential for a good user experience but secondary to the core import/export flow.
|
|
|
|
**Independent Test**: Can be tested by attempting to import various invalid files and verifying appropriate error messages appear while the current state is preserved.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** the user selects a non-JSON file (e.g., an image), **When** the import attempts to parse it, **Then** a user-facing error message is shown and the current state is unchanged.
|
|
2. **Given** the user selects a JSON file with missing required fields, **When** the import validates it, **Then** a user-facing error message is shown and the current state is unchanged.
|
|
3. **Given** the user selects a JSON file with a valid top-level structure but individual combatants with invalid fields (e.g., negative HP, unknown condition IDs), **When** the import validates it, **Then** invalid fields on otherwise valid combatants are dropped/defaulted (same as localStorage rehydration), but if the top-level structure is malformed (missing `encounter` key, wrong types), the file is rejected with an error message.
|
|
4. **Given** the user chooses clipboard import but the clipboard is empty or contains non-JSON text, **Then** a user-facing error message is shown and the current state is unchanged.
|
|
|
|
---
|
|
|
|
### Edge Cases
|
|
|
|
- What happens when the exported file is from a newer version of the application with unknown fields? The import ignores unknown fields and loads what it can validate.
|
|
- What happens when the user imports a file with player characters that conflict with existing player character IDs? The imported player characters replace the existing ones entirely (full state replacement, not merge).
|
|
- What happens when the undo/redo stacks in the imported file are empty or missing? The system loads with empty undo/redo stacks (same as a fresh session).
|
|
- What happens when the browser blocks the file download (e.g., popup blocker)? The export uses a direct download mechanism (anchor element with download attribute) that is not subject to popup blocking.
|
|
|
|
## Requirements *(mandatory)*
|
|
|
|
### Functional Requirements
|
|
|
|
- **FR-001**: The system MUST provide an export action accessible from the UI that lets the user download the application state as a `.json` file or copy it to the clipboard.
|
|
- **FR-002**: The exported data MUST contain the current encounter (combatants and turn/round state) and player character templates. Undo/redo stacks MUST be includable via a user option (default: excluded).
|
|
- **FR-003**: The exported file MUST use a human-readable default filename that includes the date. The user MAY optionally specify a custom filename; the `.json` extension is appended automatically if not provided.
|
|
- **FR-004**: The system MUST provide an import action accessible from the UI that lets the user choose between uploading a `.json` file or pasting from the clipboard.
|
|
- **FR-005**: On import, the system MUST replace the current encounter, undo/redo history, and player characters with the imported data.
|
|
- **FR-006**: The system MUST show a confirmation dialog before importing if the current encounter is non-empty (has at least one combatant).
|
|
- **FR-007**: The system MUST validate imported data using the same rules applied when loading from localStorage — invalid fields are cleaned or dropped, structurally malformed files are rejected entirely.
|
|
- **FR-008**: The system MUST show a user-facing error message when an imported file is rejected as invalid.
|
|
- **FR-009**: A failed or cancelled import MUST NOT alter the current application state.
|
|
- **FR-010**: Export and import actions MUST be accessible from the same location in the UI.
|
|
|
|
### Key Entities
|
|
|
|
- **Export Bundle**: A single JSON structure containing the encounter snapshot, undo stack, redo stack, and player character list. Represents the full application state at the time of export.
|
|
|
|
## Success Criteria *(mandatory)*
|
|
|
|
### Measurable Outcomes
|
|
|
|
- **SC-001**: Users can export the current state to a downloadable file in one click.
|
|
- **SC-002**: Users can import a previously exported file and see the full encounter restored, including combatant stats, turn tracking, and player characters.
|
|
- **SC-003**: Importing an invalid file shows an error message within 1 second without affecting the current state.
|
|
- **SC-004**: A round-trip (export then import) produces an encounter identical to the original.
|
|
|
|
## Assumptions
|
|
|
|
- The export format does not need to be backwards-compatible across application versions at this stage. Future format versioning is not included in MVP baseline.
|
|
- Export/import covers the three main state stores: encounter, undo/redo, and player characters. Bestiary cache and user settings (theme, rules edition) are excluded.
|
|
- The import is a full state replacement, not a merge. There is no selective import of individual pieces.
|
|
|
|
## Dependencies
|
|
|
|
- Undo/redo system (spec 006) must be implemented so that undo/redo stacks can be included in the export.
|