shinkan-jinkendo/.claude/docs/technical/MEDIA_ASSETS_AND_ARCHIVE_SPEC.md
Lars 7284c577d7
All checks were successful
Deploy Development / deploy (push) Successful in 35s
Test Suite / pytest-backend (push) Successful in 24s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 6s
Test Suite / playwright-tests (push) Successful in 27s
feat: enhance media management and governance in the project
- Added new documentation for media assets and lifecycle management, establishing a single source of truth in MEDIA_ASSETS_AND_ARCHIVE_SPEC.md.
- Updated project status to reflect the addition of media archive and lifecycle governance.
- Introduced a new API endpoint for platform media storage, allowing superadmin access for media management.
- Enhanced exercise media handling with improved database integration for media assets, including deduplication and effective media root resolution.
- Updated frontend API utilities to support new media storage functionalities, ensuring seamless integration with the backend.
- Incremented version to 0.8.41, reflecting the latest changes and improvements in media handling.
2026-05-07 12:36:46 +02:00

13 KiB
Raw Blame History

Medien-Assets, Archiv & Lebenszyklus (Single Source of Truth)

Status: verbindlich für Design, API und DB-Migrationen zum Thema Medien
Stand: 2026-05-07
ersetzt/ergänzt: operatives Upload-Format/Größen siehe weiterhin MEDIA_UPLOAD_SPEC.md
normative Governance: Sichtbarkeit & Mandanten wie ACCESS_LAYER_AND_GOVERNANCE_PLAN.md; bei Abweichung zwischen Dokumenten hat der Zugriffsplan Vorrang, außer dieses Dokument präzisiert explizit nur den Medien-Domain.


1. Zweck und Abgrenzung

1.1 Zweck

  • Ein physisches Medium („Datei-Asset“) wird einmal gespeichert und mehrfach mit Übungen verknüpft (Wiederverwendung, keine Dubletten auf der Platte).
  • Sichtbarkeit von Datei-Assets folgt derselben Semantik wie bei Übungen (private | club | official ggf. spätere Enum-Erweiterungen nur gemeinsam mit Migration + ACCESS_LAYER-Doku).
  • Superadmin kann Medien global freigeben (fachlich: Stufe wie „offiziell“ / plattformweit lesbar gemäß library_content_*-Regeln).
  • Copyright: pro Asset sind Vermerke vorgesehen und an official / Vereinsnutzung anzubinden (Validierungsstufen in Umsetzung festlegen).
  • Externer Speicher: Speicherung darf lokal/NAS (Filesystem) oder extern (z.B. S3-kompatibler Dienst) erfolgen die App arbeitet über eine Speicher-Abstraktion (Interface), nicht mit verstreuten Path-Annahmen.
  • Papierkorb & Retention: mehrstufiger Lebenszyklus mit automatischen und manuellen Übergängen, siehe §5.

1.2 Abgrenzung

  • Embeds (reine externe URL, kein Upload) bleiben pro Verknüpfung zur Übung möglich (embed_url o. Ä.); sie haben keinen physischen Lebenszyklus wie Datei-Assets (kein Papierkorb „Stufe 3 physische Löschung“). Trotzdem: UI kann „Link ungültig“ o. Ä. separat abbilden.
  • Übungs-Governance (wer eine Übung bearbeiten darf) bleibt maßgeblich für Anlegen/Entfernen/Umsortieren von Medien in dieser Übung; Medien erzwingen keine schärfere Edit-Policy als die Übung selbst.

2. Begriffe

Begriff Bedeutung
Media Asset Logische Entität für eine hochgeladene Datei inkl. Metadaten, Sichtbarkeit, Copyright, Speicherreferenz, Lifecycle-Status.
Übungs-Medium / Attachment Verknüpfung Übung ↔ Asset oder reines Embed; enthält u.a. context (Sektion), sort_order, übungsspezifischen Titel/Beschreibung, is_primary.
Medienmanager / Archiv Verwaltungs-UI/API für Assets (Suche, Metadaten, Lifecycle, ggf. Superadmin-global).

