# 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 } 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 } 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 } type ModelItemDTO = { key: string value: unknown unit?: string | null } type ModelSetDTO = { id: string domain: string items: ModelItemDTO[] meta?: Record } ``` ### 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.