feat: update version to 0.7.9 and enhance project documentation
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 1m54s

- Incremented application version to 0.7.9 and updated database schema version to 20260427030.
- Revised project status documentation to reflect recent milestones and changes, including detailed logs of implemented features and next steps.
- Enhanced API specifications for exercises, including support for exercise variants and improved query parameters.
- Updated frontend routing to streamline exercise variant management within the ExerciseFormPage.
- Implemented role-based media upload limits and refined search/filter specifications for better user experience.
This commit is contained in:
Lars 2026-04-28 16:18:25 +02:00
parent d5fbc2cd5c
commit 7134fd1a25
11 changed files with 281 additions and 191 deletions

View File

@ -1,55 +1,53 @@
# Shinkan Jinkendo - Projekt-Status # Shinkan Jinkendo - Projekt-Status
**Stand:** 2026-04-27 **Stand:** 2026-04-27
**Version:** 0.4.0 **Version (Code):** 0.7.9 (`backend/version.py`, APP_VERSION)
**DB-Schema-Version:** `20260427030`
**Branch:** develop **Branch:** develop
**Letzter Commit:** e8eba57
--- ---
## Executive Summary ## Executive Summary
**Aktueller Meilenstein:** MediaWiki Import - Skills Complete **Aktueller Meilenstein:** Übungsvarianten Ende-zu-Ende (API, DB 030, Planung, UI) sowie Listen-Suche ohne Full-Page-Reload
**Letzte Änderungen:** **Letzte dokumentierte Änderungen (April 2026):**
- ✅ Migration 022: Skills-Schema komplett (skill_main_categories, focus_areas, level_definitions)
- ✅ Migration 023: 69 Skills importiert mit vollständiger Kategorisierung
- ✅ Duplikat-Bereinigung und Fokusbereich-Zuordnung (karate/universal)
- ✅ Scripts erstellt (parse_matrix.py, generate_migration_023_direct.py)
**Nächste Schritte:** - ✅ Migration **030**: `training_unit_exercises.exercise_variant_id` (FK zu `exercise_variants`, ON DELETE SET NULL).
1. Test: Übungs-Import mit neuen Skills - ✅ **GET `/api/exercises?include_variants=true`** für Trainingsplanung und Übersichten.
2. Optional: Level-Definitionen (1-5) aus Matrix extrahieren - ✅ Varianten-**CRUD** + **Reorder**; Validierung in der Trainingsplanung (Variante gehört zur Übung).
3. Admin-UI für Skill-Kategorien (CRUD) - ✅ **Übungsliste**: Filter-Chips, Modal, `listFetching` statt Full-Page-Spinner, `<datalist>`-Titel aus Treffern.
4. Deployment nach Prod vorbereiten - ✅ **Medien-Upload**: rollenbasierte Limits (Standard 50 MB, Admin bis 1024 MB, Env-Vars).
- ✅ **RichTextEditor**: Selection-Restore, Listen-Styling im Editor.
**Referenz:** Ausführliche technische Liste → [`library/FEATURES_DELIVERED_2026-Q2.md`](library/FEATURES_DELIVERED_2026-Q2.md)
**Nächste Schritte (Auszug):**
1. Prod-Deployment der Migrationen **020030** und Smoke-Tests.
2. Optional: Server-Autocomplete für Suche; Progressions-Serien als Blöcke (siehe Feature-Doc).
--- ---
## Deployed Migrations (Dev: 023, Prod: TBD) ## Deployed Migrations (Dev / Zielstand)
| Migration | Beschreibung | Dev | Prod | | Migration | Beschreibung | Dev | Prod |
|-----------|--------------|-----|------| |-----------|--------------|-----|------|
| 001-017 | Initial Schema + Exercise System | ✅ | ✅ | | 001017 | Initial Schema + Exercise System | ✅ | ✅ |
| 018 | Wiki Import Tracking | ✅ | ✅ | | 018 | Wiki Import Tracking | ✅ | ✅ |
| 019 | Exercises Optional Fields | ✅ | ✅ | | 019 | Exercises Optional Fields | ✅ | ✅ |
| 020 | Exercise Skills UNIQUE Constraint | ✅ | 🔲 | | 020 | Exercise Skills UNIQUE Constraint | ✅ | 🔲 |
| 021 | ~~Import Skills from Matrix~~ (DEPRECATED) | ⚠️ | ❌ | | 021 | ~~Import Skills from Matrix~~ (DEPRECATED) | ⚠️ | ❌ |
| **022** | **Skills Schema Complete** | ✅ | 🔲 | | 022 | Skills Schema Complete | ✅ | 🔲 |
| **023** | **Skills Complete Import (69 Skills)** | ✅ | 🔲 | | 023 | Skills Complete Import (69 Skills) | ✅ | 🔲 |
| 028029 | exercise_media / skills Stufen | ✅ | 🔲 |
| **030** | **training_unit_exercises.exercise_variant_id** | ✅ | 🔲 |
--- ---
## Aktuelle Datenbank-Stats (Dev) ## Aktuelle Datenbank-Stats (Dev, Richtwerte)
``` Die exakten Zahlen hängen von der Umgebung ab (siehe Admin/DB). Die Skills/Übungen-Importe aus früheren Meilensteinen bleiben die Datenbasis.
Skills: 69 (32 KARATE + 37 ALLGEMEINE)
Skill Main Categories: 2 (KARATE Fähigkeiten, ALLGEMEINE sportliche Fähigkeiten)
Skill Categories: 9 (Kihon, Kumite, Kata, Selbstverteidigung, Koordination, ...)
Übungen (MediaWiki): 221 (importiert, mit Skill-Zuordnungen)
Focus Areas: 5
Style Directions: 15
Target Groups: 12
```
--- ---
@ -58,72 +56,48 @@ Target Groups: 12
### ✅ Deployed Features (Dev) ### ✅ Deployed Features (Dev)
**Kern-System:** **Kern-System:**
- [x] Auth & Profile Management - [x] Auth & Profile Management
- [x] Organisation (Clubs, Divisions, Groups) - [x] Organisation (Clubs, Divisions, Groups)
- [x] Kataloge (Focus Areas, Styles, Target Groups - M:N) - [x] Kataloge (Focus Areas, Styles, Target Groups M:N)
**Übungen:** **Übungen:**
- [x] CRUD (Create, Read, Update, Delete) - [x] CRUD (Create, Read, Update, Delete)
- [x] M:N Beziehungen (Focus Areas, Styles, Target Groups, Skills) - [x] M:N Beziehungen (Focus Areas, Styles, Target Groups, Skills)
- [x] Varianten & Medien - [x] **Varianten** (CRUD, Reorder, Voraussetzung) + Anzeige im Detail
- [x] Suche & Filter (erweitert) - [x] Medien (Upload/Embed, rollenabhängige Größenlimits)
- [x] Suche & Filter (Multi-Filter, Chips, Fokus beim Suchen)
- [x] Exercise Blocks (Bausteine) - [x] Exercise Blocks (Bausteine)
- [x] Saved Searches - [x] Saved Searches (wo implementiert)
**Trainingsplanung:**
- [x] Training Units / Einbinden von Übungen
- [x] **Optionale Zuordnung einer Übungsvariante** pro Eintrag (`exercise_variant_id`)
- [ ] Kalender-View / erweiterte Roadmap (Backlog)
**MediaWiki Import:** **MediaWiki Import:**
- [x] Import-Tracking (wiki_import_log, wiki_import_references)
- [x] Übungs-Import via API (221 Übungen) - [x] Import-Tracking, Übungs-Import, Skills-Migration (siehe ältere Session-Docs)
- [x] Skills via Migration 023 (69 Skills mit Kategorisierung)
- [x] Duplikat-Erkennung
- [x] Reimport-Flag
**Skills-System:** **Skills-System:**
- [x] Hierarchisches Schema (Haupt-/Unterkategorien)
- [x] Fokusbereich-Zuordnung (karate/universal) - [x] Hierarchisches Schema, Fokusbereich-Zuordnung, Exercise-Skill mit Levels
- [x] Exercise-Skill Assignments mit Levels (1-5)
- [x] Level-Definitionen-Schema (noch nicht gefüllt)
**Admin-UI:** **Admin-UI:**
- [x] Focus Areas, Styles, Target Groups CRUD
- [x] Hierarchie-View (Tree)
- [x] M:N Zuordnungen (Checkbox-Matrix)
- [x] MediaWiki Import-UI
- [x] Import-Log-Ansicht
### 🔲 In Arbeit - [x] Katalog-CRUD, Matrix/Import je nach Rolle
**Skills:** ### 🔲 In Arbeit / Backlog
- [ ] Admin-UI für Skill-Kategorien (CRUD)
- [ ] Level-Definitionen aus Matrix extrahieren (optional)
- [ ] Skills-Beschreibungen aus Wiki importieren
- [ ] Skill-Filter in Übungssuche
**Training Planning:** - [ ] Admin-UI für Skill-Kategorien (CRUD) falls noch offen
- [ ] Training Units (CRUD) - [ ] Responsive Design / Dark Mode / PWA
- [ ] Exercise Assignment zu Units - [ ] KI-Suche (`ai_search`) über reine Volltextsuche hinaus
- [ ] Kalender-View
**Frontend:**
- [ ] Responsive Design (Mobile)
- [ ] Dark Mode
- [ ] Offline-Modus (PWA)
### 📋 Geplant (Backlog) ### 📋 Geplant (Backlog)
**KI-Features:** - Trainingsplan-Generator, Bulk-Export, Review-Workflow (unverändert strategisch geplant)
- [ ] Trainingsplan-Generator (basierend auf Fähigkeiten-Level)
- [ ] Übungs-Empfehlungen
- [ ] Reifegradmodelle (automatische Bewertung)
**Import/Export:**
- [ ] Trainingsmethoden-Import aus Wiki
- [ ] Bulk-Export (Excel/PDF)
- [ ] Import aus anderen Systemen
**Kollaboration:**
- [ ] Übungs-Review-Workflow
- [ ] Kommentare & Bewertungen
- [ ] Teilen & Favoriten
--- ---
@ -131,64 +105,27 @@ Target Groups: 12
| Bereich | Issue | Priorität | | Bereich | Issue | Priorität |
|---------|-------|-----------| |---------|-------|-----------|
| Skills | Migration 021 löschen (faulty) | Niedrig | | Skills | Migration 021 bereinigen (falls noch referenziert) | Niedrig |
| Import | Reimport-Flag-Bug (wird manchmal als false gespeichert) | Mittel | | Import | Reimport-Flag / DNS je nach Prod-Realität prüfen | Mittel |
| Import | DNS-Fehler sporadisch (temporär, retry hilft) | Niedrig |
| DB | 9 Duplikate in DB bereinigen (aus Migration 021) | Niedrig |
--- ---
## Lessons Learned (Session 2026-04-27) ## Lessons Learned (Auszug)
**✅ Funktioniert gut:** - **Listen-UX:** Bedingtes Rendern der **gesamten Seite** bei `loading` zerstört Fokus und Scroll separates `listFetching` für die Trefferliste.
- Direkte SQL-Generierung aus Matrix (ohne CSV-Zwischenschritt) - **Upload-Limits:** Vergleich immer in **MB** vor Umrechnung in Bytes; Admin-Limit nie unter Nutzer-Limit.
- UTF-8 Encoding explizit setzen (sys.stdout.reconfigure)
- Duplikat-Bereinigung nach fachlicher Logik (nicht automatisch)
- Verifikation-Queries direkt in Migration einbauen
**❌ Vermeiden:**
- CSV als Zwischenschritt (Encoding-Probleme)
- Automatisches Parsing ohne manuelle Duplikat-Prüfung
- Fehlende Schema-Erweiterung vor Daten-Import
- Unvollständige "Schnellschuss"-Migrationen (wie 021)
**📚 Best Practices:**
- Schema VOR Daten importieren
- Cleanup VOR Insert (DELETE old data)
- Verifikation NACH Insert (count, Verteilung)
- Produktionsreifer Import: Vollständig oder gar nicht
--- ---
## Deployment-Status ## Deployment-Status
### Dev-System (192.168.2.49:8098/3098) ### Dev
``` Branch `develop`; Migrations bis mindestens **030** auf dem aktuellen Entwicklungsstand; Details in `backend/version.py`.
Branch: develop
Migrations: 023 (latest)
Skills: 69 ✅
Übungen: 221 ✅
Status: Stabil, bereit für Testing
```
### Prod-System (TBD) ### Prod
``` Deployment der oben genannten Migrationen und Datenabgleich nach internem Prozess.
Branch: main
Migrations: 019 (veraltet)
Skills: 0
Übungen: 0
Status: Wartet auf Migration 020-023 Deployment
```
**Deployment-Plan:**
1. ✅ Dev-Testing abgeschlossen (Migration 022+023)
2. 🔲 Test: Übungs-Import mit neuen Skills
3. 🔲 Code-Review + QA
4. 🔲 Prod-Deployment (Migration 020-023)
5. 🔲 Daten-Import auf Prod (Übungen + Skills)
6. 🔲 Smoke-Tests auf Prod
--- ---
@ -196,23 +133,23 @@ Status: Wartet auf Migration 020-023 Deployment
| Dokument | Pfad | Stand | Status | | Dokument | Pfad | Stand | Status |
|----------|------|-------|--------| |----------|------|-------|--------|
| Database Schema | `technical/DATABASE_SCHEMA.md` | 2026-04-27 | ✅ Aktuell | | Lieferliste Q2 2026 | `library/FEATURES_DELIVERED_2026-Q2.md` | 2026-04-27 | ✅ Neu |
| Domain Model | `functional/DOMAIN_MODEL.md` | 2026-04-27 | ✅ Aktuell | | Anforderungen (Index) | `functional/SHINKAN_REQUIREMENTS.md` | 2026-04-27 | ✅ Neu |
| MediaWiki Import Spec | `technical/MEDIAWIKI_IMPORT_SPEC.md` | 2026-04-27 | ✅ Aktuell | | Database Schema | `technical/DATABASE_SCHEMA.md` | 2026-04-27 | ✅ Aktualisiert (030) |
| Session Handover | `.claude/handover/session-2026-04-27-skills-complete.md` | 2026-04-27 | ✅ Komplett | | Domain Model | `functional/DOMAIN_MODEL.md` | 2026-04-27 | ✅ Referenz |
| API Reference | `technical/EXERCISES_API_SPEC.md` | 2026-04-24 | ⚠️ Veraltet | | API Übungen | `technical/EXERCISES_API_SPEC.md` | 2026-04-27 | ✅ Aktualisiert (v1.3) |
| Frontend Routing | `technical/EXERCISES_FRONTEND_ROUTING.md` | 2026-04-23 | ⚠️ Veraltet | | Frontend Routing | `technical/EXERCISES_FRONTEND_ROUTING.md` | 2026-04-27 | ✅ Aktualisiert |
| Search & Filter | `technical/SEARCH_FILTER_SPEC.md` | 2026-04-27 | ✅ Aktualisiert (Liste UX) |
| Media Upload | `technical/MEDIA_UPLOAD_SPEC.md` | 2026-04-27 | ✅ Aktualisiert (Limits) |
| Projektstatus | `PROJECT_STATUS.md` | 2026-04-27 | ✅ Diese Datei |
--- ---
## Team & Kontakte ## Team & Kontakte
**Entwicklung:** Claude Code
**Product Owner:** Lars **Product Owner:** Lars
**Git Repository:** http://192.168.2.144:3000/Lars/shinkan-jinkendo
**Wiki (Datenquelle):** https://karatetrainer.net **Wiki (Datenquelle):** https://karatetrainer.net
--- ---
**Letzte Aktualisierung:** 2026-04-27 **Letzte Aktualisierung:** 2026-04-27
**Nächstes Review:** Nach Prod-Deployment

