All checks were successful
Deploy Development / deploy (push) Successful in 34s
Test Suite / pytest-backend (push) Successful in 25s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 7s
Test Suite / playwright-tests (push) Successful in 23s
- Introduced a centralized media archive (`/media`) with lifecycle management, including soft delete and recovery options. - Enhanced media upload functionality to support multiple files and automatic type inference. - Updated documentation to reflect the new media architecture and inline media linking specifications. - Version bump to 0.8.59 to accommodate changes in media handling and database schema. Co-authored-by: Cursor <cursoragent@cursor.com>
457 lines
18 KiB
Markdown
457 lines
18 KiB
Markdown
# Shinkan Jinkendo - Datenbank-Schema (Technisch)
|
||
|
||
**Version:** 0.5.3
|
||
**Stand:** 2026-05-07
|
||
**Hinweis:** Produktiver Deploy sollte mindestens bis Migration **037** (Rahmen‑Slot‑Blueprints) und für Medien-Archiv bis **045+** (`media_assets`, …) geführt sein — Details siehe `backend/version.py` (`DB_SCHEMA_VERSION`) und **`MEDIA_ASSETS_AND_ARCHIVE_SPEC.md`**.
|
||
|
||
---
|
||
|
||
## Übersicht
|
||
|
||
Dieses Dokument beschreibt die **technische Datenbankstruktur** von Shinkan Jinkendo.
|
||
|
||
**Zuständig für fachliche Modellierung:** siehe `DOMAIN_MODEL.md`
|
||
|
||
---
|
||
|
||
## Migrations-Historie
|
||
|
||
| Nr. | Datum | Beschreibung | Status |
|
||
|-----|-------|--------------|--------|
|
||
| 001 | 2026-04-20 | Initial Schema (Auth, Profiles) | ✅ Deployed |
|
||
| 002 | 2026-04-20 | Clubs, Divisions, Groups | ✅ Deployed |
|
||
| 003 | 2026-04-20 | Skills, Methods | ✅ Deployed |
|
||
| 004 | 2026-04-21 | Training Types | ✅ Deployed |
|
||
| 005 | 2026-04-21 | Exercises (Basis) | ✅ Deployed |
|
||
| 006 | 2026-04-21 | Training Planning | ✅ Deployed |
|
||
| 007 | 2026-04-22 | Exercise Catalogs (idempotent) | ✅ Deployed |
|
||
| 008 | 2026-04-23 | M:N Exercise Relations + Hierarchical Catalogs | ✅ Deployed |
|
||
| 009 | 2026-04-23 | Target Groups M:N Refactoring (BREAKING) | ✅ Deployed |
|
||
| 010 | 2026-04-23 | Rename training_styles to style_directions | ✅ Deployed |
|
||
| 011 | 2026-04-23 | Create Training Types | ✅ Deployed |
|
||
| 012 | 2026-04-23 | Exercise Training Characters + Trainer Contexts | ✅ Deployed |
|
||
| 013 | 2026-04-23 | Training Types Focus Area | ✅ Deployed |
|
||
| 014 | 2026-04-24 | Variant Progression Search Legacy | ✅ Deployed |
|
||
| 016 | 2026-04-24 | Saved Searches | ✅ Deployed |
|
||
| 017 | 2026-04-24 | Exercise Blocks | ✅ Deployed |
|
||
| 018 | 2026-04-24 | Wiki Import Tracking | ✅ Deployed |
|
||
| 019 | 2026-04-24 | Exercises Optional Fields (goal/execution nullable) | ✅ Deployed |
|
||
| 020 | 2026-04-27 | Exercise Skills UNIQUE Constraint | ✅ Deployed |
|
||
| 021 | 2026-04-27 | ~~Import Skills from Matrix~~ (DEPRECATED) | ⚠️ Faulty |
|
||
| **022** | **2026-04-27** | **Skills Schema Complete (BREAKING)** | ✅ Deployed |
|
||
| **023** | **2026-04-27** | **Skills Complete Import (69 Skills)** | ✅ Deployed |
|
||
| 024–031 | *versch.* | Reifegradmodelle, Medien, Planvorlagen/Sektionen u. a. — siehe `backend/migrations/` | ✅ je Umgebung |
|
||
| **032** | **2026-04-30** | **Progressionsgraph Übung→Übung:** `exercise_progression_graphs`, `exercise_progression_edges` | ✅ |
|
||
| **033** | **2026-04-30** | **`exercise_progression_edges.notes`** | ✅ |
|
||
| **034** | **2026-04-30** | **Kanten-Endpunkte optional `exercise_variants`; UNIQUE/CHECK** | ✅ |
|
||
| **035** | **2026-05-05** | **Rahmenprogramm:** `training_framework_programs` (+ Ziele, Slots, früher `training_framework_slot_exercises`); **`training_plan_templates.visibility`** (Backfill `club`) — siehe `TRAINING_FRAMEWORK_SPEC.md` | ✅ |
|
||
| **036** | **2026-05-05** | **Rahmen nur Bibliothek:** Kopf mit `focus_area_id`, `style_direction_id`, M:N Trainingsarten/Zielgruppen; Entfall `plan_mode`, `group_id`; Slot‑`training_unit_id` geleert — siehe `036_framework_program_context_only_library.sql` | ✅ |
|
||
| **037** | **2026-05-05** | **Slot‑Blueprint:** `training_units.framework_slot_id` (+ CHECK Blueprint vs. Kalender), `origin_framework_slot_id`; Migration Slot‑Übungen → `training_unit_sections`/`training_unit_section_items`; **`DROP training_framework_slot_exercises`** | ✅ |
|
||
| **040–046** | **2026-05** | **Mitgliedschaft/Anträge, Übungs-Governance-Erweiterungen, `media_assets`, `platform_media_storage`, `exercise_media.media_asset_id`, Tags/GIN u. a.** — exakte Nummern: `backend/migrations/`; fachliche Norm Medien: **`MEDIA_ASSETS_AND_ARCHIVE_SPEC.md`** | ✅ je Umgebung |
|
||
|
||
## Migration 022: Skills Schema Complete (BREAKING CHANGE)
|
||
|
||
**Problem:** Skills hatten keine Kategorisierung (Haupt-/Unterkategorie, Fokusbereich).
|
||
**Lösung:** Vollständiges hierarchisches Schema für produktionsreifen Import.
|
||
|
||
**Neue Tabellen:**
|
||
```sql
|
||
-- Haupt-Kategorien (KARATE / ALLGEMEINE)
|
||
skill_main_categories (
|
||
id SERIAL PRIMARY KEY,
|
||
name VARCHAR(200) UNIQUE NOT NULL, -- "KARATE Fähigkeiten" / "ALLGEMEINE sportliche Fähigkeiten"
|
||
slug VARCHAR(50) UNIQUE NOT NULL, -- "karate" / "allgemeine"
|
||
description TEXT,
|
||
sort_order INT,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
updated_at TIMESTAMP DEFAULT NOW()
|
||
)
|
||
|
||
-- Level-Definitionen (1-5 Beschreibungen aus Fähigkeitsmatrix)
|
||
skill_level_definitions (
|
||
id SERIAL PRIMARY KEY,
|
||
skill_id INT NOT NULL REFERENCES skills(id) ON DELETE CASCADE,
|
||
level INT NOT NULL CHECK (level BETWEEN 1 AND 5),
|
||
description TEXT NOT NULL,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
updated_at TIMESTAMP DEFAULT NOW(),
|
||
UNIQUE (skill_id, level)
|
||
)
|
||
```
|
||
|
||
**Erweiterte Tabellen:**
|
||
```sql
|
||
-- skill_categories erweitert
|
||
ALTER TABLE skill_categories ADD COLUMN slug VARCHAR(50);
|
||
ALTER TABLE skill_categories ADD COLUMN main_category_id INT REFERENCES skill_main_categories(id);
|
||
ALTER TABLE skill_categories ADD CONSTRAINT skill_categories_slug_unique UNIQUE (slug);
|
||
|
||
-- skills erweitert
|
||
ALTER TABLE skills ADD COLUMN main_category_id INT REFERENCES skill_main_categories(id);
|
||
ALTER TABLE skills ADD COLUMN focus_areas JSONB DEFAULT '[]'::jsonb;
|
||
```
|
||
|
||
**Indizes:**
|
||
- `idx_skills_main_category_id`
|
||
- `idx_skills_category_id`
|
||
- `idx_skill_categories_main_category_id`
|
||
- `idx_skill_level_definitions_skill_id`
|
||
|
||
**Struktur:**
|
||
```
|
||
skill_main_categories (Hauptkategorie)
|
||
└─ skill_categories (Unterkategorie)
|
||
└─ skills (Fähigkeit)
|
||
└─ skill_level_definitions (Level 1-5 Beschreibungen)
|
||
```
|
||
|
||
---
|
||
|
||
## Migration 023: Skills Complete Import
|
||
|
||
**Quelle:** Fähigkeitsmatrix (https://karatetrainer.net/index.php?title=Fähigkeitsmatrix)
|
||
|
||
**Importiert:**
|
||
- **69 Skills** mit vollständiger Kategorisierung
|
||
- **2 Haupt-Kategorien:** KARATE Fähigkeiten, ALLGEMEINE sportliche Fähigkeiten
|
||
- **9 Unterkategorien:** Kihon, Kumite, Kata, Selbstverteidigung, Koordination, Kondition, Kognition, Soziale Fähigkeiten, Psychische Fähigkeiten
|
||
|
||
**Skills-Verteilung:**
|
||
```
|
||
KARATE Fähigkeiten (32 Skills, focus_areas: ["karate"]):
|
||
├─ Kata (8): Technik Kombination, Kata Ablauf, Bunkai, Oyo, Henka, Kakushi, Kata Atmung, Kata Rhythmus
|
||
├─ Kihon (10): Dachi Waza, Uke Waza, Zuki Waza, Uchi Waza, Geri Waza, Nage Waza, Nukite Waza, Ken Waza, Hüfteinsatz, Kime
|
||
├─ Kumite (10): Beinarbeit, Distanzkontrolle, Angriff, Abwehr Konter, Präzision, Antizipation, Timing, Taktik, Fokus, Mentale Stärke
|
||
└─ Selbstverteidigung (4): Gefahrenbewustsein, Selbstbehauptung, Selbstschutz, Gefahrenabwehr
|
||
|
||
ALLGEMEINE sportliche Fähigkeiten (37 Skills, focus_areas: ["universal"]):
|
||
├─ Kognition (5): Aufmerksamkeit, Wahrnehmung, Urteilsvermögen, Merkfähigkeit, Lernfähigkeit
|
||
├─ Kondition (15): Maximalkraft, Schnellkraft, Reaktivkraft, Kraftausdauer, Muskelaufbau,
|
||
│ Reaktionsschnelligkeit, Bewegungsschnelligkeit, Handlungsschnelligkeit,
|
||
│ Schnelligkeitsausdauer, Grundlagenausdauer, Aerobe Ausdauer, Anaerobe Ausdauer,
|
||
│ Regenerationsfähigkeit, Ermüdungswiderstandsfähigkeit, Flexibilität
|
||
├─ Koordination (7): Orientierung, Differenzierung, Kopplung, Gleichgewicht, Rhythmisierung, Reaktion, Umstellung
|
||
├─ Psychische Fähigkeiten (6): Selbstvertrauen, Konzentration, Emotionale Kontrolle, Motivation, Stressresistenz, Stressregulation
|
||
└─ Soziale Fähigkeiten (4): Deeskalation, Selbstdisziplin, Toleranz, Fairness
|
||
```
|
||
|
||
**Duplikat-Handling:**
|
||
Einige Skills kommen in der Matrix doppelt vor (Kumite + Kondition/Koordination):
|
||
- **Behalten in Kondition:** Anaerobe Ausdauer, Bewegungsschnelligkeit, Flexibilität, Reaktionsschnelligkeit, Schnelligkeitsausdauer (konditionelle Primärfähigkeiten)
|
||
- **Behalten in Kumite:** Antizipation, Timing (kampfspezifisch)
|
||
|
||
**Cleanup:**
|
||
- DELETE FROM exercise_skills (M:N Beziehungen)
|
||
- DELETE FROM skills (alte Daten)
|
||
- DELETE FROM skill_categories
|
||
- DELETE FROM skill_main_categories
|
||
|
||
**Verifikation:**
|
||
```sql
|
||
-- Sollte 69 ergeben
|
||
SELECT COUNT(*) FROM skills;
|
||
|
||
-- Zeigt Verteilung
|
||
SELECT
|
||
mc.name AS hauptkategorie,
|
||
sc.name AS unterkategorie,
|
||
COUNT(s.id) AS anzahl_skills
|
||
FROM skills s
|
||
JOIN skill_categories sc ON s.category_id = sc.id
|
||
JOIN skill_main_categories mc ON s.main_category_id = mc.id
|
||
GROUP BY mc.name, sc.name, mc.sort_order, sc.sort_order
|
||
ORDER BY mc.sort_order, sc.sort_order;
|
||
```
|
||
|
||
---
|
||
|
||
## Kern-Entitäten
|
||
|
||
### Auth & Profile
|
||
|
||
```sql
|
||
profiles (id, name, email, password_hash, role, created_at)
|
||
sessions (id, profile_id, token, created_at, expires_at)
|
||
```
|
||
|
||
### Organisation
|
||
|
||
```sql
|
||
clubs (id, name, abbreviation, description, logo_url, ...)
|
||
divisions (id, club_id, name, description, ...)
|
||
training_groups (id, division_id, name, description, focus_area, level, ...)
|
||
```
|
||
|
||
### Kataloge
|
||
|
||
#### Fokusbereiche & Stile (M:N mit Zielgruppen)
|
||
|
||
```sql
|
||
focus_areas (id, name, abbreviation, description, color, icon, ...)
|
||
style_directions (id, focus_area_id, name, abbreviation, description, parent_style_id, ...)
|
||
target_groups (id, name, description, min_age, max_age, ...) -- Global, NICHT gebunden an Stil
|
||
training_style_target_groups (style_direction_id, target_group_id, is_primary) -- M:N Junction
|
||
```
|
||
|
||
#### Fähigkeiten (Hierarchisches Schema ab Migration 022)
|
||
|
||
```sql
|
||
-- Haupt-Kategorien (2: KARATE, ALLGEMEINE)
|
||
skill_main_categories (
|
||
id, name, slug, description, sort_order, created_at, updated_at
|
||
)
|
||
|
||
-- Unterkategorien (9: Kihon, Kumite, Kata, Selbstverteidigung, Koordination, Kondition, ...)
|
||
skill_categories (
|
||
id, name, slug, description, sort_order,
|
||
main_category_id REFERENCES skill_main_categories(id),
|
||
parent_category_id, -- Optional: Hierarchie
|
||
created_at, updated_at
|
||
)
|
||
|
||
-- Fähigkeiten (69 Skills)
|
||
skills (
|
||
id, name, description,
|
||
category_id REFERENCES skill_categories(id),
|
||
main_category_id REFERENCES skill_main_categories(id),
|
||
focus_areas JSONB, -- ["karate"] oder ["universal"]
|
||
created_at, updated_at
|
||
)
|
||
|
||
-- Level-Definitionen (optional, noch nicht gefüllt)
|
||
skill_level_definitions (
|
||
id, skill_id, level, description,
|
||
created_at, updated_at,
|
||
UNIQUE (skill_id, level)
|
||
)
|
||
```
|
||
|
||
**Focus Areas Bedeutung:**
|
||
- `["karate"]` - Skill ist spezifisch für Karate (z.B. Kata Ablauf, Kihon)
|
||
- `["universal"]` - Skill ist universell einsetzbar (z.B. Maximalkraft, Konzentration, Deeskalation)
|
||
- Später möglich: `["karate", "selbstverteidigung"]` - Mehrfachzuordnung
|
||
|
||
#### Trainingscharakter
|
||
|
||
```sql
|
||
training_characters (id, name, description, ...)
|
||
trainer_contexts (id, name, description, ...) -- Neue Dimension (Migration 012)
|
||
```
|
||
|
||
### Übungen (M:N Beziehungen ab Migration 008)
|
||
|
||
```sql
|
||
exercises (
|
||
id, title, summary, goal, execution, preparation, trainer_notes,
|
||
duration_min, duration_max,
|
||
group_size_min, group_size_max,
|
||
equipment JSONB,
|
||
visibility, status, created_by, club_id,
|
||
import_source, import_id, wiki_page_id, -- MediaWiki Import (Migration 018)
|
||
created_at, updated_at
|
||
)
|
||
|
||
-- M:N Beziehungen
|
||
exercise_focus_areas (exercise_id, focus_area_id, is_primary)
|
||
exercise_style_directions (exercise_id, style_direction_id, is_primary)
|
||
exercise_target_groups (exercise_id, target_group_id, is_primary)
|
||
exercise_age_groups (exercise_id, age_group) -- Enum: Minis, Kinder, Schüler, Teenager, Erwachsene
|
||
|
||
-- Fähigkeiten-Zuordnung (mit Level)
|
||
exercise_skills (
|
||
exercise_id, skill_id,
|
||
is_primary, intensity,
|
||
required_level INT, -- Voraussetzung (1-5)
|
||
target_level INT, -- Ziel (1-5)
|
||
UNIQUE (exercise_id, skill_id) -- Migration 020
|
||
)
|
||
|
||
-- Varianten & Medien (028+ Embed/Datei; 045+ optional media_asset_id → media_assets)
|
||
exercise_variants (id, exercise_id, name, description, ...)
|
||
exercise_media (id, exercise_id, media_asset_id NULL FK, embed_url, file_path, …)
|
||
media_assets (id, sha256, visibility, club_id, lifecycle_state, copyright_notice, storage_key, …)
|
||
platform_media_storage (id, local_relative_root, …)
|
||
```
|
||
|
||
### Trainingsrahmenprogramm Bibliothek (Migrationen **035–036**)
|
||
|
||
Kopf ohne Gruppenbindung (`training_framework_programs`), Ziele, Slots. Slot‑spezifischer Ablauf liegt nach **037** nicht mehr in eigener Übungstabelle, sondern in **`training_units`** mit **`framework_slot_id`** — siehe nächster Abschnitt.
|
||
|
||
```sql
|
||
training_framework_programs (… focus_area_id, style_direction_id, visibility, club_id, created_by …)
|
||
training_framework_goals (framework_program_id, sort_order, title, notes)
|
||
training_framework_slots (framework_program_id, sort_order, title, notes, training_unit_id -- ungenutzt)
|
||
training_framework_program_training_types (framework_program_id, training_type_id)
|
||
training_framework_program_target_groups (framework_program_id, target_group_id)
|
||
```
|
||
|
||
### Training Planning & Rahmen‑Blueprint (Migrationen 006, 031, **037**)
|
||
|
||
Geplante Einheit und **Rahmen‑Slot‑Blueprint** teilen sich **`training_units`** und den strukturierten Ablauf über **Sektionen** (031). Blueprint‑Zeilen haben **`framework_slot_id`** gesetzt (genau eine Zeile pro Slot); Kalender‑Zeilen haben **`framework_slot_id IS NULL`** und **`group_id` / `planned_date`** gesetzt. Kopien aus dem Rahmen können **`origin_framework_slot_id`** setzen.
|
||
|
||
```sql
|
||
training_units (
|
||
id,
|
||
group_id INT NULL REFERENCES training_groups(id), -- Pflicht für Kalender‑Zeilen (CHECK)
|
||
planned_date DATE NULL, -- Pflicht für Kalender‑Zeilen (CHECK)
|
||
planned_time_start, planned_time_end, planned_focus,
|
||
actual_date, actual_time_start, actual_time_end, attendance_count,
|
||
status, notes, trainer_notes,
|
||
created_by, plan_template_id REFERENCES training_plan_templates(id),
|
||
framework_slot_id INT NULL REFERENCES training_framework_slots(id) ON DELETE CASCADE,
|
||
origin_framework_slot_id INT NULL REFERENCES training_framework_slots(id) ON DELETE SET NULL,
|
||
…
|
||
)
|
||
training_unit_sections (
|
||
training_unit_id, order_index, title, guidance_notes,
|
||
source_template_section_id REFERENCES training_plan_template_sections(id)
|
||
)
|
||
training_unit_section_items (
|
||
section_id, order_index, item_type CHECK ('exercise'|'note'),
|
||
exercise_id, exercise_variant_id, planned_duration_min, actual_duration_min,
|
||
notes, modifications, note_body
|
||
)
|
||
```
|
||
|
||
**Legacy (Migration 006, für ältere Codepfade noch referenzierbar):** `training_unit_exercises`; produktiver Standardablauf liegt in **Sections/Items**.
|
||
|
||
**Trainingsvorlagen (031):** `training_plan_templates`, `training_plan_template_sections`.
|
||
|
||
```sql
|
||
exercise_blocks (id, name, description, created_by, club_id, ...) -- Migration 017
|
||
```
|
||
|
||
### Progressionsgraph Übung → Übung (Migrationen 032–034)
|
||
|
||
Separater gerichteter Graph **zwischen** Übungen (nicht zu verwechseln mit Varianten-Reihen **innerhalb** einer Übung, Migration 014). Detail-DDL und REST siehe `technical/TRAINING_FRAMEWORK_SPEC.md` §3.
|
||
|
||
```sql
|
||
exercise_progression_graphs (
|
||
id, name, description, visibility, club_id, created_by,
|
||
created_at, updated_at
|
||
)
|
||
exercise_progression_edges (
|
||
id, graph_id,
|
||
from_exercise_id, to_exercise_id,
|
||
from_exercise_variant_id, -- nullable (Migration 034)
|
||
to_exercise_variant_id,
|
||
edge_type, -- z. B. next_exercise, sibling
|
||
notes, -- Migration 033
|
||
created_at
|
||
)
|
||
```
|
||
|
||
### MediaWiki Import (Migration 018)
|
||
|
||
```sql
|
||
wiki_import_log (
|
||
id, category, import_type, import_status,
|
||
items_total, items_imported, items_skipped, items_failed,
|
||
error_log JSONB,
|
||
started_at, finished_at,
|
||
imported_by
|
||
)
|
||
|
||
wiki_import_references (
|
||
id, wiki_page_id, entity_type, local_id,
|
||
created_at, updated_at
|
||
)
|
||
```
|
||
|
||
**Import-Typen:**
|
||
- `exercise` - Übungen aus `Kategorie:Übungen`
|
||
- `skill` - Fähigkeiten aus `Kategorie:Fähigkeitsbeschreibung` (veraltet, nutze Migration 023)
|
||
- `method` - Trainingsmethoden aus `Kategorie:Methodenbeschreibung`
|
||
|
||
---
|
||
|
||
## Indizes
|
||
|
||
### Performance-Indizes
|
||
|
||
```sql
|
||
-- Hierarchie-Lookups
|
||
CREATE INDEX idx_style_directions_focus_area ON style_directions(focus_area_id);
|
||
CREATE INDEX idx_skill_categories_main_category ON skill_categories(main_category_id);
|
||
CREATE INDEX idx_skills_category ON skills(category_id);
|
||
CREATE INDEX idx_skills_main_category ON skills(main_category_id);
|
||
|
||
-- M:N Joins
|
||
CREATE INDEX idx_exercise_focus_areas_exercise ON exercise_focus_areas(exercise_id);
|
||
CREATE INDEX idx_exercise_focus_areas_focus ON exercise_focus_areas(focus_area_id);
|
||
CREATE INDEX idx_exercise_style_directions_exercise ON exercise_style_directions(exercise_id);
|
||
CREATE INDEX idx_exercise_style_directions_style ON exercise_style_directions(style_direction_id);
|
||
CREATE INDEX idx_exercise_target_groups_exercise ON exercise_target_groups(exercise_id);
|
||
CREATE INDEX idx_exercise_target_groups_target ON exercise_target_groups(target_group_id);
|
||
CREATE INDEX idx_exercise_skills_exercise ON exercise_skills(exercise_id);
|
||
CREATE INDEX idx_exercise_skills_skill ON exercise_skills(skill_id);
|
||
|
||
-- Import-Tracking
|
||
CREATE INDEX idx_wiki_import_references_wiki_page ON wiki_import_references(wiki_page_id);
|
||
CREATE INDEX idx_wiki_import_references_entity ON wiki_import_references(entity_type, local_id);
|
||
```
|
||
|
||
---
|
||
|
||
## Kaskadier-Regeln
|
||
|
||
### Fokusbereich löschen
|
||
|
||
**Verhalten:** `RESTRICT` (Löschen verweigern wenn verwendet)
|
||
|
||
**Prüfung:**
|
||
```sql
|
||
SELECT COUNT(*) FROM style_directions WHERE focus_area_id = :id
|
||
SELECT COUNT(*) FROM exercise_focus_areas WHERE focus_area_id = :id
|
||
```
|
||
|
||
**Alternativen:**
|
||
1. Umrouten: Alle abhängigen Stile auf neuen Fokusbereich setzen
|
||
2. Archivieren: Status auf 'archived' setzen statt löschen
|
||
|
||
### Stil löschen
|
||
|
||
**Verhalten:** `RESTRICT` wenn Zielgruppen oder Übungen zugeordnet
|
||
|
||
**Umrouten-Workflow:**
|
||
1. Admin wählt Ziel-Stil
|
||
2. System aktualisiert:
|
||
- `training_style_target_groups.style_direction_id`
|
||
- `exercise_style_directions.style_direction_id`
|
||
3. Löschen erlaubt
|
||
|
||
### Zielgruppe löschen
|
||
|
||
**Verhalten:** `SET NULL` oder `CASCADE` in `exercise_target_groups`
|
||
|
||
**Prüfung:**
|
||
```sql
|
||
SELECT COUNT(*) FROM training_style_target_groups WHERE target_group_id = :id
|
||
SELECT COUNT(*) FROM exercise_target_groups WHERE target_group_id = :id
|
||
```
|
||
|
||
### Skill löschen
|
||
|
||
**Verhalten:** `CASCADE` zu `skill_level_definitions`, `RESTRICT` wenn in `exercise_skills`
|
||
|
||
**Prüfung:**
|
||
```sql
|
||
SELECT COUNT(*) FROM exercise_skills WHERE skill_id = :id
|
||
```
|
||
|
||
---
|
||
|
||
## Nächste Schritte
|
||
|
||
- [ ] Level-Definitionen aus Fähigkeitsmatrix extrahieren (optional)
|
||
- [ ] Skills-Import testen mit Übungs-Import
|
||
- [ ] Migration 024: Skills-Beschreibungen aus Wiki importieren
|
||
- [ ] Admin-UI für Skill-Kategorien (CRUD)
|
||
- [ ] Skill-Filter in Übungssuche integrieren
|
||
|
||
---
|
||
|
||
**Letzte Aktualisierung:** 2026-04-27
|
||
**Verantwortlich:** Claude Code
|
||
**Review:** Pending
|