3. Zieldatenmodell (Überblick)

Konkrete Tabellennamen/Migrationen beim Implementierungsstart festziehen; dieses Kapitel ist die fachliche Norm.

3.1 Tabelle media_assets (oder gleichwertiger Name)

Pflichtidee:

  • Identität, technische Metadaten: id, mime_type, byte_size, sha256 (vollständig), original_filename, created_at, updated_at.
  • Mandant & Governance: visibility, club_id (nullable je nach Semantik wie bei Übungen), uploaded_by_profile_id.
  • Copyright: mindestens copyright_notice (TEXT); optional license, attribution, source_url.
  • Speicher: storage_backend (Enum/String: z.B. local, s3, …), storage_key (relativer oder bucket-key), optional storage_url nur für interne Zwecke keine öffentlichen Secrets in der DB.
  • Lifecycle: lifecycle_state (siehe §5), Timestamps für Übergänge und geplante Purge-Termine.

Deduplizierung: Innerhalb sinnvoller Grenze (z.B. pro Verein bei club, global nur mit Superadmin-Policy) über sha256 + club_id/visibility; Konflikt bei Upload → bestehendes Asset verknüpfen oder expliziter Nutzerdialog (Umsetzungsdetail).

3.2 Verknüpfung (heute exercise_media)

  • Erweiterung um media_asset_id (FK, nullable wenn reines Embed).
  • Embed-Zeilen: media_asset_id IS NULL, embed_url/embed_platform gesetzt wie heute.
  • Übungsspezifische Felder: context (ablauf | detail | trainer_hint), sort_order, title, description, is_primary.

3.3 Referenzen & physisches Löschen

  • Vor physischem Löschen muss die Referenzanzahl aller aktiven/nicht-purged Links 0 sein (oder Quarantäne-Policy); siehe §5.3.

4. Sichtbarkeit, Lesen und Übungs-Promotion

4.1 Leseregel Datei-Asset

  • Zentrale Entscheidung analog library_content_visible_to_profile / TenantContext: Profil darf Asset lesen nur wenn Visibility+club_id+created_by zum Objekt passen (gleiche Philosophie wie Übungen).
  • GET Download / Stream: muss Asset-Governance prüfen; wenn der Aufruf im Kontext einer Übung erfolgt, zusätzlich (oder als Schnittmenge) Übung lesbar verbindlich ohne Seitenkanal (kein Download nur mit Übungs-ID, wenn Asset für Nutzer unsichtbar wäre).

4.2 Promotion Übung → official (bzw. global)

Beim Speichern/Promoten einer Übung auf official (oder vergleichbare globale Stufe):

  1. Pflicht-Dialog: Hinweis, dass alle zugeordneten Datei-Assets, die noch nicht diese Sichtbarkeit haben, mit angehoben werden (oder die Aktion schlägt fehl / erfordert Anpassung).
  2. Abbruch: Nutzer kann abbrechen oder einzelne Assets vor Freigabe anpassen / entkoppeln.
  3. Copyright: Für official sind leere oder unzureichende Copyright-Felder nicht akzeptabel (genaue Regel in Umsetzung + Validierung).

Superadmin kann Medien explizit global/offiziell machen (Archiv-Pfad), unabhängig von einer einzelnen Übung konsistent zur Rolle.

4.3 Bearbeitung Medien in der Übung

Wer die Übung bearbeiten darf (bestehende oder künftig erweiterte Regel), darf für diese Übung:

  • Medien hinzufügen (Upload neu oder Verknüpfung aus Archiv),
  • Reihenfolge / Sektion / Titel ändern,
  • Verknüpfung entfernen (Asset bleibt im Archiv, sofern nicht anderweitig gelöscht),
  • Embeds pflegen.

