Files
initiative/specs/023-clear-encounter/tasks.md

147 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tasks: Clear Encounter
**Input**: Design documents from `/specs/023-clear-encounter/`
**Prerequisites**: plan.md, spec.md, research.md, data-model.md, quickstart.md
**Tests**: Included — domain tests follow existing patterns (pure function assertions).
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
## Format: `[ID] [P?] [Story] Description`
- **[P]**: Can run in parallel (different files, no dependencies)
- **[Story]**: Which user story this task belongs to (e.g., US1, US2)
- Include exact file paths in descriptions
---
## Phase 1: Foundational (Blocking Prerequisites)
**Purpose**: Domain event type and pure function that all subsequent work depends on
**⚠️ CRITICAL**: No user story work can begin until this phase is complete
- [x] T001 Add `EncounterCleared` event interface (with `type: "EncounterCleared"` and `combatantCount: number` fields) and add it to the `DomainEvent` union type in `packages/domain/src/events.ts`
- [x] T002 Create `clearEncounter` pure function in `packages/domain/src/clear-encounter.ts` — takes an `Encounter`, returns `ClearEncounterSuccess` (with `{ encounter: { combatants: [], activeIndex: 0, roundNumber: 1 }, events: [EncounterCleared] }`) or `DomainError` (code `"encounter-already-empty"` when `combatants.length === 0`). Export `ClearEncounterSuccess` type. Follow the pattern in `packages/domain/src/remove-combatant.ts`
- [x] T003 Export `clearEncounter`, `ClearEncounterSuccess`, and `EncounterCleared` from `packages/domain/src/index.ts`
**Checkpoint**: Domain layer complete — `clearEncounter` is a pure, testable function
---
## Phase 2: User Story 1 — Clear Encounter to Start Fresh (Priority: P1) 🎯 MVP
**Goal**: Users can clear all combatants and reset round/turn counters with a single action, with the cleared state persisting across page refreshes.
**Independent Test**: Add several combatants, advance through rounds, clear the encounter, verify all combatants removed and counters reset to round 1 / index 0. Refresh the page and verify empty state persists.
### Tests for User Story 1
- [x] T004 [P] [US1] Write domain tests for `clearEncounter` in `packages/domain/src/__tests__/clear-encounter.test.ts` — cover: (1) clearing encounter with multiple combatants at round 3 returns empty encounter with roundNumber 1 and activeIndex 0, (2) clearing encounter with single combatant works, (3) clearing encounter with combatants that have HP/AC/conditions/concentration removes all data, (4) clearing already-empty encounter returns DomainError with code `"encounter-already-empty"`, (5) emits `EncounterCleared` event with correct `combatantCount`, (6) determinism — same input always produces same output
### Implementation for User Story 1
- [x] T005 [P] [US1] Create `clearEncounterUseCase` in `packages/application/src/clear-encounter-use-case.ts` — follow the pattern in `remove-combatant-use-case.ts`: get encounter from store, call `clearEncounter`, check for `DomainError`, save result, return events
- [x] T006 [US1] Export `clearEncounterUseCase` from `packages/application/src/index.ts`
- [x] T007 [US1] Update `loadEncounter` in `apps/web/src/persistence/encounter-storage.ts` to handle empty combatant arrays — when `combatants` is a valid empty array, return `{ combatants: [], activeIndex: 0, roundNumber: 1 }` directly instead of routing through `createEncounter()` (which rejects empty arrays)
- [x] T008 [US1] Add `clearEncounter` callback to `useEncounter` hook in `apps/web/src/hooks/use-encounter.ts` — call `clearEncounterUseCase(makeStore())`, check for `DomainError`, update events. Also reset `nextId.current` to 0 after clearing. Return `clearEncounter` from the hook
- [x] T009 [P] [US1] Add `onClearEncounter` prop and clear button (using Trash2 icon from Lucide) to the `TurnNavigation` component in `apps/web/src/components/turn-navigation.tsx` — place it near the round/turn controls, use `variant="ghost"` and `size="icon"` styling consistent with existing buttons
- [x] T010 [US1] Wire `clearEncounter` from `useEncounter` hook to `TurnNavigation` as `onClearEncounter` prop in `apps/web/src/App.tsx`
**Checkpoint**: User Story 1 is fully functional — clearing works end-to-end and persists across refreshes
---
## Phase 3: User Story 2 — Confirmation Before Clearing (Priority: P1)
**Goal**: Users are prompted for confirmation before the encounter is cleared, preventing accidental data loss. The clear button is disabled when there are no combatants.
**Independent Test**: Click the clear button, verify a confirmation prompt appears, cancel and verify encounter unchanged, confirm and verify encounter cleared. Verify the button is disabled when the encounter is already empty.
### Implementation for User Story 2
- [x] T011 [US2] Add `window.confirm("Clear the entire encounter? This cannot be undone.")` gate before executing `clearEncounterUseCase` in the `clearEncounter` callback in `apps/web/src/hooks/use-encounter.ts` — if user cancels, return early without modifying state (FR-006)
- [x] T012 [US2] Disable the clear encounter button when `encounter.combatants.length === 0` in `apps/web/src/components/turn-navigation.tsx` — pass combatant count or a `disabled` flag via props (FR-008)
**Checkpoint**: User Story 2 complete — accidental clears are prevented, button disabled when empty
---
## Phase 4: Polish & Cross-Cutting Concerns
**Purpose**: Verify all checks pass and feature is merge-ready
- [x] T013 Run `pnpm check` (knip + format + lint + typecheck + test) to verify merge gate passes
---
## Dependencies & Execution Order
### Phase Dependencies
- **Foundational (Phase 1)**: No dependencies — can start immediately
- **User Story 1 (Phase 2)**: Depends on Phase 1 completion
- **User Story 2 (Phase 3)**: Depends on Phase 2 completion (US2 modifies files created/modified in US1)
- **Polish (Phase 4)**: Depends on all phases complete
### User Story Dependencies
- **User Story 1 (P1)**: Can start after Foundational — no dependencies on other stories
- **User Story 2 (P1)**: Depends on User Story 1 — adds confirmation gate to the clearEncounter callback and disabled state to the button created in US1
### Within Each Phase
- Tasks marked [P] can run in parallel (different files)
- Sequential tasks depend on prior tasks in the same phase
### Parallel Opportunities
- **Phase 1**: T001 must complete before T002 (T002 imports EncounterCleared). T003 depends on both.
- **Phase 2**: T004 (tests) and T005 (use case) can run in parallel [P]. T009 (UI) can run in parallel with T005T008 [P]. T010 depends on T008 and T009.
- **Phase 3**: T011 and T012 modify different files but T012 depends on the prop interface from T009, so they should run sequentially.
---
## Parallel Example: User Story 1
```bash
# After Phase 1 completes, launch in parallel:
Task T004: "Write domain tests in packages/domain/src/__tests__/clear-encounter.test.ts"
Task T005: "Create clearEncounterUseCase in packages/application/src/clear-encounter-use-case.ts"
Task T009: "Add clear button to apps/web/src/components/turn-navigation.tsx"
# Then sequentially:
Task T006: "Export use case from packages/application/src/index.ts"
Task T007: "Update loadEncounter in apps/web/src/persistence/encounter-storage.ts"
Task T008: "Add clearEncounter to apps/web/src/hooks/use-encounter.ts"
Task T010: "Wire clearEncounter in apps/web/src/App.tsx"
```
---
## Implementation Strategy
### MVP First (User Story 1 Only)
1. Complete Phase 1: Foundational (T001T003)
2. Complete Phase 2: User Story 1 (T004T010)
3. **STOP and VALIDATE**: Test clearing end-to-end, verify persistence
4. Feature is usable at this point (clearing works, just no confirmation gate)
### Full Delivery
1. Complete Phases 12 → Clear encounter works
2. Complete Phase 3 → Confirmation prevents accidental clears
3. Complete Phase 4 → Merge gate verified
4. Feature is complete and merge-ready
---
## Notes
- [P] tasks = different files, no dependencies
- [Story] label maps task to specific user story for traceability
- US2 is intentionally sequenced after US1 because it modifies the same files (hook, component)
- The `window.confirm()` approach keeps the domain pure — confirmation logic stays in the adapter layer
- Commit after each phase for clean git history