1480 lines
30 KiB
Markdown
1480 lines
30 KiB
Markdown
|
|
# 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.
|