Das widerspricht nicht dem Papierkorb: wer kein Recht hat, ein Asset global zu Trash/ Purge zu bewegen, darf trotzdem die Verknüpfung in „seiner“ Übung lösen, solange die Übungs-Edit-Policy das erlaubt.


5. Lebenszyklus (Papierkorb) Norm

5.1 Zustände

Zustand Code (Beispiel) Neue Zuordnung zu Übungen Anzeige in Übung (Lesemodus) Anzeige Bearbeiten
Aktiv active ja normal normal
Stufe 1 Papierkorb trash_soft nein ja + Warnhinweis („wird abgeschafft“) ja + Warnhinweis
Stufe 2 Ausblendung trash_hidden nein nein (Platzhalter/„nicht verfügbar“) Recovery-Aktion sichtbar
Stufe 3 purgiert purged / Zeile entfernt nein nein nur noch historischer Hinweis nach Policy

Default-Retention (automatisch):

  • Stufe 1 → Stufe 2: ca. 30 Tage nach Eintritt in Stufe 1 (konfigurierbar).
  • Stufe 2 → Stufe 3 physisches Löschen: ca. 90 Tage (3 Monate) nach Eintritt in Stufe 2 (konfigurierbar).

Manuell: Berechtigte Rollen dürfen Übergänge vorziehen (Stufe 1 erzwingen, Stufe 2 erzwingen, Purge erzwingen) gemäß §5.2 ggf. Tier-Gates (§6).

5.2 Wer darf Lifecycle-Transitionen?

Aktion Vereins-Asset (club, Owner-Verein) Privates Asset (private, Uploader) official / plattformweit
Stufe 1 (Papierkorb) Vereinsadmin + Superadmin Uploader + Superadmin Superadmin
Stufe 2 vorziehen / erzwingen Vereinsadmin + Superadmin Uploader + Superadmin Superadmin
Recovery Stufe 2 → 1 wie Stufe 1-Eintritt, ggf. Tier wie links Superadmin
Physisches Löschen (3) Vereinsadmin + Superadmin; Systemjob nach Frist Uploader + Superadmin Superadmin

Superadmin / Systemadmin ist immer Override (Klarstellung zur „systemadmin“-Formulierung).

5.3 Konsistenz mit bestehenden Übungen

  • In Stufe 1 bleiben Verknüpfungen funktional für Anzeige bestehen; Nutzer sehen Warnung.
  • In Stufe 2 wird das Medium in der öffentlichen Übungsansicht nicht gerendert; im Bearbeitungsmodus gibt es einen Recovery-Link, der das Asset zurück auf Stufe 1 setzt (Policy: nur wer nach §5.2 Stufe 1 setzen darf, oder erweiterte Regel bei Konflikt ACCESS_LAYER + dieses Dokument anpassen).
  • Physisches Löschen: nur nach Stufe 2-Frist oder manueller Purge-Aktion; Backend entfernt Datei über Speicher-Backend und markiert Asset endgültig.

5.4 Hintergrundjobs

  • Geplanter Job (täglich o. Ä.): Transitionen 1→2 und 2→3 gemäß Timestamps.
  • Alle Zeiten konfigurierbar (Umgebungsvariablen oder DB-Config), Defaults wie §5.1.

6. Tier & Features

  • Tier kann erlauben oder verbieten: manuelles Vorziehen von Stufe 2 oder Purge, zusätzliche Speicherquoten, externes Backend, etc.
  • Tier ändert nicht die Übungs-Sichtbarkeit an sich; es limitiert nur Medien-spezifische Aktionen (Löschstufen, Archiv-Größe, …). Konkrete Feature-Keys in Umsetzung in features / tier_limits ergänzen und hier im Changelog dieses Dokuments verlinken.

