Domain Data Catalogue
This catalogue documents all domain data types used in the game.
It serves as the authoritative reference for domain concepts, their constraints,
and their GDPR classification.
Governed by the "Use Domain-Specific Data Types" ADR (linked from the project KB).
Identity Types
| Domain Type | Underlying | Constraints | Example |
GameId | UUID | Non-null, immutable | 6c9f1f0e-... |
PlayerId | UUID | Non-null, immutable | a3b2c1d0-... |
QuestionId | UUID | Non-null, immutable | 7d8e9f0a-... |
QuestionSetId | UUID | Non-null, immutable | 1a2b3c4d-... |
Game Types
| Domain Type | Underlying | Constraints | Example |
GameCode | String | Non-blank, format: Word-Word-Word | Blue-Dancing-Horse |
GameState | Enum | One of 7 defined states | PLAYING |
QuestionIndex | int | >= 0, < numberOfQuestions | 3 |
QuestionCount | int | > 0 | 10 |
TimeLimitSeconds | int | > 0 | 60 |
GameState Values
| State | Description |
AUTO_LOBBY | Waiting for players, lobby timer running |
COUNTDOWN | Game starting, countdown active |
PLAYING | Active question, accepting answers |
REVIEWING | Showing answer review for current question |
RESULTS | Showing final rankings |
COOLDOWN | Post-results cooldown |
FINISHED | Game ended |
Player Types
| Domain Type | Underlying | Constraints | GDPR | Example |
PlayerName | String | Non-blank, max 40 chars | Personal | Bob |
PlayerEmail | String | Valid email format | Personal | bob@example.com |
GDPR Notes — Player Data
PlayerName and PlayerEmail are personal data under GDPR
- Must be deletable on request (right to erasure)
- Retention: tied to game lifecycle — delete after game ends or on request
- Purpose: identifying players during gameplay
Question Types
| Domain Type | Underlying | Constraints | Example |
QuestionText | String | Non-blank | How tall is the Empire State Building? |
IsoUnit | String | Non-blank, ISO unit code | m, km, presidents |
RangeMin | double | < RangeMax | 0.0 |
RangeMax | double | > RangeMin | 1000.0 |
CorrectValue | double | Within [RangeMin, RangeMax] | 443.0 |
IllustrationUrl | String | Valid URL or null | https://media.example.com/... |
FasitSource | String | Valid URL | https://en.wikipedia.org/... |
FasitCheckedAt | String | ISO date YYYY-MM-DD | 2024-10-01 |
Answer Types
| Domain Type | Underlying | Constraints | Example |
UserMin | double | < UserMax | 380.0 |
UserMax | double | > UserMin | 450.0 |
Delta | double | Computed: UserMax - UserMin, >= 0 | 70.0 |
SubmittedAt | long | Epoch millis, > 0 | 1700000042000 |
Score & Result Types
| Domain Type | Underlying | Constraints | Example |
Rank | int | >= 1 | 1 |
AverageResponseMs | long | >= 0, milliseconds | 8200 |
Percentage | double | 0.0 to 100.0 | 45.5 |
MedianDelta | double | >= 0 | 95.0 |
Time Types
| Domain Type | Underlying | Constraints | Usage |
EpochMillis | long | > 0 | Game start, countdown end, question start |
DurationMs | long | >= 0 | Time remaining, response times |
DurationSeconds | int | > 0 | Question time limit |
Aggregate Summary
| Aggregate / Entity | Key Types | Mutable |
| Game | GameId, GameCode, GameState, QuestionIndex, QuestionCount, TimeLimitSeconds, EpochMillis | Yes (aggregate root) |
| Player | PlayerId, PlayerName, PlayerEmail, GameCode | No (record) |
| Question | QuestionId, QuestionText, IsoUnit, RangeMin, RangeMax, CorrectValue | No (record) |
| QuestionSet | QuestionSetId, List<Question> | No (record) |
| Answer | QuestionId, PlayerId, UserMin, UserMax, SubmittedAt | No (record) |
| ScoreResult | List<PlayerRanking>, ResponseTimeStat | No (record) |
| AnswerVisualization | QuestionText, CorrectValue, Percentage, List<PlayerRange> | No (record) |
Implementation Notes
- All domain types should be Java records (immutable value objects)
- Validation happens in the record constructor (compact constructor)
- Adapters convert primitives to domain types at the boundary
- Game is the only mutable aggregate — uses SMC state machine for transitions
- Primitives are allowed in private helper methods within the domain layer