- Introduced a new section for the Jinkendo Foundation, detailing design principles for the product family. - Updated README files to include references to the new design principles documentation. - Enhanced the overall documentation structure to improve navigation and accessibility of design resources. - Ensured consistency across documentation related to the Jinkendo Foundation and its principles.
18 KiB
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
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:
- Datenabruf — Lesen aus PostgreSQL (profile-scoped), optional mit Quality-Filter.
- Berechnung — Trends, Scores, Korrelationen, Aggregationen, Projektionen.
- Strukturierte Rückgabe — Dicts/Listen mit numerischen Werten, Datumsfeldern, Metadaten (
confidence,data_points). - 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:
-
Berechnungslogik in
placeholder_resolver.py— Phase-0b-Legacy; Resolver soll nur formatieren/aggregieren, nicht rechnen. -
Paralleler Roh-SQL-Kontext in
prompt_executor.execute_prompt_with_data— lädt Modul-Rohdaten per SQL, obwohl Layer 1 existiert; zweite Wahrheit. -
Legacy Insights-Pfad (
insights._prepare_template_vars) — eigene Variablen-Vorbereitung ohne Data Layer. -
Import mit fachlicher Interpretation — Apple-Schlaf-Aggregat und ähnliche Adapter verstecken Semantik im Ingest (Gitea #69).
-
Monolithische Router mit Inline-Berechnung — vor Phase 0c; gelegentlich noch Reste in nicht migrierten Pfaden.
-
Interpretation vermischt mit Layer 1 —
*_interpretation.pyliefert teils fertige Texte; für Familien-Architektur klar als Layer 2a/2b markieren oder auslagern. -
SQL-Duplikation in Chart-Payloads — manche Payload-Builder führen eigene Queries statt ausschließlich Layer-1-Ergebnisse zu visualisieren.
-
Hardcodierte Confidence global — funktioniert, aber nicht pro Metrik/Domäne konfigurierbar; Skalierung in Multi-Tenant-Produktfamilie prüfen.
-
Domänen-Module als Produktinhalt —
body_metrics, TDEE, WHR etc. sind Mitai-spezifisch; Schichtenmodell übernehmen, Formeln nicht blind kopieren. -
Fehlende runtime-Validierung des Return-Schemas —
confidence/data_pointsper Konvention, nicht per TypedDict/Pydantic erzwungen. -
Uneinheitliche Schreib-Orchestrierung — nur Activity hat
persistence_orchestrator; andere Domänen noch fragmentiert. -
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
- Extension Guide: DATA_LAYER_EXTENSION_GUIDE.md
- Fachliche Datenarchitektur: DATA_ARCHITECTURE.md
- Import-Grenze: ARCHITECTURE.md §8
- Platzhalter-Anbindung: PLACEHOLDER_REGISTRY_FRAMEWORK.md
- Prompt Engine (Konsument Layer 2a): PROMPT_ENGINE_DESIGN_PRINCIPLES.md
- Feature & Entitlement: 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 |