mitai-jinkendo/.claude/docs/jinkendo-foundation/design-principles/DATA_LAYER_DESIGN_PRINCIPLES.md

360 lines
18 KiB
Markdown
Raw Normal View History

# Data Layer – Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Multi-Layer Data Architecture (Phase 0c, Issue #53) — keine Mitai-Gesamtarchitektur, keine konkrete Gesundheits-/Ernährungsfachlogik als Produktinhalt
**Serie:** Designprinzipien für Produktfamilie · Dokument 2 von n
**Vorgänger:** [PROMPT_ENGINE_DESIGN_PRINCIPLES.md](./PROMPT_ENGINE_DESIGN_PRINCIPLES.md)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| Metriken (Layer 1) | `backend/data_layer/*_metrics.py`, `scores.py`, `correlations.py` |
| Utilities | `backend/data_layer/utils.py` |
| Visualisierung (Layer 2b) | `*_chart_payloads.py`, `*_viz.py` |
| KI-Formatierung (Layer 2a-Hilfe) | `prompt_output_compact.py` |
| Persistenz-Orchestrierung | `activity_persistence_orchestrator.py`, `activity_session_metrics.py` |
| Konsumenten | `routers/charts.py`, `placeholder_resolver.py`, `routers/exportdata.py` |
| Leitfäden | `DATA_LAYER_EXTENSION_GUIDE.md`, `docs/issues/issue-53-phase-0c-multi-layer-architecture.md` |
| Architektur-Regel Import-Grenze | `.claude/rules/ARCHITECTURE.md` §8 |
---
## Modul
**Data Layer** (Phase 0c Multi-Layer Architecture, Issue #53)
Zentrale Schicht für **Datenabruf, Berechnung und strukturierte Aufbereitung** — ohne UI-Formatierung, ohne Prompt-Texte, ohne Chart.js-spezifische Ausgabe in den Kern-Metrik-Modulen.
---
## Fachliche Verantwortung
Der Data Layer ist die **Single Source of Truth für alle abgeleiteten Messwerte und Metriken**. Er übernimmt:
1. **Datenabruf** — Lesen aus PostgreSQL (profile-scoped), optional mit Quality-Filter.
2. **Berechnung** — Trends, Scores, Korrelationen, Aggregationen, Projektionen.
3. **Strukturierte Rückgabe** — Dicts/Listen mit numerischen Werten, Datumsfeldern, Metadaten (`confidence`, `data_points`).
4. **Konsumenten-Bereitstellung** — Charts (Layer 2b), KI-Platzhalter (Layer 2a via Resolver), Export, Router-Anreicherung.
Er übernimmt **nicht**:
- CSV-Parsing und Feld-Mapping (Import-Schicht)
- Prompt-Template-Auflösung (Prompt Engine)
- React-Rendering oder Frontend-Berechnungen
- Autorisierung / Feature-Limits (Auth-Schicht)
### Schichtenmodell (Multi-Layer)
```
┌─────────────────────────────────────────────────────────┐
│ Layer 0: Persistenz (PostgreSQL) │
│ weight_log, nutrition_log, activity_log, sleep_log, … │
└──────────────────────────┬──────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────┐
│ Layer 1: DATA LAYER (Metriken) │
│ Strukturierte Daten · confidence · data_points │
│ KEINE formatierten Strings · KEINE Chart.js-Objekte │
└──────────────┬───────────────────────┬──────────────────┘
│ │
▼ ▼
┌──────────────────────────┐ ┌────────────────────────────┐
│ Layer 2a: KI / Prompts │ │ Layer 2b: Visualisierung │
│ placeholder_resolver │ │ *_chart_payloads, *_viz │
│ prompt_output_compact │ │ routers/charts.py │
└──────────────────────────┘ └────────────────────────────┘
```
### Administrierte vs. code-definierte Konfiguration
| Was | Wo | Administrierbar? |
|-----|-----|------------------|
| Berechnungslogik (Formeln, Fenster) | `data_layer/*.py` | ❌ Code + Review |
| Confidence-Schwellen | `data_layer/utils.py` | ❌ Code |
| Goal Mode / Focus Weights | DB (`profiles`, `user_focus_area_weights`) | ✅ Nutzer/Admin |
| Quality Filter (Profil) | DB (`profiles`) | ✅ Admin |
| Chart-Zeitfenster | Query-Parameter an API | ✅ Request |
| Referenzwerte (persönlich) | DB + `reference_values.py` | ✅ Nutzer |
| EAV Session Metrics | DB (`training_*_parameter`) | ✅ Admin |
**Bewusst nicht hardcodiert in Routern:** Metrik-Berechnungen — Router delegieren an Data Layer.
**Hardcodiert (Code):** Domänen-Module, Confidence-Regeln, Schwellen pro Metrik-Typ, TDEE-Fallback-Logik, Chart-Payload-Struktur.
### Trennung: Metriken · Chart-Payloads · KI-Formatierung · Persistenz
| Schicht | Module | Verantwortung |
|---------|--------|---------------|
| **Metriken** | `body_metrics.py`, `nutrition_metrics.py`, … | Reine Berechnung, strukturierte Dicts |
| **Chart-Payloads** | `nutrition_chart_payloads.py`, `correlation_chart_payloads.py`, … | Chart.js-kompatible `{ labels, datasets, metadata }` aus Layer-1-Daten |
| **Viz-Bundles** | `body_viz.py`, `fitness_viz.py`, … | Zusammengesetzte Dashboard-/History-Pakete für Frontend |
| **KI-Kompaktierung** | `prompt_output_compact.py` | Token-sparende Zahlen/JSON für Platzhalter |
| **Interpretation** | `*_interpretation.py`, `vital_signs_assessment.py` | Textliche Einordnung (WHO-Klassen etc.) — Grenze zu Layer 2a |
| **Persistenz-Orchestrator** | `activity_persistence_orchestrator.py` | Schreibpfade REST/CSV → DB + Nebenwirkungen (EAV, Eval) |
### Konsumenten (wer ruft den Data Layer auf?)
| Konsument | Muster |
|-----------|--------|
| `routers/charts.py` | Layer-1-Funktion + Chart-Payload-Builder |
| `placeholder_resolver.py` | Layer-1 → Formatierung/JSON für `{{placeholders}}` |
| `routers/exportdata.py` | `enrich_sessions_with_metrics`, `serialize_dates` |
| `routers/activity.py`, `csv_import.py` | `activity_persistence_orchestrator` (Schreiben) |
| `prompt_executor.execute_prompt_with_data` | ⚠️ teils Roh-SQL parallel zum Data Layer (Legacy) |
### Rollen
Der Data Layer hat **keine eigene Admin-UI**. Konfiguration erfolgt indirekt:
- **Admin:** Training-Parameter, Attributprofile, Referenzwert-Typen, Quality-Filter
- **Nutzer:** Profildaten, Referenzwerte, Focus-Area-Gewichte (beeinflussen Scores)
- **Entwickler:** Neue Funktionen in `data_layer/` nach Extension Guide
---
## Designprinzipien
### 1. Single Source of Truth für Berechnungen
| | |
|---|---|
| **Prinzip** | Jede Metrik wird **einmal** in `data_layer/` berechnet; Charts, KI und Export konsumieren dieselbe Funktion. |
| **Begründung** | Verhindert divergierende Zahlen zwischen Dashboard, Analyse und KI-Ausgabe. |
| **Quelle** | Issue #53 Executive Summary; `nutrition_chart_payloads.py` Kommentar „identisch zu GET /api/charts/energy-balance“ |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Nicht alle Pfade migriert (`insights._prepare_template_vars`, `execute_prompt_with_data` Roh-SQL). |
### 2. Layer 1 liefert strukturierte Daten, keine formatierten Strings
| | |
|---|---|
| **Prinzip** | Kern-Metrik-Funktionen geben Dicts mit `float`/`int`/`date` zurück — **keine** Strings mit Einheiten („86,1 kg“). |
| **Begründung** | Formatierung ist konsumentenspezifisch (DE-Locale, Chart-Achsen, KI-Token). |
| **Quelle** | `data_layer/__init__.py` Docstring: „NO FORMATTING. NO STRINGS WITH UNITS.“ |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | `placeholder_resolver` und `*_interpretation` Module formatieren teils direkt — Grenze Layer 1/2a nicht überall scharf. |
### 3. Pflicht-Metadaten: confidence + data_points
| | |
|---|---|
| **Prinzip** | Jede Metrik-Funktion liefert mindestens `confidence` (`high`\|`medium`\|`low`\|`insufficient`) und `data_points`. |
| **Begründung** | UI/KI können Datenqualität kommunizieren; Debugging und Monitoring vereinfacht. |
| **Quelle** | `DATA_LAYER_EXTENSION_GUIDE.md` § Pflicht-Felder; `calculate_confidence()` in `utils.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Nicht runtime-validiert; Disziplin per Code-Review. |
### 4. Confidence nach Metrik-Typ und Zeitfenster
| | |
|---|---|
| **Prinzip** | Schwellen unterscheiden `general`, `correlation`, `trend` und Fensterlänge (7d / 28d / 90d). |
| **Begründung** | Korrelationen brauchen mehr Paare; Trends messen Abdeckung (% der Tage). |
| **Quelle** | `data_layer/utils.py` → `calculate_confidence()` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Schwellen global hardcodiert, nicht pro Metrik konfigurierbar. |
### 5. Domänen-Module statt Monolith
| | |
|---|---|
| **Prinzip** | Ein Python-Modul pro fachlichem Bereich (`body_metrics`, `nutrition_metrics`, …), max. ~500 Zeilen, dann Split. |
| **Begründung** | Wartbarkeit, klare Ownership, parallele Entwicklung. |
| **Quelle** | `DATA_LAYER_EXTENSION_GUIDE.md` § Modul-Struktur |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Einige Module deutlich >500 Zeilen (Phase-0c-Wachstum). |
### 6. Layer 2b: Chart-Payloads als Adapter
| | |
|---|---|
| **Prinzip** | Chart.js-Strukturen leben in dedizierten `*_chart_payloads.py` / `*_viz.py`, nicht in Metrik-Modulen. |
| **Begründung** | Gleiche Metrik, verschiedene Visualisierungen; API-Endpoints bleiben dünn. |
| **Quelle** | `nutrition_chart_payloads.py`; `routers/charts.py` Imports |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Teilweise noch SQL-Duplikation in Payload-Buildern neben Layer-1-Aufruf. |
### 7. Layer 2a-Hilfe: KI-spezifische Kompaktierung getrennt
| | |
|---|---|
| **Prinzip** | Token-Reduktion für LLM-Kontext (`compact_float_for_prompt`, `compact_json_payload_for_prompts`) ist eigenes Modul, nicht in Metrik-Kern. |
| **Begründung** | KI hat andere Anforderungen als Charts (Präzision vs. Token-Kosten). |
| **Quelle** | `prompt_output_compact.py`; Tests in `tests/test_prompt_output_compact.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Nur für KI-Pfad; Charts nutzen eigene Rundung. |
### 8. Import-Grenze: Ingest vs. Interpretation
| | |
|---|---|
| **Prinzip** | CSV-Import macht Mapping + Typkonvertierung + Duplikatlogik — **keine** fachliche Auswertung beim Insert. |
| **Begründung** | Semantik gehört in Layer 1+, sonst versteckte Business-Logik in Import-Adaptern. |
| **Quelle** | `ARCHITECTURE.md` §8; Issue #53 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Legacy-Adapter (Apple-Schlaf-Aggregat, dedizierte Import-Endpoints) noch aktiv. |
### 9. Persistenz-Orchestrator für Schreibpfade
| | |
|---|---|
| **Prinzip** | Alle Schreibwege eines Domänenobjekts (REST, CSV, Legacy) laufen durch **einen** Orchestrator mit Nebenwirkungen (EAV, Evaluation). |
| **Begründung** | Konsistente Duplikat-Erkennung, Registry-Felder, keine divergierenden Insert-Logiken. |
| **Quelle** | `activity_persistence_orchestrator.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Bisher vor allem Aktivität; andere Domänen noch direkt in Routern. |
### 10. Registry als Feld-Kanon (Activity)
| | |
|---|---|
| **Prinzip** | Erlaubte persistierbare Felder für CSV/REST leiten sich aus `module_registry` ab, nicht aus Router-Hardcoding. |
| **Begründung** | Single Source of Truth für Import-Mappings und DB-Updates. |
| **Quelle** | `activity_data_canon.py`, `activity_persistence_orchestrator.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Nur Activity vollständig; andere Module noch klassische Spalten-CRUD. |
### 11. EAV-Anreicherung als Read-Layer
| | |
|---|---|
| **Prinzip** | Session-Metriken (EAV) werden beim **Lesen** angereichert (`enrich_sessions_with_metrics`), nicht pro Consumer dupliziert. |
| **Begründung** | Ein Merge-Kanon für Liste, Detail, Export, Platzhalter. |
| **Quelle** | `activity_session_metrics.py`; `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Domänenspezifisch (Training); Muster übertragbar. |
### 12. Scores als composable Layer
| | |
|---|---|
| **Prinzip** | Composite Scores (`scores.py`) kombinieren Domänen-Metriken mit nutzer-spezifischen Focus Weights — keine Score-Logik in Routern. |
| **Begründung** | Goal-Mode-/Focus-abhängige Gewichtung zentral, für KI und Dashboard gleich. |
| **Quelle** | `data_layer/scores.py`; Phase-0b-Fokus-System |
| **Tragfähigkeit** | **mittel–hoch** |
| **Einschränkung** | Eng an Mitai-Zielsystem gekoppelt; Muster „gewichtete Composite Scores“ ist generisch. |
### 13. API-First: Router delegieren, rechnen nicht
| | |
|---|---|
| **Prinzip** | `routers/charts.py` und ähnliche Endpoints rufen Data-Layer-Funktionen auf und mappen auf HTTP — keine Trend-Berechnung im Router. |
| **Begründung** | Testbarkeit; Frontend ohne Business-Logik. |
| **Quelle** | `ARCHITECTURE.md` §1.2 API-First |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | `charts.py` ist groß (2246+ Zeilen) — viel Adapter-Code, aber Berechnung delegiert. |
### 14. serialize_dates / safe_float als Querschnitt
| | |
|---|---|
| **Prinzip** | JSON/API-Serialisierung (Dates, Decimal) zentral in `utils.py`, nicht pro Modul neu erfunden. |
| **Begründung** | PostgreSQL-Typen (DATE, DECIMAL) konsistent für API und Export. |
| **Quelle** | `data_layer/utils.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 15. Extension Guide als verbindlicher Entwicklungsvertrag
| | |
|---|---|
| **Prinzip** | Neue Metriken folgen Template (Retrieve → Confidence → Early Return → Calculate → Return) und werden in `__init__.py` exportiert. |
| **Begründung** | Einheitliche Struktur für 97+ Funktionen und wachsende Codebase. |
| **Quelle** | `DATA_LAYER_EXTENSION_GUIDE.md` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Guide und Ist-Code divergieren teils (Modulgröße, `goals.py` noch nicht in `__init__`). |
---
## Nicht übernehmen
Muster, die sich nicht bewährt haben oder zu produktspezifisch sind:
1. **Berechnungslogik in `placeholder_resolver.py`** — Phase-0b-Legacy; Resolver soll nur formatieren/aggregieren, nicht rechnen.
2. **Paralleler Roh-SQL-Kontext in `prompt_executor.execute_prompt_with_data`** — lädt Modul-Rohdaten per SQL, obwohl Layer 1 existiert; zweite Wahrheit.
3. **Legacy Insights-Pfad (`insights._prepare_template_vars`)** — eigene Variablen-Vorbereitung ohne Data Layer.
4. **Import mit fachlicher Interpretation** — Apple-Schlaf-Aggregat und ähnliche Adapter verstecken Semantik im Ingest (Gitea #69).
5. **Monolithische Router mit Inline-Berechnung** — vor Phase 0c; gelegentlich noch Reste in nicht migrierten Pfaden.
6. **Interpretation vermischt mit Layer 1** — `*_interpretation.py` liefert teils fertige Texte; für Familien-Architektur klar als Layer 2a/2b markieren oder auslagern.
7. **SQL-Duplikation in Chart-Payloads** — manche Payload-Builder führen eigene Queries statt ausschließlich Layer-1-Ergebnisse zu visualisieren.
8. **Hardcodierte Confidence global** — funktioniert, aber nicht pro Metrik/Domäne konfigurierbar; Skalierung in Multi-Tenant-Produktfamilie prüfen.
9. **Domänen-Module als Produktinhalt** — `body_metrics`, TDEE, WHR etc. sind Mitai-spezifisch; **Schichtenmodell** übernehmen, **Formeln** nicht blind kopieren.
10. **Fehlende runtime-Validierung des Return-Schemas** — `confidence`/`data_points` per Konvention, nicht per TypedDict/Pydantic erzwungen.
11. **Uneinheitliche Schreib-Orchestrierung** — nur Activity hat `persistence_orchestrator`; andere Domänen noch fragmentiert.
12. **Riesige Einzeldateien** — einige Metrik-Module >>500 Zeilen widersprechen eigenem Extension Guide.
---
## Modul-Inventar (Ist-Stand)
```
backend/data_layer/
├── Kern-Metriken (Layer 1)
│ ├── body_metrics.py
│ ├── nutrition_metrics.py
│ ├── activity_metrics.py
│ ├── recovery_metrics.py
│ ├── health_metrics.py
│ ├── scores.py
│ └── correlations.py
├── Visualisierung (Layer 2b)
│ ├── *_chart_payloads.py (nutrition, recovery, correlation)
│ └── *_viz.py (body, nutrition, fitness, recovery, history_overview)
├── KI / Format (Layer 2a-Nähe)
│ ├── prompt_output_compact.py
│ └── *_interpretation.py
├── Persistenz / EAV
│ ├── activity_persistence_orchestrator.py
│ ├── activity_session_metrics.py
│ └── activity_data_canon.py
├── Querschnitt
│ ├── utils.py
│ ├── reference_values.py
│ └── nutrition_body_merge.py
└── __init__.py (Exports)
```
**Konsumenten-Endpoints (Auswahl):** 20+ Chart-Endpoints in `routers/charts.py` (E1–E5, A1–A8, R1–R5, C1–C4).
---
## Verwandte Dokumentation
- Issue #53 Abschluss: [issue-53-phase-0c-multi-layer-architecture.md](../../../../docs/issues/issue-53-phase-0c-multi-layer-architecture.md)
- Extension Guide: [DATA_LAYER_EXTENSION_GUIDE.md](../../technical/DATA_LAYER_EXTENSION_GUIDE.md)
- Fachliche Datenarchitektur: [DATA_ARCHITECTURE.md](../../functional/DATA_ARCHITECTURE.md)
- Import-Grenze: [ARCHITECTURE.md](../../../rules/ARCHITECTURE.md) §8
- Platzhalter-Anbindung: [PLACEHOLDER_REGISTRY_FRAMEWORK.md](../../technical/PLACEHOLDER_REGISTRY_FRAMEWORK.md)
- Prompt Engine (Konsument Layer 2a): [PROMPT_ENGINE_DESIGN_PRINCIPLES.md](./PROMPT_ENGINE_DESIGN_PRINCIPLES.md)
- Feature & Entitlement: [FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md](./FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md)
---
## Geplante Folgedokumente (Serie)
| # | Modul | Datei (geplant) |
|---|-------|-----------------|
| 1 | Prompt Engine | ✅ `PROMPT_ENGINE_DESIGN_PRINCIPLES.md` |
| 2 | Data Layer | ✅ dieses Dokument |
| 3 | Feature & Entitlement System | ✅ `FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md` |
| 4 | Registry-/Plugin-Muster | ✅ `REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md` |
| 5 | Auth & Session | ✅ `AUTH_SESSION_DESIGN_PRINCIPLES.md` |
| 6 | Universal Import | ✅ `UNIVERSAL_IMPORT_DESIGN_PRINCIPLES.md` |
| 7 | Dashboard Widgets | ✅ `DASHBOARD_WIDGETS_DESIGN_PRINCIPLES.md` |
| 8 | Navigation / IA | ✅ `NAVIGATION_IA_DESIGN_PRINCIPLES.md` |
| 9 | Migration & Deploy | ✅ `MIGRATION_DEPLOY_DESIGN_PRINCIPLES.md` |