shinkan-jinkendo/.claude/docs/technical/SKILLS_MATRIX_SPEC.md
Lars 6801c60604
Some checks failed
Deploy Development / deploy (push) Successful in 35s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 5s
Test Suite / playwright-tests (push) Failing after 1m55s
feat: Add MediaWiki import functionality with tracking and mapping
- Implemented a new SQL migration for wiki import tracking tables.
- Created an import router for handling MediaWiki imports of exercises, skills, and methods.
- Developed a Semantic MediaWiki API client for direct API interactions.
- Added a mapper to convert SMW properties to local database fields.
- Introduced background tasks for asynchronous import processing.
- Implemented logging and error handling for import operations.
- Added endpoints for previewing imports, checking import status, and managing import references.
2026-04-24 14:41:52 +02:00

16 KiB
Raw Blame History

Fähigkeitsmatrix / Reifegradmodell Specification

Version: 1.0 Datum: 2026-04-24 Status: DRAFT Autor: Claude Code Basis: shinkan_anforderungsdokument_entwurf.md §8 + DOMAIN_MODEL.md


1. Konzept

1.1 Was ist die Fähigkeitsmatrix?

Die Fähigkeitsmatrix verbindet globale Fähigkeiten (Skills) mit kontextspezifischen Reifegradmodellen. Sie beantwortet pro Kontext die Frage:

„Was muss ein Schüler auf Stufe X dieser Fähigkeit können, und welche Übungen trainieren ihn von Stufe A auf Stufe B?"

Drei Ebenen:

1. Globale Fähigkeit (skill)
   "Distanzgefühl"  gilt überall, für alle Stile und Zielgruppen

2. Reifegradmodell (maturity_model)
   "Karate / Shotokan / Breitensport"  definiert WIE VIELE Stufen es gibt
   und wie die Stufen heißen

3. Modell-Fähigkeitsstufe (model_skill_level)
   "Stufe 3 von Distanzgefühl im Shotokan-Breitensport-Modell" 
   beschreibt KONKRET was auf Stufe 3 erwartet wird

1.2 Warum kontextabhängig?

