shinkan-jinkendo/docs/HANDOVER.md
Lars b6de1f15ea
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
feat(media): implement centralized media archive and inline media linking
- 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>
2026-05-08 10:56:43 +02:00

151 lines
8.7 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 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 & PlanungsBlueprint (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.*