shinkan-jinkendo/backend/version.py
Lars f79f83e8f9
All checks were successful
Deploy Development / deploy (push) Successful in 39s
Test Suite / pytest-backend (push) Successful in 35s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 10s
Test Suite / playwright-tests (push) Successful in 54s
feat(P-11): enhance media asset handling with legal hold attributes and update version to 0.8.85
2026-05-11 13:07:52 +02:00

945 lines
48 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

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 Version Information
APP_VERSION = "0.8.85"
BUILD_DATE = "2026-05-11"
DB_SCHEMA_VERSION = "20260511051"
MODULE_VERSIONS = {
"legal_documents": "1.2.0", # jsPDF-Download auf LegalPage (oeffentlich) + Admin; Abschnitts-Sortierung/-Einfuegen
"auth": "1.2.3", # P-05b: reset-password min_length=8 via Pydantic PasswordResetConfirm
"profiles": "1.7.0", # exercise_list_prefs JSONB (Standard Übungsfilter); Patch via ProfileUpdate + Json()
"tenant_context": "1.0.5", # Plattform-Admin: effective_club ohne Header aus Profil active_club_id wenn Verein existiert
"clubs": "0.4.1", # Alle geschützten Endpoints Depends(get_tenant_context); profile_id/role aus TenantContext
"club_memberships": "1.0.1", # Depends(get_tenant_context)
"club_join_requests": "1.0.1", # Depends(get_tenant_context)
"admin_users": "1.0.0", # GET /api/admin/users
"platform_media_storage": "1.0.0", # GET/PUT /api/admin/platform-media-storage (Superadmin-Pfad unter MEDIA_ROOT)
"media_rights": "1.3.0", # P-11: write_audit_log_entry + legal_hold_set/released events
"media_assets": "1.17.0", # P-11: Legal-Hold-Sichtbarkeitsfilter + Admin-Endpoints (set/release/list)
"media_legal_hold": "1.0.0", # P-11: Sofortsperre-Services (set_legal_hold, release_legal_hold)
"media_lifecycle": "1.1.0", # P-11: Retention-Job ueberspringt Legal-Hold-Assets
"groups": "0.1.0",
"skills": "0.1.0",
"methods": "0.1.0",
"exercises": "2.22.0", # P-11: assert_not_under_legal_hold bei from-asset Medienverknuepfung
"training_units": "0.2.0",
"training_programs": "0.1.0",
"planning": "0.8.1", # Vorlagen Leseprüfung library_content_visible_to_profile
"import_wiki": "1.0.0",
"admin": "1.0.0",
"membership": "1.0.0",
"catalogs": "1.5.0", # Updated: Trainer Contexts API (Migration 012)
"maturity_models": "1.4.0", # matrix_stack_bundle: vollständiger Katalog+Modelle+Bindings Export/Import
}
CHANGELOG = [
{
"version": "0.8.85",
"date": "2026-05-11",
"changes": [
"Fix P-11: Listquery fehlte legal_hold_active/reason_code/reason_note/set_at — Badge und 'Sperre aufheben' im Modal waren nie sichtbar.",
"Fix P-11: submitLegalHold rief loadMedia() statt loadItems() auf ('loadMedia is not a function').",
"Fix P-11: Journal-Renderpfad verwendete nw.legal_hold_reason_code/note statt nw.reason_code/note (Keys aus dem Audit-Log).",
"Fix P-11: Archiv-Picker (ExerciseFormPage, ExerciseInlineFileMediaModal) filtert Legal-Hold-Assets auch fuer Superadmins heraus.",
],
},
{
"version": "0.8.84",
"date": "2026-05-11",
"changes": [
"Feat P-11: Legal-Hold-Sofortsperre — Migration 051 (legal_hold_active + Metadaten in media_assets; audit_log um legal_hold_set/released erweitert).",
"Feat P-11: media_legal_hold.py — zentrale Services set_legal_hold, release_legal_hold, assert_not_under_legal_hold.",
"Feat P-11: Retention-Job ueberspringt Assets mit legal_hold_active=TRUE (keine automatische Loeschung unter Hold).",
"Feat P-11: Neue Admin-Endpoints POST /api/admin/media-assets/{id}/legal-hold, POST …/legal-hold/release, GET …/legal-hold (nur Superadmin).",
"Feat P-11: Sichtbarkeitsfilter erweitert — normale Nutzer sehen Legal-Hold-Assets nicht; Superadmin/Plattform-Admin sehen sie.",
"Feat P-11: exercises from-asset prueft Legal-Hold (LEGAL_HOLD_ACTIVE 403) vor Verknuepfung.",
"Feat P-11: Frontend MediaLibraryPage — Legal-Hold-Badge, Superadmin-Aktionen, Bestaetigungs-Dialog, Journal-Renderpfad fuer legal_hold_set/released.",
"Tests: 15 Backend-Unit-Tests test_p11_legal_hold.py.",
],
},
{
"version": "0.8.83",
"date": "2026-05-11",
"changes": [
"Fix: Journal + Korrektur-Endpoint: club_admin-Pruefung nutzte falsches Schema (role-Spalte nicht in club_members, sondern in club_member_roles via has_club_role); lieferte immer 500.",
],
},
{
"version": "0.8.82",
"date": "2026-05-11",
"changes": [
"Feat P-06: Volljournal fuer Medien (Migration 050) — media_asset_audit_log protokolliert Sichtbarkeits-, Copyright-, Metadaten- und Lifecycle-Aenderungen automatisch.",
"Feat P-06: Korrektur-Deklaration (action_type='correction') via POST /api/admin/media-rights/assets/{id}/correction — zugaenglich fuer Superadmin, Uploader, Vereinsadmin.",
"Feat P-06: Journal-Endpoint gibt jetzt events[] (Deklarationen + Auditlog chronologisch gemischt) und can_correct zurueck; Zugriff fuer Superadmin + Uploader + Vereinsadmin.",
],
},
{
"version": "0.8.81",
"date": "2026-05-11",
"changes": [
"Fix P-06: check_rights_coverage gibt bei rights_status='declared' immer 'ok' zurueck — Erklaerung gilt sichtbarkeitsunabhaengig (Inhalt aendert sich nicht durch Sichtbarkeits-Promotion). 'insufficient'-Pfad entfernt. Tests angepasst.",
],
},
{
"version": "0.8.80",
"date": "2026-05-11",
"changes": [
"Fix P-06: Bei Sichtbarkeits-Promotion (private→club, club→official) oeffnet das Frontend bei RIGHTS_SCOPE_INSUFFICIENT / LEGACY_REDECLARATION_REQUIRED automatisch den Einwilligungsdialog (promotion/redeclaration-Modus) statt eines alert()-Fehlers; PATCH wird nach Bestaetigung mit P-06-Feldern wiederholt.",
],
},
{
"version": "0.8.79",
"date": "2026-05-11",
"changes": [
"Fix: profiles.username -> profiles.name in Journal-Endpoint (500er behoben); RightsDeclarationDialog: doppelter Abbrechen-Button entfernt (Header-X statt Text); Playwright P-01: Platzhalter-Pruefung optional (echtes Impressum deployed); Playwright P-06c: Selector-Konflikt durch UI-Fix beseitigt.",
],
},
{
"version": "0.8.78",
"date": "2026-05-11",
"changes": [
"P-06 Superadmin Medienjournal: GET /api/admin/media-rights/assets/{id}/journal liefert vollstaendiges Deklarations-Log pro Medium; Frontend: Journal-Button im Bearbeitungs-Modal (nur Superadmin), scrollbare Timeline aller Einwilligungserklaerungen mit Kontext-Feldern.",
],
},
{
"version": "0.8.77",
"date": "2026-05-11",
"changes": [
"P-06 Erweiterung: Migration 049 — 4 optionale Freitext-Kontextfelder in media_asset_rights_declarations (person_consent_context, parental_consent_context, music_rights_context, third_party_rights_context); copyright_notice direkt im Upload-Dialog erfassbar; alle drei Dialoge (RightsDeclarationDialog, ExerciseInlineFileMediaModal, ExerciseInlineEmbedModal) und alle Backend-Endpoints aktualisiert.",
],
},
{
"version": "0.8.76",
"date": "2026-05-11",
"changes": [
"Fix P-06: RightsDeclarationDialog in ExerciseInlineFileMediaModal (Upload-Tab) und ExerciseInlineEmbedModal integriert; vor jedem Exercise-Media-Upload oeffnet sich der vollstaendige Einwilligungsdialog statt eines nicht-benutzbaren alert()",
],
},
{
"version": "0.8.75",
"date": "2026-05-11",
"changes": [
"P-06 (Upload-Einwilligungsdialog) technisch umgesetzt unter konservativen Erstannahmen (p06-v1-conservative): Migration 048 (media_asset_rights_declarations + rights_status/rights_declared_for_visibility/rights_declared_at in media_assets); zentrales Policy-Modul media_rights.py; Bulk-Upload und PATCH/Bulk-Patch mit P-06-Enforcement; Re-Deklarations-Endpoint (POST /api/media-assets/{id}/rights-declarations); Admin-Legacy-Summary (GET /api/admin/media-rights/legacy-summary+/legacy-assets); exercises.py: P-06 bei upload_exercise_media und from-asset; Frontend: RightsDeclarationDialog + Altbestand-Indikator in Medienbibliothek. KRIT-04 bleibt offen bis juristische Validierung.",
],
},
{
"version": "0.8.74",
"date": "2026-05-10",
"changes": [
"Rechtstexte: echtes PDF-Download via jsPDF (pdf.save) statt Browser-Print-Dialog; LegalPage und AdminLegalDocumentsPage",
"Rechtstexte Admin: Abschnitts-Reihenfolge per Pfeil-Buttons aendern; neuen Abschnitt an beliebiger Stelle einfuegen",
],
},
{
"version": "0.8.73",
"date": "2026-05-10",
"changes": [
"Rechtstexte: PDF-Export via Browser-Print (kein neues Paket); Drucker-Button in AdminLegalDocumentsPage (laedt Volldokument) und auf LegalPage (nur bei veroeffentlichtem Inhalt); Dokument enthaelt Versionsnummer und Gueltigkeitsdatum",
],
},
{
"version": "0.8.72",
"date": "2026-05-10",
"changes": [
"Rechtstexte: Als-Entwurf-kopieren — POST /api/admin/legal-documents/{id}/copy-as-draft; Inhalt und Titel werden uebernommen, Versionsnummer inkrementiert",
],
},
{
"version": "0.8.71",
"date": "2026-05-10",
"changes": [
"Compliance P-01c: Admin-konfigurierbare Rechtstexte — DB 047 (legal_documents + legal_document_audit); Superadmin CRUD + Publish/Archive-Workflow; LegalPage laedt aus API mit Platzhalter-Fallback; AdminLegalDocumentsPage unter /admin/legal-documents",
],
},
{
"version": "0.8.70",
"date": "2026-05-10",
"changes": [
"Compliance P-01b: Einstellungen/Rechtliches (/settings/legal) fuer mobile/PWA-Darstellung; Hub mit Links zu Impressum, Datenschutz, Nutzungsbedingungen, Medienrichtlinie",
],
},
{
"version": "0.8.69",
"date": "2026-05-10",
"changes": [
"Compliance P-01 (KRIT-01) technischer Teil: Rechtstextseiten /impressum, /datenschutz, /nutzungsbedingungen, /medienrichtlinie als oeffentliche Routen angelegt (Platzhalter, kein Auth erforderlich)",
"Login-Seite und Desktop-Sidebar enthalten Links zu allen vier Rechtstextseiten",
],
},
{
"version": "0.8.68",
"date": "2026-05-10",
"changes": [
"Sicherheit P-12 (MITT-05): logout() bereinigt alle sj_coach_*-Schlüssel aus sessionStorage; Präfix-gezielte Löschung, keine fremden Schlüssel betroffen",
],
},
{
"version": "0.8.67",
"date": "2026-05-10",
"changes": [
"Sicherheit P-05b: PasswordResetConfirm.new_password min_length=8 (POST /auth/reset-password)",
"Sicherheit P-03b: Retention-Default HIDDEN_TO_PURGE 90->30 Tage (gemaess Loeschkonzept 30+30)",
"Sicherheit P-04: Positive Promotion-Tests haerten (explizit 200 + Payload); Umlaut in Fehlermeldung",
],
},
{
"version": "0.8.66",
"date": "2026-05-09",
"changes": [
"Sicherheit P-03: Papierkorb-Retention-Job (media_retention_job.py) als Docker-Service retention-cron aktiviert (lauft taglich um 03:00 Uhr)",
"Sicherheit P-04: Copyright-Pflicht bei Sichtbarkeits-Promotion auf club/official in PATCH und bulk-patch (media_assets)",
"Sicherheit P-05: Passwort-Mindestlange PUT /auth/pin von 4 auf 8 Zeichen angehoben",
"Sicherheit P-07: Release-Test fur ALLOW_PUBLIC_MEDIA_STATIC in test_security_release.py ergaenzt",
"Sicherheit P-23: LoginPage minLength 6 auf 8 angehoben; hartcodierter Versionsstring entfernt",
"Sicherheit P-24: CORS allow_methods und allow_headers auf benotigte Werte eingeschrankt",
],
},
{
"version": "0.8.65",
"date": "2026-05-08",
"changes": [
"Übung auf Verein: fehlende Copyrights an Datei-Assets wieder per Bestätigung + Eingabe beim Speichern setzbar (PUT default_club_media_copyright; Bulk-PATCH ebenfalls)",
],
},
{
"version": "0.8.64",
"date": "2026-05-08",
"changes": [
"Übung bearbeiten: Auto-Scroll beim Drag von Medien zu Textfeldern; Medien-Kacheln mehrspaltig; Sektion/Ablauf-Zuordnung an Medien entfernt (nur noch Titel bearbeiten); Picker: Video-Vorschau-Frame; Katalogvorschau ohne Anhangs-Medienliste; Ansehen mit Speichern-Hinweis + Zurück zur Bearbeitung von der Ansicht",
],
},
{
"version": "0.8.63",
"date": "2026-05-08",
"changes": [
"RTE/Übung Medien: Picker-Thumbnails; Dateiauswahl-Anzeige; bereits verknüpfte Archive-Medien ins Fließtext einfügen; Platzhalter-Caption data-shinkan-exercise-media-caption + Caret nach ZWSP; Lesemodus: Medienliste nur für nicht eingebettete Anhänge; bearbeiten: kompakte Kacheln mit Drag-and-Drop in Textfelder, Upload unter Medien entfällt",
],
},
{
"version": "0.8.62",
"date": "2026-05-08",
"changes": [
"RTE Inline-Medien: Modals Mediathek+Hochladen + „Embed im Text“; Darstellungsgröße small|medium|full (data-shinkan-exercise-media-size); Lesemodus begrenzt Bild/Video-Breite",
],
},
{
"version": "0.8.61",
"date": "2026-05-08",
"changes": [
"RTE „Bild/Video im Text“: eingebaute Hilfe (Caret + insertHTML/Fallback); sichtbarer 📎-Chip im Editor; Hinweis bei fehlgeschlagener Einfügung/Prompt-ID",
],
},
{
"version": "0.8.60",
"date": "2026-05-08",
"changes": [
"Inline-Medien im Übungs-Fließtext (MEDIA_SPEC §11): {{exerciseMedia:id}} → kanonisches span; nur exercise_media dieser Übung; create ohne Platzhalter",
"Frontend: ExerciseRichTextBlock mit Allowlist-Sanitize + Embed; Toolbar „Bild/Video im Text“ im RichTextEditor wenn Medien an der Übung; Detail/Katalog/Liste konsistent",
],
},
{
"version": "0.8.59",
"date": "2026-05-07",
"changes": [
"Aktiver Verein: Backend resolve_tenant_context für Plattform-Admin ohne X-Active-Club-Id nutzt gespeichertes active_club_id wenn der Verein existiert (kein effective=null nach hartem Reload mehr)",
"Frontend: Nach Vereinswechsel Profil neu laden; Dropdown-Wert aus effective_club_id / active_club_id / LocalStorage abgestimmt (getResolvedActiveClubIdForUi)",
],
},
{
"version": "0.8.58",
"date": "2026-05-07",
"changes": [
"Medienbibliothek offiziell: Ändern/Lifecycle nur Superadmin (nicht Plattform-Admin); Bearbeiten-Dialog für andere nur Lesemodus; Superadmin: Vereinsauswahl beim Archiv-Upload folgt aktiv/gesetzt effective_club_id",
],
},
{
"version": "0.8.57",
"date": "2026-05-07",
"changes": [
"Governance: visibility=official nur noch Superadmin (nicht Plattform-Admin)",
"Medienarchiv: private Uploads als Plattform-Admin erfordern explizites club_id; gleiche Ordnerstruktur wie „Verein“, private Kopien mit .u{Profil} vor Dateiendung",
"Übung visibility=Verein: angebundene Archiv-Dateien müssen aktiv sein und Copyright (≥3 Zeichen) haben; UI- und API-Fehlercodes CLUB_MEDIA_*",
"Frontend: „Offiziell“ nur Superadmin (Bibliothek, Übungsformular, Bulk-Sichtbarkeit, Progressionsgraphen)",
],
},
{
"version": "0.8.56",
"date": "2026-05-07",
"changes": [
"Medienbibliothek: Vereinsmedien unter library/{aus Name abgeleitet}-c{club_id}/ statt festem library/club/c{id}/; Sonderzeichen/Umlaute zu sicheren Ordnernamen; fehlender Name → verein-c{id}; Governance-Umzug liest aktuellen Vereinsnamen aus DB",
],
},
{
"version": "0.8.55",
"date": "2026-05-07",
"changes": [
"Medienbibliothek: Speicherpfad library/* mit Medientyp-Unterordnern (image, video, pdf, other) vor SHA-Dateinamen; Umzug bei Governance-PATCH nutzt mime_type aus DB",
],
},
{
"version": "0.8.54",
"date": "2026-05-08",
"changes": [
"Medienpfade: vereinsgeteilt (club) direkt unter library/club/c{id}/; private unter library/club/c{id}/u{profile}/ (kein Ordner „private“/„shared“); Dedupe private inkl. uploaded_by_profile_id",
],
},
{
"version": "0.8.53",
"date": "2026-05-08",
"changes": [
"Medienablage vereinsbezogen: private → library/club/c{id}/private, Vereinssichtbarkeit → …/shared, official unverändert; private Archiv-Upload: club_id oder X-Active-Club-Id; DB club_id bei private gesetzt; PATCH/Bulk: club_id für private nicht mehr blind auf NULL",
],
},
{
"version": "0.8.52",
"date": "2026-05-08",
"changes": [
"Neue lokale media_assets: hierarchische library/* Pfade; Dedupe nach sha+visibility+club_id; bei PATCH/Bulk-Patch Sichtbarkeit/Verein: Datei umziehen, exercise_media.file_path aktualisieren (Details siehe 0.8.53)",
],
},
{
"version": "0.8.51",
"date": "2026-05-07",
"changes": [
"Medienbibliothek GET: Verknüpfung zu Trainingseinheiten nur wenn Tabelle training_unit_exercises existiert (ältere/kaputte Schemas → keine 500, Einheiten-Liste leer)",
],
},
{
"version": "0.8.50",
"date": "2026-05-07",
"changes": [
"Medienbibliothek: DB 046 media_assets.tags (GIN); GET filter media_kind, club_id (Superadmin), uploaded_by; Suche über Copyright & Tags; Antwort usage exercises + training_units; PATCH/Bulk tags; UI volle Breite, Filterleiste, ©-Symbol auf Kacheln, Links zu Übungen/Planung, gleiche Sichtbarkeits-/Status-Symbole wie Übungsliste",
],
},
{
"version": "0.8.49",
"date": "2026-05-07",
"changes": [
"Medienbibliothek UI: Kacheln/Liste, Modal Bearbeiten, Video-First-Frame-Thumbs, Mobile/Safe-Area, Bulk; API: permissions pro Zeile, Uploader/Verein für Admin, PATCH Sichtbarkeit+Bezeichner, trash_soft nur Trainer-Eigenes-Privat / Vereinsorga / Plattform; purge nur Superadmin; superadmin_force_lifecycle + hard_delete; bulk-lifecycle, bulk-patch",
],
},
{
"version": "0.8.48",
"date": "2026-05-07",
"changes": [
"Medienbibliothek: GET /api/media-assets mit lifecycle (active|trash_soft|trash_hidden|all), copyright_notice in Liste; PATCH /api/media-assets/{id} (Copyright); GET …/file für Papierkorb wenn Lifecycle-Recht; Frontend /media + Admin-Nav + Link Übungsformular",
],
},
{
"version": "0.8.47",
"date": "2026-05-07",
"changes": [
"Übung „offiziell“ (§4.2): angehängte Datei-Assets müssen aktiv sein; Sichtbarkeit/Copyright per Bestätigung anheben; PUT /api/exercises/{id} + PATCH bulk-metadata: Felder promote_attached_media_for_official, default_official_media_copyright; Frontend Bestätigungsdialog",
],
},
{
"version": "0.8.46",
"date": "2026-05-07",
"changes": [
"Übung Medien-Upload: bei 409-Konflikt (Papierkorb-Dedupe) logger.warning mit exercise_id, profile_id, media_asset_id, lifecycle, visibility, club_id, sha256_prefix, Dateinamen",
"ExerciseFormPage: erklärende Medien-Hinweistexte in GUI entfernt (Kurzbeschreibung + Archiv-Dialog)",
],
},
{
"version": "0.8.45",
"date": "2026-05-07",
"changes": [
"Upload Übungsmedien: gleicher Inhalt (SHA-256) wie Papierkorb-Asset → 409 MEDIA_ASSET_IN_TRASH statt DB-Fehler; Lifecycle action reactivate (trash_soft/hidden → active)",
"Frontend: Dialog Reaktivieren + Verknüpfen; uploadExerciseMedia wertet strukturiertes 409 aus",
],
},
{
"version": "0.8.44",
"date": "2026-05-07",
"changes": [
"DELETE /api/exercises/{id}/media/{mid}: entfernt nur exercise_media; keine Datei-/media_assets-Löschung; Response orphan_media_asset_id wenn letzte Referenz",
"Übung bearbeiten: Video-Kachel (Erstframe), Dateiname; Papierkorb-Schalter entfernt; „Aus Übung entfernen“ + optional Papierkorb bei Waise",
],
},
{
"version": "0.8.43",
"date": "2026-05-07",
"changes": [
"Medienarchiv: GET /api/media-assets (Suche, nur aktive Assets, Bibliotheks-Sichtbarkeit); GET /api/media-assets/{id}/file (Thumbnails/Vorschau, ssetoken)",
"Übungen: POST /api/exercises/{id}/media/from-asset — bestehendes Archiv-Medium verknüpfen ohne Upload-Duplikat",
"Frontend Übung bearbeiten: „Aus Archiv verknüpfen…“, Medienvorschau-Modal, Kachel-Thumbnails in der Medienliste",
],
},
{
"version": "0.8.42",
"date": "2026-05-07",
"changes": [
"Medien-Papierkorb: POST /api/media-assets/{id}/lifecycle (trash_soft, trash_hidden, recover, purge); Retention-Job scripts/media_retention_job.py",
"Übungen: GET-Detail inkl. asset_lifecycle_state; Bearbeitungsrechte Erweiterung (Vereinsplanung); Frontend Übung bearbeiten: Reihenfolge, Papierkorb-Actions; Detail/Katalog: trash_hidden ausgeblendet, Hinweis trash_soft",
"Fix: ExerciseDetailPage zeigt „Hinweise für Trainer“ wieder an",
],
},
{
"version": "0.8.41",
"date": "2026-05-07",
"changes": [
"DB 045: media_assets, exercise_media.media_asset_id, platform_media_storage; Migration bestehender Medien; Upload-Dedupe pro sha256+visibility+club_id",
"Effektives Medien-Verzeichnis: MEDIA_ROOT + Superadmin local_relative_root (GET/PUT /api/admin/platform-media-storage)",
"Neue Uploads: storage_key exercises/{sha256}{ext}; Download/Delete nutzen media_assets",
"api.js: getPlatformMediaStorage, putPlatformMediaStorage",
],
},
{
"version": "0.8.40",
"date": "2026-05-06",
"changes": [
"Übungen Liste: Fokusfilter mit UND-+ (must_include) und UND- (must_exclude), nur ohne Fokusbereich (focus_only_without); Frontend Dropdown + Mit / Ohne",
],
},
{
"version": "0.8.39",
"date": "2026-05-06",
"changes": [
"Übungen DELETE: Nur eigene private / Vereinsadmin für Vereins-Übungen / Plattform für globale; keine harte Löschung bei Verwendung in Blöcken, Plan-Abschnitten oder Progressionskanten (409 → archivieren)",
"GET /api/exercises: Negativfilter (visibility_exclude_any, status_exclude_any), exclude_without_focus, include_archived; archivierte standardmäßig ausgeblendet",
"Profile exercise_list_prefs (JSONB, Migration 043): gespeicherte Standardfilter; Frontend Übungsliste Filterdialog + „Als Standard speichern“",
"Übungspicker: gleiche Negativfilter; Planung lädt archivierte Übungen immer mit (bestehende Zuordnungen)",
"pytest: tests/test_exercises_delete_policy.py",
],
},
{
"version": "0.8.38",
"date": "2026-05-06",
"changes": [
"Trainingsplanung: Vereinsadmins sehen alle Einheiten bei club_id-/Gruppenliste; GET/PUT Einheit & Löschen mit can_manage_club_org",
"Planung UI: „Trainer zuweisen“ in Vereins-Ansicht (Liste + Kalender) + eigener Modal; Mitgliederverzeichnis für Vereinsorganisation",
],
},
{
"version": "0.8.37",
"date": "2026-05-05",
"changes": [
"DB 042: training_units.assistant_trainer_profile_ids (Co-Trainer-Zuweisung je Termin; NULL = Gruppen-Standard)",
"Trainingseinheiten: POST/PUT lead_trainer_profile_id & assistant_trainer_profile_ids; Leitung für Vereinsmitglieder (Vertretung); GET-Listen inkl. Zuweisung für Sichtbarkeit/assigned_to_me",
"Frontend Trainingsplanung: Leitung/Co-Trainer pro Einheit; Dashboard-Text",
"pytest: tests/test_training_unit_assignments.py",
],
},
{
"version": "0.8.36",
"date": "2026-05-05",
"changes": [
"POST /api/profiles: nur Plattform-Admin; Anlage schema-konform (SERIAL, E-Mail, temporärer PIN-Hash); ProfileCreate mit Pflichtfeldern name + email",
"pytest: POST-Szenarien in test_profiles_read_access.py",
],
},
{
"version": "0.8.35",
"date": "2026-05-05",
"changes": [
"DELETE /api/profiles/{pid}: nur Plattform-Admin (403 sonst); Unit-Tests mit gemockter DB",
],
},
{
"version": "0.8.34",
"date": "2026-05-05",
"changes": [
"GET /api/profiles/{pid}: Zugriff nur eigenes Profil oder Plattform-Admin (403 sonst); Unit-Tests ohne DB; zwei Integrationstests mit PostgreSQL",
"Integration: zwei zusätzliche Profil-Lese-Tests in test_access_layer_integration",
],
},
{
"version": "0.8.33",
"date": "2026-05-05",
"changes": [
"CI pytest-backend wie Mitai-Jinkendo: docker compose exec backend (deployte Stacks shinkan / shinkan-dev); keine Runner-Python/Postgres-Service",
"pytest.ini: Marker smoke/slow, addopts/-q wie Schwesterprojekt; CI: -m \"not slow\", ACCESS_LAYER_STRICT + Integration im Container",
],
},
{
"version": "0.8.32",
"date": "2026-05-05",
"changes": [
"CI pytest-backend: kein setup-python — venv aus System-python3 (arm64/Debian Self-Host, Raspi)",
],
},
{
"version": "0.8.31",
"date": "2026-05-05",
"changes": [
"CI (Gitea): Job pytest-backend — Checkout, Postgres-Service, run_migrations, pytest (+ ACCESS_LAYER_INTEGRATION), ACCESS_LAYER_STRICT auf Router-Hinweis-Script",
"Workflow test.yml: pull_request auf main/develop zusätzlich zu push",
],
},
{
"version": "0.8.30",
"date": "2026-05-05",
"changes": [
"pytest: optionale PostgreSQL-Integration tests/test_access_layer_integration.py (Cross-Verein Übungen Liste/Detail; ACCESS_LAYER_INTEGRATION=1)",
"pytest.ini: Marker „integration“",
],
},
{
"version": "0.8.29",
"date": "2026-05-05",
"changes": [
"Übungen: PATCH /api/exercises/bulk-metadata (bis 500 IDs) — Sichtbarkeit und/oder Status; Ersteller oder Plattform-Admin; Governance wie Einzel-PUT",
"Übungsliste: Mehrfachauswahl, Alle auf dieser Seite, Dialog Massenänderung (Verein/offiziell nur Admins)",
],
},
{
"version": "0.8.28",
"date": "2026-05-05",
"changes": [
"ACCESS_LAYER: Übungen-, Trainingsplanung-, Rahmenprogramme-Detail nutzen library_content_visible_to_profile (einheitliche Leseprüfung)",
"pytest: backend/requirements-dev.txt, pytest.ini, backend/tests/test_access_layer.py — ohne DB (library_content_visibility_sql, parse_active_club_header)",
],
},
{
"version": "0.8.27",
"date": "2026-05-05",
"changes": [
"ACCESS_LAYER Governance-Disziplin: .cursor/rules/access-layer.mdc; ARCHITECTURE 1.4 + CODING_RULES Tenant-Pfad; CLAUDE Pflichtlektüre Zugriffsschicht",
"backend/scripts/check_access_layer_hints.py — Router ohne get_tenant_context außerhalb EXEMPT melden (optional ACCESS_LAYER_STRICT=1)",
"club_tenancy.library_content_visible_to_profile; Audit-Tabelle um globale Router (EXEMPT) ergänzt",
],
},
{
"version": "0.8.26",
"date": "2026-05-05",
"changes": [
"ACCESS_LAYER: clubs-, club_memberships-, club_join_requests-Router nutzen Depends(get_tenant_context) statt nur require_auth",
"profiles: PUT /profiles/{id} und /profile mit TenantContext; profile_document für /auth/me und intern",
"exercise_progression_graphs: Liste/Detail nach library_content_visibility_sql; Leserechte Vereins-Graphs; POST/PUT mit assert_valid_governance_visibility und club_id wie Übungen",
],
},
{
"version": "0.8.25",
"date": "2026-05-05",
"changes": [
"Übungen PUT: bei visibility club wird club_id aus aktivem Verein oder Body gesetzt (verhindert club ohne club_id für Vereinsnutzer)",
"club_tenancy: governance visibility club für Plattform-Admins ohne Vereinsmitgliedschaft (nur Existenz clubs.id)",
"Login POST /api/auth/login: Rate-Limit 30/minute pro IP (vorher 5/minute)",
],
},
{
"version": "0.8.24",
"date": "2026-05-05",
"changes": [
"Übungen-Router: get/update/delete, Varianten, Medien — Depends(get_tenant_context); Upload-Limits via TenantContext; fehlenden DELETE decorator variants gefixt",
],
},
{
"version": "0.8.23",
"date": "2026-05-05",
"changes": [
"ACCESS_LAYER: library_content_visibility_sql + TenantContext an Übungen-Liste, Rahmenprogramme, Trainingsplanung",
"POST Übung/Vorlage/Rahmenprogramm: visibility club ohne club_id → effective_club_id; POST Übung mit assert_valid_governance_visibility",
],
},
{
"version": "0.8.22",
"date": "2026-05-05",
"changes": [
"ACCESS_LAYER Stufe B: Modul tenant_context (resolve_tenant_context, Depends(get_tenant_context)); GET /profiles/me liefert effective_club_id; veralteter X-Active-Club-Id wird dort verworfen (ignore), strikt auf anderen Endpoints via Depends",
"Arbeitspapier ACCESS_LAYER_ENDPOINT_AUDIT.md für Router-Inventar",
],
},
{
"version": "0.8.21",
"date": "2026-05-05",
"changes": [
"FastAPI: Router club_memberships und club_join_requests registriert (GET /api/clubs/{id}/members, join-requests u. a.) — behoben 404 auf Vereinsseite Tab Mitglieder",
],
},
{
"version": "0.8.20",
"date": "2026-05-05",
"changes": [
"Migration 041: wenn noch kein superadmin existiert, werden ältestes Profil mit role admin zu superadmin hochgestuft",
"Registrierung: erster Nutzer und ADMIN_BOOTSTRAP_EMAILS erhalten superadmin (vorher admin)",
],
},
{
"version": "0.8.19",
"date": "2026-05-05",
"changes": [
"Portal-Admin: GET /api/admin/users (alle Nutzer + Vereine); PUT /profiles/{id} mit role/tier (Super-Admin nur durch Super-Admin); Mitgliedschaft inaktiv in Übersicht",
"GUI Admin → Nutzer: Portal-Rolle/Tier, Verein zuweisen, Vereinsrollen bearbeiten",
],
},
{
"version": "0.8.18",
"date": "2026-05-05",
"changes": [
"DB 040 club_membership_requests; API Antrag/Abrufen/annehmen/ablehnen; öffentliches Vereinsverzeichnis; Mitglieder-Directory für Trainerwahl",
"GUI: Vereinsverwaltung Tab Mitglieder & Anträge; Registrierung/Einstellungen Vereinsantrag; Gruppenformular Haupt- und Co-Trainer",
"GET /profiles nur noch für Plattform-Admins",
],
},
{
"version": "0.8.17",
"date": "2026-05-05",
"changes": [
"Multi-Tenancy Phase 4: training_plan_templates + training_framework_programs Listen und Lesen nach visibility/club wie Übungen; Schreiben nur Ersteller oder Plattform-Admin; club_tenancy.assert_valid_governance_visibility",
],
},
{
"version": "0.8.16",
"date": "2026-05-05",
"changes": [
"API Vereinsmitglieder: GET/POST/GET-one/PUT/DELETE /api/clubs/{id}/members (Plattform- oder Vereinsadmin); Frontend api.js Hooks",
],
},
{
"version": "0.8.15",
"date": "2026-05-05",
"changes": [
"DB 039 Fix: Co-Trainer-Backfill über Subquery + CASE (kein jsonb_array_length/jsonb_array_elements auf Nicht-Arrays durch Planner/LATERAL-Reihenfolge)",
],
},
{
"version": "0.8.14",
"date": "2026-05-05",
"changes": [
"DB 039 Fix: Co-Trainer-Backfill nur wenn co_trainer_ids ein JSON-Array ist (vermeidet jsonb_array_length auf Nicht-Array)",
],
},
{
"version": "0.8.13",
"date": "2026-05-05",
"changes": [
"Fix: Startup unter Windows (cp1252) — Emoji/Sonderzeichen in print durch ASCII ([OK]/[FAIL]/[WARN]) ersetzt (main, run_migrations, db_init)",
],
},
{
"version": "0.8.12",
"date": "2026-05-05",
"changes": [
"DB 039: club_members, club_member_roles, clubs.primary_admin_profile_id, profiles.active_club_id + Backfill",
"Multi-Tenancy: Vereinslisten gefiltert, Vereinsanlage nur Plattform-Admin mit primary_admin_profile_id",
"Übungen: visibility club nur für Mitglieder des zugeordneten Vereins",
"GET /api/profiles/me: clubs[], ohne pin_hash; active_club_id setzen via PUT",
"Frontend: X-Active-Club-Id, Vereins-Umschalter, Vereinsseiten angepasst",
],
},
{
"version": "0.8.11",
"date": "2026-05-05",
"changes": [
"DB 038: training_units.lead_trainer_profile_id (Vertretung / Leitung pro Termin)",
"API GET /api/training-units: club_id, assigned_to_me, sort, limit; Co-Trainer in Sichtbarkeit; lead_trainer_name / effective_lead_trainer_profile_id",
"API PUT /api/training-units/{id}: lead_trainer_profile_id (Validierung über Gruppe)",
],
},
{
"version": "0.8.10",
"date": "2026-05-05",
"changes": [
"DB 037: Rahmen-Slot-Blueprints als training_units (framework_slot_id); migration training_framework_slot_exercises → Sektionen/Items; origin_framework_slot_id für Kopien",
"API: Rahmen-Slots mit sections/exercises aus Blueprint; Kalender list_training_units ohne Blueprints; POST /api/training-units/from-framework-slot",
],
},
{
"version": "0.8.9",
"date": "2026-05-05",
"changes": [
"DB 036: Rahmenprogramm Kontext (Fokusbereich, Stilrichtung, M:N Trainingsarten & Zielgruppen); nur Bibliothek — plan_mode/group_id/Slot-training_unit entfernt.",
"API: /api/training-framework-programs ohne concrete/library; Payload focus_area_id, style_direction_id, training_type_ids, target_group_ids",
],
},
{
"version": "0.8.8",
"date": "2026-05-05",
"changes": [
"DB 035: Trainingsrahmenprogramm (Rahmen, Ziele, Slots, Slot-Übungen); plan_mode concrete|library",
"DB 035: training_plan_templates.visibility + Backfill club (CURR-007/008)",
"API: CRUD /api/training-framework-programs (AuthZ wie Übungs-/Planungsbibliothek)",
],
},
{
"version": "0.8.7",
"date": "2026-04-30",
"changes": [
"DB 034: Progressionskanten mit optionalen Varianten-Endpunkten",
"API: POST …/edges/sequence (Reihe auf einmal); POST …/edges/delete-batch",
"Frontend Progressions-UI: Sequenz-Editor, Ketten-Ansicht, Variantenwahl",
],
},
{
"version": "0.8.6",
"date": "2026-04-30",
"changes": [
"DB 033: exercise_progression_edges.notes (Entwicklungsziel)",
"API: Kanten mit notes; JOIN Übungstitel in Listen; PUT Kanten-Notiz",
"Frontend: Progressionsgraphen-Tab unter Übungen + Bereich in Übung bearbeiten",
],
},
{
"version": "0.8.5",
"date": "2026-04-30",
"changes": [
"DB 032: exercise_progression_graphs + exercise_progression_edges (Übung→Übung, edge_type next_exercise)",
"API: CRUD Progressionsgraphen und Kanten unter /api/exercise-progression-graphs",
],
},
{
"version": "0.8.4",
"date": "2026-04-27",
"changes": [
"run_migrations: Warteschlange nach numerischem Präfix der Dateien (stabile Reihenfolge auch bei ungleich langen Zahlen wie 9 vs 10)",
],
},
{
"version": "0.8.3",
"date": "2026-04-28",
"changes": [
"Migrationen: Warteschlange aller fehlenden *.sql; idempotent über schema_migrations",
"Ausführung vorzugsweise psql -1 -f (eine Transaktion pro Datei); Fallback psycopg2 + sqlparse.split",
"requirements: sqlparse wenn kein psql im PATH",
],
},
{
"version": "0.8.2",
"date": "2026-04-28",
"changes": [
"main: run_migrations — Exit-Code auswerten; bei Fehler kein API-Start (verhindert Prod ohne Skill-Tabellen wie 022)",
"SKIP_DB_MIGRATE=1 optional für lokale Runs ohne Datenbank",
],
},
{
"version": "0.8.1",
"date": "2026-04-28",
"changes": [
"skills: JSONB keywords per psycopg2.extras.Json (verhindert 500 wenn keywords als Objekt/Array gesendet wird)",
"GET /api/health/ready: DB-Verbindung + Kern-Tabellen + schema_migrations_count (ohne Auth, für Prod-Debugging)",
],
},
{
"version": "0.8.0",
"date": "2026-04-28",
"changes": [
"DB 031: Trainingsvorlagen (Sektionen) + Struktur pro Einheit (Sektionen, Übungen/Notizen, Dauer)",
"API: /api/training-plan-templates CRUD; Trainingseinheiten mit sections[] + plan_template_id",
"Trainingsplanung UI: Abschnitte, Zwischen-Anmerkungen, Vorlagen auswählen / speichern",
],
},
{
"version": "0.7.9",
"date": "2026-04-27",
"changes": [
"Übungsvarianten: POST/PUT/DELETE /api/exercises/{id}/variants + reorder",
"Übung bearbeiten: voller Varianten-Editor (Speichern pro Variante, Reihenfolge, Voraussetzung)",
"Übung Ansehen: Varianten-Metadaten (Dauer, Schwierigkeit, Material, Progression)",
"GET /exercises Detail: Varianten-Sortierung sequence_order → progression_level",
],
},
{
"version": "0.7.8",
"date": "2026-04-27",
"changes": [
"DB 030: training_unit_exercises.exercise_variant_id (FK exercise_variants)",
"GET /exercises?include_variants=true liefert Varianten für Trainingsplanung",
"Trainingseinheiten: optional exercise_variant_id beim Anlegen/Aktualisieren",
],
},
{
"version": "0.7.7",
"date": "2026-04-27",
"changes": [
"DB 029: Fähigkeitsstufen Einheit (basisoptimierung), model_levels Namen 15",
"Übungen: GET /exercises Filter Stilrichtung, Trainingsstil, Zielgruppe, Fähigkeits-Stufe min/max, ai_search (Volltext-Platzhalter)",
"API: exercise_skills Level-Normalisierung bei Schreiben/Lesen; Wiki-Import Slugs statt Zahl in DB",
],
},
{
"version": "0.7.6",
"date": "2026-04-27",
"changes": [
"API: GET/POST /api/admin/matrix-stack (shinkan.matrix_stack.v1) Fähigkeitskatalog, Reifegradmodelle, Kontext-Bindings für Test→Prod",
"DB 028: exercise_media (Embed/Metadaten), exercise_skills VARCHAR-Level/Intensität; API: POST/PUT/DELETE Medien, /media Static; Übungen-Listen-Fokus",
],
},
{
"version": "0.7.5",
"date": "2026-04-27",
"changes": [
"Resolve/Export: Legacy M:N nur noch, wenn für den Fokus keine Kontext-Bindings existieren (korrekte Striktheit für Fokus+Trainingsstil / Teil-Kontexte)",
],
},
{
"version": "0.7.4",
"date": "2026-04-27",
"changes": [
"DB 027: Bindings Fokus+Trainingsstil ohne Stilrichtung",
"resolve: alle passenden Bindings nach Spezifität mergen",
"API: Export/Import JSON (Modell + aufgelöste Matrix)",
],
},
{
"version": "0.7.3",
"date": "2026-04-27",
"changes": [
"DB 026: maturity_model_context_bindings (Fokus / Stilrichtung / Trainingsstil)",
"API: resolve merged mehrere Modelle; CRUD Bindings; training_type_id Query",
"Admin-Tab Kontext-Zuordnung",
],
},
{
"version": "0.7.2",
"date": "2026-04-27",
"changes": [
"DB: Migration 025 maturity_model_focus_areas / _style_directions / _target_groups (M:N)",
"Bootstrap-Reifegradmodell für alle importierten Skills (Wiki), Stufen 15",
"API+UI: Kontext als Mehrfachauswahl; Matrix zeigt Haupt-/Untergruppe pro Fähigkeit",
],
},
{
"version": "0.7.1",
"date": "2026-04-27",
"changes": [
"DB: Migration 024 maturity_models, model_levels, model_skills, model_skill_levels",
"API: CRUD Reifegradmodelle, Matrix-Pflege, resolve-Kontext",
"Frontend: Admin Fähigkeitsmatrix (/admin/maturity-models)",
],
},
{
"version": "0.7.0",
"date": "2026-04-24",
"changes": [
"BREAKING: Exercises v2.0 - Clean-Room Rebuild (kein Legacy-Code)",
"DB: Migration 014 - Variant Progression + Search Vector + Legacy DROP (age_groups, focus_area, secondary_areas, training_character)",
"DB: Migration 016 - Saved Exercise Searches",
"DB: Migration 017 - Exercise Blocks + Template Blocks",
"Backend: exercises.py komplett neu nach EXERCISES_API_SPEC.md v1.2",
"Backend: Nur M:N Relations, keine JSONB-Kataloge mehr",
"Backend: enrich_exercise_detail() für vollständige Objekte",
"Backend: assign_exercise_relations() für M:N Management",
"API: GET /exercises - Volltext-Suche via tsvector",
"API: POST/PUT /exercises - M:N Relations (focus_areas_multi, training_styles_multi, etc.)",
"Issue #53 konform: Import = Feld-Zuordnung, keine fachliche Interpretation",
]
},
{
"version": "0.6.0",
"date": "2026-04-24",
"changes": [
"Feature: MediaWiki Import (SMW Direct API)",
"DB: Migration 018 - wiki_import_log + wiki_import_references",
"Backend: SmwClient (login, browse, ask, categorymembers)",
"Backend: SmwMapper (SMW Properties → exercises/skills/methods)",
"Backend: import_wiki Router (preview, execute, status, logs, discover)",
"Config: MEDIAWIKI_API_URL=https://karatetrainer.net/api.php",
]
},
{
"version": "0.5.0",
"date": "2026-04-23",
"changes": [
"Feature: Trainer-Kontext-System für fokussierte Ansichten",
"DB: Migration 012 - exercise_training_characters (M:N)",
"DB: Migration 012 - trainer_contexts (Trainer-Profil-System)",
"Backend: CRUD API für Trainer-Kontexte (/api/trainer-contexts)",
"Frontend: TrainerContextsPage für Verwaltung eigener Arbeitsbereiche",
"Architektur: Flat Catalogs + Smart Filtering für 1000+ Übungen",
"Architektur: NULL = 'für alles geeignet', M:N = spezifische Zuordnung",
]
},
{
"version": "0.4.0",
"date": "2026-04-23",
"changes": [
"BREAKING: Migration 010 - Umbenennung training_styles → style_directions",
"BREAKING: Migration 011 - Neue Dimension training_types (Breitensport/Leistungssport)",
"DB: Konsistente Terminologie - Stilrichtungen vs. Trainingsstile",
"DB: Neue Tabelle training_types mit Seed-Daten (Breitensport, Leistungssport, Wettkampf)",
"DB: Neue Junction-Tabelle exercise_training_types (M:N)",
"Architektur: Fokusbereich → Stilrichtung → Trainingsstil → Zielgruppe (alle M:N)",
"Backend: Alle SQL Queries aktualisiert auf neue Tabellennamen (style_directions, style_direction_target_groups)",
"Backend: API Parameter umbenannt (training_style_id → style_direction_id)",
"Backend: CRUD Endpoints für training_types hinzugefügt",
]
},
{
"version": "0.3.4",
"date": "2026-04-23",
"changes": [
"BREAKING: Migration 009 - Zielgruppen M:N Refactoring",
"DB: target_groups.training_style_id entfernt (jetzt global unabhängig)",
"DB: Neue Junction-Tabelle training_style_target_groups (M:N)",
"API: 5 neue Endpoints für M:N Management (GET/POST/PUT/DELETE + hierarchy)",
"API: GET /training-style-target-groups mit Enrichment (focus_area_name, training_style_name)",
"API: GET /training-styles/hierarchy für Tree-View (verschachtelte Struktur)",
"API: POST /training-style-target-groups mit Upsert-Logik",
"Backward-Compatible: exercise_target_groups weiterhin unterstützt",
"Architecture: Eine Zielgruppe kann mehreren Stilen zugeordnet werden",
]
},
{
"version": "0.3.3",
"date": "2026-04-23",
"changes": [
"Fix: Admin-Navigation - Redirect /admin → /admin/catalogs",
"Fix: Admin-Link funktioniert jetzt (vorher 404)"
]
},
{
"version": "0.3.2",
"date": "2026-04-23",
"changes": [
"Feature: Zielgruppen-Verwaltung komplett (Backend + Frontend)",
"API: GET/POST/PUT/DELETE /target-groups mit hierarchischem Kontext (focus_area → training_style → target_group)",
"Admin UI: Neuer Tab 'Zielgruppen' in Katalogverwaltung",
"UX: Create/Edit-Forms mit Training-Stil-Auswahl, Altersbereich (min/max)",
"UX: Hierarchie-Anzeige in Liste (Fokusbereich → Stil → Zielgruppe)",
"Protection: DELETE mit CASCADE-Schutz (Fehler wenn Übungen zugeordnet)",
]
},
{
"version": "0.3.1",
"date": "2026-04-23",
"changes": [
"Feature: Exercises-Router unterstützt M:N Zuordnungen",
"API: GET /exercises/{id} liefert focus_areas[], training_styles[], target_groups[], age_groups_catalog[]",
"API: POST/PUT /exercises akzeptiert focus_areas_multi[], training_styles_multi[], target_groups_multi[], age_groups_catalog[]",
"Pattern: DELETE+INSERT für M:N Updates (konsistent mit skills)",
"Backward-Compatible: Legacy FK-Felder (focus_area_id, training_style_id) bleiben erhalten",
]
},
{
"version": "0.3.0",
"date": "2026-04-23",
"changes": [
"BREAKING: M:N Beziehungen für Übungen (statt 1:1)",
"Migration 008: M:N Zuordnungstabellen (exercise_focus_areas, exercise_styles, exercise_target_groups, exercise_age_groups)",
"Feature: Hierarchische Katalog-Struktur (Fokusbereich → Stil → Zielgruppe)",
"Feature: Zielgruppen-Verwaltung (training_styles.focus_area_id Hierarchie)",
"Feature: Primary/Secondary Assignments (is_primary Flag)",
"Doku: DATABASE_SCHEMA.md + DOMAIN_MODEL.md kontinuierlich gepflegt",
"Architecture: Smart Cascade-Logik (RESTRICT, Rerouting, Move)",
]
},
{
"version": "0.2.0",
"date": "2026-04-23",
"changes": [
"Feature: Admin-verwaltbare Kataloge (Focus Areas, Training Styles, Training Characters, Skill Categories)",
"Feature: Trainer-Fokusbereich-Zuordnung für rollenbasierte Filterung",
"Migration 007: Katalog-Tabellen + Seed-Daten",
"Frontend: AdminCatalogsPage mit 5 Tabs (CRUD für alle Kataloge)",
"Frontend: ExercisesPage nutzt Katalog-Dropdowns (kein Hard-Coding mehr)",
"Frontend: Trainingsstil-Dropdown hinzugefügt (fehlte komplett)",
"Standardisierung: Alle Formulare mit Labels oben, volle Breite, linksbündig",
]
},
{
"version": "0.1.0",
"date": "2026-04-21",
"changes": [
"Initial MVP Setup",
"Feature: Übungsverwaltung (Kern-Modul)",
"Feature: Fähigkeiten- und Methodenkataloge",
"Feature: Trainingsplanung für Gruppen",
"Feature: Trainingsabschnitte mit Kombinations-Flag",
"Feature: MediaWiki-Import (einseitig)",
"Feature: Freigabelogik (privat/Verein/offiziell)",
"Infrastructure: Auth + Membership von Mitai übernommen",
]
}
]