# Shinkan Jinkendo Version Information APP_VERSION = "0.8.41" BUILD_DATE = "2026-05-07" DB_SCHEMA_VERSION = "20260507045" MODULE_VERSIONS = { "auth": "1.2.1", # Login-Rate-Limit 30/minute pro IP (vorher 5/minute) "profiles": "1.7.0", # exercise_list_prefs JSONB (Standard Übungsfilter); Patch via ProfileUpdate + Json() "tenant_context": "1.0.4", # pytest: Unit test_access_layer.py + optional Integration test_access_layer_integration (PostgreSQL) "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) "groups": "0.1.0", "skills": "0.1.0", "methods": "0.1.0", "exercises": "2.11.0", # media_assets + Dedupe-Upload; effektives MEDIA_ROOT aus platform_media_storage "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.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 (basis–optimierung), model_levels Namen 1–5", "Ü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 1–5", "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", ] } ]