diff --git a/docs/compliance-implementation.md b/docs/compliance-implementation.md index e1ea070..4ea8f67 100644 --- a/docs/compliance-implementation.md +++ b/docs/compliance-implementation.md @@ -383,7 +383,7 @@ Anmerkung jsPDF (0.8.74): |-------|------------------|--------|------------| | P-01 | Rechtstexte | offen | Scope ausgeschlossen (juristischer Inhalt) | | P-02 | Self-Service-Kontolöschung + Datenexport | offen | Scope ausgeschlossen | -| P-06 | Upload-Einwilligungsdialog (Recht am eigenen Bild) | offen | Scope ausgeschlossen | +| P-06 | Upload-Einwilligungsdialog (Recht am eigenen Bild) | offen | Scope ausgeschlossen — Spezifikation erstellt (2026-05-10): `docs/p06-upload-rights-spec.md`; keine Code-Umsetzung | | P-08 | HSTS / externe Proxy-Sicherheit dokumentieren | offen | Scope ausgeschlossen (außerhalb Repo — Reverse-Proxy) | | P-09 | Admin-Audit-Log | offen | Scope ausgeschlossen | | P-10 | Mindestalter-Abfrage | offen | Scope ausgeschlossen | diff --git a/docs/compliance-package-register.md b/docs/compliance-package-register.md index 47d01b7..5d5c66c 100644 --- a/docs/compliance-package-register.md +++ b/docs/compliance-package-register.md @@ -124,8 +124,8 @@ | **Findings** | KRIT-04 | | **Etappe** | 1 | | **Status** | ❌ open | -| **Letzter Stand** | Nicht umgesetzt. Keine Pflicht-Einwilligung beim Medienupload. Juristisch zu prüfen (§22 KUG, §8 DSGVO). | -| **Verweise** | `docs/compliance-audit.md` §8.2, §8.3, §11.4, §17 | +| **Letzter Stand** | Nicht umgesetzt. Keine Pflicht-Einwilligung beim Medienupload. Juristisch zu prüfen (§22 KUG, §8 DSGVO). **Fachlich-technische Spezifikation erstellt (2026-05-10):** `docs/p06-upload-rights-spec.md` — Zielmodell: neue Tabelle `media_asset_rights_declarations` (append-only Einwilligungslog) + 3 neue Felder in `media_assets` (`rights_status`, `rights_declared_for_visibility`, `rights_declared_at`); abgestufte Einwilligungslogik nach Sichtbarkeit (upload/club/official); Legacy-Konzept für bestehende Medien (`rights_status = 'legacy_unreviewed'`); Umsetzungsplan P-06a–P-06e. Umsetzung erst nach Entscheidung über 12 juristische Klärungspunkte (§22 KUG, §8 DSGVO, Minderjährigenschutz, Widerrufsrecht) — vollständige Liste in `docs/p06-upload-rights-spec.md` §7. | +| **Verweise** | `docs/compliance-audit.md` §8.2, §8.3, §11.4, §17; `docs/p06-upload-rights-spec.md` | | **Hinweise** | **Drift-Hinweis:** In `docs/compliance-implementation.md` (vor Korrektur 2026-05-10) wurde P-06 fälschlich als „HSTS-Header" beschrieben. Der korrekte Titel ist „Upload-Einwilligungsdialog". HSTS gehört zu P-08. Korrigiert in `docs/compliance-implementation.md`. | --- diff --git a/docs/compliance-roadmap.md b/docs/compliance-roadmap.md index 8cae22f..c8225d5 100644 --- a/docs/compliance-roadmap.md +++ b/docs/compliance-roadmap.md @@ -99,7 +99,9 @@ Die folgenden Pakete sind vor der Freigabe für allgemeine öffentliche Registri **Finding:** KRIT-04 (§22 KUG, §8 DSGVO) **Warum zwingend:** Jeder hochgeladene Bildinhalt mit erkennbaren Personen ist ohne dokumentierte Einwilligung rechtlich problematisch. Das Risiko besteht nicht erst bei öffentlichen Inhalten — es beginnt beim Upload. -**Abhängigkeit:** Keine; kann als Frontend-Dialog mit Backend-Flag implementiert werden. +**Abhängigkeit:** Keine; kann als Frontend-Dialog mit Backend-Flag implementiert werden. +**Spezifikation:** Fachlich-technische Spezifikation erstellt (2026-05-10): `docs/p06-upload-rights-spec.md`. Enthält IST-Analyse, Entscheidungsmatrix, Zielmodell (neue Tabelle `media_asset_rights_declarations` + 3 neue Felder in `media_assets`), 10 Ziel-Flows, Legacy-Konzept für bestehende Medien, Umsetzungsplan P-06a–P-06e. +**Vor Umsetzung zu klären (12 Punkte):** §22-KUG-Anforderungen im Vereinskontext, Minderjährigenschutz, Einwilligungs-Widerrufsrecht, Speicherfristen — vollständige Klärungsliste in `docs/p06-upload-rights-spec.md` §7. ### Blocker 3 — P-11: Legal-Hold Lifecycle-Status @@ -225,11 +227,13 @@ Erst wenn diese Fragen beantwortet und als Spec dokumentiert sind, wird P-02 in **P-01 + P-01b + P-01c technisch vollständig umgesetzt (Version 0.8.74).** Rechtstexte über Login, Desktop-Sidebar und Einstellungen → Rechtliches (Mobile/PWA) erreichbar. Superadmin kann über `/admin/legal-documents` versionierte Rechtstexte anlegen, bearbeiten (inkl. Abschnitts-Sortierung und Einfügen an beliebiger Stelle), als Entwurf kopieren, veröffentlichen und als PDF herunterladen — sobald Inhalte eingepflegt sind, verschwindet der Platzhalter-Banner automatisch. Juristische Inhalte bleiben offen (Betreiber + Rechtsanwalt). -Die nächste technische Freigabe sollte **Etappe B** umfassen — beginnend mit dem kleinsten Paket: +Die nächste technische Freigabe sollte **Etappe B** umfassen — beginnend mit P-06: + +**P-06 Spezifikation vorhanden** (`docs/p06-upload-rights-spec.md`, 2026-05-10). Die Umsetzung setzt die Entscheidung über 12 juristische Klärungspunkte voraus (§22 KUG im Vereinskontext, §8 DSGVO Minderjährigenschutz, Widerrufsrecht, Speicherfristen für Einwilligungen). Erst nach dieser Klärung: > „Freigabe zur Umsetzung P-06: Upload-Einwilligungsdialog" -oder als Paket: +oder als Paket (nach Klärung P-06): > „Freigabe zur Umsetzung Etappe B: P-06, P-11, P-13" @@ -353,7 +357,7 @@ Diese Punkte liegen außerhalb des Code-Scopes und erfordern organisatorische Ma | ~~P-01 technisch~~ | ~~„Freigabe zur Umsetzung P-01: Rechtstexte technisch anlegen"~~ | ✅ historisch abgeschlossen (Version 0.8.69) | | ~~P-01b~~ | ~~„Freigabe zur Umsetzung P-01b: Mobile/PWA-Zugriff auf Rechtliches"~~ | ✅ historisch abgeschlossen (Version 0.8.70) | | ~~P-01c~~ | ~~„Freigabe zur Umsetzung P-01c: Admin-konfigurierbare Rechtstexte"~~ | ✅ historisch abgeschlossen (Version 0.8.71); Erweiterungen copy-as-draft (0.8.72) + jsPDF/Sortierung (0.8.74) | -| **P-06 (empfohlen)** | **„Freigabe zur Umsetzung P-06: Upload-Einwilligungsdialog"** | ⬅ nächste empfohlene Freigabe | +| **P-06 (empfohlen)** | **„Freigabe zur Umsetzung P-06: Upload-Einwilligungsdialog"** | ⬅ nächste empfohlene Freigabe — Spec vorhanden (`docs/p06-upload-rights-spec.md`); Umsetzung erst nach juristischer Klärung (§7 der Spec) | | Etappe B komplett | „Freigabe zur Umsetzung Etappe B: P-06, P-11, P-13" | offen | | P-02 Spezifikation | „Freigabe zur Spezifikation P-02: DSGVO-Self-Service-Prozess" | offen | diff --git a/docs/p06-upload-rights-spec.md b/docs/p06-upload-rights-spec.md new file mode 100644 index 0000000..fddb8c2 --- /dev/null +++ b/docs/p06-upload-rights-spec.md @@ -0,0 +1,720 @@ +# P-06 – Fachlich-technische Spezifikation: Upload-Einwilligungsdialog + +**Paket-ID:** P-06 (kanonisch, unveränderlich) +**Kanonischer Titel:** Upload-Einwilligungsdialog (Recht am eigenen Bild, Personen, Minderjährige) +**Dokument-Typ:** Spezifikation — keine Umsetzungsfreigabe +**Erstellt:** 2026-05-10 +**App-Version bei Erstellung:** 0.8.74 +**Status P-06:** ❌ offen — Umsetzung erst nach Entscheidung zu offenen juristischen Punkten +**Rechtlicher Hinweis:** Alle als „juristisch zu prüfen" markierten Einschätzungen sind keine Rechtsberatung. Keine konkrete Textfassung von Erklärungen in diesem Dokument — Formulierungen obliegen dem Rechtsanwalt. + +--- + +## 1. Kontext und Ziel + +### 1.1 Ausgangslage (Initial-Audit-Befund) + +Das Initial-Audit (`docs/compliance-audit.md`, §8.2–8.3) identifiziert folgende Lücken: + +- Keine verbindliche Rechteerklärung beim Medienupload +- Keine Abfrage, ob erkennbare Personen enthalten sind +- Keine Abfrage, ob Minderjährige abgebildet sind +- Keine Abfrage, ob erforderliche Einwilligungen abgebildeter Personen vorliegen +- Keine Dokumentation, wer wann welche Erklärung abgegeben hat + +### 1.2 Regulatorische Prüfanker (technische Modellierung) + +| Norm | Relevanz für Datenmodell | Juristisch zu prüfen | +|------|--------------------------|----------------------| +| § 22 KUG | Bildnisse erkennbarer Personen erfordern Einwilligung vor Verbreitung/Zurschaustellung | Gilt auch für vereinsinterne Sichtbarkeit? | +| Art. 8 DSGVO | Bei Minderjährigen ggf. Einwilligung Erziehungsberechtigter | Ab welchem Alter? Welche Mechanismen? | +| § 19a UrhG | Öffentliche Zugänglichmachung = eigener Nutzungstatbestand | Ab wann gilt `official` als „öffentlich zugänglich"? | +| DSGVO Art. 5(1)(e) | Datenminimierung — welche Nachweisdaten dürfen gespeichert werden? | Was ist verhältnismäßig? | + +### 1.3 Ziel dieser Spezifikation + +P-06 soll sicherstellen, dass: + +1. Jeder Medien-Upload mit einer strukturierten, gespeicherten Rechteerklärung verknüpft ist +2. Die Erklärung nach Sichtbarkeitsstufe gestuft wird (private minimal, official vollständig) +3. Bestehende Prüfungen aus P-04 (copyright_notice) komplementär erhalten bleiben +4. Juristische Textanpassungen ohne Codeänderungen möglich sind (Versionierung) +5. Altmedien ohne rückwirkenden Zwang behandelt werden können +6. Backend-Erzwingung (keine reine Frontend-Kosmetik) besteht + +--- + +## 2. IST-Analyse + +### 2.1 Upload-Pfade (vollständige Bestandsaufnahme) + +| # | Endpoint | Datei | Upload-Typ | Sichtbarkeit wählbar | Copyright bei Upload | +|---|----------|-------|-----------|---------------------|----------------------| +| U1 | `POST /api/exercises/{id}/media` | `routers/exercises.py:2518` | Einzeldatei oder Embed-URL | Folgt Übungssichtbarkeit (implizit) | Nicht abgefragt | +| U2 | `POST /api/media-assets/bulk-upload` | `routers/media_assets.py:787` | 1–n Dateien | `visibility` + `club_id` als Form-Parameter | Optional (`copyright_notice` fehlt im POST-Body, nur via PATCH nachträglich) | + +**Kein weiterer Upload-Endpoint vorhanden** (geprüft über Codebase-Suche nach `UploadFile`). + +**Weitere indirekte Upload-Pfade:** +- `POST /api/exercises/{id}/media/from-asset` (`exercises.py`) — verknüpft ein bestehendes Archiv-Asset mit einer Übung; kein Upload, kein neues Medium +- Embed-URL (`embed_url`, `embed_platform`) — keine Datei, keine Rechteerklärung für Dateiinhalte; externe Plattform verantwortlich + +### 2.2 Promotionspfade (Sichtbarkeitsänderung) + +| # | Endpoint | Datei | Mögliche Promotion | +|---|----------|-------|--------------------| +| PR1 | `PATCH /api/media-assets/{id}` | `routers/media_assets.py:1223` | private→club, private→official, club→official, auch Rückstufung | +| PR2 | `POST /api/media-assets/bulk-patch` | `routers/media_assets.py:1094` | Massenpromotion, gleiche Richtungen | +| PR3 | Implizit bei `PUT /api/exercises/{id}` | `routers/exercises.py` | Übungssichtbarkeit→club/official löst `apply_official_exercise_media_rules()` oder `apply_club_exercise_media_copyright_rules()` aus | + +**Rückstufungen** (official→club, club→private) werden nicht gesperrt — juristisch zu prüfen, ob Rückstufung Rechte-Konsequenzen hat. + +### 2.3 Datenmodell `media_assets` (Migration 045 + 046) + +``` +media_assets +├── id SERIAL PK +├── mime_type VARCHAR(100) +├── byte_size INT +├── sha256 CHAR(64) NOT NULL +├── original_filename VARCHAR(300) +├── visibility VARCHAR(32) NOT NULL DEFAULT 'private' ← Sichtbarkeitsstufe +├── club_id INT REFERENCES clubs(id) ← Vereinszuordnung +├── uploaded_by_profile_id INT REFERENCES profiles(id) ← Uploader +├── copyright_notice TEXT ← Urheberrechtshinweis (P-04) +├── storage_backend VARCHAR(32) +├── storage_key TEXT NOT NULL UNIQUE +├── lifecycle_state VARCHAR(32) DEFAULT 'active' +├── trash_soft_at, trash_hidden_at, purge_after_at TIMESTAMP +├── created_at, updated_at TIMESTAMP +└── tags TEXT[] DEFAULT '{}' +``` + +**Fehlende P-06-Felder:** Keine Einwilligungsfelder vorhanden. Keine Personenabbildungsmarkierung. Keine Deklarations-Versionierung. + +### 2.4 Rollen und Berechtigungen (Zusammenfassung `_item_permissions()`) + +| Aktion | private | club | official | +|--------|---------|------|----------| +| Upload (neu) | Jeder authentifizierte Nutzer | Vereinsmitglied + club_id | Nur Superadmin | +| `edit_metadata` | Superadmin, Plattform-Admin, Uploader | Superadmin, Plattform-Admin, Club-Admin | Nur Superadmin | +| Promotion zu club | Eigener Upload: Uploader; Club-Asset: Club-Admin | — | — | +| Promotion zu official | Nur Superadmin | Nur Superadmin | — | +| Lifecycle (trash) | Uploader, Plattform-Admin, Superadmin | Club-Admin, Plattform-Admin, Superadmin | Nur Superadmin | + +### 2.5 Bestehende Frontend-Dialoge + +| Stelle | Datei | Aktuelles Verhalten | +|--------|-------|---------------------| +| Übungsformular Medienupload | `ExerciseFormPage.jsx` | Datei-Picker, kein Einwilligungsdialog | +| Archiv Bulk-Upload | `MediaLibraryPage.jsx` | Datei-Picker + optional `copyright_notice` im Editmodal, kein Pflichtdialog | +| Übung → official (API-Error) | `ExerciseFormPage.jsx:624` | `window.prompt()` für copyright_notice nach 422-Fehler — reaktiv, kein proaktiver Dialog | +| Archiv PATCH Sichtbarkeit | `MediaLibraryPage.jsx` | Backend wirft 400 wenn copyright fehlt; Frontend-Feedback unklar | + +**Ergebnis:** Kein proaktiver strukturierter Einwilligungsdialog vorhanden. Alle Copyright-Abfragen sind reaktiv (nach API-Fehler) oder optional. + +### 2.6 Bestehende Copyright-Prüfungen P-04 (Referenz) + +P-04 erzwingt `copyright_notice` bei Promotion zu `club` oder `official`: +- `patch_media_asset()`: HTTP 400 wenn `copyright_notice` leer bei Ziel club/official +- `bulk_media_patch()`: Asset in `failed`-Liste wenn copyright fehlt +- `apply_official_exercise_media_rules()`: HTTP 422 `OFFICIAL_MEDIA_CONFIRM_REQUIRED` wenn Assets kein copyright +- Mindestlänge: 3 Zeichen (`_MIN_OFFICIAL_MEDIA_COPYRIGHT_LEN = 3`) + +**Verhältnis zu P-06:** P-04 (copyright_notice) = Attribution für Dritte (wer besitzt das Recht). P-06 = Selbsterklärung des Uploaders (habe ich das Recht, dieses Medium hochzuladen). Ergänzend, nicht konkurrierend. + +### 2.7 IST-Lücken (P-06-spezifisch) + +| Lücke | Schwere | +|-------|---------| +| Kein Pflichtfeld „Ich bin Rechteinhaber" beim Upload | Kritisch (Grundlage aller Uploads) | +| Keine Abfrage „erkennbare Personen enthalten?" | Hoch (§ 22 KUG-Risiko bei club/official) | +| Keine Abfrage „Minderjährige enthalten?" | Hoch (Art. 8 DSGVO, besonderer Schutz) | +| Keine Speicherung von Einwilligungszeitpunkt und -version | Hoch (Nachweisbarkeit) | +| Keine Erzwingung im Backend (nur Frontend-Checkbox wäre zu wenig) | Kritisch | +| Kein Einwilligungslog (wer hat wann welche Version bestätigt?) | Hoch | +| copyright_notice beim Erstupload nicht abgefragt | Mittel (P-04 fragt erst bei Promotion) | + +### 2.8 Altbestandsrisiken + +- Alle bestehenden `media_assets`-Zeilen haben keine Einwilligungsmetadaten +- Unbekannt, ob bei bestehenden Medien erkennbare Personen/Minderjährige abgebildet sind +- Medien mit `visibility=club` oder `visibility=official` existieren ohne dokumentierte Einwilligung +- Superadmin kann bestehende official-Medien weiter sehen/nutzen ohne Nachdeklaration +- Bei Neuzuweisung zu einer anderen Übung werden bestehende Medien ohne Prüfung verknüpft + +--- + +## 3. Entscheidungsmatrix + +Anforderungen nach **Sichtbarkeitsstufe** (Zeilen) × **Aktion** (Spalten). „Pflicht" = Backend-Sperre wenn fehlend. „Optional" = abfragen aber nicht erzwingen. + +| Aktion → | Erstupload | Promotion club | Promotion official | Metadaten-Edit | Reuse in neuer Übung | +|-----------|-----------|---------------|-------------------|---------------|---------------------| +| **private** | `rights_holder`: Pflicht; Personen-Fragen: optional | — | — | Keine P-06-Pflicht | Keine P-06-Pflicht | +| **club** | `rights_holder`: Pflicht; `contains_persons`: Pflicht; `person_consent`: Pflicht wenn Personen | `contains_persons` + `person_consent`: Pflicht; `contains_minors`: Pflicht | — | Keine P-06-Pflicht | Keine P-06-Pflicht | +| **official** | Alles Pflicht | Alles Pflicht | Alle Felder Pflicht + copyright_notice (P-04) | Keine P-06-Pflicht | Keine P-06-Pflicht | + +**B: Medieninhalt — Konsequenzen:** + +| Inhalt | private | club | official | +|--------|---------|------|----------| +| Keine erkennbaren Personen | `person_consent` entfällt | `person_consent` entfällt | `person_consent` entfällt | +| Erkennbare Erwachsene | Optional zu deklarieren | Einwilligung Pflicht (juristisch zu prüfen) | Einwilligung Pflicht | +| Erkennbare Minderjährige | Optional zu deklarieren | Einwilligung Erziehungsberechtigter Pflicht (juristisch zu prüfen) | Einwilligung Pflicht | +| Unklar / nicht beantwortet | Zulässig bei private | Blockiert bei club/official | Blockiert | + +**C: Rechteinhalt — Konsequenzen:** + +| Inhalt | Konsequenz | +|--------|-----------| +| Nutzer ist selbst Urheber | `rights_holder_confirmed = true` genügt | +| Nutzer hat Nutzungsrechte | `rights_holder_confirmed = true` genügt; copyright_notice sollte Rechteinhaber nennen | +| Drittmaterial enthalten | `rights_holder_confirmed = true` nur wenn Lizenz vorhanden; copyright_notice Pflicht bei club/official | +| Musik enthalten | `contains_music = true`; `music_rights_confirmed` Pflicht (juristisch zu prüfen) | +| Logos/Marken/sonstige Fremdinhalte | Fällt unter `rights_holder_confirmed`; juristisch zu prüfen | + +**D: Aktion — Blockierungslogik:** + +| Aktion | Fehlendes Pflichtfeld | Verhalten Backend | +|--------|----------------------|-------------------| +| Upload | rights_holder_confirmed fehlt | HTTP 400 `RIGHTS_DECLARATION_REQUIRED` | +| Promotion club | contains_persons / person_consent fehlt | HTTP 400 `CONSENT_REQUIRED_FOR_CLUB` | +| Promotion official | Beliebiges Pflichtfeld fehlt | HTTP 400 `CONSENT_REQUIRED_FOR_OFFICIAL` | +| Promotion mit Altmedium (legacy) | rights_status = legacy_unreviewed | HTTP 400 `LEGACY_REDECLARATION_REQUIRED` | + +--- + +## 4. Empfohlenes Zielmodell + +### 4.1 Neue Tabelle: `media_asset_rights_declarations` + +Append-only Audit-Log. Jede Erklärung (Upload, Promotion, Nachdeklaration) erzeugt einen neuen Eintrag. Bestehende Einträge werden nie geändert. + +```sql +CREATE TABLE media_asset_rights_declarations ( + id SERIAL PRIMARY KEY, + media_asset_id INT NOT NULL REFERENCES media_assets(id) ON DELETE CASCADE, + declared_by_profile_id INT REFERENCES profiles(id) ON DELETE SET NULL, + declared_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + + -- Kontext + action_type VARCHAR(50) NOT NULL + CHECK (action_type IN ( + 'upload', -- Erstupload + 'promote_club', -- Promotion zu club + 'promote_official', -- Promotion zu official + 're_declaration', -- Nachdeklaration (auf Aufforderung) + 'legacy_re_declaration' -- Altmedium: erste Deklaration nachgereicht + )), + target_visibility VARCHAR(32) NOT NULL, -- Sichtbarkeit für die erklärt wird + declaration_version VARCHAR(20) NOT NULL DEFAULT 'p06-v1.0', -- Textversion der Erklärung + + -- Pflichtfeld (alle Sichtbarkeiten) + rights_holder_confirmed BOOLEAN NOT NULL, + + -- Personenrechte (Pflicht ab club) + contains_identifiable_persons BOOLEAN, + person_consent_confirmed BOOLEAN, -- Pflicht wenn contains_identifiable_persons = true + contains_minors BOOLEAN, + parental_consent_confirmed BOOLEAN, -- Pflicht wenn contains_minors = true (juristisch zu prüfen) + + -- Drittmaterial (optional MVP, Pflicht später) + contains_music BOOLEAN, + music_rights_confirmed BOOLEAN, + third_party_content_confirmed BOOLEAN, + + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() +); + +CREATE INDEX idx_mar_declarations_asset ON media_asset_rights_declarations (media_asset_id); +CREATE INDEX idx_mar_declarations_profile ON media_asset_rights_declarations (declared_by_profile_id); +``` + +### 4.2 Neue Felder in `media_assets` + +Drei neue Schnellzugriffs-Felder (kein Ersatz für den Log, nur für performante Abfragen): + +```sql +ALTER TABLE media_assets + ADD COLUMN rights_status VARCHAR(32) + NOT NULL DEFAULT 'legacy_unreviewed' + CHECK (rights_status IN ('pending', 'declared', 'legacy_unreviewed', 'blocked')), + ADD COLUMN rights_declared_for_visibility VARCHAR(32), -- Höchste Stufe, für die erklärt wurde + ADD COLUMN rights_declared_at TIMESTAMP WITH TIME ZONE; -- Zeitpunkt der aktuellsten Erklärung +``` + +**Status-Semantik:** + +| rights_status | Bedeutung | +|---------------|-----------| +| `legacy_unreviewed` | Bestehendes Medium ohne P-06-Daten — Altbestand | +| `pending` | Neues Medium, Upload noch ohne Deklaration (Zwischenzustand, darf nie persistent sein) | +| `declared` | Gültige Deklaration vorhanden für `rights_declared_for_visibility` | +| `blocked` | Deklaration widerrufen oder durch Admin gesperrt (→ P-11/P-13 Schnittstelle) | + +**Visibility-Hierarchie für Prüfung:** +``` +private (1) < club (2) < official (3) +``` + +Promotion ist erlaubt wenn: `rights_declared_for_visibility` ≥ Ziel-Visibility. Sonst ist neue Deklaration erforderlich. + +### 4.3 Feld-Bewertung: MVP vs. später + +| Feld | MVP-Pflicht | Sinnvoll später | Unnötig / zu früh | Juristisch abhängig | +|------|-------------|-----------------|-------------------|---------------------| +| `rights_holder_confirmed` | ✅ | — | — | Nein | +| `contains_identifiable_persons` | ✅ ab club | — | — | Nein | +| `person_consent_confirmed` | ✅ wenn Personen + ≥ club | — | — | Teilweise | +| `contains_minors` | ✅ ab official | ✅ auch club | — | Ja (Schwelle) | +| `parental_consent_confirmed` | — | ✅ | — | Ja (juristisch zu klären) | +| `contains_music` | — | ✅ | — | Ja | +| `music_rights_confirmed` | — | ✅ | — | Ja | +| `third_party_content_confirmed` | — | ✅ | — | Teilweise | +| `declaration_version` | ✅ | — | — | Nein | +| `action_type` | ✅ | — | — | Nein | +| `rights_status` in media_assets | ✅ | — | — | Nein | +| `rights_declared_for_visibility` | ✅ | — | — | Nein | +| Separates Upload von Einwilligungsdokumenten | — | — | Zu früh | Ja | +| `may_be_embedded_in_exercises` | — | — | Unnötig (exercise_media-Tabelle reicht) | — | +| `declaration_scope_*` als einzelne Booleans | — | — | Unnötig (visibility-String reicht) | — | + +### 4.4 Designentscheidungen (mit Begründung) + +**Entscheidung 1: Gestufte Erklärungen je Sichtbarkeitsstufe** + +Nicht eine universale Erklärung für alle Stufen, sondern Promotion auf höhere Stufe erfordert neue Erklärung. + +*Begründung:* Rechtliche Anforderungen steigen mit Sichtbarkeit. Private Medien: nur Eigentümer sieht sie. Official-Medien: plattformweit sichtbar (ggf. öffentlich). Stufenmodell ist rechtsanschlussfähig — spätere juristische Textanpassungen pro Stufe ohne Systemwechsel möglich. + +**Entscheidung 2: Minimalset beim Erstupload** + +Pflicht beim privaten Upload: nur `rights_holder_confirmed`. Personen-Fragen: optional beim Upload, Pflicht erst bei Promotion zu club/official. + +*Begründung:* Die meisten Uploads bleiben privat und werden nie promoted. Volle Fragebogenbelastung beim Upload würde Nutzung hemmen ohne rechtlichen Mehrwert. Personen-Fragen werden erzwungen sobald der Upload für andere sichtbar wird. + +**Entscheidung 3: Keine globale Nutzer-Einwilligung (pro Upload)** + +Erklärung wird pro Upload abgegeben, nicht einmalig pro Nutzer. + +*Begründung:* Jedes Medium ist inhaltlich unterschiedlich. Eine pauschale Einwilligung beim Registrieren oder einmalig je Nutzer deckt nicht ab, ob bei diesem konkreten Video Minderjährige abgebildet sind. + +**Entscheidung 4: Append-only Audit-Log** + +Einmal abgegebene Erklärungen werden nie geändert oder gelöscht. Neue Erklärung = neuer Eintrag. + +*Begründung:* Nachweisbarkeit. Bei späterem Streit muss belegbar sein, was wann erklärt wurde. + +**Entscheidung 5: Versionierung via `declaration_version`-String** + +Wenn Rechtsanwalt Erklärungstexte ändert, wird die neue Version als "p06-v1.1" deklariert. Keine Datenbank-FK auf eine Textversion-Tabelle (zu komplex für MVP). + +*Begründung:* Einfach nachvollziehbar. Ob bei Versionswechsel alle Altdeklarationen erneuert werden müssen, ist juristisch zu entscheiden — technisch ermöglicht das System beides. + +**Entscheidung 6: copyright_notice bleibt separat (P-04 unberührt)** + +P-06 führt keine copyright_notice-Redundanz ein. copyright_notice (P-04) = Attribution. rights_holder_confirmed (P-06) = Berechtigung. Beide sind Pflicht bei official. + +--- + +## 5. Ziel-Flows + +### Flow 1: Erstupload eines privaten Mediums (Übung oder Archiv) + +**Frontend:** +1. Nutzer öffnet Upload-Dialog (Exercise oder Archiv) +2. Dateiauswahl +3. **P-06-Dialog erscheint vor Upload-Button-Aktivierung:** + - ☑ „Ich bin der Rechteinhaber oder besitze die erforderlichen Nutzungsrechte an diesem Medium." [Pflicht] + - ☐ „Das Medium enthält erkennbare Personen." [optional] + - → wenn ja: ☑ „Alle abgebildeten Personen haben der Nutzung zugestimmt." [optional bei private, Pflicht bei Promotion] + - ☐ „Das Medium enthält Minderjährige." [optional] +4. Upload-Button aktiv erst wenn Pflicht-Checkbox gesetzt + +**Backend:** +- Empfängt neue Felder: `rights_holder_confirmed`, optional `contains_identifiable_persons`, `person_consent_confirmed`, `contains_minors` +- Prüft: `rights_holder_confirmed == true` — sonst HTTP 400 `RIGHTS_DECLARATION_REQUIRED` +- INSERT in `media_assets` mit `rights_status = 'declared'`, `rights_declared_for_visibility = 'private'`, `rights_declared_at = NOW()` +- INSERT in `media_asset_rights_declarations` mit `action_type = 'upload'`, `declaration_version = 'p06-v1.0'`, alle Felder + +**Fehlermeldungen:** +- `RIGHTS_DECLARATION_REQUIRED`: "Bitte bestätige, dass du die erforderlichen Rechte an diesem Medium besitzt." + +**Tests:** +- Upload ohne `rights_holder_confirmed` → 400 +- Upload mit `rights_holder_confirmed=true` → 201, `rights_status='declared'` in DB +- Declaration-Log-Eintrag vorhanden mit korrektem `action_type='upload'` + +**Offene juristische Fragen:** Reicht Selbsterklärung oder muss der Betreiber den Upload ansonsten ablehnen? (→ §7.1) + +--- + +### Flow 2: Erstupload direkt als club-Medium (Archiv-Bulk-Upload) + +**Frontend:** +- Nutzer wählt `visibility = club` im Bulk-Upload-Dialog +- P-06-Dialog erweitert (zusätzlich zur privaten Pflicht-Checkbox): + - ☑ „Das Medium enthält erkennbare Personen." [Antwort Pflicht bei club] + - → wenn ja: ☑ „Alle abgebildeten Personen haben der vereinsinternen Nutzung zugestimmt." [Pflicht] + - ☑ „Das Medium enthält Minderjährige." [Antwort Pflicht] + - → wenn ja: ☑ „Einwilligung der Erziehungsberechtigten liegt vor." [Pflicht, juristisch zu prüfen] + +**Backend:** +- Prüft alle Pflichtfelder für club: `rights_holder_confirmed`, `contains_identifiable_persons` (must be answered), `person_consent_confirmed` (wenn contains_persons=true) +- `rights_declared_for_visibility = 'club'` +- Eintrag in `media_asset_rights_declarations` mit `action_type = 'upload'`, `target_visibility = 'club'` + +--- + +### Flow 3: Bulk-Upload durch Admin (Plattform-Admin / Superadmin) + +**Besonderheit:** Admin lädt oft viele Dateien auf einmal. Dialog-Design muss batch-fähig sein. + +**Empfehlung:** Eine Einwilligungserklärung für den gesamten Batch (nicht je Datei). Alle Dateien des Batches erhalten den gleichen Declarations-Record, jedoch referenziert je `media_asset_id`. + +**Frontend:** +- Vor Upload: Batch-Deklaration (gilt für alle Dateien des Batches) +- Alternativ: Je Datei separate Deklaration (aufwändiger aber präziser) — juristisch zu prüfen welche Variante ausreichend ist + +**Backend:** +- `action_type = 'upload'` für alle Dateien des Batches +- Wenn Batch-Deklaration: eine Deklarations-Transaktion, n Einträge in Log (je asset_id) + +**Offene juristische Fragen:** Genügt eine Sammelbestätigung für Batches? (→ §7.6) + +--- + +### Flow 4: Promotion private → club + +**Frontend:** +1. Nutzer ändert Sichtbarkeit eines Mediums zu `club` (im Archiv oder via Übungssichtbarkeit) +2. Frontend erkennt Sichtbarkeitserhöhung +3. **P-06-Promotions-Dialog:** + - ☑ „Das Medium enthält erkennbare Personen." [Pflicht — Antwort erforderlich] + - → wenn ja: ☑ „Alle abgebildeten Personen haben der vereinsinternen Nutzung zugestimmt." [Pflicht] + - ☑ „Das Medium enthält Minderjährige." [Pflicht — Antwort erforderlich] + - → wenn ja: ☑ „Einwilligung der Erziehungsberechtigten liegt vor." [Pflicht, juristisch zu prüfen] +4. Bestehende copyright_notice-Abfrage (P-04) bleibt erhalten — läuft parallel oder im gleichen Dialog + +**Backend:** +- PATCH `/api/media-assets/{id}` empfängt: `visibility='club'`, P-06-Felder, `copyright_notice` +- Prüft: rights_status='declared' AND rights_declared_for_visibility ≥ 'club' — wenn ja, keine neue Deklaration nötig (z. B. bereits als club hochgeladen) +- Wenn nicht: neue Pflichtfelder prüfen, INSERT in Declarations-Log mit `action_type='promote_club'` +- Bestehende P-04-Prüfung: copyright_notice weiterhin Pflicht +- `rights_declared_for_visibility` in media_assets auf 'club' setzen + +**Backend-Fehler:** +- `CONSENT_REQUIRED_FOR_CLUB`: Personenfragen nicht beantwortet +- `LEGACY_REDECLARATION_REQUIRED`: Altmedium, muss Nachdeklaration abgeben +- `RIGHTS_DECLARATION_REQUIRED` (P-04): copyright_notice fehlt (bestehend) + +--- + +### Flow 5: Promotion private/club → official + +**Frontend:** +1. Nur Superadmin kann zu official promoten +2. Dialog zeigt vollständige Erklärung: + - Alle Felder aus Flow 4 (Pflicht) + - ☑ zusätzlich: „Das Medium enthält Musik oder sonstige Fremdinhalte." [Pflicht — Antwort erforderlich] + - → wenn ja: ☑ „Ich besitze die erforderlichen Lizenzen für die öffentliche Nutzung." [Pflicht] +3. copyright_notice (P-04) weiterhin Pflicht (bestehende Logik) + +**Backend:** +- Prüft alle Felder + copyright_notice +- `action_type = 'promote_official'`, `target_visibility = 'official'` +- `rights_declared_for_visibility = 'official'` + +**Offene juristische Fragen:** Reicht Selbstdeklaration oder muss Superadmin bei official höhere Sorgfalt nachweisen? (→ §7.3) + +--- + +### Flow 6: Nachbearbeitung von Metadaten (ohne Sichtbarkeitsänderung) + +**Szenario:** Nutzer ändert nur `copyright_notice`, `original_filename`, `tags` — keine Sichtbarkeitsänderung. + +**P-06-Anforderung:** Keine neue Deklaration erforderlich (Metadaten-Edit ist kein Promotions-Schritt). + +**Ausnahme:** Wenn `rights_status = 'blocked'` (durch P-11/P-13 gesetzt) → Metadaten-Edit erlaubt, aber Sichtbarkeitsänderungen bleiben gesperrt. + +--- + +### Flow 7: Verwendung bestehender Medien in neuer Übung (`from-asset`) + +**Szenario:** Trainer verknüpft ein bereits im Archiv liegendes Medium mit einer neuen Übung über `POST /api/exercises/{id}/media/from-asset`. + +**P-06-Anforderung:** Keine neue Deklaration erforderlich. Die Deklaration gilt für das Medium selbst, nicht für die Verknüpfung. Voraussetzung: `rights_status` des Assets ist 'declared' für die Sichtbarkeit der Übung. + +**Backend-Prüfung (neu):** +- Asset-Sichtbarkeit ≥ Übungs-Sichtbarkeit? Bestehende Prüfung. +- `rights_declared_for_visibility` ≥ Übungs-Sichtbarkeit? → Neue Prüfung durch P-06 +- Wenn nicht: HTTP 400 `RIGHTS_DECLARATION_REQUIRED_FOR_TARGET_VISIBILITY` + +--- + +### Flow 8: Behandlung von Altmedien ohne P-06-Metadaten + +**Strategie: Soft-Block bei Promotion, kein Rückwirkungs-Zwang für private Altmedien** + +| Situation | Verhalten | +|-----------|-----------| +| Altmedium private → weiterhin privat | Unverändert zugänglich; keine Zwangs-Nachdeklaration | +| Altmedium privat → Anzeige in Übung (private) | Unverändert; keine neue Deklaration | +| Altmedium privat → Promotion zu club | Blocked: `LEGACY_REDECLARATION_REQUIRED`; Nutzer muss Nachdeklaration abgeben | +| Altmedium club → Promotion zu official | Blocked; Superadmin muss Nachdeklaration abgeben | +| Altmedium mit `rights_status = 'legacy_unreviewed'` | Einsehbar, nicht promotable | + +**Nachdeklarations-Flow:** +1. Nutzer versucht Promotion eines Altmediums +2. Backend gibt HTTP 400 `LEGACY_REDECLARATION_REQUIRED` zurück +3. Frontend zeigt Hinweis und Deklarations-Dialog (analog zu neuem Upload-Dialog) +4. Nutzer füllt Deklaration aus +5. PATCH mit `legacy_re_declaration=true` + alle Pflichtfelder + `visibility` +6. Backend: INSERT in Declarations-Log mit `action_type='legacy_re_declaration'`, aktualisiert `rights_status`, `rights_declared_for_visibility` + +**Migrationsstrategie für bestehende Daten:** +- Alle bestehenden `media_assets`-Zeilen bleiben mit `rights_status = 'legacy_unreviewed'` (Default in Migration) +- Keine rückwirkende Sperrung +- Bestehende club/official-Medien: `rights_status = 'legacy_unreviewed'` — die historische Sichtbarkeit bleibt erhalten, spätere Änderungen erfordern aber Nachdeklaration + +**Juristisch zu prüfen:** Muss der Betreiber aktiv alle Altmedien auf club/official sperren bis zur Nachdeklaration? (→ §7.8) + +--- + +### Flow 9: Widerruf / nachträglich fehlende Rechte erkannt + +**Szenario:** Abgebildete Person widerruft Einwilligung oder Uploader erkennt, dass er keine Rechte hatte. + +**P-06 implementiert keinen Widerrufsmechanismus direkt.** Anschluss an spätere Pakete: + +- **P-11 (Legal-Hold):** Superadmin kann `rights_status = 'blocked'` setzen → Medium sofort aus allen öffentlichen Abfragen entfernt +- **P-13 (Content-Melde-Backend):** Dritte können Rechtsverletzung melden → Moderationsqueue → Superadmin entscheidet über Sperrung + +**P-06-Schnittstelle:** Das Feld `rights_status = 'blocked'` in `media_assets` ist die technische Brücke zu P-11 und P-13. + +**Empfehlung:** Declaration-Log-Tabelle hat `ON DELETE CASCADE` auf `media_assets.id` — wenn ein Medium purged wird, werden auch alle Deklarationseinträge entfernt. Juristisch zu prüfen, ob Deklarationslog nach Löschung aufbewahrt werden muss (Rechenschaftspflicht Art. 5 Abs. 2 DSGVO). + +--- + +### Flow 10: Zusammenspiel mit späterem P-11 und P-13 + +| P-06-Element | P-11-Anschluss | P-13-Anschluss | +|-------------|---------------|---------------| +| `rights_status = 'blocked'` | P-11 setzt diesen Status (Legal-Hold) | P-13-Moderator triggert P-11-Sperre | +| Declaration-Log | Zeigt, welche Version bei Sperrung galt | Kontext für Moderationsentscheidung | +| `contains_identifiable_persons` | Relevant für Löschbegründung (KUG) | Relevanzmerkmal für Meldekategorie | +| `contains_minors` | Höchste Priorität bei P-11-Sofortsperrung | CSAM-Eskalationspfad in P-13 | + +P-06 darf nicht im Widerspruch zu den späteren Paketen implementiert werden. Der `rights_status`-Enum muss `'blocked'` bereits in P-06a (Migration) enthalten. + +--- + +## 6. Legacy- und Migrationskonzept + +### 6.1 Fragen und Antworten + +| Frage | Empfehlung | Juristisch zu prüfen | +|-------|-----------|----------------------| +| Dürfen Altmedien sichtbar bleiben? | Ja — keine rückwirkende Sperrung | Ja — insb. club/official ohne Einwilligung | +| Dürfen Altmedien in neuen Übungen verwendet werden? | Ja, wenn Sichtbarkeit kompatibel | Ja — falls keine Rechte vorhanden | +| Dürfen Altmedien zu club promoted werden? | Nein — Nachdeklaration erforderlich | Ja — ob Selbstdeklaration genügt | +| Dürfen Altmedien zu official promoted werden? | Nein — vollständige Nachdeklaration | Ja — höhere Anforderungen | +| Muss bei erster Bearbeitung Nachdeklaration erzwungen werden? | Nein (nur bei Promotion) | Ja — Betreiber-Ermessen | + +### 6.2 Migration-Schritte + +1. **Migration (P-06a):** Neue Spalten in `media_assets` mit `DEFAULT 'legacy_unreviewed'` → alle bestehenden Zeilen erhalten automatisch Status `legacy_unreviewed` +2. **Neue Uploads nach P-06:** Code setzt `rights_status = 'declared'` nach erfolgreicher Deklaration +3. **Altmedien-Promotion:** Backend blockiert mit `LEGACY_REDECLARATION_REQUIRED`; Nutzer muss Nachdeklaration abgeben +4. **Keine automatische Batch-Re-Deklaration** durch Betreiber (wäre fachlich falsch — Betreiber kann nicht für Uploader erklären) + +### 6.3 Empfohlene Übergangsstrategie (Minimales Risiko) + +``` +private Altmedien: weiter sichtbar und nutzbar | Promotion blockiert +club Altmedien: weiter sichtbar | Sichtbarkeitsänderung blockiert +official Altmedien: weiter sichtbar | Sichtbarkeitsänderung blockiert +``` + +*Begründung:* Vollständige Sperrung aller Altmedien würde Betrieb lahmlegen. Die Blockierung bei Promotion schützt vor Eskalation ohne existierende Nutzung zu zerstören. Juristisch bleibt das Risiko bei bereits exponierten Medien — das ist ein organisatorisches Problem, kein technisches. + +--- + +## 7. Juristische Klärungsliste + +Alle folgenden Punkte müssen durch einen Rechtsanwalt oder Datenschutzbeauftragten bewertet werden. Keine der folgenden Einschätzungen ist rechtlich bindend. + +| # | Frage | Technische Relevanz | Dringlichkeit | +|---|-------|---------------------|---------------| +| 7.1 | Welche Erklärung ist für **private** Medien (nur Uploader sieht sie) erforderlich? Reicht `rights_holder_confirmed` oder ist auch ohne Sichtbarkeit Dritter eine Personeneinwilligung nötig? | Ob Personen-Fragen bei private Pflicht werden | Vor MVP | +| 7.2 | Welche Erklärung ist für **club**-interne Sichtbarkeit (Vereinsmitglieder) erforderlich? Gilt § 22 KUG für vereinsintern? Reicht Selbsterklärung des Uploaders? | Pflichtfelder bei Promotion zu club | Vor MVP | +| 7.3 | Welche Erklärung ist für **official** (plattformweit, ggf. öffentlich) erforderlich? Reicht Selbsterklärung oder muss Einwilligung nachgewiesen werden? | Pflichtfelder bei Promotion zu official | Vor MVP | +| 7.4 | Wie ist mit erkennbaren **Minderjährigen** zu verfahren? Ab welchem Alter benötigen Minderjährige elterliche Einwilligung? Welche Einwilligungsform ist rechtssicher? | `contains_minors` + `parental_consent_confirmed` — Pflicht ab welcher Stufe? | Vor MVP | +| 7.5 | Reicht eine **Selbsterklärung** des Uploaders oder müssen Einwilligungs-Dokumente (Scan, Upload) archiviert werden? | Dateiupload für Einwilligungs-Scan nötig? (MVP oder später?) | Vor MVP | +| 7.6 | Ist eine **Batch-Deklaration** (eine Erklärung für mehrere Dateien des Uploads) rechtlich ausreichend? | Flow 3: Bulk-Upload-Design | Vor MVP | +| 7.7 | Muss die **Textfassung** der Erklärungen (Checkbox-Labels) durch Rechtsanwalt freigegeben werden? Welche konkreten Formulierungen sind erforderlich? | `declaration_version` Textbasis | Vor MVP | +| 7.8 | Wie sind **Altmedien** zu behandeln, die bereits mit club/official-Sichtbarkeit in der DB stehen? Muss der Betreiber diese sperren bis zur Nachdeklaration? | Migrationsstrategie §6.3 | Zeitnah | +| 7.9 | Wie ist bei **Widerruf** einer Einwilligung vorzugehen? Welche Fristen gelten? Muss das Medium sofort gelöscht oder nur gesperrt werden? | rights_status='blocked', Schnittstelle P-11 | Vor P-11 | +| 7.10 | Welche **Nachweisdaten** dürfen/sollen gespeichert werden (Datensparsamkeit vs. Rechenschaftspflicht)? Wie lange muss der Declaration-Log aufbewahrt werden? | Retention-Policy für `media_asset_rights_declarations` | Vor MVP | +| 7.11 | Welche Anforderungen gelten für **Trainingsvideos mit mehreren Personen**? Muss jede Person einzeln einwilligen oder reicht eine kollektive Erklärung? | `person_consent_confirmed` als Boolean vs. Mehrfach-Einwilligung | Vor MVP | +| 7.12 | Welche Anforderungen gelten für **Musik, Logos, Marken, Grafiken** von Dritten im Video/Bild? Ab wann ist eine separate Lizenz nötig? Reicht `music_rights_confirmed` als Selbsterklärung? | `contains_music`, `music_rights_confirmed` — MVP oder Pflicht? | Mittel | + +--- + +## 8. Umsetzungsplan (für spätere Codephase — keine Umsetzungsfreigabe) + +### P-06a – Datenmodell / Migration + +| Feld | Wert | +|------|------| +| **Ziel** | Neue Tabelle `media_asset_rights_declarations` anlegen; drei neue Spalten in `media_assets` | +| **Betroffene Dateien** | `backend/migrations/048_media_rights_declarations.sql` (neu) | +| **Migrationsbedarf** | Neue Migration; `DEFAULT 'legacy_unreviewed'` automatisch für bestehende Zeilen | +| **Abhängigkeiten** | Keine (neue Tabelle) | +| **Testbedarf** | Migration idempotent; bestehende `media_assets`-Zeilen haben `rights_status='legacy_unreviewed'` nach Migration; neue Zeilen haben `rights_status='declared'` nach P-06b | +| **Akzeptanzkriterien** | Tabelle angelegt, alle Spalten korrekt typisiert, Indizes vorhanden, ALTER-Migration ohne Downtime anwendbar | +| **Risiko** | Niedrig (neue Tabelle + ALTER mit DEFAULT ohne Table-Lock in PostgreSQL 16) | +| **Rollback** | DROP TABLE media_asset_rights_declarations; ALTER TABLE media_assets DROP COLUMN rights_status, rights_declared_for_visibility, rights_declared_at | + +--- + +### P-06b – Backend-Erzwingung + +| Feld | Wert | +|------|------| +| **Ziel** | Backend blockiert Upload und Promotion wenn Pflichtfelder fehlen; schreibt Declarations-Log | +| **Betroffene Dateien** | `backend/routers/media_assets.py` (bulk-upload + patch + bulk-patch), `backend/routers/exercises.py` (upload_exercise_media, from-asset), neues Modul `backend/media_rights.py` (Hilfslogik) | +| **Neue Pydantic-Models** | `RightsDeclaration` (Pflichtfelder + optionale Felder); Integration in `MediaAssetPatch` + Upload-Endpoints | +| **Neue Fehlercodes** | `RIGHTS_DECLARATION_REQUIRED`, `CONSENT_REQUIRED_FOR_CLUB`, `CONSENT_REQUIRED_FOR_OFFICIAL`, `LEGACY_REDECLARATION_REQUIRED`, `RIGHTS_DECLARATION_REQUIRED_FOR_TARGET_VISIBILITY` | +| **Abhängigkeiten** | P-06a (Migration) muss abgeschlossen sein | +| **Testbedarf** | Unit-Tests für jeden neuen Fehlercode; Integrationstests Upload → Deklarationslog; Promotion ohne/mit Deklaration; Legacy-Block | +| **Akzeptanzkriterien** | Upload ohne `rights_holder_confirmed` → 400; promotion ohne Personen-Deklaration → 400; gültige Deklaration → Eintrag in DB vorhanden; bestehender P-04-Test weiterhin grün | +| **Risiko** | Mittel (Breaking Change für alle Upload-Clients); Feature-Flag zum schrittweisen Rollout empfohlen | +| **Rollback** | Feature-Flag deaktivieren; kein DB-Rollback nötig | + +--- + +### P-06c – Frontend-Dialoge + +| Feld | Wert | +|------|------| +| **Ziel** | Einwilligungsdialog in allen Upload-Pfaden; Promotions-Dialog bei Sichtbarkeitsänderung | +| **Betroffene Dateien** | `frontend/src/components/RightsDeclarationDialog.jsx` (neu, wiederverwendbar), `frontend/src/pages/ExerciseFormPage.jsx`, `frontend/src/pages/MediaLibraryPage.jsx`, `frontend/src/utils/api.js` | +| **Dialog-Typen** | Upload-Dialog (privat/club/official je nach Kontext), Promotions-Dialog (erkennt Sichtbarkeitserhöhung), Nachdeklarations-Dialog (für Legacy) | +| **Abhängigkeiten** | P-06b (Backend-Codes müssen definiert sein); juristische Textfreigabe für Checkbox-Labels | +| **Testbedarf** | Playwright E2E: Dialog erscheint; Upload ohne Checkbox → deaktivierter Button; Dialog mit allem ausgefüllt → erfolgreicher Upload; Backend-Fehler → korrekte Fehlermeldung | +| **Akzeptanzkriterien** | Dialog erscheint bei allen Upload-Pfaden; Checkbox-State korrekt; Labels entsprechen juristisch geprüften Formulierungen; Promotions-Dialog erkennt Sichtbarkeitserhöhung | +| **Risiko** | Mittel (UX-Änderung an häufig genutzten Pfaden) | +| **Rollback** | Feature-Flag; Dialoge können ohne Backend-Änderung deaktiviert werden | + +--- + +### P-06d – Tests / Dokumentation + +| Feld | Wert | +|------|------| +| **Ziel** | Vollständige Testabdeckung für P-06 + Doku-Update | +| **Betroffene Dateien** | `backend/tests/test_media_rights_declaration.py` (neu), `tests/dev-smoke-test.spec.js` (neue P-06-Tests), `docs/compliance-implementation.md`, `docs/compliance-package-register.md`, Access-Layer-Audit aktualisieren | +| **Backend-Tests** | Upload-Flows, Promotions-Flows, Legacy-Block, Declaration-Log, alle Fehlercodes | +| **Playwright-Tests** | Dialog erscheint, Checkbox-Validierung, vollständiger Upload-Flow, Promotions-Dialog | +| **Abhängigkeiten** | P-06a, P-06b, P-06c abgeschlossen | +| **Akzeptanzkriterien** | Alle neuen Tests grün; bestehende Tests unverändert grün; ACCESS_LAYER_STRICT=1 grün | +| **Risiko** | Niedrig | + +--- + +### P-06e – Legacy-Nacharbeit (optional, nach juristischer Klärung) + +| Feld | Wert | +|------|------| +| **Ziel** | Massenprüfung und ggf. Sperrung bestehender club/official-Medien ohne Deklaration, falls juristisch notwendig | +| **Betroffene Dateien** | `backend/scripts/media_rights_audit.py` (neu), evtl. Admin-UI | +| **Inhalt** | Script listet alle `visibility IN ('club', 'official')` mit `rights_status='legacy_unreviewed'`; Superadmin kann Massenmarkierung oder individuelle Überprüfung anstoßen | +| **Abhängigkeiten** | P-06a–d; juristische Klärung §7.8 | +| **Akzeptanzkriterien** | Script läuft ohne Fehler; erzeugt CSV-Report mit betroffenen Assets | +| **Risiko** | Mittel (wenn Sperrung aktiv: Betriebsunterbrechung für Vereinsmedien) | +| **Hinweis** | Erst nach juristischer Entscheidung über Altbestand-Behandlung umsetzen | + +--- + +## 9. Abschlussbewertung + +### 9.1 Neue / geänderte Dokumente + +| Dokument | Änderung | +|----------|---------| +| `docs/p06-upload-rights-spec.md` | Neu erstellt (dieses Dokument) | +| `docs/compliance-roadmap.md` | P-06: Spezifikation erstellt vermerkt; nächste Freigabe angepasst | +| `docs/compliance-implementation.md` | Kurzer P-06-Eintrag: Spezifikation erstellt, keine Umsetzung | +| `docs/compliance-package-register.md` | P-06 Letzter Stand: Spezifikation vorhanden | + +### 9.2 Empfohlene P-06-Zielarchitektur (Kurzfassung) + +- **Append-only Log-Tabelle** `media_asset_rights_declarations` (Wer, Wann, Was, Welche Version) +- **Drei Status-Felder** in `media_assets`: `rights_status` / `rights_declared_for_visibility` / `rights_declared_at` +- **Gestufte Erklärungen**: Upload = Minimalset; Promotion club = Personen-Pflicht; Promotion official = vollständig +- **Backend-Erzwingung** über neue Fehlercodes; keine reine Frontend-Checkbox +- **Versionierung** über `declaration_version`-String; kein FK auf Texttabelle +- **Legacy**: `rights_status = 'legacy_unreviewed'`; Promotion blockiert; Nachdeklarations-Flow + +### 9.3 Kritische Designentscheidungen + +| Entscheidung | Begründung | +|-------------|-----------| +| Gestufte Erklärungen je Sichtbarkeitsstufe | Rechtsrisiko steigt mit Sichtbarkeit; Rechtsanschlussfähigkeit | +| Minimalset beim Erstupload | Nutzbarkeit vs. Compliance; Pflicht-Erweiterung bei Promotion | +| Append-only Log (nie löschen/ändern) | Nachweisbarkeit; Audit-Integrität | +| rights_status = 'legacy_unreviewed' per Default | Keine rückwirkende Sperrung; kontrollierbarer Übergang | +| Kein Einwilligungs-Datei-Upload (MVP) | Aufwand vs. Mehrwert; spätere Nachrüstung möglich | +| `rights_status = 'blocked'` als P-11-Schnittstelle | Zukunftssicherheit; P-11/P-13 können sofort anschließen | + +### 9.4 Offene juristische Fragen (Priorisiert) + +| Priorität | Frage | Paket-Impact | +|-----------|-------|-------------| +| Vor MVP | §7.7 Textfassung der Erklärungen | P-06c (Dialog-Labels) | +| Vor MVP | §7.1 Private: Reicht rights_holder allein? | Pflichtfeld-Definition | +| Vor MVP | §7.2 Club: § 22 KUG vereinsintern? | contains_persons bei club Pflicht? | +| Vor MVP | §7.4 Minderjährige: Schwelle und Form | parental_consent MVP oder später | +| Vor MVP | §7.5 Selbsterklärung oder Dokumenten-Upload? | Scope P-06c | +| Zeitnah | §7.8 Altmedien club/official: Sperrpflicht? | P-06e Scope | +| Vor P-11 | §7.9 Widerruf: Fristen und Mechanismus | P-11-Design | +| Mittel | §7.10 Aufbewahrung Declaration-Log | Retention-Policy | + +### 9.5 Empfohlene spätere Umsetzungsschritte + +1. Rechtsanwalt beauftragt für §7.7 (Texte) und §7.1–7.3 (Anforderungen je Stufe) +2. Nach Klärung §7.7: Freigabe P-06a + P-06b parallel (kein Frontend-Merge nötig) +3. Nach §7.7 Textfreigabe: Freigabe P-06c (Frontend-Dialoge) +4. P-06d: Tests + Doku beim gleichen Merge wie P-06b/P-06c +5. Nach §7.8-Klärung: ggf. P-06e (Legacy-Massenprüfung) + +### 9.6 Implementierungsbereitschaft + +| Kriterium | Einschätzung | +|-----------|-------------| +| P-06 implementierungsreif | Teilweise — Datenmodell und Backend-Logik spezifizierbar; Dialog-Labels nicht ohne juristische Textfreigabe | +| Juristische Vorabklärung erforderlich | Ja — §7.7 (Textfassung) blockiert P-06c; §7.1–7.3 bestimmen Pflichtfelder | +| P-06a (Migration) vorab umsetzbar | Ja — unabhängig von juristischen Texten | +| P-06b (Backend) vorab umsetzbar | Ja — mit Platzhalter-Fehlercodes, Texte nachrüstbar | +| P-06c (Frontend-Dialog) vorab umsetzbar | Nein — Dialog-Labels müssen juristisch freigegeben sein | + +### 9.7 Scope-Drift-Prüfung + +| Prüfung | Ergebnis | +|---------|---------| +| Codeänderungen vorgenommen? | Nein | +| Neue Migrationen erstellt? | Nein | +| Neue Endpoints erstellt? | Nein | +| Paket-ID geändert? | Nein | +| Andere Paket-IDs berührt? | Nein (P-11, P-13 nur als Referenz) | +| P-06 bleibt nach dieser Arbeit offen? | Ja | + +--- + +**P-06 fachlich-technisch spezifiziert. Keine Codeänderungen vorgenommen.** + +--- + +*Erstellt: 2026-05-10 | Autor: Claude Code | Kein Rechtsanwalt; alle rechtlichen Einschätzungen sind juristisch zu prüfen.*