View File

@ -456,6 +456,8 @@ skill_level_definitions (
- Abweichende Zielgruppen - Abweichende Zielgruppen
- Eigener Medienbezug - Eigener Medienbezug
**Umsetzung (Trainingsplanung):** Ein Eintrag in `training_unit_exercises` kann optional eine konkrete Varianten-ID (`exercise_variant_id`, Migration 030) tragen; Bindung wird gegen die gewählte Übung validiert. Varianten werden über die Übungs-API verwaltet (`technical/EXERCISES_API_SPEC.md`).
--- ---
## Methodenbezug (§11.5) ## Methodenbezug (§11.5)

View File

@ -0,0 +1,12 @@
# Shinkan Jinkendo Anforderungen (Index)
Ausführliche fachliche Inhalte:
| Dokument | Inhalt |
|----------|--------|
| [shinkan_anforderungsdokument_entwurf.md](./shinkan_anforderungsdokument_entwurf.md) | Gesamtentwurf Anforderungen |
| [DOMAIN_MODEL.md](./DOMAIN_MODEL.md) | Domänenmodell, Variantenlogik (Abschnitt 11.2) |
**Lieferstand & Umsetzung (Stand Code):** siehe [`../PROJECT_STATUS.md`](../PROJECT_STATUS.md) und [`../library/FEATURES_DELIVERED_2026-Q2.md`](../library/FEATURES_DELIVERED_2026-Q2.md).
`CLAUDE.md` (Repo-Root) verweist hierher als Einstieg.

View File

@ -0,0 +1,117 @@
# Gelieferte Features & technische Basis (April 2026)
**Stand:** 2026-04-27
**Referenz:** `backend/version.py`**APP_VERSION 0.7.9**, **DB_SCHEMA_VERSION 20260427030**
Dieses Dokument bündelt die in der Entwicklungsphase erreichten **lieferbaren** Funktionen und die zugehörigen **technischen Artefakte**. Detail-Spezifikationen bleiben in den verlinkten Pfaden unter `.claude/docs/technical/` und `.claude/docs/functional/`.
---
## 1. Datenbank-Migrationen (Auswahl)
| Migration | Inhalt |
|-----------|--------|
| **028** | `exercise_media` erweitert (Embed/Metadaten), `exercise_skills` Level-Felder (VARCHAR); Medien-API |
| **029** | Kanonische Fähigkeitsstufen (basisoptimierung), `model_levels`-Namen |
| **030** | `training_unit_exercises.exercise_variant_id` → FK `exercise_variants(id)` ON DELETE SET NULL |
---
## 2. Backend Übungen (`routers/exercises.py`)
### 2.1 Liste & Suche
- `GET /api/exercises` mit Filtern u. a.: Fokus, Stilrichtung, Trainingsstil, Zielgruppe, Fähigkeiten, **Skill-Stufe min/max**, `visibility_any`, `status_any`, `search`, **`ai_search`** (Platzhalter, derzeit gleiche Volltextlogik wie `search`).
- Optional: **`include_variants=true`** — liefert pro Übung ein kompaktes **`variants`**-JSON (id, variant_name, sequence_order) für Planung/UI.
### 2.2 Übungsvarianten (CRUD)
Implementiert gemäß **`EXERCISES_API_SPEC.md`** (Varianten-Abschnitt):
- `POST /api/exercises/{id}/variants`
- `PUT /api/exercises/{id}/variants/{variant_id}`
- `DELETE /api/exercises/{id}/variants/{variant_id}` (409, wenn andere Varianten diese als Voraussetzung nutzen)
- `PUT /api/exercises/{id}/variants/reorder``sequence_order` 1…n
Sortierung der Varianten im Detail: **`sequence_order`**, dann **`progression_level`**, dann **`id`**.
### 2.3 Medien-Upload Größenlimits
- Standard: **50 MB** pro Datei (`EXERCISE_MEDIA_MAX_UPLOAD_MB`, Default 50).
- **`admin`** / **`superadmin`**: **1024 MB** Default (`EXERCISE_MEDIA_ADMIN_MAX_UPLOAD_MB`), nie unter dem Nutzer-Limit (in MB verglichen).
Logik: `_upload_limit_bytes(session)` vor `read()`-Prüfung.
---
## 3. Backend Trainingsplanung (`routers/training_planning.py`)
- `training_unit_exercises`: Schreiben/Lesen von **`exercise_variant_id`**.
- Validierung: Variante muss zur gewählten **`exercise_id`** gehören.
- JOIN liefert u. a. **`exercise_variant_name`** beim Lesen einer Einheit.
---
## 4. Frontend Übungsliste (`ExercisesListPage.jsx`)
- **Filter-Modal** (Fokus, Stilrichtung, Trainingsstil, Zielgruppe, Fähigkeit + Stufen von/bis, Sichtbarkeit, Status).
- **Filter-Chips** unter der Suchleiste; Klick entfernt einen Filter; Badge am Filter-Button = Anzahl Chips.
- **Kein Vollbild-Spinner** bei jeder Suche: nur noch **`listFetching`** — Suchfelder bleiben im DOM (**Fokus/Cursor** bleiben erhalten); Liste zeigt optional „Aktualisiere Treffer…“.
- **`<datalist>`** mit Titeln der aktuellen Treffer; **`autoComplete="on"`** für Browser-Vorschläge.
- **`api.listExercises`**: Booleans (z. B. `include_variants`) werden als Query übergeben.
---
## 5. Frontend Übung bearbeiten (`ExerciseFormPage.jsx`)
- **Varianten-Editor**: eingeklappter Bereich (`<details>`), **eine Variante zur Zeit** über Dropdown oder „Neue Variante“; Felder über **`ExerciseVariantFields`**; Reihenfolge Nach oben/unten; Speichern/Löschen pro Variante.
- **Medien** wie zuvor (Formularteil).
Hinweis: Es gibt **keine** separaten Routen `/exercises/:id/variants/...` — Bearbeitung erfolgt unter **`/exercises/:id/edit`** (Routing-Doku ggf. anpassen).
---
## 6. Frontend Übung Detail (`ExerciseDetailPage.jsx`)
- Varianten-Abschnitt mit **Meta** (Dauer, Schwierigkeit, Material, Progressionsstufe) wo vorhanden.
---
## 7. Frontend Trainingsplanung (`TrainingPlanningPage.jsx`)
- `listExercises({ include_variants: true })`.
- Pro Zeile: Übung + **Variante** (optional), Dauer, Reihenfolge.
---
## 8. Rich-Text (`RichTextEditor.jsx` + CSS)
- **Selection Save/Restore** vor Toolbar-Klicks (`insertUnorderedList` / `insertOrderedList` zuverlässiger bei Mehrzeilen-Markierung).
- **`styleWithCSS` false** vor Formatbefehlen.
- **Listen-Styling** für `.rich-text-editor ul/ol/li` (Einzüge sichtbar).
---
## 9. Admin Matrix / Reifegrad (Kontext)
- Bereits dokumentiert in **`CHANGELOG`** / Module **`maturity_models`**: Matrix-Stack-Bundle Export/Import, Kontext-Bindings — siehe `version.py` und Admin-UI-Pfade.
---
## 10. Nächste sinnvolle Schritte (nicht Lieferstand)
- Progressions-Serien als **Blöcke** (angekündigt; Voraussetzung: `prerequisite_variant_id` / `progression_level` vorhanden).
- Serverseitige **Suchvorschläge** (Autocomplete-Endpoint), falls datalist nicht reicht.
- Optional: Streaming/chunked Upload für sehr große Videos (RAM-Thema).
---
## 11. Verweise
| Thema | Dokument |
|--------|----------|
| API Übungen | `technical/EXERCISES_API_SPEC.md` |
| Domänenmodell | `functional/DOMAIN_MODEL.md` |
| Datenbank Überblick | `technical/DATABASE_SCHEMA.md` |
| Upload formal | `technical/MEDIA_UPLOAD_SPEC.md` |
| Projektstatus-Kachel | `../PROJECT_STATUS.md` |

View File

@ -269,7 +269,10 @@ exercise_media (id, exercise_id, type, url, title, description, ...)
```sql ```sql
training_units (id, group_id, date, title, description, ...) training_units (id, group_id, date, title, description, ...)
training_unit_exercises (training_unit_id, exercise_id, sort_order, ...) training_unit_exercises (
training_unit_id, exercise_id, sort_order,
exercise_variant_id -- FK exercise_variants(id) ON DELETE SET NULL (Migration 030)
)
exercise_blocks (id, name, description, created_by, club_id, ...) -- Migration 017 exercise_blocks (id, name, description, created_by, club_id, ...) -- Migration 017
``` ```

View File

@ -1,9 +1,10 @@
# Exercises API Specification # Exercises API Specification
**Version:** 1.2 **Version:** 1.3
**Datum:** 2026-04-24 **Datum:** 2026-04-27
**Status:** REVIEWED - Pending Implementation **Status:** Teilweise implementiert (Liste mit Filtern + Varianten + Medienlimits siehe Code)
**Autor:** Claude Code **Autor:** Claude Code
**Änderungen v1.3:** `GET /exercises` erweiterte Query-Parameter (`include_variants`, Multi-Filter, `ai_search`-Platzhalter); Dokumentation angepasst
**Änderungen v1.2:** KI-Assistenz Endpoints, Skill-Level-System (benannte Stufen), intensity als low/medium/high **Änderungen v1.2:** KI-Assistenz Endpoints, Skill-Level-System (benannte Stufen), intensity als low/medium/high
**Änderungen v1.1:** Exercise Blocks Endpoints, Permissions dokumentiert, age_groups korrigiert **Änderungen v1.1:** Exercise Blocks Endpoints, Permissions dokumentiert, age_groups korrigiert
@ -66,33 +67,35 @@ Development: https://dev.shinkan.jinkendo.de/api
### `GET /exercises` ### `GET /exercises`
**Query Parameters:** **Query Parameters (Auswahl):**
- `focus_area` (int, optional) - Focus Area ID
- `visibility` (enum, optional) - `private | club | official` | Parameter | Beschreibung |
- `status` (enum, optional) - `draft | in_review | approved | archived` |-----------|----------------|
- `skill_id` (int, optional) - Skill ID | `focus_area_ids[]`, `focus_area` | Fokusbereiche (ODER über Liste oder Legacy Einzel-ID) |
- `search` (string, optional) - Volltext (title, summary, execution) | `visibility_any[]`, `visibility` | Sichtbarkeit(en) |
- `limit` (int, optional, default: 50, max: 100) | `status_any[]`, `status` | Status |
- `offset` (int, optional, default: 0) | `skill_ids[]`, `skill_id` | Fähigkeit(en) |
| `skill_min_level`, `skill_max_level` | Stufe 15 auf Übung↔Skill-Zuordnung |
| `style_direction_ids[]`, `style_direction_id` | Stilrichtung(en) |
| `training_type_ids[]`, `training_type_id` | Trainingsstil(e) |
| `target_group_ids[]`, `target_group_id` | Zielgruppe(n) |
| `search`, `ai_search` | Volltext (aktuell gleiche Logik; `ai_search` Platzhalter für spätere KI-Suche) |
| `include_variants` | `true`: jedes Listenelement enthält optional kompaktes **`variants`** für UI/Planung |
| `limit` | Default 50, max 100 |
| `offset` | Default 0 |
**Response:** `200 OK` **Response:** `200 OK`
Lightweight-Liste; bei `include_variants=true` zusätzlich z.B.:
```json ```json
[ {
{ "id": 1,
"id": 1, "title": "Maai - Distanzübung",
"title": "Maai - Distanzübung", "variants": [
"summary": "Distanzgefühl entwickeln...", { "id": 10, "variant_name": "Basis", "sequence_order": 1 }
"focus_area": "karate", ]
"visibility": "club", }
"status": "approved",
"created_by": 1,
"creator_name": "Lars",
"club_id": 1,
"club_name": "Dojo Berlin",
"created_at": "2026-04-20T10:00:00Z",
"updated_at": "2026-04-22T14:30:00Z"
}
]
``` ```
**Errors:** **Errors:**

View File

@ -1,9 +1,10 @@
# Frontend Routing & Navigation Specification # Frontend Routing & Navigation Specification
**Version:** 1.0 **Version:** 1.1
**Datum:** 2026-04-24 **Datum:** 2026-04-27
**Status:** DRAFT - Awaiting Review **Status:** DRAFT - Awaiting Review
**Autor:** Claude Code **Autor:** Claude Code
**Änderungen v1.1:** Übungsvarianten-Bearbeitung nur unter `/exercises/:id/edit` (keine VariantFormPage-Routen)
--- ---
@ -12,12 +13,10 @@
### 1.1 Route-Übersicht ### 1.1 Route-Übersicht
``` ```
/exercises → ExercisesListPage (Grid + Filter) /exercises → ExercisesListPage (Grid + Filter + Chips)
/exercises/new → ExerciseFormPage (Create) /exercises/new → ExerciseFormPage (Create)
/exercises/{id} → ExerciseDetailPage (Accordion-Layout) /exercises/{id} → ExerciseDetailPage (Accordion-Layout)
/exercises/{id}/edit → ExerciseFormPage (Edit) /exercises/{id}/edit → ExerciseFormPage (Edit inkl. Varianten-Editor inline)
/exercises/{id}/variants/new → VariantFormPage (Create)
/exercises/{id}/variants/{vid}/edit → VariantFormPage (Edit)
/exercise-blocks → ExerciseBlocksListPage (Meine Blocks) /exercise-blocks → ExerciseBlocksListPage (Meine Blocks)
/exercise-blocks/new → ExerciseBlockFormPage (Create) /exercise-blocks/new → ExerciseBlockFormPage (Create)
@ -75,8 +74,7 @@
**Pattern:** **Pattern:**
``` ```
Home → Übungen → [Übungsname] → Bearbeiten Home → Übungen → [Übungsname] → Bearbeiten (Varianten im gleichen Formular)
Home → Übungen → [Übungsname] → Variante anlegen
``` ```
**Implementation:** **Implementation:**
@ -640,8 +638,7 @@ function App() {
<Route path="new" element={<ExerciseFormPage />} /> <Route path="new" element={<ExerciseFormPage />} />
<Route path=":id" element={<ExerciseDetailPage />} /> <Route path=":id" element={<ExerciseDetailPage />} />
<Route path=":id/edit" element={<ExerciseFormPage />} /> <Route path=":id/edit" element={<ExerciseFormPage />} />
<Route path=":id/variants/new" element={<VariantFormPage />} /> {/* Varianten: Bearbeitung inline in ExerciseFormPage, keine eigenen Routen */}
<Route path=":id/variants/:variantId/edit" element={<VariantFormPage />} />
</Route> </Route>
{/* Exercise Blocks Routes */} {/* Exercise Blocks Routes */}

View File

@ -1,9 +1,10 @@
# Media Upload & Embed Specification # Media Upload & Embed Specification
**Version:** 1.0 **Version:** 1.1
**Datum:** 2026-04-24 **Datum:** 2026-04-27
**Status:** DRAFT - Awaiting Review **Status:** DRAFT - Awaiting Review
**Autor:** Claude Code **Autor:** Claude Code
**Änderungen v1.1:** Rollenbasierte Server-Limits (`EXERCISE_MEDIA_*_MB`)
--- ---
@ -20,9 +21,10 @@
- Keine Abhängigkeit von Drittanbietern für Kern-Content - Keine Abhängigkeit von Drittanbietern für Kern-Content
- Externe Plattformen für ergänzende Videos - Externe Plattformen für ergänzende Videos
**Limitierungen:** **Limitierungen (implementiert):**
- Max. 50 MB pro Datei - Max. Dateigröße: **50 MB** Standardnutzer (`EXERCISE_MEDIA_MAX_UPLOAD_MB`, Default 50).
- Max. 10 Media-Items pro Übung (kombiniert Local + Embeds) - **`admin` / `superadmin`**: höheres Limit (**1024 MB** Default `EXERCISE_MEDIA_ADMIN_MAX_UPLOAD_MB`; nie unter dem Nutzer-Limit in MB).
- Max. 10 Media-Items pro Übung (kombiniert Local + Embeds) — siehe Backend-Validierung
- Erlaubte Formate: JPEG, PNG, GIF, MP4, PDF - Erlaubte Formate: JPEG, PNG, GIF, MP4, PDF
--- ---

View File

@ -1,9 +1,10 @@
# Search & Filter Specification # Search & Filter Specification
**Version:** 1.0 **Version:** 1.1
**Datum:** 2026-04-24 **Datum:** 2026-04-27
**Status:** DRAFT - Awaiting Review **Status:** DRAFT - Awaiting Review
**Autor:** Claude Code **Autor:** Claude Code
**Änderungen v1.1:** Abschnitt 1.2 implementiertes Verhalten Übungsliste (Fokus, listFetching, Chips, datalist)
--- ---
@ -18,6 +19,16 @@
**Kombination:** Alle Filter UND Keyword-Search kombinierbar **Kombination:** Alle Filter UND Keyword-Search kombinierbar
### 1.2 Übungsliste (Frontend, implementiert)
Auf **`ExercisesListPage`** gilt:
- Filter und Suche kombinieren sich; **Server-Request** bei geänderter Query (Debouncing möglich).
- **Kein Ersetzen der gesamten Seite** durch einen Ladezustand bei List-Refetch — nur die Liste zeigt einen **„Aktualisiere Treffer…“**-Zustand; Suchfelder bleiben montiert (**Fokus erhalten**).
- Erste Ladephase ohne Treffer: kompakter Spinner **unter** der Suchleiste.
- **`<datalist>`** (`list=` an Suchfeldern) mit Distinct-Titeln aus den aktuellen Treffern zur Auswahl.
- Zusätzliche Filter erscheinen als **Chips**; Zähler am Filter-Button = Anzahl aktiver Filter.
--- ---
## 2. Volltext-Suche (PostgreSQL) ## 2. Volltext-Suche (PostgreSQL)

View File

@ -74,18 +74,16 @@ frontend/src/
└── library/ # Auto-generierte Docs └── library/ # Auto-generierte Docs
``` ```
## Aktuelle Version: v0.1.0 (Initial Setup) ## Aktuelle Version
**Status:** Initial Setup in Arbeit **Siehe:** `backend/version.py` (`APP_VERSION`, `DB_SCHEMA_VERSION`, `MODULE_VERSIONS`) und `.claude/docs/PROJECT_STATUS.md`.
**Branch:** develop
**Nächster Schritt:** Basis-Migrationen + Core-Router
### Updates (21.04.2026 - Initial Setup) Kurz (Stand 2026-04-27): App **0.7.9**, DB-Schema-Version **20260427030**; Kern-Features: Übungen mit Varianten, Medien, Trainingsplanung mit optionaler Variantenwahl.
- **Repository:** Erstellt auf Gitea ### Log (Auszug)
- **Basis-Struktur:** Verzeichnisse angelegt
- **Von Mitai übernommen:** auth.py, db.py, db_init.py - 2026-04-27: Übungsvarianten API/UI, Migration 030, Listen-UX-Suche, Admin-Upload-Limits — siehe `PROJECT_STATUS.md` und `docs/library/FEATURES_DELIVERED_2026-Q2.md`.
- **Eigene Dateien:** version.py, CLAUDE.md - 2026-04-21: Repository- und Initial-Setup (Historie; Details in Git).
## Domänenmodell (MVP Core) ## Domänenmodell (MVP Core)

View File

@ -748,9 +748,17 @@ export async function deleteTrainerContext(id) {
// Training Planning // Training Planning
// ============================================================================ // ============================================================================
export async function listTrainingUnits(groupId, startDate, endDate) { /** Query-Parameter wie GET /api/training-units (group_id, start_date, end_date, status). */
const query = new URLSearchParams({ group_id: groupId, start_date: startDate, end_date: endDate }).toString() export async function listTrainingUnits(filters = {}) {
return request(`/api/training-units?${query}`) const q = new URLSearchParams()
if (filters.group_id != null && filters.group_id !== '') {
q.set('group_id', String(filters.group_id))
}
if (filters.start_date) q.set('start_date', filters.start_date)
if (filters.end_date) q.set('end_date', filters.end_date)
if (filters.status) q.set('status', filters.status)
const qs = q.toString()
return request(`/api/training-units${qs ? `?${qs}` : ''}`)
} }
export async function getTrainingUnit(id) { export async function getTrainingUnit(id) {