4.0 KiB
Implementation Plan: Combat Conditions
Branch: 017-combat-conditions | Date: 2026-03-06 | Spec: spec.md
Input: Feature specification from /specs/017-combat-conditions/spec.md
Summary
Add a conditions field to the domain Combatant type representing a set of active D&D 5e status conditions (blinded, charmed, etc.). A single toggleCondition domain operation manages the set with immutable state transitions (adds if absent, removes if present). The web layer renders conditions as compact Lucide icon tags with color coding below the combatant name, with a "+" button opening a popover picker for toggling conditions on/off.
Technical Context
Language/Version: TypeScript 5.8 (strict mode, verbatimModuleSyntax) Primary Dependencies: React 19, Vite 6, Tailwind CSS v4, Lucide React (icons) Storage: Browser localStorage (existing adapter, transparent JSON serialization) Testing: Vitest Target Platform: Browser (single-user, local-first) Project Type: Web application (monorepo with domain/application/web layers) Performance Goals: N/A (single-user local app, no performance-critical paths) Constraints: Conditions are visual tracking only; no mechanical effects in MVP Scale/Scope: 15 fixed conditions per the D&D 5e SRD
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
| Principle | Status | Notes |
|---|---|---|
| I. Deterministic Domain Core | PASS | toggleCondition is a pure function; condition registry is static data |
| II. Layered Architecture | PASS | Domain defines condition types and operations; Application orchestrates via use cases; Web renders UI |
| III. Agent Boundary | N/A | No agent layer involvement |
| IV. Clarification-First | PASS | Two clarifications resolved (display order, "+" button visibility) |
| V. Escalation Gates | PASS | Spec complete and clarified before planning |
| VI. MVP Baseline Language | PASS | FR-001 uses "MVP MUST support" language; homebrew conditions explicitly deferred |
| VII. No Gameplay Rules | PASS | Constitution contains no condition mechanics; spec handles that |
Project Structure
Documentation (this feature)
specs/017-combat-conditions/
├── plan.md # This file
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output
├── quickstart.md # Phase 1 output
└── tasks.md # Phase 2 output (created by /speckit.tasks)
Source Code (repository root)
packages/domain/src/
├── types.ts # Add conditions field to Combatant
├── conditions.ts # NEW: ConditionId type, CONDITION_DEFINITIONS registry, ordering
├── toggle-condition.ts # NEW: toggleCondition domain operation (adds if absent, removes if present)
├── events.ts # Add ConditionAdded, ConditionRemoved events
├── index.ts # Re-export new symbols
└── __tests__/
└── toggle-condition.test.ts # NEW
packages/application/src/
├── toggle-condition-use-case.ts # NEW
└── index.ts # Re-export new use case
apps/web/src/
├── components/
│ ├── combatant-row.tsx # Add conditions area below name
│ ├── condition-tags.tsx # NEW: renders active condition icon tags + "+" button
│ └── condition-picker.tsx # NEW: popover picker for toggling conditions
├── hooks/
│ └── use-encounter.ts # Add toggleCondition callback
└── persistence/
└── encounter-storage.ts # Add conditions rehydration validation
Structure Decision: Follows existing monorepo structure with domain/application/web layers. New domain files mirror the set-ac.ts pattern. UI components split into condition-tags (display) and condition-picker (interaction) for clarity.
Complexity Tracking
No violations. No entries needed.