# Phase 0c – Architecture Cleanup & Refactoring

**Datum:** 2026-03-28
**Voraussetzung:** Phase 0b abgeschlossen
**Geschätzter Aufwand:** 12-16 Stunden

---

## Ziele

Phase 0c fokussiert auf **Architektur-Verbesserungen** und **Structured Data**, ohne neue Features hinzuzufügen.

**Kernprinzip:** Von Formatted Strings zu Structured Data → Basis für Phase 0c Refactoring (Charts/Diagramme).

---

## Task 1: Dynamic Aggregation Methods (3-4h)

**Problem:** Aggregationsmethoden sind im Frontend hardcoded.

**Lösung:**

### Backend
```python
# backend/routers/goal_types.py
@router.get("/aggregation-methods")
def get_aggregation_methods():
    """Return all available aggregation methods with metadata"""
    return [
        {
            "value": "latest",
            "label_de": "Letzter Wert",
            "label_en": "Latest",
            "description": "Aktuellster Wert aus Tabelle",
            "compatible_types": ["DECIMAL", "INTEGER", "FLOAT"],
            "requires_numeric": False
        },
        {
            "value": "avg_7d",
            "label_de": "Durchschnitt 7 Tage",
            "label_en": "7-day average",
            "description": "Mittelwert über 7 Tage",
            "compatible_types": ["DECIMAL", "INTEGER", "FLOAT"],
            "requires_numeric": True
        },
        # ... alle Methoden aus goal_utils.py
    ]
```

**Implementierung:**
1. Endpoint erstellen (goal_types.py)
2. Auto-Discovery aus goal_utils.py Docstrings oder Introspection
3. Frontend anpassen (AdminGoalTypesPage.jsx)
4. Migration für Backfill (falls nötig)

**Dokumentation:** `.claude/docs/technical/AGGREGATION_METHODS.md` (exists)

---

## Task 2: Dynamic Placeholder Catalog (4-5h)

**Problem:** Platzhalter sind im Frontend nicht sichtbar/suchbar.

**Lösung:**

### Backend
```python
# backend/routers/prompts.py
@router.get("/placeholders/catalog")
def get_placeholder_catalog(session: dict = Depends(require_auth)):
    """
    Return all registered placeholders with metadata.
    Enables auto-complete and placeholder selector in frontend.
    """
    return {
        "categories": [
            {
                "name": "Profil",
                "placeholders": [
                    {
                        "key": "name",
                        "placeholder": "{{name}}",
                        "description": "Name des Nutzers",
                        "example": "Lars",
                        "data_type": "string"
                    },
                    # ...
                ]
            },
            # ... weitere Kategorien
        ],
        "total_count": 111
    }
```

### Frontend
```javascript
// PlaceholderSelector Component
<PlaceholderSelector
  onSelect={(placeholder) => insertAtCursor(placeholder)}
  categories={fetchedCatalog.categories}
  searchable={true}
  showExamples={true}
/>
```

**Implementierung:**
1. Endpoint erstellen (nutzt PLACEHOLDER_CATALOG aus placeholder_resolver.py)
2. React Component: PlaceholderSelector
3. Integration in UnifiedPromptModal (Prompt-Editor)
4. Keyboard-Shortcuts (Strg+Space für Auto-Complete)

**Dokumentation:** `.claude/docs/technical/PLACEHOLDER_SYSTEM.md` (neu erstellen)

---

## Task 3: Calculation Functions → Structured Return (5-7h)

**Problem:** Calculation Functions returnen formatted strings statt strukturierte Daten.

**Lösung:** Refactoring aller Calculation Functions zu structured return.

### Beispiel-Refactoring

**Vorher (Phase 0b):**
```python
def calculate_weight_trend(profile_id: str) -> str:
    # ... calculation ...
    return f"sinkend (-0.9 kg in 28 Tagen)"
```

**Nachher (Phase 0c):**
```python
def calculate_weight_trend(profile_id: str) -> Dict:
    # ... calculation ...
    return {
        "raw_value": -0.9,
        "unit": "kg",
        "period_days": 28,
        "direction": "decreasing",  # "increasing", "stable"
        "confidence": "high",       # "high", "medium", "low"
        "data_points": 15,
        "slope_per_day": -0.032
    }
```

