shinkan-jinkendo/.claude/docs/technical/TRAINING_FRAMEWORK_SPEC.md
Lars 1d698e4b0a
Some checks failed
Deploy Development / deploy (push) Failing after 22s
Test Suite / pytest-backend (push) Successful in 35s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Failing after 3s
Test Suite / k6 /health Baseline (push) Successful in 33s
Test Suite / playwright-tests (push) Successful in 1m14s
Implement Phase 3 Enhancements for Skill Scoring and Profiles
- Added capabilities for weighted skill profiles, allowing trainers to compare training modules, frameworks, and regression paths based on skill contributions.
- Updated the skill scoring specification to include peer context separation and list filtering, ensuring accurate comparisons among visible artifacts of the same type.
- Enhanced the API to support batch summaries for skill profiles and discovery suggestions, improving data retrieval efficiency.
- Refactored frontend components to display skill metrics, including scores and peer percentages, with improved filtering options for better user experience.
- Updated documentation to reflect the latest changes and enhancements in the skill scoring system.
2026-05-21 12:35:45 +02:00

196 lines
15 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Trainingsrahmenprogramm — Technische Spezifikation
**Status:** RahmenBibliothek + SlotBlueprint dokumentiert · **Stand:** 2026-05-05 (Migration **036037**)
**Bindendes Fachkonzept / Entscheide:** `.claude/docs/functional/TRAINING_CURRICULUM_AND_GOVERNANCE_CONCEPT.md` (CURR001 bis CURR013)
**Relevant für nächsten Schritt:** CURR002 **(2)** Trainingsplanung / Rahmen über mehrere Einheiten — der hier dokumentierte **Progressionsgraph Stufe 1** ist bewusst **unterstützend**, keine Pflicht für Slot-Zuordnungen (**CURR013**).
---
## 1. Abgrenzung zu anderen Dokumenten
| Dokument | Rolle · warum **nicht** hier hineinmischen |
|----------|--------------------------------------------|
| `EXERCISES_DATABASE_FINAL.md`, `EXERCISES_ARCHITECTURE.md`, `EXERCISES_API_SPEC.md` | **Übungskatalog** inkl. Varianten-Progression **innerhalb einer Übung** (Migration 014). Kanten **zwischen** Übungen siehe **§3**. |
| `DATABASE_SCHEMA.md` | **Nachgeordnete** Übersicht: Migrationshistorie und Tabellenliste; Detail-DDL primär **hier §2§3** + SQL unter `backend/migrations/`. |
| `functional/DOMAIN_MODEL.md` | Fachliche Begriffe; Kurzverweis auf Progressionsgraph ergänzt. |
| `TRAINING_CURRICULUM_AND_GOVERNANCE_CONCEPT.md` | **Was** und **warum** (Bibliothek vs. Instanz, Governance, CURRTabelle). |
| `functional/PARALLEL_TRAINING_STREAMS_CONCEPT.md`, `technical/PARALLEL_TRAINING_STREAMS_SPEC.md` | **Parallele Streams / Breakout innerhalb einer Einheit** — orthogonale Domäne zu **RahmenSlots** (SerienSessions). |
| `technical/SKILL_SCORING_SPEC.md` | **Fähigkeiten-Profil** der RahmenSlots / Module / Pfade; Listen-Filter und PeerVergleich (nur gleicher Artefakttyp). |
**Konsequenz:** Diese Datei bleibt der **technische Arbeitspool** für Rahmenprogramm Stufe 12. Abschnitt **§4** beschreibt explizit den **aktuellen Produktfreigabe-Umfang** und **bekannte Lücken** (damit Trainingsplanung weiter gebaut werden kann ohne falscher Erwartung an „AlternativePakete“ in der UI).
---
## 2. Rahmenprogramm (CURR002 Stufe2) — Checkliste & technische Ausarbeitung
### 2.0 Technische Entscheidung: nur Bibliothek + SlotBlueprint = `training_units`
**Fachlich:** Das Rahmenprogramm ist eine **wiederverwendbare Bibliotheksvorlage** ohne Bindung an eine Trainingsgruppe oder einen Kalendertermin (**Migration 036** entfernte `plan_mode`, `group_id` am Kopf sowie die Nutzung von `training_framework_slots.training_unit_id` für „konkrete“ Kopplung).
**SlotInhalt (Migration 037):** Pro `training_framework_slot` existiert genau eine **BlueprintZeile** in `training_units` mit **`framework_slot_id`** (partieller **UNIQUE**-Index); der Ablauf entspricht **derselben** Struktur wie geplante Einheiten über **`training_unit_sections`** und **`training_unit_section_items`** (Übungen, Notizen, Varianten wie in der Planung). Die frühere Tabelle **`training_framework_slot_exercises`** wird nach Datenübernahme **`DROP`**pt.
**Geplante Einheit aus Rahmen:** **`POST /api/training-units/from-framework-slot`** kopiert diese BlueprintUnit (**tiefe Kopie**) mit **`group_id` + `planned_date`**; **`origin_framework_slot_id`** hält die Herkunft (LineageLight). **`GET /api/training-units`** blendet Einheiten mit **`framework_slot_id IS NOT NULL`** aus (Kalender/APIListe ohne RahmenBlueprints).
**CHECKConstraint auf `training_units`:** Zeile ist entweder **Blueprint** (`framework_slot_id` gesetzt, `group_id`/`planned_date` NULL, kein `origin_framework_slot_id`) oder **KalenderEinheit** (`framework_slot_id` NULL, `group_id` und `planned_date` gesetzt; `origin_framework_slot_id` optional).
**Konsequenz KonzeptCURR012 („concrete/library“):** Persistiert wird **ein** Kopf ohne Modus-Spalte: Immer BibliotheksRolle; Konkretisierung nur über Planung/APIKopie. Historische DDL mit `plan_mode` siehe **`035`**/`036` in dieser Datei (**§5 Changelog**) und `backend/migrations/`.
### 2.1 Checkliste (Abhak-Stand)
- [x] **Entität(en):** `training_framework_programs` (**CURR009**); `training_plan_templates` unverändert **eineEinheitMikrovorlage** (**C5**).
- [x] **Bibliothek only (036):** Kopf ohne `plan_mode`/`group_id`; Kontextfilter **`focus_area_id`**, **`style_direction_id`**; M:N **`training_framework_program_training_types`**, **`training_framework_program_target_groups`**.
- [x] **Zielliste:** `training_framework_goals`, API **1** Ziel (**CURR011**).
- [x] **Slots:** `training_framework_slots` mit **`sort_order`**, optional **Titel/Notizen**; **Ablauf** über zugehörige **Blueprint`training_units`** + Sektionen/Items (**037**), nicht mehr `training_framework_slot_exercises`.
- [x] **Progressionsgraph:** Stufe1 (**§3§4**); **kein Pflichtbezug** pro Slot (**CURR013**).
- [x] **Kein LiveWrite** von Kalendereinheiten zurück in die Vorlage (**CURR006**); Konkretisierung = **Kopie** (siehe **§2.4**).
- [x] **Instanziierung (MVP):** `POST /api/training-units/from-framework-slot` — weiterer Ausbau: Bulk, KalenderUIFlow, **`training_plan_template_id` pro Slot** weiterhin optional/deferred (**CURR010**).
- [x] **Governance:** `visibility`, `club_id`, **`training_plan_templates.visibility`** (**035**) — (**CURR005008**).
- [x] **REST Rahmenprogramm:** `/api/training-framework-programs` (**§2.3**); Planung (**§2.4**).
### 2.2 DDLÜberblick (Migrationen **035** → **036** → **037**)
Auszug aktueller Zustand nach **036/037** (Details: `backend/migrations/035_training_framework_programs.sql`, `036_framework_program_context_only_library.sql`, `037_training_framework_blueprint_units.sql`):
```sql
-- Kopf (ohne Modus-Spalten nach 036)
training_framework_programs (
id, title NOT NULL, description,
planned_period_start, planned_period_end NULL,
visibility NOT NULL, club_id, created_by,
focus_area_id, style_direction_id NULL REFERENCES ,
timestamps
)
training_framework_goals (
id, framework_program_id FK CASCADE, sort_order UNIQUE per framework,
title, notes
)
training_framework_slots (
id, framework_program_id FK CASCADE, sort_order UNIQUE per framework,
title, notes,
training_unit_id FK (Spalte technisch noch vorhanden; fachlich ungenutzt, per 036 geleert)
)
-- Blueprint: eigene Einheit wie in der Planung (031)
training_units.framework_slot_id -- UNIQUE (partial index), FK → slots ON DELETE CASCADE
training_units.origin_framework_slot_id -- optional auf Kopien aus dem Rahmen (SET NULL)
-- CHECK chk_training_units_blueprint_vs_scheduled (Blueprint vs. KalenderZeile)
-- training_framework_slot_exercises → entfallen (037)
```
**Löschkaskaden:** Rahmen löschen ⇒ Ziele + Slots; **Slot löschen** ⇒ zugehörige Blueprint`training_unit` per **`ON DELETE CASCADE`** auf `framework_slot_id`.
### 2.3 RESTÜberblick (`router` `training_framework_programs`)
| Methode | Pfad | Zweck |
|---------|------|--------|
| GET | `/training-framework-programs` | Liste; Admin/Superadmin alle, sonst eigene (`created_by`); u. a. `goals_count`, `slots_count`, KontextCounts |
| GET | `/training-framework-programs/{id}` | Detail inkl. `goals[]`, `slots[]` mit je **`blueprint_training_unit_id`**, **`sections[]`**, **`exercises[]`** (letzteres aus Sektionen geflacht, kompatibel zum Editor) |
| POST | `/training-framework-programs` | Neu; **Pflicht:** `title`, **`goals`** (≥1); optional `slots` (weiterhin **`exercises[]`** pro Slot möglich — Backend materialisiert Sektionen); Header: `focus_area_id`, `style_direction_id`, `training_type_ids`, `target_group_ids`, … |
| PUT | `/training-framework-programs/{id}` | Header; volles Ersetzen von **`goals`** und/oder **`slots`** (neue Slots ⇒ neue BlueprintUnits) |
| DELETE | `/training-framework-programs/{id}` | Rahmen + Kinder |
**AuthZ:** wie zuvor — Planungsrolle zum Schreiben; Lesen/Schreiben/Löschen des Rahmens: Admin/Superadmin oder Ersteller.
**PayloadHinweise (JSON), Slots:**
- Weiterhin: `exercises: [{ exercise_id, exercise_variant_id?, order_index? }]` (wird intern in eine Sektion übernommen).
- Erweitert möglich: `sections` wie bei **`PUT /api/training-units/{id}`** (voller Ablauf mit Notizen/Items).
### 2.4 Planung / Kalender (`router` `training_planning.py`, Auszug)
| Methode | Pfad | Zweck |
|---------|------|--------|
| GET | `/training-units` | Nur **KalenderEinheiten** (`framework_slot_id IS NULL`) |
| GET/PUT | `/training-units/{id}` | Blueprint lesen/bearbeiten: möglich mit RahmenAuth; spezielle Regeln im **PUT** (kein TemplateReset, kein `plan_template_id` am Blueprint) |
| DELETE | `/training-units/{id}` | Blueprint **nicht** über diesen Pfad löschen (Fehlerhinweis); Slot entfernen über Rahmen**PUT** |
| POST | `/training-units/from-framework-slot` | Body: `framework_slot_id`, `group_id`, `planned_date` — tiefe Kopie + **`origin_framework_slot_id`** |
**Frontend:** `createTrainingUnitFromFrameworkSlot` in `frontend/src/utils/api.js`.
---
## 3. Progressionsgraph Übung → Übung (implementierter Stand)
### 3.1 Abgrenzung
- **Zwischen Übungen:** gerichtete Kanten auf Ebene **`exercises`** mit optionalen Endpunkten auf konkreten **`exercise_variants`** (Knoten = „Übung“ oder „Übung · Variante“). Migrationen **032034**.
- **Innerhalb einer Übung:** Reihenfolge / Progressionsmetadaten der Varianten unverändert über **`exercise_variants`** (Migration **014**) — nicht duplizieren.
AuthZ analog **`training_plan_templates`**: Graph nur für **Admin/Superadmin** oder **Ersteller** (`created_by`); Anlegen neuer Graphen mit **`_has_planning_role`**.
### 3.2 Migrationen & Schema (Kurz)
| Mig. | Inhalt |
|------|--------|
| **032** | `exercise_progression_graphs` (Name, Beschreibung, **`visibility`**, **`club_id`**, **`created_by`**); `exercise_progression_edges` (`graph_id`, von/nach Übung, `edge_type` VARCHAR Default `next_exercise`). FK CASCADE zu Graph und Übungen. |
| **033** | `exercise_progression_edges.notes` (freier Text / „Entwicklungsziel“ pro Kante). |
| **034** | `from_exercise_variant_id`, `to_exercise_variant_id` (nullable, FK `exercise_variants`, CASCADE). CHECK: gleiche Übung nur mit **zwei verschiedenen Varianten**. UNIQUE-Index über Graph + Endpunkte inkl. `COALESCE(variant_id,0)` + `edge_type`. |
Kantentypen in Produktnutzung: **`next_exercise`** (Nachfolger), **`sibling`** (Schwester / gleiche „Entwicklungslage“, semantisch oft Paar — weiterhin eine gerichtete Kante in DB).
Listenqueries liefern JoinFelder **`from_exercise_title`**, **`to_exercise_title`**, **`from_variant_name`**, **`to_variant_name`**.
### 3.3 REST (`/api`, Router `exercise_progression_graphs.py`)
| Methode | Pfad | Zweck |
|---------|------|--------|
| GET | `/exercise-progression-graphs` | Liste (+ `edges_count`); Admin sieht alle, sonst nur eigene. |
| GET | `/exercise-progression-graphs/{id}` | Detail; `?include_edges=true` |
| POST | `/exercise-progression-graphs` | Graph anlegen |
| PUT | `/exercise-progression-graphs/{id}` | Metadaten |
| DELETE | `/exercise-progression-graphs/{id}` | Graph + Kanten |
| GET | `/exercise-progression-graphs/{id}/edges` | Kanten; Query optional `from_exercise_id`, `to_exercise_id` |
| POST | `/exercise-progression-graphs/{id}/edges` | Einzelkante; Duplikat/Constraint → **409** |
| POST | `/exercise-progression-graphs/{id}/edges/sequence` | **Bulk:** `{ steps: [{ exercise_id, variant_id? }, …], segment_notes?: [...] }` — nur **`next_exercise`**, Transaktion alle oder keine Zeile |
| PUT | `/exercise-progression-graphs/{id}/edges/{edge_id}` | z.B. **`notes`** |
| DELETE | `/exercise-progression-graphs/{id}/edges/{edge_id}` | eine Kante |
| POST | `/exercise-progression-graphs/{id}/edges/delete-batch` | `{ edge_ids: [...] }` — z.B. gesamte sichtbare „Reihe“ löschen |
### 3.4 Frontend (Stand Code)
- **`ExercisesListPage`:** Tabs **Liste** · **Progressionsgraphen****`ExerciseProgressionGraphPanel`**.
- **`ExerciseFormPage`** (nur Edit): eingeklappter Block **Progressionsgraph** mit Kontext „diese Übung“ + Filter „nur betroffene Kanten“.
- PanelFunktionen: **SequenzEditor** (mehrere Schritte → ein BulkSpeichern), zusammengefasste **ReihenLesart** für `next_exercise`, eigene Liste für **Schwestern**, Einzelkantenbereich, Tab **Alle Kanten (Tabelle)**.
- APIClient: `frontend/src/utils/api.js` (`createExerciseProgressionSequence`, `deleteExerciseProgressionEdgesBatch`, …).
---
## 4. Zwischenstand für Produkt / Trainingsplanung (bewusste Grenzen)
**Freigabe:** Der beschriebene Stand unterstützt **RahmenBibliothek mit vollem Ablauf pro Slot** (wie Planung) und **Kopie in die Gruppenplanung**; der **Progressionsgraph** bleibt **unterstützend** (**CURR013**). Offen: KalenderUIFlow, BulkInstanziierung, erweiterte Lineage/Feedback (**Konzept Schritt E**).
**Was gut nutzbar ist**
- Lineare **Reihen** mehrerer Übungen (bzw. VariantenKnoten) über **SequenzAPI** bzw. SequenzUI.
- **NachfolgerLesart** als zusammenhängende Kette in der Übersicht.
- **SchwesterKanten** als eigene Liste (Alternative gleicher „Stufe“ zwischen zwei Knoten).
- **Einzelkanten** für Sonderfälle und Verzweigungen.
**Was noch nicht „ein Knopf“ ist (bekannt)**
- **Parallele gleichwertige Alternativen** („Paket B bestehend aus mehreren Übungen als echte Alternative zu Paket A“) sind **nicht** als ersteKlassUX modelliert: mehrere Nachfolger aus einem Knoten sind technisch möglich (mehrere `next_exercise`Kanten), aber **keine** dedizierte Gruppe „AlternativSet“. Pflege kann mehrzeilig und koplastisch wirken.
- **Visualisierung echter Bäume** (JoinPoints, mehrere ausgehende Pfeile in einem Bild) ist nur eingeschränkt über ReihenZusammenfassung + Tabelle abbildbar.
**Nächste sinnvolle Ausbaustufen** (Backlog GraphUX, nicht Blocker Planung)
- Semantik **`alternative_group_id`** oder **Hyperkanten** (ein UXSchritt legt mehrere Kanten mit gemeinsamer Gruppe an).
- Komfort beim Pflegen **symmetrischer Schwestern** (ein Klick für zwei Richtungen / Dedupe).
- Karten-/BaumLayout statt nur Zeilen.
Details weiterhin Diskussionsgrundlage in `TRAINING_CURRICULUM_AND_GOVERNANCE_CONCEPT.md` §6 (Kantentypen).
---
## 5. Changelog (Dokument)
| Datum | Änderung |
|-------|----------|
| 2026-05-05 | **037 / API:** Nur Bibliothek + **Blueprint** pro Slot über `training_units` + Sektionen/Items; `training_framework_slot_exercises` entfernt; `POST …/training-units/from-framework-slot`; Planungsliste ohne Blueprints. **036** dokumentiert am Kopf (Kontext, M:N, kein plan_mode/group_id). **§2** vollständig ersetzt. |
| 2026-05-05 | **CURR002 (2):** §2 Rahmenprogramm — Entscheid **eine Tabelle + `plan_mode`**, DDLSkizze, RESTÜberblick; Migration **035**; `training_plan_templates.visibility`. *(Historisch — Modus-Spalten durch **036** ersetzt.)* |
| 2026-04-30 | **Zwischen-Doku:** §3 auf Migrationen 032034 + API **sequence/delete-batch** + Frontend erweitert; **§4** Produktfreigabe vs. Lücken (parallele Alternativen); Changelog §5. |
| 2026-04-30 | §3: erste Fassung Migration 032 + RESTBasis (CURR002 (1)). |
| 2026-04-28 | Erstanlage Stub mit Checkliste. |