Files
initiative/specs/017-combat-conditions/plan.md

81 lines
4.0 KiB
Markdown

# Implementation Plan: Combat Conditions
**Branch**: `017-combat-conditions` | **Date**: 2026-03-06 | **Spec**: [spec.md](./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)
```text
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)
```text
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.