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>
151 lines
8.7 KiB
Markdown
151 lines
8.7 KiB
Markdown
# Shinkan Jinkendo – Entwicklungsstand & Handover
|
||
|
||
**Stand:** 2026-05-07
|
||
**App-Version / DB-Schema:** App **0.8.59**, DB-Schema siehe `backend/version.py` (`DB_SCHEMA_VERSION`)
|
||
|
||
Diese Datei ist die **Einstiegs-Doku für neue Chat-Sessions**: Anforderungen im Detail stehen in `.claude/docs/` (siehe unten); hier der **implementierte Stand**, **Medien-Meilenstein** und **sinnvolle nächste Schritte**.
|
||
|
||
### Produktion: `relation … does not exist` (z. B. `skill_main_categories`)
|
||
|
||
Das Schema ist gegenüber dem Code zurück: Migration **`022_skills_schema_complete`** (und ggf. Folgende) wurden auf dieser Datenbank noch nicht erfolgreich ausgeführt.
|
||
|
||
- **Automatisch:** Die Dateien `migrations/*.sql` (numerisch sortiert) bilden eine **Warteschlange**. Bereits erfolgreiche Läufe stehen in `schema_migrations` — diese Dateien werden **übersprungen** (idempotent). Pro Datei läuft **eine Transaktion** (im Container vorzugsweise `psql -1 -f`, sonst Fallback `sqlparse` + psycopg2).
|
||
|
||
- **Fix / manuell:** `docker exec shinkan-api python /app/run_migrations.py` — Exit-Code **0**.
|
||
- Aktuelle Builds: Bei fehlgeschlagenem Migrate startet **`main.py`** die API nicht. Lokal ohne DB: **`SKIP_DB_MIGRATE=1`**.
|
||
|
||
---
|
||
|
||
## 1. Pflichtlektüre (Kontext & Anforderungen)
|
||
|
||
| Thema | Pfad |
|
||
|--------|------|
|
||
| Projekt-Setup, Domain grob | `.claude/docs/working/SHINKAN_PROJECT_SETUP.md` |
|
||
| **Projekt-Status (aktuell)** | `.claude/docs/PROJECT_STATUS.md` |
|
||
| **Medien-Archiv, Lifecycle, Inline-Plan (§11)** | `.claude/docs/technical/MEDIA_ASSETS_AND_ARCHIVE_SPEC.md` |
|
||
| Übungen: API, DB, Architektur, Routing | `.claude/docs/technical/EXERCISES_API_SPEC.md`, `EXERCISES_DATABASE_FINAL.md`, `EXERCISES_ARCHITECTURE.md`, `EXERCISES_FRONTEND_ROUTING.md` |
|
||
| Media / Upload-Limits / Embed | `.claude/docs/technical/MEDIA_UPLOAD_SPEC.md` |
|
||
| MediaWiki-Import | `.claude/docs/technical/MEDIAWIKI_IMPORT_SPEC.md` |
|
||
| Zugriffsschicht, Mandant, Governance | `.claude/docs/technical/ACCESS_LAYER_AND_GOVERNANCE_PLAN.md` |
|
||
| Tenant-Endpoints (Audit) | `.claude/docs/working/ACCESS_LAYER_ENDPOINT_AUDIT.md` |
|
||
| Rahmenprogramm · Planung | `.claude/docs/technical/TRAINING_FRAMEWORK_SPEC.md` |
|
||
| Überblick DB | `.claude/docs/technical/DATABASE_SCHEMA.md` |
|
||
| Domäne | `.claude/docs/functional/DOMAIN_MODEL.md` |
|
||
| **Lieferliste inkl. Medien** | `.claude/docs/library/FEATURES_DELIVERED_2026-Q2.md` §12 |
|
||
|
||
---
|
||
|
||
## 2. Implementierter Stand: Fähigkeiten & Reifegradmodelle
|
||
|
||
### 2.1 Datenbank
|
||
|
||
- **`maturity_models`**, **`model_levels`**, **`model_skills`**, **`model_skill_levels`**: Matrix-Inhalt pro Modell.
|
||
- **Kontext am Modell (Legacy, M:N):** `maturity_model_focus_areas`, `maturity_model_style_directions`, `maturity_model_target_groups` (Migration 025).
|
||
- **Hierarchische Kontext-Zuordnung (Resolve):** `maturity_model_context_bindings` mit optional `style_direction_id`, `training_type_id` (Migration 026, 027).
|
||
- **027:** u. a. `Fokus + Trainingsstil` ohne Stilrichtung (partielle Unique-Indizes).
|
||
|
||
### 2.2 Resolve-Logik (Backend)
|
||
|
||
- **`GET /api/maturity-models/resolve`**: Bindings zum Fokus, die zur Anfrage passen; Merge nach Spezifität (weniger spezifisch zuerst); spezifischere Zeilen überschreiben Zelltexte.
|
||
- **Matching:** Gesetzte Spalten einer Binding-Zeile müssen mit der Anfrage übereinstimmen; `NULL` in der Zeile = Wildcard.
|
||
- **Legacy-Fallback:** Nur wenn für den **Fokus keine einzige** Zeile in `maturity_model_context_bindings` existiert.
|
||
|
||
### 2.3 Export / Import (einzelnes Modell & aufgelöst)
|
||
|
||
- **`GET /api/maturity-models/{id}/export`**: `shinkan.maturity_model.v1` inkl. `context_bindings_for_model` (IDs).
|
||
- **`GET /api/maturity-models/export-resolved`**: `shinkan.maturity_matrix_resolved.v1` (Query: `focus_area_id`, optional `style_direction_id`, `training_type_id`).
|
||
- **`POST /api/maturity-models/import`**: `create` | `replace`, optional `import_bindings`.
|
||
|
||
### 2.4 Komplett-Stack Test → Prod
|
||
|
||
- **`GET /api/admin/matrix-stack/export`**, **`POST /api/admin/matrix-stack/import`** — siehe `matrix_stack_bundle.py`.
|
||
|
||
### 2.5 Frontend (Admin)
|
||
|
||
- **`AdminMaturityModelsPage.jsx`**, **`MaturityModelBindingsAdmin.jsx`**, **`MaturityMatrixToolsAdmin.jsx`**; APIs in `api.js`.
|
||
|
||
---
|
||
|
||
## 3. Trainingsrahmenprogramm & Planungs‑Blueprint (kurz)
|
||
|
||
- **036 / 037:** Bibliotheks-Rahmen, Slot-Inhalt als **`training_units`** mit **`framework_slot_id`**; **`POST /api/training-units/from-framework-slot`**.
|
||
- **Code:** `training_framework_programs.py`, `training_planning.py`; Frontend **`TrainingFrameworkProgramEditPage.jsx`**, **`createTrainingUnitFromFrameworkSlot`** in `api.js`.
|
||
|
||
---
|
||
|
||
## 4. Stand: Medien-Management (Ist, 2026-05-07)
|
||
|
||
**Datenmodell (Kurz):**
|
||
|
||
- **`media_assets`:** Physische oder logische Archiv-Datei (u. a. `sha256`, `visibility`, `club_id`, `lifecycle_state`, `copyright_notice`, Speicherpfad/`storage_key`, `tags` ab passender Migration).
|
||
- **`exercise_media`:** optional **`media_asset_id`**; weiterhin Embeds ohne Asset; Kontext/Sortierung/Titel wie bisher.
|
||
- **`platform_media_storage`:** Superadmin — relativer Unterpfad unter `MEDIA_ROOT`.
|
||
|
||
**API (Auszug):**
|
||
|
||
- **`GET /api/media-assets`**, Filter (Lifecycle, `media_kind`, Verein, Suche, Tags), Berechtigungen pro Zeile.
|
||
- **`PATCH /api/media-assets/{id}`** / Bulk-PATCH, **Lifecycle** (`POST …/lifecycle`, Bulk).
|
||
- **`GET …/media-assets/{id}/file`** (inkl. Kontext `ssetoken` wo vorgesehen).
|
||
- **`POST /api/exercises/{id}/media/from-asset`:** bestehendes Asset verknüpfen.
|
||
- Übungs-Uploads erzeugen/verknüpfen **`media_assets`**; Governance wie **`library_content_*`** / TenantContext.
|
||
|
||
**Frontend:**
|
||
|
||
- Route **`/media`** (Medienbibliothek): Kacheln/Liste, Filter, Copyright, Lifecycle-Actions (Rollen gemäß Spec; **`official`:** bearbeiten/Lifecycle im Wesentlichen **Superadmin**, andere Rollen **Lesemodus** im Bearbeiten-Dialog).
|
||
- Übungsformular: Archiv-Picker, Vorschau, Reaktivierung bei Dedupe-Konflikt (Papierkorb).
|
||
|
||
**Speicher & Pfade:**
|
||
|
||
- Struktur unter **`library/`** mit Vereinssegment (aus Vereinsname abgeleitet + `c{id}`), Unterordner nach Medienkind (`image`/`video`/`pdf`/`other`), Dateiname z. B. SHA-basiert — Details und Drift-Vermeidung in **`MEDIA_ASSETS_AND_ARCHIVE_SPEC.md`**.
|
||
|
||
**Governance & Mandant:**
|
||
|
||
- **`visibility=official`** für Übungen: nur **Superadmin**; Medien **`official`:** Lifecycle/PATCH schwerpunktmäßig Superadmin (Plattform-Admin nicht gleich Superadmin).
|
||
- **Aktiver Verein:** `profiles.active_club_id`, Header **`X-Active-Club-Id`**, Response **`effective_club_id`** — nach **0.8.59** konsistent inkl. Plattform-Admin beim Reload (Backend **`tenant_context`**, Frontend **`getResolvedActiveClubIdForUi`** + Profil-Refresh nach Vereinswechsel).
|
||
|
||
---
|
||
|
||
## 5. Geplant: Inline-Medienverlinkung (nicht umgesetzt)
|
||
|
||
**Ziel:** Mediendarstellung **innerhalb** von Fließtext-Feldern (Ablauf, Ziele, Trainerhinweise), konsistent mit derselben **`exercise_media`‑** bzw. Asset-Governance wie die Medienliste.
|
||
|
||
**Norm:** **`MEDIA_ASSETS_AND_ARCHIVE_SPEC.md` §11** — u. a.:
|
||
|
||
- Verweis auf **`exercise_media.id`** (oder kanonisch übersetzte Markup-Syntax), **keine** zweite Sichtbarkeitslogik.
|
||
- **Ein** zentraler Render-/Sanitize-Pfad für Übungstexte; keine verstreuten „roh `dangerouslySetInnerHTML`“-Pfade.
|
||
- XSS/CSP: nur Allowlist-HTML und kontrollierte Player-Komponenten.
|
||
|
||
**Reihenfolge:** Archiv & aktuelle Governance gelten als Basis; Inline ist die **nächste** inhaltliche Ausbaustufe für Medien (siehe **`PROJECT_STATUS.md`** Nächste Schritte).
|
||
|
||
---
|
||
|
||
## 6. Nächste Session — sinnvolle Arbeitspakete
|
||
|
||
1. **Inline §11:** Syntax festlegen (z. B. `{{exerciseMedia:id}}` → kanonisches HTML), Server normalisieren bei Speichern, einen **`renderExerciseRichText()`**-Pfad im Frontend.
|
||
2. **Tests:** pytest für `media_assets`-Router (Leserechte, Lifecycle, `from-asset`); ggf. Snapshot der Pfad-Umzug-Logik.
|
||
3. **Retention:** Job-Dokumentation + Betrieb (ENV, Intervall); Dry-Run beschreiben.
|
||
4. **S3/Adapter:** Speicher-Abstraktion §7 — wenn Produkt es verlangt.
|
||
5. **Rahmen/UI:** Kalender „aus Rahmen übernehmen“ weiter anbinden (parallel, unabhängig von Medien).
|
||
|
||
---
|
||
|
||
## 7. Technische Referenz (kurz)
|
||
|
||
| Bereich | Einstieg |
|
||
|---------|----------|
|
||
| Backend API | `backend/main.py`; u. a. **`media_assets.py`**, **`exercises.py`**, **`profiles.py`**, **`training_framework_programs.py`**, `tenant_context.py` |
|
||
| Migrationen | `backend/migrations/` (040+ Mitgliedschaft/Governance; **045+** Medien-Stack) |
|
||
| Frontend API | `frontend/src/utils/api.js` |
|
||
| Aktiver Verein (UI) | `frontend/src/utils/activeClub.js`, `AuthContext.jsx` |
|
||
| Version / Changelog | `backend/version.py` |
|
||
|
||
---
|
||
|
||
## 8. Veraltete Hinweise
|
||
|
||
`.claude/docs/working/HANDOVER_NEXT_SESSION.md` verweist auf **dieses** Dokument (`docs/HANDOVER.md`) als aktuelle Basis.
|
||
|
||
---
|
||
|
||
*Ende Handover-Dokument.*
|