- 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.
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. |