### Formatting Layer
```python
# placeholder_resolver.py
def format_weight_trend(data: Dict) -> str:
    """Format structured weight trend for AI prompts"""
    direction_de = {"decreasing": "sinkend", "increasing": "steigend", "stable": "stabil"}
    return f"{direction_de[data['direction']]} ({data['raw_value']} {data['unit']} in {data['period_days']} Tagen)"
```

### Betroffene Module
- `calculations/body_metrics.py` (~15 Funktionen)
- `calculations/nutrition_metrics.py` (~12 Funktionen)
- `calculations/activity_metrics.py` (~18 Funktionen)
- `calculations/recovery_metrics.py` (~10 Funktionen)
- `calculations/scores.py` (~8 Funktionen)

**Gesamt:** ~63 Funktionen zu refactoren

### Strategie
1. **Phase 0c/1:** Body Metrics (Proof of Concept)
2. **Phase 0c/2:** Nutrition + Activity
3. **Phase 0c/3:** Recovery + Scores
4. **Phase 0c/4:** Placeholder Resolver anpassen (Formatter)

**Dokumentation:**
- `.claude/docs/technical/CALCULATION_FUNCTIONS.md` (neu)
- `.claude/docs/functional/mitai_jinkendo_konzept_diagramme_auswertungen_v2.md` (exists, Kontext für Chart-System)

---

## Task 4: Stats/Chart Endpoints (Optional, 3-4h)

**Voraussetzung:** Task 3 abgeschlossen

**Lösung:** Separate Endpoints für Chart-Daten (nutzen structured calculation returns)

```python
# backend/routers/stats.py (new)
@router.get("/stats/body/weight-trend")
def get_weight_trend_stats(
    days: int = 30,
    session: dict = Depends(require_auth)
):
    """Return structured weight trend data for charts"""
    trend_data = calculate_weight_trend(session['profile_id'])
    return {
        "trend": trend_data,
        "timeseries": [...],  # Daily data points
        "projections": {...}  # Linear projection
    }
```

**Implementierung:**
1. Neuer Router: `stats.py`
2. Endpoints für alle Chart-relevanten Metriken
3. OpenAPI Schema (für Frontend Type-Generation)

---

## Abhängigkeiten

```
Task 1 (Aggregation Methods)  ─┐
                               ├─> Unabhängig, parallel möglich
Task 2 (Placeholder Catalog)  ─┘

Task 3 (Structured Returns)   ──> Voraussetzung für Task 4
Task 4 (Stats Endpoints)       ──> Optional, nutzt Task 3 Results
```

---

## Akzeptanzkriterien Phase 0c

**Muss (Must-Have):**
- ✅ Aggregation Methods API-gesteuert
- ✅ Placeholder Catalog API verfügbar
- ✅ Mindestens 1 Modul (Body Metrics) zu structured return refactored
- ✅ Dokumentation für alle 3 Tasks

**Sollte (Should-Have):**
- ✅ Alle Calculation Functions refactored
- ✅ Frontend Placeholder Selector implementiert
- ✅ Stats Endpoints für Body + Nutrition

**Kann (Nice-to-Have):**
- ⚪ Stats Endpoints für alle Module
- ⚪ Chart-Preview in Admin-Panel
- ⚪ TypeScript Type-Generation aus OpenAPI

---

## Rollback-Plan

Falls Task 3 (Structured Returns) Probleme verursacht:
1. Calculation Functions returnen **beide** Formate:
   ```python
   return {
       "formatted": "sinkend (-0.9 kg)",  # Backward-compat
       "structured": {...}                 # New format
   }
   ```
2. Placeholder Resolver nutzt `formatted` weiterhin
3. Stats Endpoints nutzen `structured`
4. Schrittweise Migration ohne Breaking Changes

---

## Timeline (geschätzt)

**Option A (Serial):** 12-16 Stunden über 2-3 Tage
**Option B (Parallel):** 8-10 Stunden mit 2 Personen

**Empfehlung:** Option A, da Tasks eng verzahnt sind.

---

## Nach Phase 0c

**Enabler für:**
- ✅ Chart/Diagram System (Phase 1)
- ✅ Goal Progress Visualizations
- ✅ Custom Dashboards
- ✅ PDF/Excel Export mit strukturierten Daten
- ✅ API für externe Tools (z.B. Home Assistant)

**Nächste Phase (Phase 1):**
- Chart Library Integration (Recharts/Victory)
- Interactive Dashboards
- Goal Progress Tracking UI
