# Issue #55: Dynamic Aggregation Methods for Goal Types **Status:** 📋 Planned **Priorität:** Low (Nice-to-Have) **Aufwand:** 2-3h **Erstellt:** 28. März 2026 **Abhängigkeiten:** Keine --- ## Problem **Aktuell:** ```javascript // frontend/src/pages/AdminGoalTypesPage.jsx (Lines 28-38) const AGGREGATION_METHODS = [ { value: 'latest', label: 'Letzter Wert' }, { value: 'avg_7d', label: 'Durchschnitt 7 Tage' }, { value: 'avg_30d', label: 'Durchschnitt 30 Tage' }, { value: 'sum_30d', label: 'Summe 30 Tage' }, { value: 'count_7d', label: 'Anzahl 7 Tage' }, { value: 'count_30d', label: 'Anzahl 30 Tage' }, { value: 'min_30d', label: 'Minimum 30 Tage' }, { value: 'max_30d', label: 'Maximum 30 Tage' }, { value: 'avg_per_week_30d', label: 'Durchschnitt pro Woche (30d)' } ] ``` **Probleme:** - ❌ Hardcoded im Frontend - ❌ Backend kennt diese Liste nicht → keine Validierung - ❌ Neue Aggregationsmethoden erfordern Frontend-Änderung - ❌ Nicht konsistent mit dynamischer Platzhalter-Liste --- ## Lösung: Backend-definierte Aggregation Methods ### Konzept **Backend definiert** die verfügbaren Methoden: ```python # backend/routers/goal_types.py AGGREGATION_METHODS = [ { "value": "latest", "label_de": "Letzter Wert", "label_en": "Latest Value", "description": "Neuester Messwert im Zeitfenster", "applicable_to": ["weight", "caliper", "circumference", "vitals"], "example": "Aktuellstes Gewicht (heute oder letzter Eintrag)" }, { "value": "avg_7d", "label_de": "Durchschnitt 7 Tage", "label_en": "7-day Average", "description": "Mittelwert der letzten 7 Tage", "applicable_to": ["weight", "nutrition", "vitals", "sleep"], "example": "Durchschnittskalorien der letzten Woche" }, # ... alle Methoden ... ] @router.get("/goal-types/aggregation-methods") def get_aggregation_methods(session: dict = Depends(require_auth)): """ Get available aggregation methods for goal types. Returns: List of aggregation method definitions with metadata """ return { "methods": AGGREGATION_METHODS, "default": "latest" } ``` **Frontend lädt** die Methoden dynamisch: ```javascript // frontend/src/pages/AdminGoalTypesPage.jsx const [aggregationMethods, setAggregationMethods] = useState([]) useEffect(() => { loadAggregationMethods() }, []) const loadAggregationMethods = async () => { const data = await api.getAggregationMethods() setAggregationMethods(data.methods) } // Render: ``` --- ## Implementierung ### Phase 1: Backend Endpoint (1h) **Datei:** `backend/routers/goal_types.py` 1. Definiere `AGGREGATION_METHODS` Konstante mit Metadata 2. Erstelle Endpoint `GET /api/goal-types/aggregation-methods` 3. Optional: Validierung bei Goal Type Create/Update ### Phase 2: Frontend Integration (1h) **Datei:** `frontend/src/pages/AdminGoalTypesPage.jsx` 1. Remove hardcoded `AGGREGATION_METHODS` 2. Add `loadAggregationMethods()` in useEffect 3. Update dropdown to use loaded methods 4. Add `api.getAggregationMethods()` in `api.js` ### Phase 3: Optional Enhancements (1h) - Tooltips mit method.description - Filtering nach applicable_to (nur relevante Methoden für gewählte Tabelle zeigen) - Beispiel-Text anzeigen (method.example) --- ## Vorteile - ✅ Single Source of Truth im Backend - ✅ Backend kann Aggregationsmethoden validieren - ✅ Neue Methoden ohne Frontend-Änderung hinzufügbar - ✅ Konsistent mit PlaceholderPicker-Architektur - ✅ Bessere UX (Tooltips, Beispiele, Filtering) --- ## Akzeptanzkriterien - [ ] Backend Endpoint `/api/goal-types/aggregation-methods` existiert - [ ] Frontend lädt Methoden dynamisch beim Laden der Seite - [ ] Dropdown zeigt alle verfügbaren Methoden - [ ] Hardcoded Array aus Frontend entfernt - [ ] Backend validiert aggregation_method bei Create/Update --- ## Related Issues - ✅ #54: Dynamic Placeholder System (UI bereits implementiert) - ✅ #53: Phase 0c Multi-Layer Architecture (abgeschlossen) - ✅ #50: Goals System (Basis vorhanden) --- ## Notes - **Priorität Low**, weil System funktioniert (nur nicht dynamisch) - **Nice-to-Have** für Admin-UX-Verbesserung - Kann jederzeit später implementiert werden ohne Breaking Changes