mitai-jinkendo/.claude/docs/technical/ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md

147 lines
9.0 KiB
Markdown
Raw Normal View History

# Activity Session Metrics (EAV) – Umsetzungs- & Agent-Guide
**Stand:** 2026-04-14
**Status:** Kern-Backend (Migration 054, Layer 1, Admin- & Nutzer-API) umgesetzt; Admin-UI & CSV-Mapping folgen.
**Ziel:** Sportspezifische **Attributprofile** (Kategorie + optional Trainingstyp-Override) administrierbar; Messwerte pro Session in **EAV**; **alle Auswertungen** sollen künftig über **Layer 1** (`data_layer`) laufen.
**Zielarchitektur, Phasenplan (Produktionsreife):** [`ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md`](./ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md) – Kanon `activity_log`/EAV, Composites, Import, Layer 1/2, Reihenfolge A–F.
**Composite-Parameter (EAV, JSONB, Archetypen):** detailliertes Umsetzungskonzept für Agenten: [`ACTIVITY_COMPOSITE_METRICS_IMPLEMENTATION_CONCEPT.md`](./ACTIVITY_COMPOSITE_METRICS_IMPLEMENTATION_CONCEPT.md).
**Kanon (Code):** `backend/data_layer/activity_data_canon.py` (Repo-Root) — CSV-Modul `activity` vs. EAV-primär; Migration **057**.
---
## 1. Produktions-Migrationen (Pflicht)
- **Nur additive Änderungen** bis zur Stabilisierung: neue Tabellen/Spalten **nullable**, kein `DROP COLUMN` / `DELETE` von Altbestand in derselben Story.
- Neue Migrationen: **`backend/migrations/054_*.sql`** (nächste freie Nummer nach 053 einhalten).
- **Prod-Checkliste vor Deploy:**
1. Backup / Snapshot der DB.
2. Migration auf **Kopie** der Prod-DB laufen lassen; Container-Start (`db_init`) verifizieren.
3. Stichprobe: `activity_log`-Zeilen unverändert; neue Tabellen leer oder nur Seed.
- **Datenhaltung:** Bestehende Spalten in `activity_log` bleiben **Quelle für Alt-Daten**; EAV (`activity_session_metrics`) ist der **kanonische Ort für konfigurierte Session-Metriken**, sobald geschrieben. Backfill Altspalten → EAV ist **separater Schritt** (siehe §6).
---
## 2. Datenmodell (Ist nach Migration 054)
| Tabelle | Zweck |
|---------|--------|
| `training_parameters` | Katalog messbarer Größen (`key`, `data_type`, `unit`, `validation_rules`, …) – bereits Migration 013; Admin-API ergänzt. |
| `training_category_parameter` | Welche Parameter für welche **`training_types.category`** (z. B. `cardio`) gelten: `sort_order`, `required`, `ui_group`. |
| `training_type_parameter` | Zusatzparameter oder **Overrides** pro **`training_types.id`**: `sort_order`, `required`, `ui_group` (NULL = von Kategorie erben). |
| `activity_session_metrics` | EAV: `(activity_log_id, training_parameter_id)` eindeutig; genau eine Wertspalte `value_num` / `value_int` / `value_text` / `value_bool`. |
| `activity_log` | **Neu:** `started_at`, `ended_at` (`TIMESTAMPTZ`, nullable) – für spätere Dedupe/Intervalle; **kein** Pflichtfeld in v1. |
**Merge-Logik effektives Schema** (Layer 1, eine Funktion):
1. Kategorie ermitteln: aus Zeile `training_category` oder aus `training_types.category` via `training_type_id`.
2. Basis = alle Zeilen `training_category_parameter` für diese Kategorie, Join auf `training_parameters` (aktiv).
3. Für jeden Eintrag in `training_type_parameter` zum gewählten Typ: gleiche `training_parameter_id` → Overrides anwenden; nur im Typ vorhanden → anhängen.
4. Sortierung: `sort_order` aufsteigend, dann `key`.
---
## 3. Layer 1 – Kanonische Module
| Modul | Pfad | Aufgabe |
|-------|------|---------|
| Session-Metriken & Schema | `backend/data_layer/activity_session_metrics.py` | `resolve_activity_attribute_schema`, `fetch_activity_session_metrics`, `replace_activity_session_metrics`, `get_activity_session_logical_unit`, `enrich_sessions_with_metrics`, `merge_column_backed_and_eav_metrics`. |
**Spalten vs. EAV (Lesepfad):** `merge_column_backed_and_eav_metrics` / `get_activity_session_logical_unit` / `enrich_sessions_with_metrics` werten Parameter mit `source_field` **primär aus `activity_log`** aus; EAV ist Fallback (z. B. Legacy) oder für Parameter ohne Spalte. **Kein** automatischer Spalte→EAV-Schreib-Sync mehr in `run_activity_post_write_hooks` / Import-Hooks (vermeidet Doppelhaltung).
**Regeln für Agenten:**
- **Keine** zweite Implementierung derselben Merge- oder Validierungslogik in Routern.
- Platzhalter / Charts, die Session-Details brauchen: **nur** diese Layer-1-Helfer erweitern oder aufrufen (z. B. `activity_metrics.get_training_sessions_recent_weeks_data` nutzt `enrich_sessions_with_metrics`).
- Router: `get_db`, `get_cursor`, Auth; Business-Validierung delegieren an `activity_session_metrics`.
**KI-Kontext:** In `training_sessions_recent_json` enthält jedes Element von `session_metrics` neben `key`/`value` die Felder `name_de`, `name_en`, `description_de`, `description_en` (aus dem effektiven Schema). Für nicht selbsterklärende Keys soll im Katalog `training_parameters.description_*` gepflegt werden (Admin). Ergänzend liefert der Platzhalter `{{training_parameters_glossary_md}}` die gesamte aktive Parameter-Legende als Markdown-Tabelle (`get_training_parameters_ki_glossary_data` → `get_training_parameters_glossary_md`).
---
## 4. API (Ist / geplant)
### Admin (`require_admin`)
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| GET/POST | `/api/admin/training-parameters` | Katalog lesen / Parameter anlegen |
| PUT/DELETE | `/api/admin/training-parameters/{id}` | Aktualisieren / Soft-deaktivieren (`is_active`) |
| GET | `/api/admin/training-category-parameters?category=` | Zuordnungen Kategorie |
| POST | `/api/admin/training-category-parameters` | Zuordnung anlegen |
| DELETE | `/api/admin/training-category-parameters/{id}` | Zuordnung entfernen |
| GET | `/api/admin/training-type-parameters?training_type_id=` | Zuordnungen Typ |
| POST | `/api/admin/training-type-parameters` | Zuordnung anlegen |
| DELETE | `/api/admin/training-type-parameters/{id}` | Zuordnung entfernen |
Router: `backend/routers/admin_training_parameters.py`, `backend/routers/admin_activity_attribute_profiles.py`.
### Nutzer (`require_auth`)
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| GET | `/api/activity/{eid}` | Session-Kopf + `schema` + `metrics` (Layer 1) |
| PUT | `/api/activity/{eid}/metrics` | **Voller Ersatz** der EAV-Metriken für diese Session (Liste `{parameter_key, value}`) |
`ActivityEntry` unverändert für bestehende Create/Update-Routen; optionale Erweiterung um `started_at`/`ended_at` in späterem Schritt.
---
## 5. Agent-Checkliste (nächste Iterationen)
**Layer 2a (Platzhalter Aktivität):** Abgleich Registry ↔ Resolver ↔ Layer 1 — [`ACTIVITY_LAYER2A_PLACEHOLDER_AUDIT.md`](./ACTIVITY_LAYER2A_PLACEHOLDER_AUDIT.md) (Issue #53). **Schritt 2:** `semantic_contract` / `known_limitations` für dynamische `session_metrics` und Korrektur `trainingstyp_verteilung` in der Registry.
Siehe **Phasen A–F** in [`ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md`](./ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md). Kurz:
- [x] **Phase A:** Kanon-Tabelle (eine Quelle pro Semantik) — [`ACTIVITY_SCALAR_KANON_TABLE.md`](./ACTIVITY_SCALAR_KANON_TABLE.md).
- [ ] **Phase B:** Lesepfad Layer 1 härten (Consumer-Audit fortlaufend — siehe `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` §4 Phase B).
- [ ] **Phase C:** Schreibpfad: Doppelhaltung / Sync stufenweise abschalten.
- [ ] **Phase D:** Composite-MVP (ein Archetyp E2E).
- [ ] **Phase E:** Archetypen ausbauen + CSV-Typkonvertierung vollständig + Mapping-UX.
- [ ] **Phase F:** Härtung Prod (Indizes, Observability, Doku).
Legacy-Punkte:
- [x] Admin-UI: `frontend/src/pages/AdminActivityAttributeProfilesPage.jsx`, Route `/admin/activity-attribute-profiles`, Admin-Nav-Gruppe „Trainingstypen“.
- [x] `/activity` Frontend: Bearbeiten lädt `GET /api/activity/{id}`, dynamische Felder + `PUT /api/activity/{id}/metrics`.
- [ ] Universal CSV: Mapping inkl. EAV/Composite-Ziele + Executor (fortlaufend).
- [ ] Optional: Backfill / Abschluss `source_field`-Pfad nach Kanon (Phase A/C).
- [ ] Dedupe Polar/Apple: nach stabilen `started_at`/`ended_at` + Policy (eigenes Issue).
---
## 6. Backfill (nicht in Migration 054)
Separates Skript oder Migration **055+**, wenn fachlich freigegeben:
- Pro aktivem `training_parameter` mit gesetztem `source_field`: Wert aus `activity_log` lesen, in EAV schreiben, wenn noch keine Zeile existiert.
- Idempotent (`ON CONFLICT DO NOTHING` oder Upsert-Regel dokumentieren).
---
## 7. Automatische Tests (pytest, ohne DB)
Aus **`backend/`**:
```bash
python -m pytest tests/test_activity_session_metrics.py -v
```
Abdeckung: reine Merge-Logik (`merge_parameter_schema_rows`), Validierung (`_validate_single_value`), `resolve_activity_attribute_schema` mit Mock-Cursor, `enrich_sessions_with_metrics` mit Mock-Cursor.
---
## 8. Referenzen
- Migration 013: `training_parameters`
- Migration 004/014: `training_types`, `activity_log`-Erweiterungen
- Pattern Admin-Katalog: `routers/admin_reference_value_types.py`
- Platzhalter Session-JSON: `data_layer/activity_metrics.py` → `get_training_sessions_recent_weeks_data`
- KI-Legende: `get_training_parameters_ki_glossary_data`, Platzhalter `{{training_parameters_glossary_md}}`
---
**Version:** 1.1 · Bei Schema- oder API-Änderungen dieses Dokument und ggf. `CLAUDE.md` Kurzverweis aktualisieren.