7. Externe Speicherung (Server / S3)

  • Abstraktion StorageAdapter: put, get, delete, ggf. exists.
  • Konfiguration über ENV (z.B. Endpoint, Bucket, Credentials) nie im Frontend.
  • NAS / anderer Rechner als App-Host: In der Praxis MEDIA_ROOT in Compose/ENV auf den Mount-Punkt des NAS (oder NFS/SMB) setzen die App läuft z.B. auf dem Raspberry, die Bytes liegen auf dem Speichersystem. Kein »Mediaserver« mit eigener Geschäftslogik nötig.
  • Pfadkonvention auf der Platte z.B. clubs/{club_id}/… für Mandantentrennung (Umsetzung schrittweise; neue Uploads können zuerst unter exercises/{sha256}{ext} liegen).

7.1 Konfiguration: Bootstrap vs. Superadmin (Laufzeit)

Ebene Inhalt Wer / Wo
Bootstrap Basis-Verzeichnis MEDIA_ROOT (Container/Host), ggf. S3-Secrets Deployment (.env, Docker Compose) Container muss ohne UI starten können
Laufzeit (nicht-geheim) Zusätzlicher relativer Unterpfad unter MEDIA_ROOT (local_relative_root), später: aktives Backend local | s3, öffentlicher Endpoint/Bucket-Name Superadmin über Tabelle platform_media_storage + API; keine Secrets für S3 im Klartext in der DB (Keys nur ENV/Vault)
Effektives Wurzelverzeichnis Path(MEDIA_ROOT) / local_relative_root nach Normalisierung (kein .., kein absoluter Pfad im relativen Segment) berechnet im Backend bei jedem Zugriff

Hinweis Beta: Primär ein Verein, Videos auf separatem physischen System → typischerweise ein NAS-Mount als MEDIA_ROOT; Superadmin kann bei Bedarf einen Unterordner setzen, ohne neues Image zu bauen.

Drift: Jede Änderung an Speicher-Konfiguration oder Asset-Schema → Migration + Eintrag §10 Changelog + bei neuen Endpoints ACCESS_LAYER_ENDPOINT_AUDIT.md.


8. Embeds & Streaming-Plattformen

  • Embeds bleiben erste Klasse; bestehende Plattform-Erkennung erweiterbar (embed_platform).
  • Roadmap: weitere Hosts (Player-Komponente, oEmbed, CSP) ohne Änderung am Asset-Lifecycle-Modell.

9. Pflichten zur Drift-Vermeidung

Änderung an … Pflegepflicht
DB-Schema Medien Neue Migration + Abschnitt/Changelog in diesem Dokument (Datum, Kurzbeschreibung)
Sichtbarkeit / Enums Zuerst ACCESS_LAYER_AND_GOVERNANCE_PLAN.md, dann dieses Dokument synchron halten
Neue Endpoints Medien/Archiv ACCESS_LAYER_ENDPOINT_AUDIT.md + get_tenant_context/Governance
Implementierungs-Meilenstein backend/version.py (MODULE_VERSIONS / Schema-Kommentar) und bei größerem Release PROJECT_STATUS.md

10. Changelog

Datum Änderung
2026-05-07 Erstfassung als Single Source of Truth (verbindlich); Abstimmung mit Stakeholder: Promotion Übung↔Medien, Copyright, Papierkorb 3-stufig, externe Speicher, Embeds getrennt vom Asset-Lifecycle.
2026-05-07 §7.1 Konfiguration Bootstrap vs. Superadmin (platform_media_storage), NAS/Mount-Hinweis, Drift-Regel. Umsetzung Start: DB media_assets, FK exercise_media.media_asset_id, API Speichereinstellungen Superadmin.

11. Referenzen

  • .claude/docs/technical/ACCESS_LAYER_AND_GOVERNANCE_PLAN.md
  • .claude/docs/technical/MEDIA_UPLOAD_SPEC.md (Limits, MIME, Embed-Typen im aktuellen Backend)
  • .claude/docs/working/ACCESS_LAYER_ENDPOINT_AUDIT.md
  • backend/routers/exercises.py Ist-Zustand exercise_media bis Refactor