Dieselbe Fähigkeit (z.B. „Distanzgefühl") hat in verschiedenen Kontexten unterschiedliche Bedeutungen:

Kontext Stufe 3 Bedeutung
Karate / Shotokan / Breitensport Distanzkontrolle in einfachen Partnerübungen
Karate / Shotokan / Leistungssport Stabile Distanz im freien Kumite
Selbstverteidigung / Erwachsene Sicherheitsabstand in Alltagssituationen einschätzen

Ein Modell hat variable Stufenanzahl (3-7, nicht fest 5):

Shotokan Breitensport → 5 Stufen (Einsteiger bis Experte)
Kinder-Karate        → 4 Stufen (Kinder-gerecht vereinfacht)
Leistungssport       → 7 Stufen (feiner granuliert)

1.3 Abgrenzung zu exercise_skills

exercise_skills:     Übung trainiert Fähigkeit mit Intensität und
                     suggested required/target Stufe
                     → kontextunabhängig (gilt für alle Modelle)

model_skill_levels:  Für dieses Modell bedeutet "Stufe 3" von Fähigkeit X:
                     "[konkrete Beschreibung]"
                     → kontextspezifisch

2. Datenmodell

2.1 Entity-Übersicht

focus_areas (global, existiert)
    └─ style_directions (existiert, früher training_styles)
        └─ target_groups (M:N, existiert)

maturity_models (NEU)
    ├─ focus_area_id FK (optional, NULL = gilt für alle Fokusbereiche)
    ├─ style_direction_id FK (optional)
    ├─ target_group_id FK (optional)
    └─ level_count (INT)  wie viele Stufen hat das Modell?

model_levels (NEU)  Stufen-Definitionen
    ├─ maturity_model_id FK
    ├─ level_number (1 bis level_count)
    ├─ name (z.B. "Einsteiger", "Grundlagen", ...)
    └─ description

model_skill_levels (NEU)  Was bedeutet Stufe X für Fähigkeit Y im Modell Z?
    ├─ maturity_model_id FK
    ├─ skill_id FK
    ├─ level_number (muss in maturity_model.level_count liegen)
    ├─ description (Pflicht-Text: was soll der Lernende können?)
    ├─ observable_criteria (Beobachtungskriterien für Trainer)
    └─ example_exercises JSONB (Empfohlene Übungs-Typen, keine FK)

2.2 Vollständige Migration (019_maturity_models.sql)

-- Migration 019: Fähigkeitsmatrix / Reifegradmodelle
-- Autor: Claude Code
-- Datum: 2026-04-24

DO $$
BEGIN

-- ============================================================================
-- MATURITY MODELS (Reifegradmodelle)
-- ============================================================================

CREATE TABLE IF NOT EXISTS maturity_models (
    id SERIAL PRIMARY KEY,
    name VARCHAR(200) NOT NULL,
    description TEXT,

    -- Kontext-Bindung (alle optional  NULL bedeutet "gilt allgemein")
    -- Je mehr gesetzt, desto spezifischer das Modell
    focus_area_id       INT REFERENCES focus_areas(id)       ON DELETE RESTRICT,
    style_direction_id  INT REFERENCES style_directions(id)  ON DELETE RESTRICT,
    target_group_id     INT REFERENCES target_groups(id)     ON DELETE RESTRICT,

    -- Stufenanzahl (flexibel, nicht fest auf 5)
    level_count INT NOT NULL DEFAULT 5 CHECK (level_count BETWEEN 3 AND 10),

    -- Sichtbarkeit & Freigabe
    -- 'draft': in Bearbeitung | 'active': in Nutzung | 'archived': nicht mehr aktiv
    status VARCHAR(20) DEFAULT 'draft' CHECK (status IN ('draft', 'active', 'archived')),

    -- Versionierung
    version VARCHAR(20) DEFAULT '1.0',

    -- Ownership
    created_by  INT REFERENCES profiles(id) ON DELETE SET NULL,
    club_id     INT REFERENCES clubs(id)    ON DELETE SET NULL,

    -- Import-Tracking (für Semantic MediaWiki Import)
    import_source VARCHAR(50),
    import_id     VARCHAR(200),

    -- Timestamps
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW(),

    -- Constraint: Name + Kontext eindeutig
    UNIQUE(name, focus_area_id, style_direction_id, target_group_id)
);

-- ============================================================================
-- MODEL LEVELS (Stufendefinitionen pro Modell)
-- ============================================================================

CREATE TABLE IF NOT EXISTS model_levels (
    id SERIAL PRIMARY KEY,
    maturity_model_id INT NOT NULL REFERENCES maturity_models(id) ON DELETE CASCADE,
    level_number      INT NOT NULL CHECK (level_number >= 1),
    name              VARCHAR(100) NOT NULL,  -- z.B. "Einsteiger", "Grundlagen", "Aufbau"
    description       TEXT,                  -- Was zeichnet diese Stufe generell aus?
    sort_order        INT NOT NULL,

    created_at TIMESTAMP DEFAULT NOW(),

    UNIQUE(maturity_model_id, level_number)
);

-- ============================================================================
-- MODEL SKILL LEVELS
-- Was bedeutet "Stufe X der Fähigkeit Y im Modell Z"?
-- ============================================================================

CREATE TABLE IF NOT EXISTS model_skill_levels (
    id SERIAL PRIMARY KEY,
    maturity_model_id INT NOT NULL REFERENCES maturity_models(id) ON DELETE CASCADE,
    skill_id          INT NOT NULL REFERENCES skills(id)          ON DELETE RESTRICT,
    level_number      INT NOT NULL CHECK (level_number >= 1),

    -- Was wird auf dieser Stufe erwartet? (Pflichtfeld)
    description TEXT NOT NULL,

    -- Konkrete Beobachtungskriterien für Trainer
    -- z.B. "Kann Distanz in ruhigen Partnerübungen halten (3/3 Versuchen)"
    observable_criteria TEXT,

    -- Empfohlene Übungs-Typen (keine FK, nur Hinweise)
    -- z.B. {"types": ["Grundübung", "Partnerübung"], "max_duration_min": 15}
    example_exercise_hints JSONB,

    -- KI-generiert?
    ai_generated BOOLEAN DEFAULT false,

    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW(),

    UNIQUE(maturity_model_id, skill_id, level_number),

    -- level_number muss im Bereich des Modells liegen
    -- (wird per Trigger oder Backend-Validierung geprüft)
    CONSTRAINT ck_level_positive CHECK (level_number > 0)
);

-- ============================================================================
-- SKILL CATALOG: Felder für Matrix-Nutzung (falls noch nicht vorhanden)
-- ============================================================================

-- Fähigkeiten können einem bestimmten Fokusbereich "zugehören" (primär)
-- bleiben aber global nutzbar (secondary assignments über M:N)
ALTER TABLE skills
ADD COLUMN IF NOT EXISTS primary_focus_area_id INT REFERENCES focus_areas(id) ON DELETE SET NULL,
ADD COLUMN IF NOT EXISTS is_cross_domain BOOLEAN DEFAULT false;  -- gilt für alle Fokusbereiche

-- ============================================================================
-- INDEXES
-- ============================================================================

CREATE INDEX IF NOT EXISTS idx_maturity_models_focus    ON maturity_models(focus_area_id);
CREATE INDEX IF NOT EXISTS idx_maturity_models_style    ON maturity_models(style_direction_id);
CREATE INDEX IF NOT EXISTS idx_maturity_models_target   ON maturity_models(target_group_id);
CREATE INDEX IF NOT EXISTS idx_maturity_models_status   ON maturity_models(status);

CREATE INDEX IF NOT EXISTS idx_model_levels_model       ON model_levels(maturity_model_id);

CREATE INDEX IF NOT EXISTS idx_model_skill_levels_model ON model_skill_levels(maturity_model_id);
CREATE INDEX IF NOT EXISTS idx_model_skill_levels_skill ON model_skill_levels(skill_id);
CREATE INDEX IF NOT EXISTS idx_model_skill_levels_combo ON model_skill_levels(maturity_model_id, skill_id);

-- ============================================================================
-- TRIGGERS
-- ============================================================================

DROP TRIGGER IF EXISTS maturity_models_update ON maturity_models;
CREATE TRIGGER maturity_models_update
BEFORE UPDATE ON maturity_models
FOR EACH ROW EXECUTE FUNCTION update_timestamp();

DROP TRIGGER IF EXISTS model_skill_levels_update ON model_skill_levels;
CREATE TRIGGER model_skill_levels_update
BEFORE UPDATE ON model_skill_levels
FOR EACH ROW EXECUTE FUNCTION update_timestamp();

RAISE NOTICE 'Migration 019 completed successfully (Maturity Models / Fähigkeitsmatrix)';

END $$;

3. Beispiel-Daten

3.1 Beispiel-Modell: Karate Shotokan Breitensport (5 Stufen)

INSERT INTO maturity_models (name, focus_area_id, style_direction_id, target_group_id, level_count, status)
VALUES ('Karate Shotokan Breitensport', 1, 1, 1, 5, 'active');

-- Stufennamen
INSERT INTO model_levels (maturity_model_id, level_number, name, description, sort_order) VALUES
(1, 1, 'Einsteiger',      'Erste Begegnung  keine Vorkenntnisse erforderlich', 1),
(1, 2, 'Grundlagen',      'Grundprinzipien bekannt, in ruhigen Situationen anwendbar', 2),
(1, 3, 'Aufbau',          'Semi-intuitiver Einsatz, mit gelegentlicher Korrektur', 3),
(1, 4, 'Fortgeschritten', 'Intuitiver Einsatz auch unter Druck', 4),
(1, 5, 'Experte',         'Vollständig automatisiert, stabile Leistung auf Spitzenniveau', 5);

-- Fähigkeitsstufen: Distanzgefühl im Shotokan-Breitensport-Modell
INSERT INTO model_skill_levels (maturity_model_id, skill_id, level_number, description, observable_criteria)
VALUES
(1, 10, 1, 'Versteht das Konzept "Distanz" und kann erklären warum es wichtig ist.',
    'Kann auf Frage benennen, was Maai bedeutet.'),
(1, 10, 2, 'Hält in langsamen, geführten Partnerübungen die Angriffsdistanz.',
    'In 3 von 3 langsamen Wiederholungen korrekte Distanz eingenommen.'),
(1, 10, 3, 'Kontrolliert Distanz in mittlerer Geschwindigkeit bei Standardtechniken.',
    'Trainer bewertet Distanzkontrolle mit "gut" in Kihon-Ippon-Kumite.'),
(1, 10, 4, 'Stabiler Einsatz im Jiyu-Ippon-Kumite, selten vom Partner überrascht.',
    'In freiem Jiyu-Kumite hält Schüler Linie in >70% der Aktionen.'),
(1, 10, 5, 'Feingefühl für minimale Distanzveränderungen, taktischer Einsatz im Shiai.',
    'Wettkampferfolge durch bewusstes Distanzmanagement nachweisbar.');

4. API-Endpoints

4.1 Übersicht

Method Endpoint Beschreibung
GET /maturity-models Liste aller Modelle (mit Filter)
GET /maturity-models/{id} Modell-Detail mit Stufen + Skills
POST /maturity-models Neues Modell erstellen (Admin)
PUT /maturity-models/{id} Modell bearbeiten (Admin)
DELETE /maturity-models/{id} Modell löschen (Admin)
GET /maturity-models/{id}/skills Alle Fähigkeiten + Stufen dieses Modells
PUT /maturity-models/{id}/skills/{skill_id}/levels Stufen-Beschreibungen setzen (Admin)
GET /maturity-models/resolve Bestes Modell für Kontext finden

4.2 GET /maturity-models/resolve

Findet das spezifischste Modell für einen gegebenen Kontext. Wird von der KI und vom Frontend verwendet.

Query Parameters:

  • focus_area_id (int, optional)
  • style_direction_id (int, optional)
  • target_group_id (int, optional)

Response:

{
  "model": {
    "id": 1,
    "name": "Karate Shotokan Breitensport",
    "level_count": 5,
    "match_specificity": "full"
  },
  "fallback_used": false
}

Auflösungslogik (Most Specific First):

  1. Alle drei passen (focus + style + target) → match_specificity: "full"
  2. focus + style passen → match_specificity: "style"
  3. Nur focus passt → match_specificity: "focus"
  4. Allgemeines Modell (alle FK = NULL) → match_specificity: "generic"
  5. Kein Modell vorhanden → match_specificity: null, 404

5. Verbindung zu Übungen

5.1 Wie exercise_skills das Modell referenziert

exercise_skills speichert required_level und target_level als Stufen-Namen (einsteiger/grundlagen/aufbau/fortgeschritten/experte), die modellunabhängig sind.

Das Frontend kann bei Bedarf die konkrete Modell-Beschreibung nachladen:

exercise_skills.required_level = "grundlagen"
→ GET /maturity-models/resolve?focus_area_id=1
→ Model: Karate Shotokan Breitensport (level_count=5)
→ model_levels: level_number=2, name="Grundlagen"
→ model_skill_levels für skill_id=10: "Hält in ruhigen Partnerübungen Distanz"

5.2 Darstellung in der Übungsdetail-Ansicht

Fähigkeiten
─────────────────────────────────────────────
★ Distanzgefühl                    (primär)
  Voraussetzung: Grundlagen  →  Ziel: Aufbau
  Intensität: Hoch
  ────────────────────────────────
  Grundlagen: "Hält in ruhigen Partnerübungen
               Distanz"
  Aufbau: "Kontrolle in mittlerer
            Geschwindigkeit"
  [Kontext: Shotokan Breitensport ▼]
─────────────────────────────────────────────
◦ Reaktionsschnelligkeit           (sekundär)
  Voraussetzung: Einsteiger  →  Ziel: Grundlagen
  Intensität: Mittel

Kontext-Dropdown: Trainer kann Modell wechseln um kontextspezifische Beschreibungen zu sehen.


6. KI-Unterstützung für Modell-Pflege

Die KI kann model_skill_levels-Beschreibungen vorschlagen.

Prompt-Placeholder:

  • {{skill_name}} Name der Fähigkeit
  • {{model_name}} Name des Reifegradmodells
  • {{level_count}} Anzahl der Stufen
  • {{level_names}} Namen der Stufen (z.B. "Einsteiger, Grundlagen, Aufbau...")
  • {{focus_area}} Fokusbereich
  • {{target_group}} Zielgruppe

Endpoint: POST /maturity-models/{id}/ai/suggest-skill-levels

// Request
{
  "skill_id": 10,
  "regenerate_existing": false
}

// Response
{
  "skill": {"id": 10, "name": "Distanzgefühl"},
  "suggestions": [
    {
      "level_number": 1,
      "level_name": "Einsteiger",
      "description": "...",
      "observable_criteria": "...",
      "ai_generated": true
    },
    ...
  ]
}

7. Semantic MediaWiki Import

Die bestehende Fähigkeitsmatrix im SMW enthält bereits Stufen-Beschreibungen.

Erweiterung der MEDIAWIKI_IMPORT_SPEC.md:

Wiki-Feld Ziel-Tabelle Transformation
SMW Property: Stufe 1 Beschreibung model_skill_levels.description (level=1) Direkt
SMW Property: Stufe N Beschreibung model_skill_levels.description (level=N) Direkt
SMW Property: Modell maturity_models.name Lookup/Create
SMW Property: Fokusbereich maturity_models.focus_area_id Name → ID

Import-Endpoint: POST /import/mediawiki/execute mit import_type: "maturity_model"


8. Admin-Workflow

8.1 Modell anlegen (Admin)

1. Admin wählt: Fokusbereich + Stil + Zielgruppe
2. Admin legt Stufenanzahl + Stufennamen fest
3. Admin weist Fähigkeiten dem Modell zu (Pflicht-/Optional-Skills)
4. Für jede Fähigkeit × Stufe: Beschreibung eingeben
   → Optional: KI-Vorschlag generieren
5. Modell auf "active" stellen

8.2 SMW-Migration-Workflow

1. SMW-Import: Bestehende Modelle und Beschreibungen importieren
2. Review: Trainer prüft importierte Beschreibungen
3. KI-Ergänzung: Für fehlende Stufen KI-Vorschläge generieren
4. Freigabe: status → 'active'

Version: 1.0 Datum: 2026-04-24 Status: DRAFT Nächste Schritte:

  • SMW-Struktur analysieren (User legt Daten ins Repo)
  • Migration 019 implementieren
  • Admin-UI für Modellpflege spezifizieren (UI_COMPONENTS_SPEC.md ergänzen)