T001–T006: Phase 1 setup (workspace, Biome, TS, Vitest, layer boundary enforcement)
This commit is contained in:
128
specs/001-advance-turn/tasks.md
Normal file
128
specs/001-advance-turn/tasks.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# 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.
|
||||
|
||||
- [ ] 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
|
||||
- [ ] T008 [P] [US1] Define domain events in `packages/domain/src/events.ts` — `TurnAdvanced`, `RoundAdvanced`, `DomainEvent` union (plain data, no classes)
|
||||
- [ ] T009 [US1] Implement `advanceTurn` in `packages/domain/src/advance-turn.ts` — pure function `(Encounter) => { encounter, events } | DomainError`, implements FR-001 through FR-005
|
||||
- [ ] 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
|
||||
- [ ] 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.
|
||||
|
||||
- [ ] T012 Define port interface in `packages/application/src/ports.ts` — `EncounterStore` port: `get(): Encounter`, `save(e: Encounter)`
|
||||
- [ ] T013 Implement `AdvanceTurnUseCase` in `packages/application/src/advance-turn-use-case.ts` — accepts `EncounterStore`, calls `advanceTurn`, saves result, returns events
|
||||
- [ ] T014 Export public API from `packages/application/src/index.ts` — re-export use case and port types
|
||||
- [ ] 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
|
||||
- [ ] 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)
|
||||
Reference in New Issue
Block a user