mitai-jinkendo/.claude/docs/technical/functional_concept_composite_data.md
Lars fa3e66fb31
All checks were successful
Deploy Development / deploy (push) Successful in 51s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 18s
feat: Update activity documentation and enhance API responses with session metrics
- Added new updates for Phase A and Phase B in `CLAUDE.md`, detailing the completion of Phase A and the introduction of enriched session metrics in the API response for `GET /api/activity`.
- Enhanced the README to include references to new documentation files for scalar canon and composite metrics implementation.
- Updated `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` to reflect the current status of phases and added navigation rules for data access.
- Improved `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md` with links to new implementation concepts for composite metrics.
- Refactored the activity router to integrate enriched session metrics into the activity list responses, ensuring a more comprehensive data presentation.
2026-04-17 12:55:12 +02:00

1480 lines
30 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Konzeptpapier: Speicherung und Bereitstellung von Scalar- und Composite-Sportdaten
## Status
Arbeitsstand auf Basis der fachlichen und architektonischen Diskussion.
Dieses Dokument dient als Rahmenwerk für einen Coding Agent und beschreibt die Zielarchitektur, die Abgrenzung der Schichten sowie die empfohlene technische Struktur für Scalar- und Composite-Werte.
---
## 1. Ziel und Einordnung
Das System soll zu beliebigen Sportarten Daten speichern und für unterschiedliche nachgelagerte Zwecke bereitstellen, insbesondere:
- Diagramme
- Kennzahlen
- Scores
- regelbasierte Bewertungen
- KI-Platzhalter und KI-Kontextdaten
Das System ist bereits mehrschichtig aufgebaut. Diese Schichtung ist fachlich und technisch sinnvoll und soll ausdrücklich erhalten bleiben.
### Bestehende Schichten
- **Persistenz / Datenbank**
- reiner Wertespeicher
- Speicherung von Scalars und Composites
- **Layer 1**
- Lesen der Daten
- technische Aufbereitung
- minimale Normalisierung
- Validierung
- **Layer 2a**
- fachliche Aufbereitung für Diagramme, Kennzahlen, Regeln, Auswertungen
- **Layer 2b**
- fachliche Aufbereitung für KI-Platzhalter, KI-Zusammenfassungen, KI-Argumente
### Zentrale Erkenntnis
Die Persistenz darf **nicht** mit fachlichen Interpretationen aus Layer 2 überladen werden.
Das bedeutet konkret:
- Die Datenbank speichert **Fakten und strukturierte Werte**
- Layer 1 stellt **kanonische, technische Leseobjekte** bereit
- Layer 2 erzeugt daraus **fachliche Bedeutung**
---
## 2. Problemstellung
Bisher werden überwiegend **Scalar-Werte** gespeichert:
- Datentyp
- Ausprägung (`value`)
- Einheit
Nun sollen zusätzlich **Composite-Werte** gespeichert werden.
Aktuell ist der gewünschte Ansatz:
- derselbe Value Store
- `datatype = composite`
- `value = jsonb`
Die Herausforderung besteht darin, Composite-Werte so einzuführen, dass:
1. die Architektur einfach bleibt
2. die Schichtentrennung nicht verletzt wird
3. das System sportartenübergreifend nutzbar bleibt
4. spätere Auswertungslogik nicht bereits in die Persistenz gepresst wird
5. die Lösung für Diagramme, Kennzahlen und KI gleichermaßen nutzbar ist
---
## 3. Architektonische Leitentscheidung
### 3.1 Grundsatz
**Composite-Werte werden als strukturierte Fakten gespeichert, nicht als fachlich fertig interpretierte Analyseobjekte.**
Das bedeutet:
- Die Datenbank kennt nur wenige **technische Composite-Container**
- Fachliche Archetypen entstehen erst in Layer 2
- Layer 1 vermittelt zwischen Persistenz und fachlicher Verarbeitung
### 3.2 Was bewusst vermieden wird
Nicht in die Persistenz gehören als Teil des Basis-Composite:
- Scores
- fachliche Bewertungen
- Trainingsqualitätsurteile
- KI-Texte
- narrative Einordnungen
- Interpretationen wie „intervallartig“, „polarisiert“, „gut regeneriert“
- abgeleitete Kennzahlen wie `switch_rate`, `transition_entropy`, `readiness_index`, `plan_match_score`
Diese Dinge sind **sekundäre Ableitungen** und gehören in Layer 2.
---
## 4. Fachliche Kernaussage des Konzepts
Die frühere Diskussion über viele fachliche Composite-Archetypen war fachlich sinnvoll, aber für die Persistenz zu komplex.
Deshalb wird das Modell in zwei Ebenen getrennt:
### Ebene A: technische Speicherformen
Diese werden in der Datenbank als `jsonb` gespeichert.
### Ebene B: fachliche Analyse-Archetypen
Diese werden in Layer 2 aus den technischen Speicherformen abgeleitet.
Damit gilt:
- **wenige Speicherformen**
- **viele fachliche Projektionen**
Das ist die zentrale Designentscheidung dieses Dokuments.
---
## 5. Zielbild
### 5.1 Persistenzebene
Einheitlicher Value Store für:
- Scalars
- Composites
#### Scalar
- `datatype != composite`
- `value` ist scalar
- `unit` als separate Spalte oder Feld
#### Composite
- `datatype = composite`
- `value` ist `jsonb`
- `jsonb` folgt einem kleinen, stabilen Basisschema
### 5.2 Layer 1
Layer 1 liefert für Composite-Werte:
- validierte Daten
- minimal normalisierte Daten
- kanonische Leseobjekte
- keine fachlichen Scores oder Bewertungen
### 5.3 Layer 2a
Layer 2a erzeugt aus Layer-1-Daten:
- Diagrammserien
- Kennzahlen
- Übergangsmetriken
- Intervallstrukturen
- Auswertungsobjekte
- sportartspezifische Projektionen
### 5.4 Layer 2b
Layer 2b erzeugt aus Layer-1- oder Layer-2a-Daten:
- KI-Platzhalter
- KI-Faktenlisten
- zusammengefasste Trainingsmerkmale
- explizite, strukturierte Aussagen für Prompts
---
## 6. Technische Speicherformen für Composite-Werte
Statt vieler spezieller Composite-Typen werden nur vier technische Container eingeführt:
1. `group_set`
2. `distribution_set`
3. `sequence_set`
4. `model_set`
Diese vier Typen reichen als Speicherebene aus.
---
## 7. Der gemeinsame Basiskern jedes Composite-Objekts
Jedes Composite-JSONB soll auf einem kleinen gemeinsamen Kern basieren.
### 7.1 Basisschema
```json
{
"v": 1,
"kind": "group_set",
"domain": "recovery",
"basis": null,
"items": [],
"meta": {
"source": "reported",
"definition_ref": null,
"quality": null
}
}
```
### 7.2 Pflichtfelder
- `v`
- `kind`
- `domain`
- `items`
### 7.3 Optionale, aber empfohlene Felder
- `basis`
- `meta.source`
- `meta.definition_ref`
- `meta.quality`
### 7.4 Semantik der Felder
#### `v`
Schema-Version des gespeicherten JSON-Objekts.
#### `kind`
Technischer Composite-Container.
Erlaubte Werte:
- `group_set`
- `distribution_set`
- `sequence_set`
- `model_set`
#### `domain`
Fachlicher Bezugsraum der Daten, zum Beispiel:
- `heart_rate`
- `power`
- `speed`
- `recovery`
- `intervals`
- `technique`
- `critical_power`
#### `basis`
Optionale Bezugsgröße, zum Beispiel:
- `time`
- `distance`
- `repetitions`
- `work`
- `count`
- `score`
#### `items`
Liste der eigentlichen Teilwerte oder Segmente.
#### `meta.source`
Ursprung des Composite-Werts, z. B.:
- `reported`
- `imported`
- `detected`
- `derived_l1`
#### `meta.definition_ref`
Referenz auf eine externe oder interne Definition, etwa:
- HF-Zonenmodell
- Power-Zonenmodell
- Intervall-Template
- Testprotokoll
- Schwellenmodell
#### `meta.quality`
Optionale Qualitätskennzeichnung, z. B.:
- `raw`
- `validated`
- `estimated`
- `reported`
- `derived`
---
## 8. Composite-Typ 1: `group_set`
### 8.1 Zweck
Speicherung einer kleinen Menge benannter Teilwerte ohne zwingende Reihenfolge und ohne Bandgrenzen.
### 8.2 Typische Einsatzfälle
- HRV-Bundle
- Wellness-/Readiness-Bundle
- Technik-Bundle
- Submetriken eines Tests
- kleine Sammlungen korrelierter Werte
### 8.3 Struktur
```json
{
"v": 1,
"kind": "group_set",
"domain": "recovery",
"items": [
{ "key": "rmssd", "value": 42.1, "unit": "ms" },
{ "key": "resting_hr", "value": 54, "unit": "bpm" },
{ "key": "sleep_score", "value": 78, "unit": "score" }
],
"meta": {
"source": "reported",
"definition_ref": "morning_readiness_protocol_v1",
"quality": "validated"
}
}
```
### 8.4 Pflichtfelder pro Item
- `key`
- `value`
### 8.5 Optionale Item-Felder
- `unit`
- `label`
- `note`
### 8.6 Regeln
- `key` muss innerhalb eines Objekts eindeutig sein
- `value` darf scalar oder `null` sein
- keine fachliche Interpretation im Objekt selbst
### 8.7 Nicht speichern in `group_set`
Nicht in `group_set` speichern:
- `readiness_index`
- `recovery_flag`
- `trend_direction`
- generierte Scores
Diese gehören in Layer 2.
---
## 9. Composite-Typ 2: `distribution_set`
### 9.1 Zweck
Speicherung einer Verteilung über Bänder, Klassen oder Bereiche.
### 9.2 Typische Einsatzfälle
- Herzfrequenzzonen
- Power-Zonen
- Geschwindigkeitszonen
- Pace-Bänder
- Kadenz-Zonen
- Beschleunigungsbänder
- Sprunghöhenklassen
### 9.3 Struktur
```json
{
"v": 1,
"kind": "distribution_set",
"domain": "heart_rate",
"basis": "time",
"items": [
{
"key": "z1",
"value": 420,
"unit": "s",
"lower": 50,
"upper": 60,
"range_unit": "%hr_max"
},
{
"key": "z2",
"value": 780,
"unit": "s",
"lower": 60,
"upper": 70,
"range_unit": "%hr_max"
},
{
"key": "z3",
"value": 360,
"unit": "s",
"lower": 70,
"upper": 80,
"range_unit": "%hr_max"
}
],
"meta": {
"source": "reported",
"definition_ref": "hr_zone_model_5_hrmax",
"quality": "validated"
}
}
```
### 9.4 Pflichtfelder pro Item
- `key`
- `value`
### 9.5 Empfohlene Item-Felder
- `unit`
- `lower`
- `upper`
- `range_unit`
### 9.6 Regeln
- `key` muss eindeutig sein
- `items` sollen logisch sortierbar sein
- `lower` und `upper` sind optional, aber bei bandbasierten Sets empfohlen
- `basis` definiert, worauf sich `value` bezieht, etwa Zeit, Distanz, Wiederholungen
### 9.7 Nicht speichern in `distribution_set`
Nicht in `distribution_set` speichern:
- Wechselhäufigkeit
- mittlere Verweildauer
- Polarized Index
- Pyramidal Index
- Intervallklassifikation
Das sind Auswertungsergebnisse aus Layer 2.
---
## 10. Composite-Typ 3: `sequence_set`
### 10.1 Zweck
Speicherung geordneter Sequenzen, Segmente, Zustandsfolgen oder Intervallblöcke.
### 10.2 Typische Einsatzfälle
- Work-/Recovery-Blöcke
- erkannte HF-Zonen-Segmente
- Pace-Wechsel
- Satz-/Rundenabfolgen
- Drill-Sequenzen
- Ereignisfolgen
### 10.3 Struktur: Intervallblöcke
```json
{
"v": 1,
"kind": "sequence_set",
"domain": "intervals",
"basis": "time",
"items": [
{ "seq": 1, "label": "work", "start": 0, "duration": 180, "unit": "s" },
{ "seq": 2, "label": "recovery", "start": 180, "duration": 90, "unit": "s" },
{ "seq": 3, "label": "work", "start": 270, "duration": 180, "unit": "s" }
],
"meta": {
"source": "detected",
"definition_ref": "interval_template_optional",
"quality": "derived_l1"
}
}
```
### 10.4 Struktur: Zustandssegmente
```json
{
"v": 1,
"kind": "sequence_set",
"domain": "heart_rate_zone_state",
"basis": "time",
"items": [
{ "seq": 1, "label": "z2", "start": 0, "duration": 300, "unit": "s" },
{ "seq": 2, "label": "z4", "start": 300, "duration": 90, "unit": "s" },
{ "seq": 3, "label": "z2", "start": 390, "duration": 120, "unit": "s" }
],
"meta": {
"source": "detected",
"definition_ref": "hr_zone_model_5_hrmax"
}
}
```
### 10.5 Pflichtfelder pro Item
- `seq`
- mindestens eines von:
- `label`
- `key`
- mindestens eines von:
- `duration`
- `start` und `end`
### 10.6 Optionale Item-Felder
- `unit`
- `start`
- `end`
- `value`
- `note`
### 10.7 Regeln
- `seq` muss eindeutig und aufsteigend sein
- Segmente müssen logisch geordnet sein
- bei zeitbasierten Segmenten sollen Start/Dauer-Ende konsistent sein
- keine fachlich interpretierten Kennzahlen im Objekt
### 10.8 Nicht speichern in `sequence_set`
Nicht in `sequence_set` speichern:
- `switch_count`
- `switch_rate_per_min`
- `transition_entropy`
- `density_index`
- `plan_match_score`
Diese Metriken entstehen erst in Layer 2.
---
## 11. Composite-Typ 4: `model_set`
### 11.1 Zweck
Speicherung kleiner, strukturierter Parametersätze eines Modells.
### 11.2 Typische Einsatzfälle
- Critical Power / W
- Critical Speed
- Last-Geschwindigkeits-Profil
- Schwellenmodelle
- Testmodellparameter
### 11.3 Struktur
```json
{
"v": 1,
"kind": "model_set",
"domain": "critical_power",
"items": [
{ "key": "cp", "value": 286, "unit": "W" },
{ "key": "w_prime", "value": 16800, "unit": "J" },
{ "key": "r_squared", "value": 0.98, "unit": "ratio" }
],
"meta": {
"source": "derived_l1",
"definition_ref": "critical_power_2_parameter",
"quality": "validated"
}
}
```
### 11.4 Pflichtfelder pro Item
- `key`
- `value`
### 11.5 Optionale Item-Felder
- `unit`
- `ci_low`
- `ci_high`
- `error`
- `note`
### 11.6 Regeln
- `key` eindeutig
- Modellname und Herleitung über `meta.definition_ref`
- Modellinterpretation nicht im Objekt selbst speichern
### 11.7 Nicht speichern in `model_set`
Nicht in `model_set` speichern:
- Trainingsdiagnosen
- Handlungsempfehlungen
- automatische Coachingtexte
---
## 12. Warum genau diese vier Typen
Diese vier Typen decken den größten Teil realistisch auftretender Composite-Fälle ab, ohne die Persistenz fachlich zu überfrachten.
### `group_set`
Für kleine Bündel benannter Werte
### `distribution_set`
Für Verteilungen über Klassen oder Bänder
### `sequence_set`
Für geordnete Folgen, Segmente und Intervallstrukturen
### `model_set`
Für modellbasierte Parametersätze
Weitere Speichertypen sollen nur eingeführt werden, wenn ein neuer Fall mit diesen vier Typen **nicht sinnvoll oder nur mit klaren Verformungen** modellierbar ist.
---
## 13. Was ausdrücklich nicht Teil der Persistenz-Basisschicht ist
Die Persistenzschicht speichert keine fachlichen Endprodukte.
Nicht Bestandteil der Basis-Composite-Struktur sind:
- Visualisierungsvorgaben
- Diagrammfarblogik
- Scoring-Ergebnisse
- Kennzahlen aus Übergangsanalysen
- narrative KI-Bausteine
- Trainingsklassifikationen
- Empfehlungen
- Bewertungen
- Interpretationen
- sportartspezifische Schlussfolgerungen
---
## 14. Layer-1-Konzept
### 14.1 Zweck von Layer 1
Layer 1 ist die technische Aufbereitungsschicht zwischen Persistenz und Fachlogik.
Layer 1 darf:
- Composite-JSON validieren
- Schema-Version prüfen
- `kind` prüfen
- Items lesen
- Einheiten normalisieren
- Basisreferenzen auflösen
- technische DTOs erzeugen
- leichte Plausibilitätsprüfungen durchführen
Layer 1 darf nicht:
- Scores berechnen
- fachliche Bewertungen erzeugen
- Intervallqualität beurteilen
- KI-Platzhalter formulieren
- Trainingscharakter interpretieren
### 14.2 Layer-1-Output
Layer 1 erzeugt kanonische interne Datenobjekte, zum Beispiel:
- `ScalarValueDTO`
- `GroupSetDTO`
- `DistributionSetDTO`
- `SequenceSetDTO`
- `ModelSetDTO`
### 14.3 Beispielhafte DTOs
```ts
type ScalarValueDTO = {
id: string
datatype: string
value: number | string | boolean | null
unit?: string | null
}
type GroupItemDTO = {
key: string
value: unknown
unit?: string | null
}
type GroupSetDTO = {
id: string
domain: string
items: GroupItemDTO[]
meta?: Record<string, unknown>
}
type DistributionItemDTO = {
key: string
value: number | null
unit?: string | null
lower?: number | null
upper?: number | null
rangeUnit?: string | null
}
type DistributionSetDTO = {
id: string
domain: string
basis?: string | null
items: DistributionItemDTO[]
meta?: Record<string, unknown>
}
type SequenceItemDTO = {
seq: number
label?: string | null
start?: number | null
end?: number | null
duration?: number | null
unit?: string | null
value?: unknown
}
type SequenceSetDTO = {
id: string
domain: string
basis?: string | null
items: SequenceItemDTO[]
meta?: Record<string, unknown>
}
type ModelItemDTO = {
key: string
value: unknown
unit?: string | null
}
type ModelSetDTO = {
id: string
domain: string
items: ModelItemDTO[]
meta?: Record<string, unknown>
}
```
### 14.4 Layer-1-Validierungsregeln
#### Allgemein
- JSON muss parsebar sein
- `v` muss unterstützt sein
- `kind` muss bekannt sein
- `domain` darf nicht leer sein
- `items` muss Array sein
#### `group_set`
- jeder Eintrag braucht `key`
- `key` eindeutig
#### `distribution_set`
- jeder Eintrag braucht `key`
- `key` eindeutig
- `value` numerisch oder `null`
- `lower <= upper`, wenn beide gesetzt sind
#### `sequence_set`
- jeder Eintrag braucht `seq`
- `seq` eindeutig
- `seq` sortierbar
- zeitliche Felder konsistent
#### `model_set`
- jeder Eintrag braucht `key`
- `key` eindeutig
### 14.5 Layer-1-Normalisierungen
Layer 1 darf minimale Normalisierung durchführen:
- Sekunden, Minuten, Stunden intern vereinheitlichen
- Meter/Kilometer intern vereinheitlichen
- Prozentwerte intern konsistent repräsentieren
- Feldnamen aus Legacy-Importen normalisieren
Wichtig:
Diese Normalisierung ist technisch, nicht fachlich interpretierend.
---
## 15. Layer-2a-Konzept: fachliche Analyse- und Diagrammprojektionen
Layer 2a konsumiert Daten aus Layer 1 und erzeugt daraus fachliche Sichtweisen.
Die früher diskutierten fachlichen Archetypen leben **hier**, nicht in der Persistenz.
### 15.1 Fachliche Archetypen in Layer 2a
1. `BandDistribution`
2. `TransitionProfile`
3. `IntervalBlockProfile`
4. `EventActionProfile`
5. `CouplingEfficiencyProfile`
6. `ModelParameterProfile`
7. `TechniqueCycleProfile`
8. `ReadinessRecoveryProfile`
### 15.2 Mapping von Speicherformen auf Layer-2a-Archetypen
#### `distribution_set`
kann projiziert werden auf:
- `BandDistribution`
#### `sequence_set`
kann projiziert werden auf:
- `TransitionProfile`
- `IntervalBlockProfile`
- `EventActionProfile`
#### `group_set`
kann projiziert werden auf:
- `TechniqueCycleProfile`
- `ReadinessRecoveryProfile`
- Teile eines `EventActionProfile`
#### `model_set`
kann projiziert werden auf:
- `ModelParameterProfile`
#### Kombination mehrerer Werte
kann projiziert werden auf:
- `CouplingEfficiencyProfile`
### 15.3 Beispiel: TransitionProfile aus `sequence_set`
Aus einer Zustandssequenz wie:
- z2 -> 300s
- z4 -> 90s
- z2 -> 120s
- z5 -> 60s
kann Layer 2a berechnen:
- Anzahl Wechsel
- Wechselrate
- mittlere Verweildauer pro Zustand
- längste Verweildauer
- Zustandsübergänge
- Intervallcharakter
Diese Werte werden **nicht** im Basis-Composite gespeichert, sondern von Layer 2a berechnet.
### 15.4 Beispiel: BandDistribution aus `distribution_set`
Aus HF-Zonen-Zeiten kann Layer 2a erzeugen:
- Diagrammserien
- Prozentanteile
- Schwerpunktzone
- Exposition oberhalb einer Schwelle
- Intensitätsverteilung
Auch dies entsteht erst in Layer 2a.
---
## 16. Layer-2b-Konzept: KI-Projektionen
Layer 2b soll keine Rohwerte direkt in Prompts kippen, sondern fachlich brauchbare Platzhalter erzeugen.
### 16.1 Grundsatz
Layer 2b konsumiert bevorzugt:
- Layer-1-Daten für einfache Fakten
- Layer-2a-Daten für fachlich verdichtete Aussagen
### 16.2 Ziel von Layer 2b
Erzeugung strukturierter KI-Bausteine wie:
- „Zeit in hoher Intensität“
- „Intervallstruktur erkannt“
- „Belastungsdichte hoch“
- „geringe Variabilität“
- „Readiness reduziert“
- „Technikmetriken auffällig“
- „intern-externe Lastkopplung stabil“
### 16.3 Beispielhafte KI-Platzhalter
```json
{
"high_intensity_time_s": 480,
"interval_structure_detected": true,
"switch_count": 12,
"dominant_hr_zone": "z2",
"readiness_state": "normal",
"technique_variability_flag": "elevated"
}
```
Wichtig:
Auch diese Objekte sind **keine Persistenz-Basisobjekte**, sondern bereitgestellte Kontexte für KI.
---
## 17. Composite-Speicherung im bestehenden Value Store
### 17.1 Annahme über den aktuellen Store
Der bestehende Store speichert Werte als Datensätze mit:
- Datentyp
- Value
- Einheit
- weiteren Metadaten
### 17.2 Empfohlene Nutzung
#### Scalar
unverändert speichern
#### Composite
als Datensatz mit:
- `datatype = composite`
- `value = jsonb`
- `unit = null` oder optional leer, sofern Einheit innerhalb der Items gespeichert wird
### 17.3 Empfohlene Zusatzmetadaten außerhalb von `value`
Soweit euer bestehendes Modell das unterstützt, sind diese Felder außerhalb des JSONB sinnvoll:
- `id`
- `athlete_id`
- `session_id`
- `source_system`
- `measured_at`
- `datatype`
- `subtype` oder `kind` als Hilfsspalte
- `domain` als Hilfsspalte
- `created_at`
- `updated_at`
### Empfehlung
`kind` und `domain` sollten nach Möglichkeit zusätzlich indexierbar sein, selbst wenn sie primär im JSONB liegen.
---
## 18. JSONB-Schema-Regeln
### 18.1 Schema-Versionierung
Jedes Composite trägt `v`.
Regel:
- neue inkompatible Strukturen erhöhen `v`
- Layer 1 unterstützt definierte Versionen
- unbekannte Versionen werden abgelehnt oder in Fallback-Modus versetzt
### 18.2 Rückwärtskompatibilität
Wenn möglich:
- neue optionale Felder hinzufügen, ohne `v` zu erhöhen
- nur strukturelle Brüche führen zu neuer Version
### 18.3 Dokumentgröße
Composite-Objekte sollen fachlich zusammenhängend, aber nicht unnötig groß sein.
Regel:
- ein Composite speichert einen **atomaren strukturierten Sachverhalt**
- keine beliebig großen Sammelobjekte
- keine Vermischung mehrerer unabhängiger Analyseebenen
---
## 19. Definitionen, Referenzen und Kataloge
Die Basis-Composite-Objekte können Definitionen referenzieren, sollen diese aber nicht voll duplizieren.
### 19.1 Beispiele für `definition_ref`
- `hr_zone_model_5_hrmax`
- `hr_zone_model_5_hrr`
- `power_zone_model_7_ftp`
- `morning_readiness_protocol_v1`
- `critical_power_2_parameter`
- `boxing_round_structure_3x3`
- `karate_interval_template_v2`
### 19.2 Nutzen von `definition_ref`
Damit kann Layer 2:
- bandbezogene Logik verstehen
- Diagrammbeschriftungen korrekt erzeugen
- Schwellenmodelle zuordnen
- KI-Kontext korrekt ableiten
Wichtig:
`definition_ref` verweist auf eine Definition, ersetzt diese aber nicht.
---
## 20. Abgeleitete Werte zurückspeichern
### 20.1 Grundsatz
Falls Layer-2-Ergebnisse persistiert werden sollen, sollen sie **nicht** in das Basis-Composite zurückgeschrieben werden.
Stattdessen werden sie als eigene abgeleitete Werte gespeichert.
### 20.2 Begründung
So werden vermieden:
- doppelte Wahrheit
- inkonsistente alte Berechnungsergebnisse
- Vermischung von Fakt und Interpretation
- schwierige Rebuilds
### 20.3 Empfohlenes Muster
Ein abgeleiteter Wert bekommt:
- eigenen Datensatz
- Herkunftskennzeichnung
- Regel-/Berechnungsversion
- Referenz auf Quellwerte
### 20.4 Beispiel
```json
{
"origin": "derived",
"layer": "2a",
"rule": "transition_profile_v2",
"source_ids": ["value_4711", "value_4712", "value_4713"]
}
```
---
## 21. Beispielhafte Ende-zu-Ende-Flows
### 21.1 Flow A: Herzfrequenzzonen
#### Persistenz
`distribution_set` mit Zonenzeiten
#### Layer 1
`DistributionSetDTO`
#### Layer 2a
- Prozentanteile
- Diagrammwerte
- dominante Zone
- Zeit oberhalb bestimmter Zonen
- Intensitätsprofil
#### Layer 2b
- KI-Platzhalter wie:
- `dominant_hr_zone`
- `high_intensity_time_s`
- `intensity_distribution_type`
### 21.2 Flow B: Intervalltraining
#### Persistenz
`sequence_set` mit Work-/Recovery-Segmenten
#### Layer 1
`SequenceSetDTO`
#### Layer 2a
- Anzahl Blöcke
- Work-Recovery-Verhältnis
- mittlere Blockdauer
- Dichte
- Compliance
- Intervallcharakter
#### Layer 2b
- KI-Platzhalter wie:
- `interval_block_count`
- `work_recovery_ratio`
- `interval_density_state`
### 21.3 Flow C: Readiness
#### Persistenz
`group_set` mit RMSSD, Ruhepuls, Schlafscore
#### Layer 1
`GroupSetDTO`
#### Layer 2a
- Baseline-Abweichung
- Trend
- Zustandsklassifikation
#### Layer 2b
- `readiness_state`
- `recovery_attention_flag`
### 21.4 Flow D: Critical Power
#### Persistenz
`model_set` mit `cp`, `w_prime`, `r_squared`
#### Layer 1
`ModelSetDTO`
#### Layer 2a
- Modellgüte
- Vergleich zum Verlauf
- Zonen-/Schwellenableitung
#### Layer 2b
- KI-konforme Modellzusammenfassung
---
## 22. Regeln zur Entscheidung: Scalar oder Composite
### 22.1 Scalar verwenden, wenn
- genau ein Wert gespeichert wird
- keine strukturierte Untergliederung nötig ist
- keine zusammenhängende Teilwertgruppe existiert
Beispiele:
- Durchschnittspuls
- Maximalpuls
- Distanz
- Dauer
- Durchschnittsleistung
### 22.2 Composite verwenden, wenn
- mehrere Teilwerte logisch zusammengehören
- die Teilwerte nur gemeinsam sinnvoll interpretierbar sind
- Reihenfolge, Verteilung oder Modellstruktur relevant ist
Beispiele:
- HF-Zonen
- Intervallblöcke
- Readiness-Bundle
- Critical-Power-Parameter
### 22.3 Nicht jedes Mehrfachfeld ist automatisch Composite
Wenn mehrere Werte unabhängig voneinander existieren und auch einzeln sinnvoll sind, sollen sie weiterhin als Scalars gespeichert werden.
Composite nur dann verwenden, wenn die Gruppe selbst eine eigenständige semantische Einheit ist.
---
## 23. Regeln zur Einführung neuer Composite-Formate
Ein neues Composite-Format darf nur eingeführt werden, wenn mindestens eine der folgenden Bedingungen erfüllt ist:
1. Der neue Fall lässt sich mit den vier Basis-Typen nicht sinnvoll ausdrücken
2. Eine Abbildung wäre nur durch unsaubere oder missbräuchliche Nutzung möglich
3. Die Lesbarkeit und Wartbarkeit würden mit den vorhandenen Typen stark leiden
Vor Einführung eines neuen Typs ist zu prüfen:
- Kann es als `group_set` modelliert werden?
- Kann es als `distribution_set` modelliert werden?
- Kann es als `sequence_set` modelliert werden?
- Kann es als `model_set` modelliert werden?
Nur wenn alle vier Antworten fachlich und technisch nicht tragfähig sind, soll ein neuer Speichertyp diskutiert werden.
---
## 24. Implementierungsrichtlinien
### 24.1 Parser
Implementiere einen zentralen Composite-Parser:
- Eingang: Value-Record mit `datatype = composite`
- Ausgabe: konkretes Layer-1-DTO je `kind`
### 24.2 Validator
Implementiere einen zentralen Validator:
- allgemeine Prüfung
- kind-spezifische Prüfung
- strukturierte Fehlermeldungen
### 24.3 Mapper
Implementiere Mapper:
- `CompositeRecord -> GroupSetDTO`
- `CompositeRecord -> DistributionSetDTO`
- `CompositeRecord -> SequenceSetDTO`
- `CompositeRecord -> ModelSetDTO`
### 24.4 Projection Services in Layer 2
Beispiele:
- `BandDistributionProjectionService`
- `TransitionProfileService`
- `IntervalAnalysisService`
- `ReadinessProjectionService`
- `CouplingAnalysisService`
- `TechniqueProjectionService`
### 24.5 KI-Mapping in Layer 2b
Beispiele:
- `AiPlaceholderBuilder`
- `AiFactsBuilder`
- `AiNarrativeInputBuilder`
---
## 25. Fehler- und Fallback-Strategie
### 25.1 Ungültiges Composite
Wenn ein Composite ungültig ist:
- Layer 1 liefert strukturierten Fehler
- der Datensatz wird nicht als fachlich gültig weitergereicht
- optional kann ein „raw passthrough“ für Debugging existieren
### 25.2 Unbekannte Version
Wenn `v` unbekannt ist:
- Datensatz markieren
- nicht stillschweigend interpretieren
- optional Migration oder Fallback-Parser nutzen
### 25.3 Teilweise fehlende Felder
Wenn optionale Felder fehlen:
- lesen, sofern Kernschema gültig bleibt
- fehlende Informationen in Layer 2 berücksichtigen
- keine stillschweigende Erfindung fachlicher Werte
---
## 26. Performance- und Wartungsaspekte
### 26.1 Grundsatz
Die Persistenz soll flexibel, aber strukturiert bleiben.
### 26.2 Empfehlungen
- kleine, atomare Composite-Objekte
- keine übergroßen Sammelcontainer
- `kind` und `domain` indexierbar halten
- Definitionen referenzieren statt duplizieren
- fachliche Projektionen nicht als Pflichtbestandteil der Persistenz speichern
### 26.3 Vorteil dieser Struktur
- geringe Kopplung
- stabile Persistenz
- evolvierbare Fachlogik
- gute Eignung für mehrere Sportarten
- gute Wiederverwendbarkeit in Layer 2a und 2b
---
## 27. Migrationsstrategie
Falls bereits Composite-Ansätze existieren, wird folgendes Vorgehen empfohlen:
### Phase 1
- Einführung der vier `kind`-Typen
- Aufbau von Validator und Parser
- Speicherung neuer Composites nach neuem Muster
### Phase 2
- Layer-1-DTOs einführen
- bestehende Reader umstellen
### Phase 3
- Layer-2a-Projektionen implementieren
- Diagramme und Kennzahlen umstellen
### Phase 4
- Layer-2b-KI-Platzhalter auf neue Projektionen aufsetzen
### Phase 5
- bestehende Altformate optional migrieren oder kompatibel lesen
---
## 28. Nicht-Ziele dieses Dokuments
Dieses Dokument definiert bewusst nicht:
- konkrete UI-Diagrammgestaltung
- konkrete Score-Formeln
- sportartspezifische Bewertungslogiken
- konkrete KI-Prompttexte
- konkrete Datenbanktabellenmigrationen im Detail
- konkrete API-Endpunkte
Diese Punkte sind nachgelagerte Spezifikationen.
---
## 29. Offene Erweiterungspunkte
Die Architektur lässt folgende spätere Erweiterungen zu, ohne die Persistenzbasis zu brechen:
- zusätzliche `definition_ref`-Kataloge
- sportartspezifische Layer-2-Projektionen
- neue KI-Platzhaltertypen
- zusätzliche Qualitäts- und Provenienzfelder
- Rückspeicherung abgeleiteter Werte als eigene Datensätze
- spezielle Event-Detektion in Layer 2a
---
## 30. Endgültige Entscheidung
### Die Persistenzschicht speichert:
- Scalars
- vier einfache technische Composite-Typen
### Layer 1 übernimmt:
- Lesen
- Validieren
- minimale Normalisierung
- DTO-Bildung
### Layer 2a übernimmt:
- fachliche Analyse
- Diagrammaufbereitung
- Kennzahlen
- Profile
- Scores
- Interpretationen
### Layer 2b übernimmt:
- KI-Platzhalter
- KI-Fakten
- KI-Zusammenfassungen
- KI-taugliche Verdichtungen
---
## 31. Kurzfassung für einen Coding Agent
### Ziel
Erweitere den bestehenden Value Store um Composite-Werte auf `jsonb`-Basis, ohne fachliche Analyse-Logik in die Persistenz zu verlagern.
### Implementiere
1. Unterstützung für `datatype = composite`
2. vier `kind`-Typen:
- `group_set`
- `distribution_set`
- `sequence_set`
- `model_set`
3. Layer-1-Validatoren und Parser
4. kanonische DTOs pro `kind`
5. klare Trennung:
- Persistenz = strukturierte Fakten
- Layer 1 = technische Aufbereitung
- Layer 2a = fachliche Projektionen
- Layer 2b = KI-Projektionen
### Vermeide
- Scores im Basis-Composite
- Interpretationen im Basis-Composite
- Diagramm- oder KI-Logik in der Persistenz
- zu viele spezialisierte Composite-Speichertypen
---
## 32. Akzeptanzkriterien
Die Umsetzung gilt als fachlich passend, wenn:
1. ein Composite-Value mit `jsonb` gespeichert werden kann
2. Layer 1 den Typ sicher validieren und lesen kann
3. die Persistenz keine fachlichen Layer-2-Interpretationen erzwingt
4. HF-Zonen als `distribution_set` abbildbar sind
5. Intervallblöcke als `sequence_set` abbildbar sind
6. Readiness-Bundles als `group_set` abbildbar sind
7. Modellparameter als `model_set` abbildbar sind
8. Layer 2a daraus fachliche Projektionen erzeugen kann
9. Layer 2b daraus KI-Platzhalter erzeugen kann
10. neue Sportarten ohne neue Persistenzarchitektur integrierbar sind
---
## 33. Schlussformel
Die Leitentscheidung dieses Konzepts lautet:
**Die Datenbank speichert Struktur.
Layer 1 liefert kanonische technische Objekte.
Layer 2 erzeugt fachliche Bedeutung.
KI konsumiert diese Bedeutung, nicht die rohe Persistenzstruktur.**
Damit bleibt das System einfach genug für die Implementierung und offen genug für spätere sportartspezifische Erweiterungen.