- .gitignore: .claude/docs, rules, commands tracken; settings.local weiter ignorieren - DOCUMENTATION.md: verbindliche Ablage functional/technical/working/issues - .claude/README.md: Agent-Einstieg; GITEA_ISSUES_INDEX aus MCP (Stand 2026-04-08) - Arbeitspapiere von docs/ nach .claude/docs/working/ verschoben - docs/MEMBERSHIP_SYSTEM.md als Stub; kanonisch technical/MEMBERSHIP_SYSTEM.md - CLAUDE.md Pflichtlektüre und Links angepasst; docs/README.md vereinfacht Made-with: Cursor
65 KiB
Phase 0b Placeholder Improvements & Missing Values
Status: 🔴 Draft - User Input in Progress Datum: 29.03.2026 Zweck: Sammlung fehlender Platzhalter und Verbesserungspotenziale nach Phase 0b
Executive Summary: Zwei Kritische Gaps (29.03.2026)
🚨 Gap #1: Quality Label wird nicht berücksichtigt
Activity Platzhalter berücksichtigen quality_label nicht!
- ❌ Alle activity-bezogenen Platzhalter nutzen ALLE Trainings (inkl. poor/excluded)
- ⚠️ Betroffene Platzhalter:
{{activity_summary}},{{activity_detail}},{{trainingstyp_verteilung}},{{training_minutes_week}},{{training_frequency_7d}},{{ability_balance_*}}, etc. - ✅ Einzige Ausnahme:
{{quality_sessions_pct}}(zählt nur excellent/good) - 🔧 Infrastruktur vorhanden:
quality_filter.pyexistiert bereits, wird aber NICHT genutzt
Auswirkung: Standard-Auswertungen in KI-Prompts zählen schlechte/ausgeschlossene Trainings mit → verfälschte Analysen!
Empfohlene Lösung:
- Quality-Filter in
data_layer/activity_metrics.pyeinbauen (6-8h) - Neue Platzhalter für Evaluation-Breakdown (3h)
- Quality-Weighted Metrics (2h) Teilsumme: 11-13h
🚨 Gap #2: Keine Trainingstyp-spezifischen Platzhalter
KI kann nicht nach Trainings-Kategorien differenzieren!
- ❌ Keine Kategorie-spezifischen Platzhalter (Kraft, Cardio, Kampfsport getrennt)
- ❌ Keine Subcategory-Differenzierung (Hypertrophie vs. Maximalkraft vs. Kraftausdauer)
- ❌ Keine Ruhepausen-Analyse nach Trainingstyp (48h zwischen Kraft-Einheiten?)
- ❌ Keine Muskelerhalt-Logik (mind. 2x/Woche Kraft?)
- ❌ Keine Balance-Analysen (Cardio:Kraft Ratio, fehlende Kategorien)
- ✅ Was existiert:
{{trainingstyp_verteilung}}(nur Top 3 Kategorien),{{ability_balance_*}}
Auswirkung: KI kann NICHT coachen zu:
- "Zu wenig Krafttraining für Muskelerhalt" (kein
{{strength_frequency}}) - "48h Pause zwischen Kraft-Einheiten" (kein
{{days_since_last_strength}}) - "Zu cardio-lastig, mehr Kraft empfohlen" (kein
{{cardio_to_strength_ratio}}) - "Kein Mobility-Training in 30 Tagen" (kein
{{missing_categories}})
Empfohlene Lösung:
- Kategorie-spezifische Count/Minutes Platzhalter (4-5h)
- Ruhepausen-Analyse nach Kategorie (3h)
- Balance-Scores & Ratios (2-3h)
- Subcategory-Analysen (2h) Teilsumme: 11-13h
GESAMT: 22-26h Implementierung für beide Gaps
0. Governance-Anforderungen & Fit/Gap-Analyse (User Requirements)
Quelle:
placeholder_requirements_for_development.md(29.03.2026) Zweck: Professionelle Placeholder-Governance für Prompt-Bibliothek V1
Governance-Prinzipien (verbindlich):
- Platzhalter = API-Verträge - keine Ad-hoc-Erfindungen in Prompts
- Keine stillschweigenden Änderungen - Semantik, Zeitfenster, Einheit stabil
- Fehlende Werte explizit -
nulloder strukturierter Status, nicht "nicht verfügbar" - Atomare Platzhalter bevorzugt - einzelne Felder statt Freitext-Blobs
- Zeitbezug immer eindeutig -
*_7d,*_28d,*_90dim Namen - JSON vor Freitext - strukturierte Objekte für komplexe Daten
- Verfügbarkeit trennen -
*_availableFlags für kritische Felder - Zwei-Stufen-Architektur - Komplexe Interpretationen via KI statt hardcodiert ⭐ NEU
Placeholder-Typen (Architektur):
Typ 1: Atomic Placeholders
- Direkt aus Daten (keine Interpretation)
- Beispiel:
{{weight_aktuell}},{{training_frequency_7d}} - Implementierung: Python-Funktion → direkter Wert
Typ 2: Raw Data Placeholders
- Strukturierte JSONs für KI-Input (keine Interpretation)
- Beispiel:
{{goal_priority_raw_data}},{{constraints_raw_data}} - Implementierung: Python aggregiert Rohdaten → JSON
- Verwendung: Input für Basis-Prompts
Typ 3: Interpreted Placeholders
- Von KI generiert (via Basis-Prompt)
- Beispiel:
{{goal_weighted_priority}},{{main_constraint}} - Implementierung: Basis-Prompt interpretiert Raw Data → strukturierter Output
- Verwendung: In übergeordneten Prompts
Priorisierte Anforderungen (Sprint 1-3):
Sprint 1 (Must-Have für V1): 10 Items (P1-P10 + strukturelle) Sprint 2 (Diagnose-Ebene): 7 Items (P21-P27) Sprint 3 (Verfeinerung): 6 Items (niedrigere Priorität)
0.1 Fit/Gap-Analyse: P1-P27 vs. Aktuelle Datenstruktur
✅ Vollständig möglich (mit aktueller Struktur):
P1. goal_summary_json ✅
- Datenquelle:
goalstable (Migration 022) - Struktur vorhanden: id, name, goal_type, status, start_value, target_value, current_value, progress_percentage, target_date, is_primary, focus_contributions
- Implementierung: Neue data_layer Funktion
get_goal_summary_data()→ JSON formatieren - Aufwand: 2h (Funktion + Platzhalter)
P2. focus_area_summary_json ✅
- Datenquelle:
focus_area_definitions+user_focus_area_weights+goal_focus_contributions - Struktur vorhanden: name, category, user_weight, goal_count, progress per focus area
- Implementierung: Neue data_layer Funktion
get_focus_area_summary_data() - Aufwand: 2h
P3-P4. *_score_available Flags ✅
- Datenquelle: Berechnete Scores
- Implementierung: Prüfen ob Score berechnet werden konnte (nicht None)
- Aufwand: 1h (alle Score-Platzhalter erweitern)
P5. domain_availability_json ✅
- Datenquelle: Alle Domain-Tabellen (weight_log, nutrition_log, activity_log, sleep_log, etc.)
- Berechnung:
{ "body": {"available": true, "confidence": "high", "last_entry": "2026-03-29", "days_coverage_28d": 25}, "nutrition": {"available": true, "confidence": "medium", "last_entry": "2026-03-28", "days_coverage_28d": 18}, "activity": {"available": true, "confidence": "high", "last_entry": "2026-03-29", "days_coverage_28d": 12}, "sleep": {"available": true, "confidence": "low", "last_entry": "2026-03-15", "days_coverage_28d": 8}, "vitals": {"available": true, "confidence": "medium", "last_entry": "2026-03-27", "days_coverage_28d": 15}, "goals": {"available": true, "confidence": "high", "active_goals": 3}, "focus_areas": {"available": true, "confidence": "high", "weighted_areas": 5} } - Implementierung: Neue Funktion
calculate_domain_availability() - Aufwand: 3-4h (alle Domains prüfen)
P8-P11. Body Change Availability Flags ✅
- Datenquelle:
weight_log,caliper_log,circumference_log - Implementierung: Prüfen ob genug Datenpunkte für Trend (mind. 2 Messungen, 28d Zeitfenster)
- Aufwand: 1h
P12. body_change_summary_json ✅
- Datenquelle: Phase 0c data_layer/body_metrics.py Funktionen
- Struktur:
{ "weight_trend_28d": {"delta_kg": -2.5, "slope": -0.089, "confidence": "high"}, "fm_change_28d": {"delta_kg": -3.1, "available": true, "confidence": "medium"}, "lbm_change_28d": {"delta_kg": 0.6, "available": true, "confidence": "medium"}, "waist_delta_28d": {"delta_cm": -2.5, "available": true}, "hip_delta_28d": {"delta_cm": -1.2, "available": true}, "waist_hip_ratio": 0.85, "recomposition_quadrant": "fat_loss_muscle_gain" } - Implementierung: Aggregation bestehender Funktionen
- Aufwand: 2h
P13. activity_structure_json ✅
- Datenquelle: Phase 0c data_layer/activity_metrics.py Funktionen
- Struktur:
{ "volume_weekly_min": 180, "frequency_7d": 4, "type_distribution": {"cardio": 45, "strength": 35, "mobility": 10, "recovery": 10}, "quality_sessions_pct": 75, "proxy_load_7d": 450, "monotony_score": 1.2, "strain_score": 540, "rest_day_compliance_pct": 85, "patterns": ["cardio-heavy", "good-recovery-compliance"] } - Implementierung: Aggregation bestehender Funktionen
- Aufwand: 2h
P16. sleep_summary_json ✅
- Datenquelle:
sleep_log(Migration 009), Phase 0c recovery_metrics.py - Struktur vorhanden: duration, segments (deep, rem, light, awake)
- Implementierung: Neue Funktion
get_sleep_summary_data() - Aufwand: 2h
P17. recovery_summary_json ✅
- Datenquelle:
vitals_baseline(RHR, HRV),sleep_log,rest_days,activity_log(load) - Struktur:
{ "recovery_score": 75, "main_drivers": ["good_sleep", "hrv_above_baseline"], "rhr_status": "normal", "hrv_status": "above_baseline", "hrv_vs_baseline_pct": 5.2, "rhr_vs_baseline_pct": -3.1, "recent_load_interaction": "balanced", "confidence": "high" } - Implementierung: Aggregation bestehender recovery_metrics Funktionen
- Aufwand: 3h
P18. vitals_summary_json ✅
- Datenquelle:
vitals_baseline(Migration 015) - Struktur vorhanden: resting_hr, hrv, vo2_max, spo2, respiratory_rate
- Implementierung: Neue Funktion
get_vitals_summary_data() - Aufwand: 1-2h
P19-P20. HRV/RHR Availability Flags ✅
- Datenquelle:
vitals_baseline - Implementierung: Prüfen ob Baseline berechnet werden kann (mind. 7 Messungen)
- Aufwand: 30min
P21. correlation_summary_json ✅
- Datenquelle: Phase 0c correlations.py Funktionen
- Struktur:
{ "energy_weight_lag": {"best_lag_days": 7, "correlation": 0.68, "confidence": "high"}, "protein_lbm": {"correlation": 0.52, "confidence": "medium"}, "load_hrv_lag": {"best_lag_days": 3, "correlation": -0.45, "confidence": "medium"}, "load_rhr_lag": {"best_lag_days": 2, "correlation": 0.38, "confidence": "low"}, "sleep_recovery": {"correlation": 0.61, "confidence": "high"} } - Implementierung: Aggregation bestehender Korrelationsfunktionen
- Aufwand: 2h
P22-P24. Plateau & Drivers ✅
- Datenquelle: Phase 0c correlations.py (
detect_plateau_periods(),identify_top_drivers()) - Struktur:
{ "plateau_status": "likely", # likely / possible / not_detected / insufficient_data "plateau_detected_at": "2026-03-15", "plateau_duration_days": 14, "top_drivers_positive": [ {"driver": "protein_adequacy", "impact_score": 0.72}, {"driver": "sleep_quality", "impact_score": 0.65} ], "top_drivers_negative": [ {"driver": "training_monotony", "impact_score": -0.58}, {"driver": "insufficient_strength_volume", "impact_score": -0.42} ], "confidence": "medium" } - Implementierung: Wrapper um bestehende Funktionen + Klassifikation
- Aufwand: 2-3h
P25-P27. Underfueling Risk ✅
- Datenquelle:
nutrition_log(kcal),activity_log(kcal_active),weight_log(trend) - Berechnung:
# Energy Availability = (intake - training_expenditure) / lean_body_mass # RED-S Risk: EA < 30 kcal/kg LBM/day { "underfueling_risk_flag": true, "underfueling_risk_reason": "ea_below_threshold", "energy_availability_summary": { "intake_avg_7d": 1800, "training_expenditure_avg_7d": 600, "net_availability": 1200, "ea_per_kg_lbm": 25.5, # kcal/kg/day "deficit_magnitude": "moderate", "load_context": "high", "recovery_context": "impaired", "warning_level": "high", "confidence": "medium" } } - Implementierung: Neue Funktion
calculate_energy_availability() - Aufwand: 3-4h (RED-S Logik komplex)
⚠️ Teilweise möglich (braucht Erweiterung):
P7. critical_missing_fields_json ⚠️
- Problem: Braucht Meta-Tracking welche Felder wann erfasst wurden
- Was fehlt: Keine Tabelle die "expected fields" vs. "captured fields" trackt
- Lösung: Heuristik basierend auf entry counts pro Domain
- Beispiel:
{ "critical_missing": [ {"field": "body_fat_measurements", "last_entry": "2026-02-15", "days_ago": 42, "impact": "high"}, {"field": "hrv_measurements", "last_entry": null, "days_ago": null, "impact": "medium"}, {"field": "sleep_tracking", "coverage_28d": 8, "expected": 28, "impact": "medium"} ], "recommendation_priority": ["body_fat_measurements", "hrv_measurements", "sleep_tracking"] } - Aufwand: 3h (Heuristik-Logik)
P14. training_quality_score ⚠️
- Was existiert:
quality_labelper Activity,quality_sessions_pctPlatzhalter - Was fehlt: Aggregierter Quality-Score über alle Sessions (gewichtet)
- Berechnung:
# Weighted average: excellent=100, good=80, acceptable=60, poor=30, excluded=0 quality_score = sum(quality_weight × duration) / total_duration - Aufwand: 1h
P15. load_balance_class ⚠️
- Was existiert:
proxy_internal_load_7dPlatzhalter - Was fehlt: Klassifikation in low/moderate/high/strained
- Berechnung:
if load < 300: "low" elif load < 600: "moderate" elif load < 900: "high" else: "strained" - Aufwand: 30min
✅ Möglich mit Zwei-Stufen-Architektur (Data + KI Interpretation):
P31. goal_weighted_priority ✅ (2-Stufen)
- Was existiert: Goals + Focus Areas + Priorisierungssystem
- Architektur:
- Stufe 1 (Data Layer):
get_goal_priority_raw_data()→ strukturiertes JSON{ "goals": [ { "id": 1, "name": "Gewichtsverlust 85kg", "progress_pct": 42, "behind_schedule_days": 5, "focus_contributions": [ {"focus_area": "Körpergewicht", "weight": 40} ], "total_focus_weight": 75 } ], "focus_area_weights": {"Körper": 75, "Aktivität": 20}, "context": {...} } - Stufe 2 (KI-Prompt): Basis-Prompt "Goal Priority Interpreter" interpretiert Rohdaten
- Input:
{{goal_priority_raw_data}} - Output:
{{goal_weighted_priority}}(strukturiertes JSON mit Prioritäten + Rationale)
- Input:
- Stufe 1 (Data Layer):
- Aufwand: 3h (2h Data Layer + 1h Basis-Prompt)
P32. main_constraint ✅ (2-Stufen)
- Was existiert: Activity patterns, frequency, gaps
- Architektur:
- Stufe 1:
get_constraints_raw_data()→ JSON{ "time_budget": { "avg_sessions_per_week": 3.2, "longest_gap_days": 4, "typical_session_duration_min": 45 }, "activity_patterns": { "weekday_sessions": 2.5, "weekend_sessions": 0.7 }, "missing_categories": ["mobility", "recovery"], "data_gaps": {...} } - Stufe 2: Basis-Prompt "Constraint Identifier"
- Input:
{{constraints_raw_data}} - Output:
{{main_constraint}}(Haupteinschränkung + Typ)
- Input:
- Stufe 1:
- Aufwand: 2-3h (2h Data Layer + 1h Basis-Prompt)
P33. main_strength ✅ (2-Stufen)
- Was existiert: Tracking compliance, consistency scores, quality metrics
- Architektur:
- Stufe 1:
get_strengths_raw_data()→ JSON{ "tracking_compliance": { "weight_entries_28d": 28, "nutrition_entries_28d": 26, "activity_entries_28d": 12 }, "consistency_scores": { "macro_consistency": 85, "training_frequency_stability": 92 }, "quality_metrics": { "quality_sessions_pct": 78, "sleep_regularity": 0.85 }, "standout_values": [ {"metric": "protein_adequacy", "value": 95, "percentile": "top_10"} ] } - Stufe 2: Basis-Prompt "Strength Identifier"
- Input:
{{strengths_raw_data}} - Output:
{{main_strength}}(Hauptstärke + Begründung)
- Input:
- Stufe 1:
- Aufwand: 2-3h (2h Data Layer + 1h Basis-Prompt)
P34. next_best_actions ⚠️ (2-Stufen, teilweise)
- Was existiert: Gaps, low scores, fehlende Kategorien
- Architektur:
- Stufe 1:
get_improvement_opportunities_raw_data()→ JSON{ "gaps": [ {"domain": "activity", "gap": "no_strength_training_7d", "severity": "high"}, {"domain": "nutrition", "gap": "protein_below_target", "severity": "medium"} ], "low_scores": [ {"metric": "mobility_sessions_28d", "value": 0, "target": 4} ], "quick_wins": [ {"opportunity": "add_1_strength_session", "effort": "low", "expected_impact": "medium"} ], "high_impact": [ {"opportunity": "increase_protein_20g", "effort": "medium", "expected_impact": "high"} ] } - Stufe 2: Basis-Prompt "Action Recommender"
- Input:
{{improvement_opportunities_raw_data}} - Output:
{{next_best_actions}}(Top 3 Actions mit Begründung)
- Input:
- Stufe 1:
- Problem: Braucht domänenspezifisches Wissen (z.B. welche Proteinmenge sinnvoll)
- Aufwand: 3-5h (3h Data Layer + 2h Basis-Prompt mit Domänen-Wissen)
❌ Nicht möglich / Redundant:
P6. domain_confidence_json ❌ REDUNDANT
- Problem: Überschneidung mit P5
domain_availability_json - Lösung: In P5 integrieren (bereits confidence per domain)
- Aufwand: 0h
P30. blood_pressure_summary_json ⚠️ OPTIONAL (Sprint 3)
- Was existiert:
blood_pressure_logtable (Migration 015) - Was fehlt: Aggregationsfunktion für BP summary
- Berechnung:
{ "mean_systolic_28d": 125, "mean_diastolic_28d": 82, "category": "elevated", # WHO/ISH classification "contexts": {"nüchtern": 15, "nach_essen": 8, "nach_training": 5}, "trend_28d": "stable", "irregularity_count": 2, "afib_detected": false, "confidence": "high" } - Aufwand: 2h (neue data_layer Funktion)
- Empfehlung: Sprint 3 (niedrigere Priorität als P31-P34)
📊 Zusammenfassung Fit/Gap (aktualisiert):
| Kategorie | Anzahl | Aufwand | Details |
|---|---|---|---|
| ✅ Vollständig möglich (direkt) | 20 Items | 35-40h | P1-P5, P8-P13, P16-P27 |
| ✅ Möglich (2-Stufen-Architektur) | 4 Items | 10-14h | P31-P34 (Data Layer + KI) |
| ⚠️ Teilweise möglich | 3 Items | 4-5h | P7, P14, P15 |
| ❌ Redundant / Optional | 2 Items | 2h | P6 (redundant), P30 (optional) |
| TOTAL MÖGLICH | 27 Items | 49-59h | Alle User Requirements umsetzbar! |
Architektur-Verbesserung durch 2-Stufen-Ansatz:
- ✅ P31-P34 von "nicht möglich" → "möglich" durch intelligente Architektur
- ✅ Gleicher Aufwand wie ursprünglich geschätzt (10-14h)
- ✅ Bessere Qualität: Flexibler, wartbarer, erweiterbarer
- ✅ Nutzt bestehendes System: Unified Prompt System + Basis-Prompts
0.2 Governance-Implementierung
Konkrete Maßnahmen für Governance-Regeln:
G1-G2: API-Stabilität & Keine Semantikänderungen
Maßnahme: Placeholder Versioning System einführen
PLACEHOLDER_MAP_V1 = {
'{{weight_aktuell}}': {
'resolver': get_latest_weight,
'version': '1.0.0',
'semantic': 'latest weight entry, no averaging',
'unit': 'kg',
'timeframe': 'latest',
'fallback': 'nicht verfügbar'
},
# ...
}
Aufwand: 3h (Metadata-System + alle Platzhalter dokumentieren)
G3: Fehlende Werte explizit
Maßnahme 1: Alle "nicht verfügbar" Strings durch null ersetzen
Maßnahme 2: Neue Platzhalter mit *_available Flags
'{{goal_progress_score}}': 75,
'{{goal_progress_score_available}}': true,
'{{goal_progress_score_reason}}': null # or "insufficient_goals"
Aufwand: 2h (alle betroffenen Platzhalter umstellen)
G4: JSON vor Freitext
Maßnahme: Alle Summary-Felder erhalten strukturierte JSON-Pendants
{{activity_summary}}bleibt → +{{activity_structure_json}}{{caliper_summary}}bleibt → +{{body_change_summary_json}}Aufwand: Bereits in P1-P27 enthalten
G5: Zeitfenster im Namen
Maßnahme: Alle zeitabhängigen Platzhalter prüfen und ggf. umbenennen
# ❌ Unklar:
'{{weight_trend}}' # 7d? 28d? 90d?
# ✅ Klar:
'{{weight_trend_28d}}'
'{{weight_slope_28d}}'
Aufwand: 2h (Audit + Renaming + Migration)
G6: Verfügbarkeit trennen
Maßnahme: Systematisch alle kritischen Platzhalter mit Flags ergänzen
- Body:
{{fm_28d_change_available}},{{lbm_28d_change_available}}, etc. - Vitals:
{{hrv_vs_baseline_available}},{{rhr_vs_baseline_available}} - Goals:
{{goal_progress_score_available}}Aufwand: Bereits in P3-P4, P8-P11, P19-P20 enthalten
G7: Keine Ad-hoc-Platzhalter
Maßnahme: Placeholder Approval Process einführen
- Neuer Platzhalter → Request in PHASE_0B_IMPROVEMENTS.md
- Bewertung gegen Governance-Regeln
- Implementierung nur nach Approval
- Dokumentation in placeholder_catalog aktualisieren Aufwand: 1h (Process-Dokumentation)
G8: Zwei-Stufen-Architektur für komplexe Interpretationen ⭐ NEU
Maßnahme: Komplexe Logik NICHT hardcoded, sondern via KI-Interpretation
Wann Zwei-Stufen-Ansatz nutzen:
- Interpretation braucht Kontext-Verständnis
- Logik ist nicht eindeutig regelbasiert
- Flexibilität wichtiger als Performance
- Domänen-Wissen erforderlich
Implementierungs-Pattern:
- Data Layer:
get_<topic>_raw_data()→ strukturiertes JSON (Typ 2 Placeholder) - Basis-Prompt: Interpretiert Rohdaten → strukturierter Output (Typ 3 Placeholder)
- Verwendung: Übergeordnete Prompts nutzen Typ 3 Placeholder
Beispiel:
# Data Layer (Python)
def get_goal_priority_raw_data(profile_id):
return {
"goals": [...],
"focus_weights": {...},
"context": {...}
}
# Platzhalter Typ 2 (Raw Data)
'{{goal_priority_raw_data}}': lambda pid: json.dumps(get_goal_priority_raw_data(pid))
# Basis-Prompt (KI)
Name: "Goal Priority Interpreter"
Input: {{goal_priority_raw_data}}
Output: JSON mit priority_ranking
# Platzhalter Typ 3 (Interpreted)
'{{goal_weighted_priority}}': <von KI generiert via Basis-Prompt>
Aufwand: 0h (bereits in P31-P34 enthalten)
Vorteile:
- ✅ Flexibler: Prompt-Änderung ohne Code-Deploy
- ✅ Wartbarer: Klare Trennung Data vs. Interpretation
- ✅ Erweiterbarer: Gleiche Rohdaten für mehrere Prompts nutzbar
- ✅ Testbarer: Rohdaten-Struktur separat testbar
0.3 Sprint-Planung (User Requirements integriert)
Sprint 1: Must-Have für V1 (20 Items, 35-40h)
Governance & Infrastructure (8h):
- Placeholder Versioning System (3h)
- "nicht verfügbar" → null Migration (2h)
- Zeitfenster-Audit & Renaming (2h)
- Approval Process Dokumentation (1h)
Strukturierte JSONs (15-18h):
- P1: goal_summary_json (2h)
- P2: focus_area_summary_json (2h)
- P5: domain_availability_json (3-4h)
- P12: body_change_summary_json (2h)
- P13: activity_structure_json (2h)
- P16: sleep_summary_json (2h)
- P17: recovery_summary_json (3h)
- P18: vitals_summary_json (1-2h)
Availability Flags (3h):
- P3-P4: Score availability flags (1h)
- P8-P11: Body change availability (1h)
- P19-P20: HRV/RHR availability (30min)
- P7: critical_missing_fields_json (3h) - teilweise
Diagnose & Correlation (5-6h):
- P21: correlation_summary_json (2h)
- P22-P24: plateau_status + drivers (2-3h)
- P14: training_quality_score (1h) - teilweise
- P15: load_balance_class (30min) - teilweise
Energy Availability (3-4h):
- P25-P27: underfueling risk + energy_availability_summary (3-4h)
Sprint 1 Gesamt: 34-41h
Sprint 2: Quality Label + Training Categories (16-19h + 10-13h = 26-32h)
Quality Label Gap (bereits definiert in Sektion 7):
- Quality-Filter in activity_metrics.py (6-8h)
- Evaluation-Breakdown (1h)
- Placeholder-Updates (2h)
- Dedizierte Quality-Platzhalter (2h)
- Poor Sessions Warning (1h)
Training Categories Gap (bereits definiert in Sektion 7):
- Category-Specific Metrics (2h)
- Kategorie-spezifische Platzhalter (3h)
- Days Since Last Training (2h)
- Training Balance Calculator (2-3h)
- Weitere Kategorie-Platzhalter (2h)
- Subcategory Distribution (3h)
Sprint 2 Gesamt: 26-32h
Sprint 3: Zwei-Stufen-Platzhalter + Optional (10-16h)
P31-P34: Zwei-Stufen-Architektur (10-14h):
- P31: goal_weighted_priority (3h) - Data Layer + Basis-Prompt
- P32: main_constraint (2-3h) - Data Layer + Basis-Prompt
- P33: main_strength (2-3h) - Data Layer + Basis-Prompt
- P34: next_best_actions (3-5h) - Data Layer + Basis-Prompt (komplex)
Optional (falls gewünscht, 2h):
- P30: blood_pressure_summary_json (2h)
Sprint 3 Gesamt: 12-16h
Besonderheit Sprint 3:
- Nutzt Unified Prompt System für KI-Interpretation
- Basis-Prompts sind wiederverwendbar
- Flexibler als hardcodierte Logik
- Kann iterativ verfeinert werden (Prompt-Änderung ohne Code-Deploy)
Gesamtaufwand (alle 3 Sprints):
| Sprint | Inhalt | Aufwand |
|---|---|---|
| Sprint 1 | User Requirements P1-P27 + Governance | 34-41h |
| Sprint 2 | Quality Label + Training Categories | 26-32h |
| Sprint 3 | Blood Pressure + Goal-Weighted (optional) | 12-16h |
| TOTAL | Alle Requirements + Beide Gaps | 72-89h |
1. Fehlende Platzhalter
Kategorie: Körper (Body Metrics)
{{placeholder_name}}
- Zweck: Wofür wird der Wert benötigt?
- Datenquelle: Tabelle/Funktion (z.B.
weight_log,body_metrics.py) - Berechnung: Wie soll er ermittelt werden?
- Format: Beispiel-Output (z.B. "4.5 kg", "85%", "nicht verfügbar")
- Use Case: In welchem Prompt wird das benötigt?
Kategorie: Ernährung (Nutrition)
{{placeholder_name}}
- Zweck:
- Datenquelle:
- Berechnung:
- Format:
- Use Case:
Kategorie: Training / Aktivität
{{activity_summary_acceptable_plus}}
- Zweck: Aktivitäts-Zusammenfassung nur mit mindestens "acceptable" Qualität
- Datenquelle:
activity_logWHERE quality_label IN ('excellent', 'good', 'acceptable') - Berechnung: Wie aktuelles
{{activity_summary}}, aber mit quality_filter - Format: "8 Einheiten in 14 Tagen (Ø 45 min/Einheit, 2400 kcal gesamt)"
- Use Case: Standard-Auswertungen, die nur valide Trainings berücksichtigen
{{activity_summary_excellent}}
- Zweck: Aktivitäts-Zusammenfassung nur mit "excellent" Qualität
- Datenquelle:
activity_logWHERE quality_label = 'excellent' - Berechnung: Wie aktuelles
{{activity_summary}}, aber nur excellent - Format: "3 Einheiten in 14 Tagen (Ø 60 min/Einheit, 1200 kcal gesamt)"
- Use Case: Analyse von Top-Trainings, Benchmark für Qualität
{{poor_sessions_count}}
- Zweck: Anzahl schlechter/ausgeschlossener Trainings
- Datenquelle:
activity_logWHERE quality_label IN ('poor', 'excluded') - Berechnung: COUNT(*) der poor/excluded sessions (7d oder 28d)
- Format: "2 Sessions" oder "keine schlechten Sessions"
- Use Case: Warnung bei zu vielen schlechten Trainings
{{evaluation_breakdown}}
- Zweck: Verteilung der Trainings nach Evaluation-Stufen
- Datenquelle:
activity_logGROUP BY quality_label - Berechnung: COUNT(*) pro quality_label mit Prozentangaben
- Format: "Excellent: 3 (25%), Good: 5 (42%), Acceptable: 3 (25%), Poor: 1 (8%)"
- Use Case: Qualitäts-Übersicht in Coaching-Prompts
{{training_minutes_quality}}
- Zweck: Trainingsminuten nur mit acceptable+ Qualität
- Datenquelle:
activity_logWHERE quality_label IN ('excellent', 'good', 'acceptable') - Berechnung: SUM(duration_min) mit quality_filter (7d)
- Format: "180 Minuten" (nur valide Trainings)
- Use Case: WHO-Empfehlung Vergleich (150-300 min/Woche)
Kategorie: Training / Aktivität - Trainingstyp-spezifisch ⚠️ NEU
{{strength_training_count_7d}}
- Zweck: Anzahl Krafttrainings in letzten 7 Tagen
- Datenquelle:
activity_logWHERE training_category = 'strength' - Berechnung: COUNT(*) mit quality='quality' filter (7d)
- Format: "3 Einheiten" oder "keine Krafttrainings"
- Use Case: Muskelerhalt-Check (mind. 2x/Woche empfohlen)
{{strength_training_minutes_7d}}
- Zweck: Trainingsminuten Kraft in letzten 7 Tagen
- Datenquelle:
activity_logWHERE training_category = 'strength' - Berechnung: SUM(duration_min) mit quality='quality' filter (7d)
- Format: "135 Minuten" oder "0 Minuten Krafttraining"
- Use Case: Volumen-Check für Muskelerhalt
{{cardio_training_count_7d}}
- Zweck: Anzahl Cardio-Trainings in letzten 7 Tagen
- Datenquelle:
activity_logWHERE training_category = 'cardio' - Berechnung: COUNT(*) mit quality='quality' filter (7d)
- Format: "4 Einheiten"
- Use Case: WHO-Empfehlung (3-5x/Woche Cardio)
{{cardio_training_minutes_7d}}
- Zweck: Trainingsminuten Cardio in letzten 7 Tagen
- Datenquelle:
activity_logWHERE training_category = 'cardio' - Berechnung: SUM(duration_min) mit quality='quality' filter (7d)
- Format: "180 Minuten"
- Use Case: WHO-Empfehlung (150-300 min/Woche)
{{martial_arts_frequency_28d}}
- Zweck: Kampfsport-Frequenz (Sessions/Woche durchschnittlich über 28d)
- Datenquelle:
activity_logWHERE training_category = 'martial_arts' - Berechnung: COUNT(*) / 4 Wochen
- Format: "2.5 Einheiten/Woche" oder "kein Kampfsport in 28 Tagen"
- Use Case: Kampfsport-spezifisches Coaching
{{recovery_sessions_count_28d}}
- Zweck: Anzahl aktiver Erholungseinheiten
- Datenquelle:
activity_logWHERE training_category = 'recovery' - Berechnung: COUNT(*) (28d)
- Format: "3 Erholungseinheiten"
- Use Case: Regenerations-Balance prüfen
{{mobility_sessions_count_28d}}
- Zweck: Anzahl Mobility/Dehnung Sessions
- Datenquelle:
activity_logWHERE training_category = 'mobility' - Berechnung: COUNT(*) (28d)
- Format: "2 Mobility-Einheiten" oder "keine Mobility-Trainings"
- Use Case: Mobility-Warnung bei 0 Sessions
{{days_since_last_strength}}
- Zweck: Tage seit letzter Krafteinheit
- Datenquelle:
activity_logWHERE training_category = 'strength' - Berechnung: CURRENT_DATE - MAX(date)
- Format: "2 Tage" oder ">7 Tage (kritisch!)"
- Use Case: Ruhepausen-Check / Muskelerhalt-Warnung
{{days_since_last_cardio}}
- Zweck: Tage seit letzter Cardio-Einheit
- Datenquelle:
activity_logWHERE training_category = 'cardio' - Berechnung: CURRENT_DATE - MAX(date)
- Format: "1 Tag" oder ">5 Tage"
- Use Case: Ausdauer-Kontinuität prüfen
{{days_since_last_martial_arts}}
- Zweck: Tage seit letzter Kampfsport-Einheit
- Datenquelle:
activity_logWHERE training_category = 'martial_arts' - Berechnung: CURRENT_DATE - MAX(date)
- Format: "3 Tage" oder ">14 Tage"
- Use Case: Technik-Kontinuität prüfen
{{cardio_to_strength_ratio}}
- Zweck: Verhältnis Cardio zu Kraft (Minuten-basiert, 28d)
- Datenquelle:
activity_logWHERE training_category IN ('cardio', 'strength') - Berechnung: cardio_minutes / strength_minutes
- Format: "3:1 (cardio-lastig)" oder "1:2 (kraft-lastig)" oder "balanced"
- Use Case: Balance-Coaching
{{training_balance_score}}
- Zweck: Balance-Score 0-100 basierend auf Kategorie-Verteilung
- Datenquelle:
activity_log(alle Kategorien) - Berechnung: Score = 100 - std_dev(category_percentages) × 2
- Format: "75" (Zahl 0-100)
- Use Case: Gesamtbalance bewerten
{{missing_training_categories}}
- Zweck: Liste fehlender Trainings-Kategorien (28d)
- Datenquelle:
activity_log(alle Kategorien) - Berechnung: Vergleich [cardio, strength, mobility, recovery] mit tatsächlichen
- Format: "Fehlt: Mobility, Recovery" oder "Alle Kategorien abgedeckt"
- Use Case: Lücken-Identifikation
{{strength_frequency_adequate}}
- Zweck: Ja/Nein Check für Muskelerhalt (mind. 2x/Woche Kraft)
- Datenquelle:
activity_logWHERE training_category = 'strength' - Berechnung: COUNT(*) >= 2 in 7d?
- Format: "Ja" oder "Nein (nur 1x Kraft/Woche - Risiko Muskelabbau)"
- Use Case: Direkter Muskelerhalt-Check
{{muscle_preservation_risk}}
- Zweck: Warnung bei zu wenig Krafttraining
- Datenquelle:
activity_logWHERE training_category = 'strength' - Berechnung: IF strength_count_7d < 2 THEN "Risiko: nur Xx Kraft"
- Format: "Kein Risiko" oder "Risiko: nur 1x Kraft in 7d"
- Use Case: Explizite Warnung für KI-Prompt
{{strength_type_distribution}}
- Zweck: Verteilung innerhalb Krafttraining (Subcategories)
- Datenquelle:
activity_logJOINtraining_typesWHERE category = 'strength' - Berechnung: COUNT(*) per subcategory (hypertrophy, maxstrength, endurance)
- Format: "Hypertrophie: 60%, Maximalkraft: 30%, Kraftausdauer: 10%"
- Use Case: Periodisierungs-Analyse
{{hypertrophy_vs_maxstrength_ratio}}
- Zweck: Verhältnis Hypertrophie zu Maximalkraft
- Datenquelle:
activity_logWHERE subcategory IN ('hypertrophy', 'maxstrength') - Berechnung: hypertrophy_count / maxstrength_count (28d)
- Format: "3:1" oder "nur Hypertrophie" oder "nur Maximalkraft"
- Use Case: Kraft-Periodisierungs-Check
{{technique_vs_sparring_balance}}
- Zweck: Technik vs. Kampf im Kampfsport (Subcategories)
- Datenquelle:
activity_logWHERE subcategory IN ('technique', 'sparring') - Berechnung: Verhältnis technique / sparring (28d)
- Format: "2:1 (technik-lastig)" oder "balanced"
- Use Case: Kampfsport-spezifisches Coaching
Kategorie: Erholung / Vitalwerte
{{placeholder_name}}
- Zweck:
- Datenquelle:
- Berechnung:
- Format:
- Use Case:
Kategorie: Ziele (Goals)
{{placeholder_name}}
- Zweck:
- Datenquelle:
- Berechnung:
- Format:
- Use Case:
Kategorie: Korrelationen
{{placeholder_name}}
- Zweck:
- Datenquelle:
- Berechnung:
- Format:
- Use Case:
2. Verbesserungspotenziale bei existierenden Platzhaltern
{{activity_summary}} ⚠️ KRITISCH
- Aktuelles Verhalten: Zeigt ALLE Aktivitäten ohne Rücksicht auf quality_label
- Problem: Schlechte/ausgeschlossene Trainings werden mitgezählt → verfälscht Auswertungen
- Vorschlag:
- Option A: Default auf quality='acceptable_plus' ändern (Breaking Change)
- Option B: Neuen Parameter
quality_levelhinzufügen, default='all' (Non-Breaking) - Option C: Neuer Platzhalter
{{activity_summary_quality}}, alter bleibt (Redundanz)
- Breaking Change: Ja (Option A), Nein (Option B+C)
- Use Case: ALLE Standard-Coaching-Prompts sollten nur valide Trainings nutzen
{{activity_detail}} ⚠️ KRITISCH
- Aktuelles Verhalten: Listet ALLE Aktivitäten ohne quality_label Berücksichtigung
- Problem: Schlechte Trainings erscheinen in Detail-Liste ohne Kennzeichnung
- Vorschlag:
- Entweder quality_filter hinzufügen (nur acceptable+)
- Oder quality_label als Badge in Output aufnehmen: "30.03. Laufen (60 min) [excellent]"
- Breaking Change: Teilweise (Format-Änderung)
- Use Case: Detail-Analyse sollte Qualität pro Training zeigen
{{trainingstyp_verteilung}} ⚠️
- Aktuelles Verhalten: Zeigt Verteilung ALLER Trainingstypen
- Problem: Schlechte Sessions werden in Kategorie-Statistik mitgezählt
- Vorschlag: quality_filter auf acceptable+ anwenden
- Breaking Change: Ja (Zahlen ändern sich)
- Use Case: Verteilung sollte nur valide Trainings zeigen
{{training_minutes_week}} ⚠️
- Aktuelles Verhalten: Summiert ALLE Trainingsminuten
- Problem: Schlechte Trainings werden voll gezählt
- Vorschlag:
- Nur acceptable+ Trainings zählen
- Oder: quality_weighted sum (excellent=1.0, good=0.95, acceptable=0.85, poor=0.5)
- Breaking Change: Ja
- Use Case: WHO-Empfehlung sollte nur valide Minuten berücksichtigen
{{training_frequency_7d}} ⚠️
- Aktuelles Verhalten: Zählt ALLE Sessions
- Problem: Poor/excluded sessions werden mitgezählt
- Vorschlag: Nur acceptable+ Sessions zählen
- Breaking Change: Ja
- Use Case: Frequenz-Statistik sollte nur valide Trainings zählen
{{ability_balance_*}} ⚠️
- Aktuelles Verhalten: Berechnet Balance aus ALLEN Activities
- Problem: Schlechte Trainings beeinflussen Ability-Balance
- Vorschlag: Nur acceptable+ Activities für Berechnung nutzen
- Breaking Change: Ja (Balance-Scores ändern sich)
- Use Case: Balance-Berechnung sollte nur valide Trainings nutzen
{{proxy_internal_load_7d}} ℹ️ TEILWEISE KORREKT
- Aktuelles Verhalten: Nutzt quality_label als Gewichtungsfaktor (excellent=1.15, poor=0.75)
- Problem: Lädt ALLE Activities, gewichtet sie dann runter - aber poor sollte gar nicht gezählt werden
- Vorschlag: Filter auf acceptable+ PLUS quality-Gewichtung
- Breaking Change: Teilweise
- Use Case: Load-Monitoring sollte nur valide Trainings berücksichtigen
3. Neue Berechnungslogik / Funktionen
Feature: Quality-Aware Activity Metrics
- Beschreibung: Alle activity_metrics Funktionen erhalten quality_level Parameter
- Input:
profile_id: strdays: intquality_level: str = 'quality'(new parameter)
- Output: Wie bisher, aber gefiltert nach quality_level
- Algorithmus:
from quality_filter import get_quality_filter_sql def get_activity_summary_data(profile_id, days=14, quality_level='quality'): profile = get_profile_data(profile_id) profile['quality_filter_level'] = quality_level quality_sql = get_quality_filter_sql(profile) # Returns "AND quality_label IN (...)" query = f""" SELECT COUNT(*) as count, ... FROM activity_log WHERE profile_id=%s AND date >= %s {quality_sql} """ - Modul:
backend/data_layer/activity_metrics.py(alle Funktionen) - Dependencies:
quality_filter.py(bereits vorhanden)get_profile_data()für quality_filter_level
Feature: Evaluation Breakdown Calculator
- Beschreibung: Berechnet Verteilung nach quality_label für Zeitraum
- Input:
profile_id: str,days: int = 28 - Output:
{ "excellent": {"count": 3, "percentage": 25, "minutes": 180}, "good": {"count": 5, "percentage": 42, "minutes": 225}, "acceptable": {"count": 3, "percentage": 25, "minutes": 90}, "poor": {"count": 1, "percentage": 8, "minutes": 30}, "excluded": {"count": 0, "percentage": 0, "minutes": 0}, "total": 12, "confidence": "high" } - Algorithmus:
SELECT quality_label, COUNT(*) as count, SUM(duration_min) as minutes FROM activity_log WHERE profile_id = %s AND date >= CURRENT_DATE - INTERVAL '%s days' GROUP BY quality_label - Modul:
backend/data_layer/activity_metrics.py(neue Funktion) - Dependencies: Keine
Feature: Category-Specific Activity Metrics
- Beschreibung: Count/Minutes pro Trainings-Kategorie
- Input:
profile_id: str,category: str,days: int = 7,quality_level: str = 'quality' - Output:
{ "category": "strength", "count": 3, "total_minutes": 135, "avg_minutes_per_session": 45, "sessions_per_week": 3.0, "percentage_of_total": 35.0, # 35% aller Trainings "confidence": "high", "days_analyzed": 7 } - Algorithmus:
def get_category_activity_data(profile_id, category, days=7, quality_level='quality'): profile = get_profile_data(profile_id) profile['quality_filter_level'] = quality_level quality_sql = get_quality_filter_sql(profile) query = f""" SELECT COUNT(*) as count, SUM(duration_min) as total_minutes FROM activity_log WHERE profile_id = %s AND training_category = %s AND date >= CURRENT_DATE - INTERVAL '%s days' {quality_sql} """ # Calculate derived metrics... - Modul:
backend/data_layer/activity_metrics.py(neue Funktion) - Dependencies: quality_filter.py
Feature: Days Since Last Training (per Category)
- Beschreibung: Tage seit letzter Einheit einer bestimmten Kategorie
- Input:
profile_id: str,category: str,quality_level: str = 'quality' - Output:
{ "category": "strength", "days_since_last": 2, "last_date": "2026-03-27", "status": "ok", # ok / warning / critical "recommendation": "Nächste Einheit in 1-2 Tagen empfohlen", "confidence": "high" } - Algorithmus:
SELECT MAX(date) as last_date FROM activity_log WHERE profile_id = %s AND training_category = %s AND quality_label IN ('excellent', 'good', 'acceptable')days_since = (datetime.now().date() - last_date).days # Status logic (category-specific thresholds) if category == 'strength': status = 'critical' if days_since > 7 else 'warning' if days_since > 3 else 'ok' elif category == 'cardio': status = 'critical' if days_since > 5 else 'warning' if days_since > 2 else 'ok' # etc. - Modul:
backend/data_layer/activity_metrics.py(neue Funktion) - Dependencies: quality_filter.py
Feature: Training Category Balance Calculator
- Beschreibung: Berechnet Balance-Score basierend auf Verteilung
- Input:
profile_id: str,days: int = 28 - Output:
{ "balance_score": 75, # 0-100 "cardio_pct": 45, "strength_pct": 35, "mobility_pct": 10, "recovery_pct": 5, "martial_arts_pct": 5, "missing_categories": ["hiit"], "recommendation": "Gut balanciert, aber kein HIIT in 28 Tagen", "cardio_to_strength_ratio": "1.3:1", "status": "balanced" # balanced / cardio_heavy / strength_heavy } - Algorithmus:
# Get category distribution categories = {'cardio': 0, 'strength': 0, 'mobility': 0, 'recovery': 0, ...} for category, minutes in distribution.items(): categories[category] = (minutes / total_minutes) * 100 # Balance score = 100 - (std_dev × 2) balance_score = 100 - (statistics.stdev(categories.values()) * 2) # Ratio calculations cardio_to_strength = categories['cardio'] / categories['strength'] # Missing categories (expected but 0) expected = ['cardio', 'strength', 'mobility'] missing = [c for c in expected if categories[c] == 0] - Modul:
backend/data_layer/activity_metrics.py(neue Funktion) - Dependencies: statistics
Feature: Subcategory Distribution (within Category)
- Beschreibung: Verteilung nach Subcategories innerhalb einer Kategorie
- Input:
profile_id: str,category: str = 'strength',days: int = 28 - Output:
{ "category": "strength", "distribution": [ {"subcategory": "hypertrophy", "count": 6, "percentage": 60}, {"subcategory": "maxstrength", "count": 3, "percentage": 30}, {"subcategory": "endurance", "count": 1, "percentage": 10} ], "total_sessions": 10, "ratio_hypertrophy_to_max": "2:1", "recommendation": "Gut verteilt, Periodisierung erkennbar", "confidence": "high" } - Algorithmus:
SELECT tt.subcategory, COUNT(*) as count FROM activity_log a JOIN training_types tt ON a.training_type_id = tt.id WHERE a.profile_id = %s AND a.training_category = %s AND a.date >= CURRENT_DATE - INTERVAL '%s days' AND a.quality_label IN ('excellent', 'good', 'acceptable') GROUP BY tt.subcategory ORDER BY count DESC - Modul:
backend/data_layer/activity_metrics.py(neue Funktion) - Dependencies: training_types table, quality_filter.py
Feature: Zwei-Stufen-Architektur für Interpretations-Platzhalter ⭐ NEU
Architektur-Überblick:
Data Layer (Python) → Raw Data Placeholder (JSON) → Basis-Prompt (KI) → Interpreted Placeholder
Beispiel: Goal-Weighted Priority
Stufe 1: Data Layer
# backend/data_layer/scores.py (neu)
def get_goal_priority_raw_data(profile_id: str) -> Dict:
"""
Aggregiert Rohdaten für Goal-Priorisierung.
KEINE Interpretation, nur strukturierte Daten!
"""
with get_db() as conn:
cur = get_cursor(conn)
# 1. Aktive Ziele mit Focus Contributions
cur.execute("""
SELECT g.id, g.name, g.goal_type, g.progress_percentage,
g.target_date, g.start_date, g.is_primary,
COALESCE(
json_agg(
json_build_object(
'focus_area', fad.name_de,
'category', fad.category,
'contribution_weight', gfc.contribution_weight
)
) FILTER (WHERE fad.id IS NOT NULL),
'[]'::json
) as focus_contributions
FROM goals g
LEFT JOIN goal_focus_contributions gfc ON g.id = gfc.goal_id
LEFT JOIN focus_area_definitions fad ON gfc.focus_area_id = fad.id
WHERE g.profile_id = %s AND g.status = 'active'
GROUP BY g.id
""", (profile_id,))
goals = [dict(row) for row in cur.fetchall()]
# 2. Focus Area Weights
from data_layer.scores import get_user_focus_weights
focus_weights = get_user_focus_weights(profile_id)
# 3. Calculate derived metrics
for goal in goals:
# Total focus weight (Summe aller Contributions)
goal['total_focus_weight'] = sum(
fc['contribution_weight'] for fc in goal['focus_contributions']
)
# Behind schedule calculation
if goal['target_date']:
from datetime import datetime
today = datetime.now().date()
target = goal['target_date']
start = goal['start_date']
total_days = (target - start).days
elapsed_days = (today - start).days
expected_progress = (elapsed_days / total_days) * 100
actual_progress = goal['progress_percentage']
goal['behind_schedule_days'] = int(
((expected_progress - actual_progress) / 100) * total_days
)
else:
goal['behind_schedule_days'] = None
# 4. Context
context = {
"behind_schedule_count": sum(
1 for g in goals if g.get('behind_schedule_days', 0) > 0
),
"on_track_count": sum(
1 for g in goals if g.get('behind_schedule_days', 0) <= 0
),
"primary_goal": next(
(g['name'] for g in goals if g['is_primary']),
None
)
}
return {
"goals": goals,
"focus_area_weights": focus_weights,
"context": context
}
Stufe 2: Platzhalter-Registration (Raw Data)
# backend/placeholder_resolver.py
PLACEHOLDER_MAP = {
# ... existing placeholders ...
# Raw Data Placeholders (Typ 2)
'{{goal_priority_raw_data}}': lambda pid: json.dumps(
get_goal_priority_raw_data(pid),
indent=2
),
}
Stufe 3: Basis-Prompt (KI Interpretation)
# Admin → KI-Prompts → Neuer Basis-Prompt
Name: Goal Priority Interpreter
Type: base
Output Format: json
Output Schema:
{
"priority_ranking": [
{
"goal_name": "string",
"priority_score": "number (0-100)",
"rationale": "string",
"conflicts": ["string"]
}
],
"recommended_focus": "string",
"goal_conflicts": [
{
"goal_a": "string",
"goal_b": "string",
"conflict_type": "string",
"severity": "string"
}
]
}
Template:
---
Analysiere die folgenden Ziel-Rohdaten und erstelle eine priorisierte Liste.
# Rohdaten
{{goal_priority_raw_data}}
# Aufgabe
1. Sortiere Ziele nach kombinierter Priorität:
- Focus-Weight (höheres Gewicht = höhere Priorität)
- Behind-Schedule Status (hinter Plan = höhere Priorität)
- Primary-Flag (Primary-Goal = Boost)
2. Für jedes Ziel:
- Berechne Priority-Score (0-100)
- Begründe die Priorisierung
- Identifiziere Konflikte mit anderen Zielen
3. Identifiziere Goal-Konflikte:
- Muskelaufbau vs. Kaloriendefizit (konfliktär)
- Gewichtsverlust + Kraftaufbau (möglich mit Rekomposition)
- etc.
4. Empfehle Fokus-Reihenfolge für nächste 4 Wochen
# Output
Gib das Ergebnis als JSON zurück (siehe Schema oben).
---
Stufe 4: Interpreted Placeholder (von KI generiert)
# Wird automatisch durch Unified Prompt System erzeugt
# Wenn Basis-Prompt "Goal Priority Interpreter" ausgeführt wird:
'{{goal_weighted_priority}}' = <KI-generiertes JSON>
# Beispiel-Output:
{
"priority_ranking": [
{
"goal_name": "Gewichtsverlust 85kg",
"priority_score": 92,
"rationale": "Höchstes Focus-Weight (75) + 5 Tage hinter Plan + Primary Goal",
"conflicts": ["Kraftaufbau (moderate Konflikt bei zu großem Defizit)"]
},
{
"goal_name": "Kraftaufbau",
"priority_score": 58,
"rationale": "Moderates Focus-Weight (20) + On Track + Secondary Goal",
"conflicts": ["Gewichtsverlust (erfordert moderates Defizit)"]
}
],
"recommended_focus": "Primär Gewichtsverlust mit moderatem Defizit, dabei Krafttraining 2-3x/Woche für Muskelerhalt",
"goal_conflicts": [
{
"goal_a": "Gewichtsverlust",
"goal_b": "Kraftaufbau",
"conflict_type": "energy_availability",
"severity": "moderate"
}
]
}
Stufe 5: Verwendung in übergeordneten Prompts
# Pipeline-Prompt: "Weekly Coaching Report"
Template:
---
# Ziel-Priorisierung
{{goal_weighted_priority}}
# Basierend auf deinen Prioritäten...
[restlicher Prompt nutzt die Priorisierung]
---
Vorteile dieser Architektur:
- Flexibilität: Prompt-Änderung ohne Code-Deploy
- Wartbarkeit: Klare Trennung Data vs. Interpretation
- Erweiterbarkeit: Gleiche Rohdaten für mehrere Prompts nutzbar
- Testbarkeit: Rohdaten-Struktur separat testbar
- Transparenz: Rohdaten sichtbar (Debug-Modus)
- Iterierbarkeit: KI-Interpretation kann verfeinert werden
Implementierungs-Aufwand:
- Data Layer Funktion: 2h (get_goal_priority_raw_data)
- Placeholder Registration: 10min (einfacher Lambda)
- Basis-Prompt: 1h (Prompt-Engineering + Testing)
- TOTAL: 3h
Anwendbar für:
- P31: goal_weighted_priority ✅
- P32: main_constraint ✅
- P33: main_strength ✅
- P34: next_best_actions ⚠️ (braucht mehr Domänen-Wissen)
4. Datenqualität & Edge Cases
Problem: Activities ohne quality_label (NULL values)
- Beschreibung: Alte Activities oder Imports haben kein quality_label → NULL
- Betroffene Platzhalter: ALLE activity-bezogenen Platzhalter
- Vorschlag: Wie sollte damit umgegangen werden?
- NULL behandeln als "uncategorized" (separate Kategorie)
- Bei quality_filter: NULL = excluded (nicht mitzählen)
- Batch-Evaluation für alte Activities nachholen
- Warnung in confidence_score wenn >20% NULL
Problem: Quality-Filter zu strikt für manche Platzhalter
- Beschreibung: Bei "excellent" only → zu wenig Daten für Statistik
- Betroffene Platzhalter:
{{activity_summary_excellent}}, etc. - Vorschlag: Wie sollte damit umgegangen werden?
- Confidence-Score anpassen (insufficient wenn <3 activities)
- Fallback-Message: "Nur 2 excellent Sessions in 14 Tagen (zu wenig für Statistik)"
- Zeitraum automatisch erweitern (14d → 28d → 90d)
Problem: quality_label vs. user quality_filter_level
- Beschreibung: Es gibt zwei Quality-Konzepte, die verwechselt werden können:
quality_label(DB-Spalte): Evaluation-Ergebnis pro Activity (excellent, good, acceptable, poor, excluded)quality_filter_level(Profile-Einstellung): User-Präferenz für globalen Filter (all, quality, very_good, excellent)
- Betroffene Platzhalter: Alle activity-bezogenen Platzhalter
- Vorschlag:
- Platzhalter verwenden IMMER default='quality' (acceptable+) → konsistent für KI-Analysen
- User quality_filter_level nur für manuelle UI-Filter (Charts, Activity Page)
- Keine Vermischung: Platzhalter = fix 'quality', UI = user preference
- Dokumentation: Klarstellung der beiden Konzepte
5. Placeholder-Kategorisierung & Organisation
Vorschlag für neue Kategorien:
- Kategorie-Name: ___
- Platzhalter:
{{...}},{{...}} - Begründung: ___
- Platzhalter:
Umstrukturierung existierender Kategorien:
- Von Kategorie X nach Y verschieben:
{{placeholder}}- Begründung: ___
6. Dokumentation & Metadaten
Fehlende Beschreibungen:
{{placeholder}}- Beschreibung fehlt oder ist unklar
Fehlende Beispiele:
{{placeholder}}- Beispiel-Output fehlt
7. Prioritäten & Abhängigkeiten
Must-Have (kritisch für Prompt-Qualität):
Gap #1: Quality Label
- Quality-Filter in data_layer/activity_metrics.py - ALLE Funktionen betroffen
- Breaking Change, aber notwendig für korrekte Auswertungen
- Dauer: 4-6h (9 Funktionen + Tests)
- Blockiert: Alle neuen Platzhalter
- Neue Platzhalter für Evaluation-Breakdown
{{evaluation_breakdown}}- Übersicht über Qualitätsverteilung- Dauer: 1h (Funktion + Platzhalter)
- Placeholder-Updates in placeholder_resolver.py
- Alle activity-Platzhalter auf quality='quality' umstellen
- Dauer: 2h (Updates + Testen)
Teilsumme Gap #1: 7-9h
Gap #2: Training Categories
- Category-Specific Activity Metrics (data_layer)
get_category_activity_data(category)- Count/Minutes pro Kategorie- Dauer: 2h (1 Funktion, alle Kategorien abdecken)
- Kategorie-spezifische Platzhalter (Top Priority)
{{strength_training_count_7d}},{{strength_training_minutes_7d}}{{cardio_training_count_7d}},{{cardio_training_minutes_7d}}{{strength_frequency_adequate}},{{muscle_preservation_risk}}- Dauer: 3h (6-8 Platzhalter, kritisch für Muskelerhalt-Coaching)
- Days Since Last Training (per Category)
get_days_since_last_training(category)- Funktion{{days_since_last_strength}},{{days_since_last_cardio}}, etc.- Dauer: 2h (Funktion + 3-4 Platzhalter)
- Training Balance Calculator
get_training_balance_data()- Balance-Score + Ratios{{cardio_to_strength_ratio}},{{training_balance_score}},{{missing_training_categories}}- Dauer: 2-3h (Funktion + 3 Platzhalter)
Teilsumme Gap #2: 9-10h
TOTAL Must-Have: 16-19h
Should-Have (sinnvolle Ergänzungen):
Gap #1: Quality Label
- Dedizierte Quality-Platzhalter
{{activity_summary_acceptable_plus}},{{activity_summary_excellent}}- Dauer: 2h (4-5 neue Platzhalter)
- Poor Sessions Warning Platzhalter
{{poor_sessions_count}},{{poor_sessions_warning}}- Dauer: 1h
Gap #2: Training Categories
- Weitere Kategorie-Platzhalter
{{martial_arts_frequency_28d}},{{recovery_sessions_count_28d}},{{mobility_sessions_count_28d}}- Dauer: 2h (3-4 Platzhalter)
- Subcategory Distribution
get_subcategory_distribution(category)- Funktion{{strength_type_distribution}},{{hypertrophy_vs_maxstrength_ratio}},{{technique_vs_sparring_balance}}- Dauer: 3h (Funktion + 3 Platzhalter)
- NULL-Handling für alte Activities
- Batch-Evaluation Script für Activities ohne quality_label
- Dauer: 2h
Teilsumme Should-Have: 10h
Nice-to-Have (optional):
- Quality-Weighted Metrics
{{training_minutes_quality_weighted}}- gewichtet nach Qualität- Dauer: 1h
- Auto-Timeframe-Expansion
- Bei insufficient data: automatisch von 14d → 28d → 90d erweitern
- Dauer: 3h (Logik + alle Funktionen anpassen)
- Advanced Subcategory Analysen
- Periodisierungs-Erkennung (Maximalkraft-Phase → Hypertrophie-Phase?)
- Dauer: 2-3h
Teilsumme Nice-to-Have: 6-7h
Geschätzte Gesamt-Dauer (Original):
- Must-Have (Gap #1 + #2): 16-19h (beide Gaps kritisch!)
- Should-Have: 10h
- Nice-to-Have: 6-7h
- TOTAL (ohne User Requirements): 32-36h
Gesamt-Dauer (mit User Requirements P1-P27):
- Sprint 1 (User Req + Governance): 34-41h
- Sprint 2 (Gap #1 + #2): 26-32h
- Sprint 3 (Optional): 12-16h
- TOTAL (inkl. User Requirements): 72-89h
Empfehlung: Sprint 1 + Sprint 2 parallel bearbeiten wo möglich (viele unabhängige Tasks)
Abhängigkeiten:
- Quality-Filter in activity_metrics.py (MUSS zuerst)
- Dann: Neue Platzhalter können parallel implementiert werden
- Dann: Tests für alle Änderungen
- Letzter Schritt: Bestehende Prompts auf neue Platzhalter umstellen
Notizen
Technische Details: quality_label System
Verfügbare Quality Labels (activity_log.quality_label):
'excellent'- ⭐ Exzellentes Training (z.B. HR in Zone, Dauer optimal, RPE passend)'very_good'- ✓✓ Sehr gutes Training'good'- ✓ Gutes Training'acceptable'- ✓ Akzeptables Training (Mindestschwelle)'poor'- ⚠ Schlechtes Training (zu kurz, HR zu niedrig, etc.)'excluded'- ❌ Auszuschließen (fehlerhafte Messung, Dummy-Eintrag)NULL- Nicht evaluiert (alte Einträge, Imports ohne Evaluation)
Quality Filter Levels (für User-Präferenz, nicht Platzhalter!):
'all'- Alle Activities (kein Filter)'quality'- Hochwertig (acceptable+) ← DEFAULT für Platzhalter'very_good'- Sehr gut+ (excellent, good)'excellent'- Nur exzellent
Bestehende Infrastruktur (quality_filter.py):
get_quality_filter_sql(profile, table_alias='')
# Returns: "AND quality_label IN ('excellent', 'good', 'acceptable')"
get_quality_filter_tuple(profile)
# Returns: ('excellent', 'good', 'acceptable')
filter_activities_by_quality(activities, profile)
# Post-query filtering
Migration Path:
- Alle data_layer Funktionen erweitern um
quality_level='quality'Parameter - Alle Platzhalter updaten:
lambda pid: get_activity_summary_data(pid, quality_level='quality') - Neue Platzhalter für andere Levels:
{{activity_summary_excellent}} - Tests schreiben für alle Kombinationen
- Bestehende Prompts prüfen und ggf. anpassen
Verfügbare Trainings-Kategorien & Subcategories:
7 Hauptkategorien (training_category):
- cardio → Ausdauer
- Subcategories: running, cycling, swimming, rowing, other
- strength → Kraft
- Subcategories: hypertrophy, maxstrength, endurance, functional
- hiit → Schnellkraft
- Subcategories: hiit, explosive, circuit
- martial_arts → Kampfsport
- Subcategories: technique, sparring, strength
- mobility → Beweglichkeit
- Subcategories: static, dynamic, yoga, fascia
- recovery → Erholung (aktiv)
- Subcategories: walk, swim_light, regeneration
- other → Sonstiges
Abilities-Mapping (JSONB in training_types.abilities):
- strength, endurance, mental, coordination, mobility
Bestehende Platzhalter (nutzen bereits Categories):
{{trainingstyp_verteilung}}- Top 3 Kategorien mit %{{ability_balance_strength}}- Ability-Score 0-100 (nutzt abilities JSONB){{ability_balance_endurance}}- Ability-Score 0-100
Migration Path Training Categories:
- Neue data_layer Funktionen: get_category_activity_data(), get_days_since_last_training(), etc.
- Platzhalter für JEDE Kategorie (mindestens count + minutes für strength/cardio)
- Balance-Funktionen (Ratios, fehlende Kategorien)
- Subcategory-Analysen (innerhalb strength, martial_arts)
- Tests für alle Kombinationen
- Bestehende Prompts erweitern mit neuen Platzhaltern
Offene Fragen:
Gap #1: Quality Label
- Breaking Change akzeptabel? Zahlen ändern sich bei allen activity-Platzhaltern
- NULL-Handling: Als 'excluded' behandeln oder separate Kategorie?
- Batch-Evaluation: Alte Activities nachträglich evaluieren? (Performance-Impact?)
- Confidence-Anpassung: Thresholds senken wenn quality_filter aktiv? (weniger Daten)
Gap #2: Training Categories
- Ruhepausen-Thresholds: Welche Schwellenwerte pro Kategorie?
- Kraft: >3d warning, >7d critical?
- Cardio: >2d warning, >5d critical?
- Kampfsport: >7d warning, >14d critical?
- Balance-Definition: Was ist "gut balanciert"?
- Cardio:Kraft 2:1 bis 1:1 ok?
- Mobility mindestens 5% aller Trainings?
- Subcategory-Priorität: Welche Subcategories zuerst?
- Kraft (hypertrophy/maxstrength/endurance) → Top Priority
- Kampfsport (technique/sparring) → Nice-to-Have?
- Missing Categories Logic: Welche Kategorien sind "Pflicht"?
- Core: cardio, strength, mobility
- Optional: recovery, hiit, martial_arts?
User Requirements Summary (P1-P27):
Sprint 1 - Must-Have (10 Core Items):
- goal_summary_json → vollständige Zielübersicht
- focus_area_summary_json → strukturierte Focus Areas
- domain_availability_json → Verfügbarkeit pro Domäne
- body_change_summary_json → Körperentwicklung strukturiert
- activity_structure_json → Training strukturiert
- sleep_summary_json → Schlaf strukturiert
- recovery_summary_json → Erholung strukturiert
- vitals_summary_json → Vitalwerte strukturiert
- correlation_summary_json → Korrelationen strukturiert
- plateau_status + top_drivers → Diagnose strukturiert
Sprint 1 - Governance (4 Items):
- Placeholder Versioning System
- "nicht verfügbar" → null Migration
- Zeitfenster-Audit & Renaming
- Availability Flags (systematic)
Sprint 2 - Energy & Risk:
- underfueling_risk_flag + energy_availability_summary
- training_quality_score (aggregiert)
- load_balance_class (klassifiziert)
Sprint 3 - Zwei-Stufen-Architektur (P31-P34):
- goal_weighted_priority (✅ möglich via 2-Stufen)
- main_constraint (✅ möglich via 2-Stufen)
- main_strength (✅ möglich via 2-Stufen)
- next_best_actions (⚠️ teilweise, braucht Domänen-Wissen)
Sprint 3 - Optional:
- blood_pressure_summary_json (niedrigere Priorität)
User Input benötigt:
Gap #1: Quality Label
- Strategie-Entscheidung: Breaking Change (Option A) vs. Non-Breaking (Option B)?
- NULL-Handling: excluded oder uncategorized?
- Batch-Evaluation: Ja/Nein?
Gap #2: Training Categories
- Ruhepausen-Thresholds definieren (pro Kategorie)
- Balance-Kriterien festlegen (Ratios, Mindest-%)
- Subcategory-Priorität: Kraft zuerst, dann Kampfsport? Oder parallel?
- Muskelerhalt-Schwelle: 2x/Woche Kraft ok? Oder 3x?
User Requirements (P1-P27):
- Sprint-Priorisierung: Sprint 1 + Sprint 2 parallel? Oder sequentiell?
- Sprint 3: Zwei-Stufen-Platzhalter (P31-P34) gewünscht? Oder später?
- Governance: Placeholder Versioning System sofort einführen oder später?
- Breaking Changes: "nicht verfügbar" → null jetzt oder schrittweise?
- JSON-Struktur-Review: Beispiel-Strukturen (siehe P1-P27) absegnen?
Zwei-Stufen-Architektur (⭐ NEU):
- Architektur-Approval: Zwei-Stufen-Ansatz (Data + KI) für P31-P34 ok?
- Basis-Prompts: Wer erstellt/reviewed die Basis-Prompts? (User oder Claude?)
- Prompt-Governance: Wie werden Basis-Prompts versioniert/getestet?
- Raw Data Sichtbarkeit: Sollen Raw Data Placeholders auch in UI-Export sichtbar sein?
- Iterative Verfeinerung: Basis-Prompts initial "good enough" oder erst perfekt dann deployen?
📊 Finale Zusammenfassung: Impact der Fit/Gap-Analyse
Vor der Analyse (Original):
- Gap #1 (Quality Label): 11-13h
- Gap #2 (Training Categories): 11-13h
- TOTAL: 22-26h
- User Requirements: Nicht bewertet
- P31-P34: Als "nicht möglich" eingestuft
Nach der Analyse (aktualisiert):
- Sprint 1 (User Req + Governance): 34-41h
- Sprint 2 (Gap #1 + #2): 26-32h
- Sprint 3 (Zwei-Stufen-Architektur): 12-16h
- TOTAL: 72-89h
- Alle 27 User Requirements: ✅ Umsetzbar!
- P31-P34: ✅ Möglich via Zwei-Stufen-Architektur
Wichtigste Erkenntnisse:
✅ Architektur-Durchbruch:
Zwei-Stufen-Architektur löst das Problem komplexer Interpretations-Platzhalter:
- Data Layer stellt strukturierte Rohdaten bereit
- KI interpretiert via Basis-Prompts
- Flexibler, wartbarer, erweiterbarer als hardcodierte Logik
✅ Vollständige Umsetzbarkeit:
Alle 27 User Requirements (P1-P34) sind umsetzbar:
- 20 Items direkt möglich (mit aktueller Datenstruktur)
- 4 Items möglich via Zwei-Stufen-Architektur
- 3 Items teilweise möglich (einfache Erweiterungen)
- Nur P6 redundant, P30 optional
✅ Governance-Framework:
8 verbindliche Governance-Regeln für stabile Placeholder-API:
- Platzhalter = API-Verträge
- Keine stillschweigenden Änderungen
- JSON vor Freitext
- Zwei-Stufen-Architektur für Interpretationen
✅ Klare Sprint-Struktur:
3 Sprints mit klaren Zielen:
- Sprint 1: Foundation (User Req + Governance)
- Sprint 2: Quality + Categories (kritische Gaps)
- Sprint 3: Interpretations-Platzhalter (Zwei-Stufen)
Empfohlenes Vorgehen:
- User-Entscheidungen einholen (siehe "User Input benötigt")
- Sprint 1 starten (strukturierte JSONs + Governance)
- Sprint 2 parallel (Quality + Categories, unabhängig von Sprint 1)
- Sprint 3 nach Approval (Zwei-Stufen-Architektur)
Geschätzter Gesamtaufwand:
- Minimum: 72h (optimistisch, parallele Arbeit)
- Realistisch: 89h (inkl. Testing, Iterationen, Reviews)
- Mit Buffer: 100-110h (Puffer für Unvorhergesehenes)
ROI / Nutzen:
- ✅ Stabile Placeholder-API für professionelle Prompt-Bibliothek
- ✅ Alle 27 User Requirements erfüllt
- ✅ Zukunftssichere Architektur (Zwei-Stufen erweiterbar)
- ✅ Quality + Categories Gaps geschlossen (kritisch für KI-Coaching)
- ✅ Governance-Framework verhindert technische Schulden
Status: 🔴 Draft - Bereit für User Review & Entscheidungen Nächster Schritt: User Input einholen → Umsetzungskonzept erstellen → Sprint 1 starten