# Zielesystem: Prioritäts-Analyse **Datum:** 26. März 2026 **Frage:** Zielesystem vor oder nach Platzhaltern/Charts? **Antwort:** **Minimales Zielesystem VOR Platzhaltern, volles System parallel** --- ## 1. Kritische Erkenntnis aus Fachkonzept ### Zitat Fachkonzept (Zeile 20-28): > **Wichtig ist, dass das System zielabhängig interpretiert:** > - Gewichtsreduktion > - Muskel-/Kraftaufbau > - Konditions-/Ausdaueraufbau > - Körperrekomposition > - allgemeine Gesundheit > > **Dasselbe Rohsignal kann je nach Ziel anders bewertet werden.** > Ein Kaloriendefizit ist z. B. bei Gewichtsreduktion oft positiv, > bei Kraftaufbau aber potenziell hinderlich. ### Konsequenz ❌ **Charts OHNE Zielesystem = falsche Interpretationen** ✅ **Charts MIT Zielesystem = korrekte, zielspezifische Aussagen** --- ## 2. Abhängigkeits-Matrix ### Was hängt vom Zielesystem ab? | Komponente | Zielabhängig? | Beispiel | |------------|---------------|----------| | **Rohdaten-Charts** | ❌ Nein | Gewichtsverlauf, Umfänge-Trend | | **Score-Gewichtung** | ✅ JA | Body Progress Score: 30% bei weight_loss, 20% bei strength | | **Interpretationen** | ✅ JA | Kaloriendefizit: "gut" bei weight_loss, "kritisch" bei strength | | **Hinweise** | ✅ JA | "Gewicht stagniert" → bei weight_loss: Warnung, bei strength: egal | | **Platzhalter (Berechnungen)** | ⚠️ TEILWEISE | Trends: Nein, Scores: JA | | **KI-Prompts** | ✅ JA | Analyse-Kontext ändert sich komplett | ### Fachkonzept: Score-Gewichtung (Zeile 185-216) ```yaml score_weights: weight_loss: body_progress: 0.30 # Körper wichtig nutrition: 0.25 activity: 0.20 recovery: 0.15 health_risk: 0.10 strength: body_progress: 0.20 nutrition: 0.25 activity: 0.30 # Training wichtiger recovery: 0.20 health_risk: 0.05 # Weniger kritisch endurance: body_progress: 0.10 # Körper unwichtiger activity: 0.35 # Training am wichtigsten recovery: 0.25 # Recovery sehr wichtig ``` ### Beispiel: Body Progress Score **OHNE Zielesystem:** ```python def calculate_body_progress_score(): # Generisch, für niemanden wirklich passend fm_delta_score = calculate_fm_change() # -5kg lbm_delta_score = calculate_lbm_change() # -2kg return (fm_delta_score + lbm_delta_score) / 2 # Score: 50/100 (FM gut runter, aber LBM auch runter) ``` **MIT Zielesystem:** ```python def calculate_body_progress_score(goal_mode): fm_delta_score = calculate_fm_change() # -5kg lbm_delta_score = calculate_lbm_change() # -2kg if goal_mode == "weight_loss": # FM runter: sehr gut, LBM runter: tolerierbar wenn nicht zu viel return 0.70 * fm_delta_score + 0.30 * lbm_delta_score # Score: 78/100 (FM wichtiger, LBM-Verlust weniger kritisch) elif goal_mode == "strength": # FM runter: ok, LBM runter: SEHR SCHLECHT return 0.30 * fm_delta_score + 0.70 * lbm_delta_score # Score: 32/100 (LBM-Verlust ist Hauptproblem!) elif goal_mode == "recomposition": # FM runter: gut, LBM runter: schlecht return 0.50 * fm_delta_score + 0.50 * lbm_delta_score # Score: 50/100 (ausgewogen bewertet) ``` **Ergebnis:** - Gleiche Daten (-5kg FM, -2kg LBM) - ABER: 78/100 bei weight_loss, 32/100 bei strength - **Ohne Ziel: völlig falsche Bewertung!** --- ## 3. Ziel-Erkennung aus Daten ### Fachkonzept erwähnt dies NICHT explizit, aber logisch ableitbar: **Pattern-Erkennung:** ```python def suggest_goal_from_data(profile_id): """Schlägt Ziel basierend auf Daten-Mustern vor.""" # Analyse der letzten 28 Tage training_types = get_training_distribution_28d(profile_id) nutrition = get_nutrition_pattern_28d(profile_id) body_changes = get_body_changes_28d(profile_id) # Pattern 1: Viel Kraft + viel Protein + LBM steigt if (training_types['strength'] > 60% and nutrition['protein_g_per_kg'] > 1.8 and body_changes['lbm_trend'] > 0): return { 'suggested_goal': 'strength', 'confidence': 'high', 'reasoning': 'Krafttraining dominant + hohe Proteinzufuhr + Muskelaufbau erkennbar' } # Pattern 2: Viel Cardio + Kaloriendefizit + Gewicht sinkt if (training_types['endurance'] > 50% and nutrition['kcal_balance_avg'] < -300 and body_changes['weight_trend'] < 0): return { 'suggested_goal': 'weight_loss', 'confidence': 'high', 'reasoning': 'Ausdauertraining + Kaloriendefizit + Gewichtsverlust' } # Pattern 3: Mixed Training + Protein hoch + Gewicht stabil + Rekomposition if (training_types['mixed'] == True and nutrition['protein_g_per_kg'] > 1.6 and abs(body_changes['weight_trend']) < 0.05 and body_changes['fm_trend'] < 0 and body_changes['lbm_trend'] > 0): return { 'suggested_goal': 'recomposition', 'confidence': 'medium', 'reasoning': 'Gemischtes Training + Rekomposition sichtbar (FM↓, LBM↑)' } # Default: Nicht genug Muster erkennbar return { 'suggested_goal': 'health', 'confidence': 'low', 'reasoning': 'Keine klaren Muster erkennbar, gesundheitsorientiertes Training angenommen' } ``` ### Voraussetzungen für Ziel-Erkennung: 1. ✅ Mindestens 21-28 Tage Daten 2. ✅ Training-Type Distribution 3. ✅ Ernährungs-Pattern 4. ✅ Körper-Trends (FM, LBM, Gewicht) 5. ✅ Berechnet → **braucht Platzhalter!** **ABER:** Ziel-Erkennung ist **nachgelagert**, nicht Voraussetzung. --- ## 4. Empfohlene Implementierungs-Strategie ### Hybrid-Ansatz: Minimal-Ziele SOFORT, Voll-System parallel ## Phase 0a: Minimal-Zielesystem (2-3h) ⭐ **START HIER** ### Ziel User kann manuell Ziel setzen, System nutzt es für Berechnungen. ### Implementierung **1. DB-Schema erweitern:** ```sql -- Migration 023 ALTER TABLE profiles ADD COLUMN goal_mode VARCHAR(50) DEFAULT 'health'; ALTER TABLE profiles ADD COLUMN goal_weight DECIMAL(5,2); ALTER TABLE profiles ADD COLUMN goal_bf_pct DECIMAL(4,1); ALTER TABLE profiles ADD COLUMN goal_set_date DATE; ALTER TABLE profiles ADD COLUMN goal_target_date DATE; COMMENT ON COLUMN profiles.goal_mode IS 'Primary goal: weight_loss, strength, endurance, recomposition, health'; ``` **2. Goal-Mode Konstanten:** ```python # backend/goals.py (NEU) GOAL_MODES = { 'weight_loss': { 'label': 'Gewichtsreduktion', 'description': 'Fettabbau bei Erhalt der Magermasse', 'score_weights': { 'body_progress': 0.30, 'nutrition': 0.25, 'activity': 0.20, 'recovery': 0.15, 'health_risk': 0.10 }, 'focus_areas': ['fettmasse', 'gewichtstrend', 'kalorienbilanz', 'protein_sicherung'] }, 'strength': { 'label': 'Kraftaufbau', 'description': 'Muskelaufbau und Kraftsteigerung', 'score_weights': { 'body_progress': 0.20, 'nutrition': 0.25, 'activity': 0.30, 'recovery': 0.20, 'health_risk': 0.05 }, 'focus_areas': ['trainingsqualitaet', 'protein', 'lbm', 'recovery'] }, 'endurance': { 'label': 'Ausdaueraufbau', 'description': 'Kondition und VO2max verbessern', 'score_weights': { 'body_progress': 0.10, 'nutrition': 0.20, 'activity': 0.35, 'recovery': 0.25, 'health_risk': 0.10 }, 'focus_areas': ['trainingsvolumen', 'intensitaetsverteilung', 'vo2max', 'recovery'] }, 'recomposition': { 'label': 'Körperrekomposition', 'description': 'Fettabbau bei gleichzeitigem Muskelaufbau', 'score_weights': { 'body_progress': 0.30, 'nutrition': 0.25, 'activity': 0.25, 'recovery': 0.15, 'health_risk': 0.05 }, 'focus_areas': ['lbm', 'fettmasse', 'protein', 'trainingsqualitaet'] }, 'health': { 'label': 'Allgemeine Gesundheit', 'description': 'Ausgeglichenes Gesundheits- und Fitnesstraining', 'score_weights': { 'body_progress': 0.20, 'nutrition': 0.20, 'activity': 0.20, 'recovery': 0.20, 'health_risk': 0.20 }, 'focus_areas': ['bewegung', 'blutdruck', 'schlaf', 'gewicht', 'regelmaessigkeit'] } } ``` **3. API-Endpoint:** ```python # routers/goals.py (NEU) from fastapi import APIRouter, Depends from auth import require_auth from goals import GOAL_MODES router = APIRouter(prefix="/api/goals", tags=["goals"]) @router.get("/modes") def get_goal_modes(): """Return all available goal modes with descriptions.""" return GOAL_MODES @router.get("/current") def get_current_goal(session: dict = Depends(require_auth)): """Get user's current goal settings.""" profile_id = session['profile_id'] with get_db() as conn: cur = get_cursor(conn) cur.execute( """SELECT goal_mode, goal_weight, goal_bf_pct, goal_set_date, goal_target_date FROM profiles WHERE id=%s""", (profile_id,) ) row = r2d(cur.fetchone()) return { **row, 'mode_config': GOAL_MODES.get(row['goal_mode'], GOAL_MODES['health']) } @router.post("/set") def set_goal( goal_mode: str, goal_weight: Optional[float] = None, goal_bf_pct: Optional[float] = None, target_date: Optional[str] = None, session: dict = Depends(require_auth) ): """Set user's goal.""" if goal_mode not in GOAL_MODES: raise HTTPException(400, f"Invalid goal_mode. Must be one of: {list(GOAL_MODES.keys())}") profile_id = session['profile_id'] with get_db() as conn: cur = get_cursor(conn) cur.execute( """UPDATE profiles SET goal_mode=%s, goal_weight=%s, goal_bf_pct=%s, goal_set_date=CURRENT_DATE, goal_target_date=%s WHERE id=%s""", (goal_mode, goal_weight, goal_bf_pct, target_date, profile_id) ) conn.commit() return {"success": True, "goal_mode": goal_mode} ``` **4. Frontend UI (Settings.jsx):** ```jsx // Minimal Goal Selector function GoalSettings() { const [goalModes, setGoalModes] = useState({}) const [currentGoal, setCurrentGoal] = useState(null) const [selectedMode, setSelectedMode] = useState('health') useEffect(() => { loadGoalModes() loadCurrentGoal() }, []) const loadGoalModes = async () => { const modes = await api.getGoalModes() setGoalModes(modes) } const loadCurrentGoal = async () => { const goal = await api.getCurrentGoal() setCurrentGoal(goal) setSelectedMode(goal.goal_mode || 'health') } const saveGoal = async () => { await api.setGoal({ goal_mode: selectedMode, goal_weight: goalWeight, goal_bf_pct: goalBfPct, target_date: targetDate }) loadCurrentGoal() } return (
{goalModes[selectedMode]?.description}