shinkan-jinkendo/.claude/docs/technical/DATABASE_SCHEMA.md
Lars c4fbabd8f6
Some checks failed
Deploy Development / deploy (push) Successful in 36s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 6s
Test Suite / playwright-tests (push) Failing after 39s
chore: update versioning and enhance training framework features
- Incremented APP_VERSION to 0.8.10 and DB_SCHEMA_VERSION to 20260505037.
- Updated project status and domain model documentation to reflect recent changes.
- Enhanced training framework program handling with new slot-blueprint structure.
- Introduced API endpoint for creating training units from framework slots.
- Improved documentation for training planning and governance concepts.
2026-05-05 13:39:30 +02:00

456 lines
18 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.

# Shinkan Jinkendo - Datenbank-Schema (Technisch)
**Version:** 0.5.2
**Stand:** 2026-05-05
**Hinweis:** Produktiver Deploy sollte mindestens bis Migration **037** (RahmenSlotBlueprints in `training_units`; Entfall `training_framework_slot_exercises`) geführt sein — Details siehe `backend/version.py` (`DB_SCHEMA_VERSION`).
---
## Ü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 |
| 024031 | *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** | **SlotBlueprint:** `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`** | ✅ |
---
## 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
exercise_variants (id, exercise_id, name, description, ...)
exercise_media (id, exercise_id, type, url, title, description, ...)
```
### Trainingsrahmenprogramm Bibliothek (Migrationen **035036**)
Kopf ohne Gruppenbindung (`training_framework_programs`), Ziele, Slots. Slotspezifischer 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 & RahmenBlueprint (Migrationen 006, 031, **037**)
Geplante Einheit und **RahmenSlotBlueprint** teilen sich **`training_units`** und den strukturierten Ablauf über **Sektionen** (031). BlueprintZeilen haben **`framework_slot_id`** gesetzt (genau eine Zeile pro Slot); KalenderZeilen 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 KalenderZeilen (CHECK)
planned_date DATE NULL, -- Pflicht für KalenderZeilen (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 032034)
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