Implement the 017-combat-conditions feature that adds D&D 5e status conditions to combatants with icon tags, color coding, and a compact toggle picker in the encounter tracker
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
88
specs/017-combat-conditions/data-model.md
Normal file
88
specs/017-combat-conditions/data-model.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Data Model: Combat Conditions
|
||||
|
||||
## Entities
|
||||
|
||||
### ConditionId (new type)
|
||||
|
||||
String literal union representing the 15 valid condition identifiers.
|
||||
|
||||
```
|
||||
"blinded" | "charmed" | "deafened" | "exhaustion" | "frightened" |
|
||||
"grappled" | "incapacitated" | "invisible" | "paralyzed" | "petrified" |
|
||||
"poisoned" | "prone" | "restrained" | "stunned" | "unconscious"
|
||||
```
|
||||
|
||||
- Order of literals in the union defines the canonical display order (FR-003).
|
||||
- Extensible: future conditions can be added to the union.
|
||||
|
||||
### ConditionDefinition (new type)
|
||||
|
||||
Static metadata for each condition.
|
||||
|
||||
| Field | Type | Description |
|
||||
| --------- | ----------- | ------------------------------------------------ |
|
||||
| id | ConditionId | Unique identifier |
|
||||
| label | string | Human-readable display name (e.g., "Blinded") |
|
||||
| iconName | string | Lucide icon component name (e.g., "EyeOff") |
|
||||
| color | string | Color category (e.g., "neutral", "pink", "amber") |
|
||||
|
||||
- Registry: `CONDITION_DEFINITIONS` — a static readonly array of all 15 definitions, ordered by display priority.
|
||||
- No lifecycle/state transitions — definitions are immutable reference data.
|
||||
|
||||
### Combatant (modified)
|
||||
|
||||
| Field | Type | Change |
|
||||
| ---------- | ----------------------------- | -------- |
|
||||
| id | CombatantId | existing |
|
||||
| name | string | existing |
|
||||
| initiative | number \| undefined | existing |
|
||||
| maxHp | number \| undefined | existing |
|
||||
| currentHp | number \| undefined | existing |
|
||||
| ac | number \| undefined | existing |
|
||||
| conditions | readonly ConditionId[] \| undefined | **new** |
|
||||
|
||||
- `conditions` is optional; `undefined` means no conditions active.
|
||||
- When present, the array contains unique `ConditionId` values sorted in definition order.
|
||||
- Maximum cardinality: 15 (one of each condition).
|
||||
|
||||
## Relationships
|
||||
|
||||
```
|
||||
Encounter 1──* Combatant
|
||||
Combatant 0──* ConditionId (from CONDITION_DEFINITIONS registry)
|
||||
```
|
||||
|
||||
## Validation Rules
|
||||
|
||||
- A condition can appear at most once per combatant.
|
||||
- Only valid `ConditionId` values are accepted (unknown strings rejected).
|
||||
- The conditions array is always sorted in definition order after any mutation.
|
||||
- An empty conditions array is normalized to `undefined`.
|
||||
|
||||
## Domain Events
|
||||
|
||||
### ConditionAdded
|
||||
|
||||
| Field | Type |
|
||||
| ----------- | ----------- |
|
||||
| type | "ConditionAdded" |
|
||||
| combatantId | CombatantId |
|
||||
| condition | ConditionId |
|
||||
|
||||
Emitted when a condition is toggled on or explicitly added.
|
||||
|
||||
### ConditionRemoved
|
||||
|
||||
| Field | Type |
|
||||
| ----------- | ----------- |
|
||||
| type | "ConditionRemoved" |
|
||||
| combatantId | CombatantId |
|
||||
| condition | ConditionId |
|
||||
|
||||
Emitted when a condition is toggled off (via picker or tag click).
|
||||
|
||||
## Persistence
|
||||
|
||||
- Serialization: `conditions` array serializes to JSON as `["blinded", "poisoned"]`.
|
||||
- Deserialization: Filter stored values through the `ConditionId` set; discard unknown strings. If resulting array is empty, set to `undefined`.
|
||||
- No schema migration required (field is optional with `undefined` default).
|
||||
Reference in New Issue
Block a user