129 lines
6.7 KiB
Markdown
129 lines
6.7 KiB
Markdown
# Tasks: Advance Turn
|
||
|
||
**Input**: Design documents from `/specs/001-advance-turn/`
|
||
**Prerequisites**: plan.md (required), spec.md (required)
|
||
|
||
**Organization**: Tasks follow the phased structure from plan.md. There is only one user story (US1 — Advance Turn, P1), so phases map directly to the plan's milestones.
|
||
|
||
## Format: `[ID] [P?] [Story?] Description`
|
||
|
||
- **[P]**: Can run in parallel (different files, no dependencies)
|
||
- **[US1]**: User Story 1 — Advance Turn
|
||
- Exact file paths included in every task
|
||
|
||
---
|
||
|
||
## Phase 1: Setup (Milestone 1 — Tooling)
|
||
|
||
**Purpose**: Initialize pnpm monorepo, Biome, TypeScript, Vitest, and layer boundary enforcement
|
||
|
||
- [X] T001 Initialize pnpm workspace and root config — create `pnpm-workspace.yaml`, `.nvmrc` (Node 22), root `package.json` (with `packageManager` pinning pnpm 10.6 and scripts: check, test, lint, format, typecheck), `biome.json`, and `tsconfig.base.json` (strict, composite, path aliases)
|
||
- [X] T002 [P] Create `packages/domain` package skeleton — `packages/domain/package.json` (`@initiative/domain`, no deps), `packages/domain/tsconfig.json` (extends base, composite), empty `packages/domain/src/index.ts`
|
||
- [X] T003 [P] Create `packages/application` package skeleton — `packages/application/package.json` (`@initiative/application`, depends on `@initiative/domain`), `packages/application/tsconfig.json` (extends base, references domain), empty `packages/application/src/index.ts`
|
||
- [X] T004 [P] Create `apps/web` package skeleton — `apps/web/package.json` (React 19, Vite 6.2, depends on both packages), `apps/web/tsconfig.json`, `apps/web/vite.config.ts`, `apps/web/index.html`, `apps/web/src/main.tsx`, `apps/web/src/App.tsx` (placeholder)
|
||
- [X] T005 Configure Vitest — add `vitest` as root dev dependency, create `vitest.config.ts` at root (workspace mode or per-package), verify `pnpm test` exits 0
|
||
- [X] T006 Create layer boundary check — `scripts/check-layer-boundaries.mjs` (scans domain/application for forbidden imports) and `packages/domain/src/__tests__/layer-boundaries.test.ts` (wraps script as Vitest test)
|
||
|
||
**Checkpoint**: `pnpm install` succeeds, `biome check .` runs, `tsc --build` compiles, `pnpm test` exits 0 with layer boundary test green.
|
||
|
||
---
|
||
|
||
## Phase 2: Domain Implementation — User Story 1: Advance Turn (Priority: P1) (Milestone 1)
|
||
|
||
**Goal**: Implement the complete AdvanceTurn domain logic as a pure function with all 8 acceptance scenarios and invariant tests.
|
||
|
||
**Independent Test**: Pure state transition — given an Encounter value and AdvanceTurn action, assert resulting Encounter and emitted domain events. No I/O, persistence, or UI needed.
|
||
|
||
- [X] T007 [US1] Define domain types in `packages/domain/src/types.ts` — `CombatantId` (branded/opaque), `Combatant`, `Encounter` (combatants, activeIndex, roundNumber), factory `createEncounter` enforcing INV-1, INV-2, INV-3
|
||
- [X] T008 [P] [US1] Define domain events in `packages/domain/src/events.ts` — `TurnAdvanced`, `RoundAdvanced`, `DomainEvent` union (plain data, no classes)
|
||
- [X] T009 [US1] Implement `advanceTurn` in `packages/domain/src/advance-turn.ts` — pure function `(Encounter) => { encounter, events } | DomainError`, implements FR-001 through FR-005
|
||
- [X] T010 [US1] Write tests for all 8 acceptance scenarios + invariants in `packages/domain/src/__tests__/advance-turn.test.ts` — scenarios 1–8, INV-1 through INV-5, event ordering on round wrap
|
||
- [X] T011 [US1] Export public API from `packages/domain/src/index.ts` — re-export types, events, `advanceTurn`, `createEncounter`
|
||
|
||
**Checkpoint (Milestone 1)**: `pnpm check` passes (format + lint + typecheck + test + layer boundaries). All 8 scenarios + invariants green. No React/Vite imports in domain or application.
|
||
|
||
---
|
||
|
||
## Phase 3: Application + Web Shell (Milestone 2)
|
||
|
||
**Goal**: Wire up the application use case and minimal React UI with a "Next Turn" button.
|
||
|
||
- [X] T012 Define port interface in `packages/application/src/ports.ts` — `EncounterStore` port: `get(): Encounter`, `save(e: Encounter)`
|
||
- [X] T013 Implement `AdvanceTurnUseCase` in `packages/application/src/advance-turn-use-case.ts` — accepts `EncounterStore`, calls `advanceTurn`, saves result, returns events
|
||
- [X] T014 Export public API from `packages/application/src/index.ts` — re-export use case and port types
|
||
- [X] T015 Implement `useEncounter` hook in `apps/web/src/hooks/use-encounter.ts` — in-memory `EncounterStore` via React state, exposes encounter state + `advanceTurn` action, hardcoded 3-combatant demo
|
||
- [X] T016 Wire up `apps/web/src/App.tsx` — display current combatant, round number, combatant list with active indicator, "Next Turn" button, emitted events
|
||
|
||
**Checkpoint (Milestone 2)**: `pnpm check` passes. `vite build` succeeds. Clicking "Next Turn" cycles combatants and increments rounds correctly.
|
||
|
||
---
|
||
|
||
## Dependencies & Execution Order
|
||
|
||
### Phase Dependencies
|
||
|
||
- **Phase 1 (Setup)**: No dependencies — start immediately
|
||
- **Phase 2 (Domain)**: Depends on Phase 1 completion
|
||
- **Phase 3 (App + Web)**: Depends on Phase 2 completion (needs domain types and `advanceTurn`)
|
||
|
||
### Within Phase 1
|
||
|
||
- T001 must complete first (workspace and root config)
|
||
- T002, T003, T004 can run in parallel [P] after T001
|
||
- T005 depends on T001 (needs root package.json)
|
||
- T006 depends on T002 and T005 (needs domain package + Vitest)
|
||
|
||
### Within Phase 2
|
||
|
||
- T007 must complete first (types needed by everything)
|
||
- T008 can run in parallel [P] with T007 (events are independent types)
|
||
- T009 depends on T007 and T008 (uses types and events)
|
||
- T010 depends on T009 (tests the implementation)
|
||
- T011 depends on T007, T008, T009 (exports all public API)
|
||
|
||
### Within Phase 3
|
||
|
||
- T012 first (port interface)
|
||
- T013 depends on T012 (uses port)
|
||
- T014 depends on T013 (exports use case)
|
||
- T015 depends on T014 (uses application layer)
|
||
- T016 depends on T015 (uses hook)
|
||
|
||
---
|
||
|
||
## Parallel Opportunities
|
||
|
||
```text
|
||
# After T001 completes:
|
||
T002, T003, T004 — all package skeletons in parallel
|
||
|
||
# After T007 starts:
|
||
T008 — domain events can be written in parallel with types
|
||
|
||
# Independent stories: only one user story (US1), so parallelism is within-phase only
|
||
```
|
||
|
||
---
|
||
|
||
## Implementation Strategy
|
||
|
||
### MVP First (Milestone 1)
|
||
|
||
1. Complete Phase 1: Setup (T001–T006)
|
||
2. Complete Phase 2: Domain (T007–T011)
|
||
3. **STOP and VALIDATE**: `pnpm check` passes, all 8 scenarios green
|
||
|
||
### Full Feature (Milestone 2)
|
||
|
||
4. Complete Phase 3: App + Web Shell (T012–T016)
|
||
5. **VALIDATE**: `pnpm check` passes, app runs in browser
|
||
|
||
---
|
||
|
||
## Notes
|
||
|
||
- All task IDs (T001–T016) match plan.md — no scope expansion
|
||
- Single user story (US1: Advance Turn) — no cross-story dependencies
|
||
- Tests (T010) are included as specified in plan.md and spec.md
|
||
- Domain package must have zero React/Vite imports (enforced by T006)
|