2.5 KiB
2.5 KiB
Quickstart: Combatant Armor Class Display
Feature: 016-combatant-ac | Date: 2026-03-06
Overview
This feature adds an optional Armor Class (AC) field to combatants, displayed as a shield icon with the numeric value in the encounter list. It follows the exact patterns established by initiative and HP fields.
Layer-by-Layer Implementation Order
1. Domain Layer (packages/domain/src/)
Pattern to follow: set-initiative.ts (single optional numeric field)
- Add
readonly ac?: numbertoCombatantinterface intypes.ts - Create
set-ac.tswith asetAcpure function:- Find combatant by ID (error if not found)
- Validate AC is non-negative integer when defined
- Return updated encounter +
AcSetevent
- Add
AcSetevent toevents.tsand theDomainEventunion - Export from
index.ts - Write tests in
__tests__/set-ac.test.ts
2. Application Layer (packages/application/src/)
Pattern to follow: set-initiative-use-case.ts
- Create
set-ac-use-case.ts: get encounter from store, callsetAc, save result - Export from
index.ts
3. Web Layer (apps/web/src/)
Pattern to follow: Initiative input in combatant-row.tsx + MaxHpInput editing pattern
- Persistence (
persistence/encounter-storage.ts): Add AC validation in rehydration logic - Hook (
hooks/use-encounter.ts): AddsetAccallback usingsetAcUseCase - UI (
components/combatant-row.tsx):- Add
onSetActoCombatantRowProps - Add AC display: Lucide
Shieldicon + value, between name and HP - Inline editable input (same pattern as
MaxHpInput) - Hidden when AC is
undefined
- Add
Key Files to Read First
| File | Why |
|---|---|
packages/domain/src/set-initiative.ts |
Closest pattern for single optional field |
packages/domain/src/events.ts |
Event type definitions |
apps/web/src/components/combatant-row.tsx |
UI layout and inline input patterns |
apps/web/src/persistence/encounter-storage.ts |
Rehydration validation pattern |
Testing Strategy
- Domain: Pure function tests for
setAc(set, clear, validation errors, combatant not found) - Persistence: Round-trip test for AC field in localStorage
- No UI tests: Consistent with existing approach (no component tests in codebase)
Commands
pnpm test # Run all tests
pnpm vitest run packages/domain/src/__tests__/set-ac.test.ts # Run AC domain tests
pnpm check # Full merge gate (must pass before commit)