Implement the 012-turn-navigation feature that adds a RetreatTurn domain operation and relocates turn controls to a navigation bar at the top of the encounter tracker

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-05 23:11:11 +01:00
parent a0d85a07e3
commit 7d440677be
19 changed files with 946 additions and 13 deletions

View File

@@ -0,0 +1,153 @@
# Tasks: Turn Navigation
**Input**: Design documents from `/specs/012-turn-navigation/`
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/
**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, US3)
- Include exact file paths in descriptions
---
## Phase 1: Setup (Shared Infrastructure)
**Purpose**: No new project setup needed -- existing monorepo structure is in place. This phase is empty.
**Checkpoint**: Existing infrastructure is sufficient. Proceed directly to foundational work.
---
## Phase 2: Foundational (Blocking Prerequisites)
**Purpose**: Add new domain event types. These are shared by US1 (domain logic) and US2/US3 (UI).
**CRITICAL**: No user story work can begin until this phase is complete.
- [x] T001 Add TurnRetreated and RoundRetreated event interfaces to the DomainEvent union in `packages/domain/src/events.ts`
**Checkpoint**: Foundation ready -- event types defined, user story implementation can begin.
---
## Phase 3: User Story 1 - Go Back to the Previous Turn (Priority: P1) MVP
**Goal**: Implement the RetreatTurn pure domain function and its application use case so that turns can be reversed programmatically.
**Independent Test**: Call retreatTurn with various encounter states and verify correct activeIndex, roundNumber, and emitted events. All tests are pure-function assertions with no I/O.
### Implementation for User Story 1
- [x] T003 [US1] Create retreatTurn pure function in `packages/domain/src/retreat-turn.ts` implementing: decrement activeIndex, wrap to last combatant on round boundary, decrement roundNumber on wrap, error on empty encounter, error on round 1 index 0
- [x] T004 [US1] Write acceptance scenario tests for retreatTurn in `packages/domain/src/__tests__/retreat-turn.test.ts` covering all 5 spec scenarios: mid-round retreat, round-boundary retreat, start-of-encounter error, single-combatant retreat, empty-encounter error
- [x] T005 [US1] Re-export retreatTurn from domain index in `packages/domain/src/index.ts`
- [x] T006 [US1] Create retreatTurnUseCase in `packages/application/src/retreat-turn-use-case.ts` following the advanceTurnUseCase pattern (get encounter from store, call retreatTurn, save result or return error)
- [x] T007 [US1] Export retreatTurnUseCase from application index in `packages/application/src/index.ts`
- [x] T008 [US1] Run `pnpm check` to verify all tests pass, types check, and no lint/format issues
**Checkpoint**: RetreatTurn domain logic is fully functional and tested. UI work can proceed.
---
## Phase 4: User Story 2 - Turn Navigation Controls at the Top (Priority: P1)
**Goal**: Create a turn navigation bar at the top of the tracker with Previous and Next Turn buttons, relocating Next Turn from the bottom action bar.
**Independent Test**: Load the tracker with combatants, verify Previous/Next buttons appear above the combatant list, click Next to advance, click Previous to retreat, verify disabled states.
### Implementation for User Story 2
- [x] T009 [US2] Add retreatTurn handler to the encounter hook in `apps/web/src/hooks/use-encounter.ts` (mirror the existing advanceTurn handler pattern)
- [x] T010 [US2] Create TurnNavigation component in `apps/web/src/components/turn-navigation.tsx` with Previous/Next buttons, round number display, active combatant name, and disabled states (Previous disabled at round 1 index 0 or no combatants; Next disabled when no combatants)
- [x] T011 [US2] Wire TurnNavigation into App between header and combatant list in `apps/web/src/App.tsx`, passing encounter state, onAdvanceTurn, and onRetreatTurn
- [x] T012 [US2] Remove Next Turn button from ActionBar in `apps/web/src/components/action-bar.tsx` (keep only the Add Combatant form)
**Checkpoint**: Turn navigation is fully functional at the top of the tracker. Previous and Next Turn work correctly with proper disabled states.
---
## Phase 5: User Story 3 - Modern, Sleek Turn Navigation Design (Priority: P2)
**Goal**: Polish the turn navigation bar with clear visual hierarchy, directional icons, and a clean modern design consistent with the existing shadcn/ui-style components.
**Independent Test**: Visually inspect the turn navigation area -- buttons have directional icons, round/combatant info is clearly displayed, disabled state is visually distinct, layout is balanced and clean.
### Implementation for User Story 3
- [x] T014 [US3] Add directional icons (e.g., ChevronLeft, ChevronRight from Lucide React) to the Previous/Next buttons in `apps/web/src/components/turn-navigation.tsx`
- [x] T015 [US3] Style the turn navigation bar with proper spacing, border, background, and visual hierarchy consistent with existing card/action-bar styling in `apps/web/src/components/turn-navigation.tsx`
- [x] T016 [US3] Ensure disabled button state has reduced opacity and no hover effects, visually distinct from active state in `apps/web/src/components/turn-navigation.tsx`
**Checkpoint**: Turn navigation is visually polished with clear directional indicators and modern design.
---
## Phase 6: Polish & Cross-Cutting Concerns
**Purpose**: Final validation across all stories.
- [x] T018 Verify layer boundary compliance -- retreatTurn in domain has no application/adapter imports (covered by existing `layer-boundaries.test.ts`)
- [x] T019 Run full quality gate with `pnpm check` and verify clean pass
- [x] T020 Verify localStorage persistence handles retreat correctly (existing persistence should work transparently since it saves the Encounter state)
---
## Dependencies & Execution Order
### Phase Dependencies
- **Foundational (Phase 2)**: No dependencies -- can start immediately
- **User Story 1 (Phase 3)**: Depends on Phase 2 (event types must exist)
- **User Story 2 (Phase 4)**: Depends on Phase 3 (retreatTurn domain + use case must exist)
- **User Story 3 (Phase 5)**: Depends on Phase 4 (TurnNavigation component must exist to polish)
- **Polish (Phase 6)**: Depends on all user stories being complete
### User Story Dependencies
- **User Story 1 (P1)**: Can start after Foundational (Phase 2) -- pure domain work, no UI dependency
- **User Story 2 (P1)**: Depends on US1 completion -- needs retreatTurn use case to wire into the UI
- **User Story 3 (P2)**: Depends on US2 completion -- polishes the component created in US2
### Within Each User Story
- Domain function before tests (or TDD: tests first, then function)
- Domain before application use case
- Application use case before adapter/UI wiring
- UI component creation before styling polish
### Parallel Opportunities
- T014, T015, T016 can run in parallel (same file but independent style concerns -- may be done in one pass)
---
## Implementation Strategy
### MVP First (User Story 1 Only)
1. Complete Phase 2: Foundational (event types)
2. Complete Phase 3: User Story 1 (retreatTurn domain + tests + use case)
3. **STOP and VALIDATE**: All acceptance scenarios pass as pure-function tests
4. Domain logic is fully verified before any UI work
### Incremental Delivery
1. Phase 2: Foundation -> Event types defined
2. Phase 3: US1 -> RetreatTurn domain logic tested and working (MVP domain!)
3. Phase 4: US2 -> Turn navigation bar at top, Previous/Next buttons functional (MVP UI!)
4. Phase 5: US3 -> Visual polish with icons and consistent styling
5. Phase 6: Polish -> Final cross-cutting validation
---
## Notes
- [P] tasks = different files, no dependencies
- [Story] label maps task to specific user story for traceability
- US2 depends on US1 (needs the domain function); US3 depends on US2 (polishes the component)
- This feature has a linear dependency chain, limiting parallel opportunities
- Commit after each phase checkpoint
- The existing advance-turn pattern (domain -> use case -> hook -> component) serves as the reference implementation for all new code