Files
hoopscout-v2/docs/adr/0006-initial-domain-model.md

157 lines
7.2 KiB
Markdown

# ADR-0006: Initial Domain Model Baseline
## Status
Accepted
## Context
ADR-0005 defined the scouting search domain semantics and MVP filter realism. Before implementing Django models, HoopScout v2 needs an explicit conceptual domain model baseline that translates those search decisions into stable entities, relationships, and ownership boundaries.
The goal of this ADR is to define an MVP domain model that is predictable, implementation-ready, and extensible without premature schema complexity.
## Decision
### 1. Core MVP entities
The initial MVP conceptual model includes these entities:
- Player
- Competition
- Team
- Season
- PlayerSeason
- PlayerSeasonStats
Entity intent:
- Player: canonical person/athlete identity and durable personal/physical profile.
- Competition: league/tournament context in which team and season participation occurs.
- Team: club/franchise identity with competition association in a given season context.
- Season: time-bounded campaign context (for example 2025-2026).
- PlayerSeason: player participation context for one season, optionally linked to a primary team and competition.
- PlayerSeasonStats: objective statistical snapshot attached to one `PlayerSeason`.
MVP split decision:
- Keep `PlayerSeason` and `PlayerSeasonStats` separate.
- `PlayerSeason` owns participation/classification context.
- `PlayerSeasonStats` owns metric values used for search filters.
### 2. Entity relationships (conceptual)
- One `Player` can have many `PlayerSeason` records.
- One `Season` can have many `PlayerSeason` records.
- One `Team` can have many `PlayerSeason` records.
- One `Competition` can have many `Team` and many `PlayerSeason` records.
- One `PlayerSeason` has zero or one `PlayerSeasonStats` record in MVP.
Stats ownership decision:
- Search statistics conceptually belong to the player-in-season unit (`PlayerSeason`) and are stored in `PlayerSeasonStats`.
- Team and competition are contextual links to that player-season record.
### 3. Position, role, specialty modeling approach
- Position:
- Conceptual type: bounded choice set (enum/choice behavior).
- Cardinality in MVP: single-valued on `PlayerSeason`.
- Ownership: normalized source-aligned value with optional internal correction.
- Role:
- Conceptual type: dedicated taxonomy entity (not a hardcoded enum).
- Cardinality in MVP: many-to-many classification from `PlayerSeason` to role taxonomy.
- Ownership: internal scouting taxonomy, manually curated and extensible.
- Specialty:
- Conceptual type: tag-like taxonomy entity.
- Cardinality in MVP: many-to-many classification from `PlayerSeason` to specialty taxonomy.
- Ownership: internal scouting tag vocabulary, multi-valued and extensible.
Rationale:
- Position is stable and bounded; role and specialty are interpretive and expected to evolve.
### 4. Imported vs internal vs inferred boundary
- Imported source data (objective):
- Height, weight, date of birth (source attributes)
- Per-game stats: points, assists, steals, turnovers, blocks
- Advanced metrics when provided by source: eFG%, TS%, plus/minus, offensive rating, defensive rating
- Position when supplied by source (subject to normalization)
- Inferred/derived data:
- Age (derived from date of birth and reference date)
- eFG% and TS% when computed from source totals
- Optional role suggestions generated from rules/models (if introduced later)
- Internal/manual scouting enrichment:
- Role assignments
- Specialty tags
- Position overrides when source labels are inconsistent
- Wingspan when collected manually due to sparse public coverage
Hybrid note:
- Position remains hybrid (source-derived baseline plus internal override path).
### 5. Optional-data handling
Domain-level required vs optional in MVP:
- Required for MVP search baseline:
- Position (normalized single value)
- Age (derived, if DOB available)
- Height, weight (if available from source; model permits null when missing)
- Core per-game stats (points, assists, steals, turnovers, blocks)
- Optional in MVP domain:
- Wingspan
- Role classifications
- Specialty classifications
- Plus/minus, offensive rating, defensive rating
- Any personal/physical field missing from public source coverage
Optionality rule:
- Missing optional fields must not block player ingestion or baseline search eligibility.
### 6. MVP scope discipline (intentionally excluded now)
The initial domain model intentionally excludes:
- manual scouting notes/journal objects
- watchlists and shortlist collaboration objects
- player-to-player comparison artifacts
- transfer-history and contract-history modeling
- multi-source provenance graph complexity beyond basic source attribution needs
- versioned taxonomy governance workflows
### 7. Implementation guidance for future prompts
Future Django model implementation prompts should assume:
- First model wave: `Player`, `Competition`, `Team`, `Season`, `PlayerSeason`, `PlayerSeasonStats`, plus taxonomy models for role and specialty.
- Keep MVP simple: one primary stats record per player-season context.
- Position remains a bounded choice; role and specialty must be extensible taxonomies.
- Role and specialty fields are optional and many-to-many from player-season context.
- Objective/imported metrics and internal scouting classifications remain semantically separate in naming and model structure.
- Domain-level optional fields must be nullable/omissible without breaking ingestion flows.
## Alternatives considered
### A. Single flat Player model with season/stat columns
Rejected. It mixes durable identity with seasonal context and creates update ambiguity.
### B. Attach stats directly to PlayerSeason without a separate stats entity
Rejected for MVP baseline. Keeping a dedicated `PlayerSeasonStats` concept preserves a clean boundary between participation context and metric payload.
### C. Model role and specialty as fixed enums
Rejected. These are internal scouting taxonomies expected to evolve and require extensibility.
### D. Require wingspan, role, and specialty at ingest time
Rejected due to high data-availability risk and poor MVP practicality.
## Trade-offs
- Pros: clear context boundaries, predictable first implementation pass, extensible scouting taxonomies, realistic handling of missing public data.
- Cons: introduces more entities than a flat schema and defers richer provenance/taxonomy governance details to later ADRs.
## Consequences
- Future model implementation can proceed without re-deciding core entity boundaries.
- Search/filter implementation can rely on player-season as the primary statistical context.
- Internal scouting enrichment can evolve independently from imported objective stats.
- Additional complexity (notes, watchlists, provenance depth) remains available for later incremental decisions.
## Follow-up decisions needed
1. Exact uniqueness constraints for `PlayerSeason` identity (player + season + team + competition semantics).
2. Minimal provenance metadata required on imported records in MVP.
3. Normalization standards for team/competition naming and cross-source identity mapping.
4. Taxonomy governance policy for role/specialty lifecycle changes.
5. Rules for handling mid-season team changes in MVP vs post-MVP.
6. Whether advanced metrics should be persisted, computed on read, or both.