shinkan-jinkendo/backend/migrations/048_media_rights_declarations.sql

76 lines
3.7 KiB
MySQL
Raw Permalink Normal View History

feat(compliance): P-06 Upload-Einwilligungsdialog v1-conservative Implementiert server-seitige Rechteerklärungspflicht für alle Medien-Uploads und Sichtbarkeits-Promotions (konservative Erstannahme: alle Uploads). Backend: - backend/media_rights.py (NEU): Kernmodul — validate_rights_declaration, check_rights_coverage, assert_rights_for_promotion, assert_rights_for_exercise_link, write_rights_declaration, update_rights_quick_fields - backend/migrations/048_media_rights_declarations.sql (NEU): Tabelle media_asset_rights_declarations (Append-only Audit-Log), Felder rights_status/rights_visibility_level in media_assets - backend/routers/media_assets.py: P-06-Pflichtprüfung in PATCH (single + bulk), POST /api/media-assets/{id}/rights-declarations (Re-Deklaration), GET /api/admin/media-rights/legacy-summary|legacy-assets (Admin-Endpoints) - backend/routers/exercises.py: P-06-Felder in upload_exercise_media, assert_rights_for_exercise_link in attach_exercise_media_from_asset - backend/main.py: admin_rights_router registriert Frontend: - frontend/src/components/RightsDeclarationDialog.jsx (NEU): 9-Felder-Dialog (konservativ: immer alle Fragen), Client-Validierung, VORLÄUFIG-Hinweis - frontend/src/pages/MediaLibraryPage.jsx: Dialog-Intercept vor Upload, Altbestand-Indikator (legacy_unreviewed) - frontend/src/utils/api.js: P-06-Felder in bulkUploadMediaAssets weitergeleitet Tests: - backend/tests/test_media_rights_declaration.py (NEU): 28 Unit-/Integrationstests - backend/tests/test_media_assets_archive.py: P-06 fetchone-Slots + Mock ergänzt - backend/tests/test_media_assets_copyright_promotion.py: check_rights_coverage gemockt - tests/dev-smoke-test.spec.js: 5 P-06 E2E-Tests ergänzt Dokumentation: - docs/compliance-implementation.md: P-06-Abschnitt - docs/compliance-package-register.md: Status ⚠️ teilweise umgesetzt (KRIT-04 offen) - docs/compliance-roadmap.md: P-06 im Freigaben-Log Offen: KRIT-04 (rechtliche Finalisierung Einwilligungsformulierung) — technisch vollständig, Rechtstext VORLÄUFIG. version: 0.8.75 module: media_rights 1.0.0, media_assets 1.13.0, exercises 2.20.0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 08:12:44 +02:00
-- Migration 048: P-06 Upload-Einwilligungsdialog
-- Append-only Deklarations-Log + Schnellfelder in media_assets
-- Alle bestehenden Medien erhalten rights_status = 'legacy_unreviewed'
-- Deklarations-Log (append-only, wird nie geaendert oder geloescht)
CREATE TABLE IF NOT EXISTS 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 TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- Kontext der Erklaerung
action_type VARCHAR(50) NOT NULL
CHECK (action_type IN (
'upload', -- Erstupload
'promote_club', -- Promotion zu club
'promote_official', -- Promotion zu official
're_declaration', -- Freiwillige Nacherklaerung
'legacy_re_declaration' -- Altmedium: erste Erklaerung nachgereicht
)),
target_visibility VARCHAR(32) NOT NULL
CHECK (target_visibility IN ('private', 'club', 'official')),
-- Textversion der Erklaerung; 'p06-v1-conservative' = konservative Erstannahmen
-- VORLAEUTIG: Texte noch nicht juristisch geprueft
declaration_version VARCHAR(40) NOT NULL DEFAULT 'p06-v1-conservative',
-- Pflichtfeld (alle Sichtbarkeiten, alle Aktionen)
rights_holder_confirmed BOOLEAN NOT NULL,
-- Personen (konservative Annahme: immer abgefragt, auch bei 'private')
contains_identifiable_persons BOOLEAN,
person_consent_confirmed BOOLEAN, -- Pflicht wenn contains_identifiable_persons = true
-- Minderjaehrige
contains_minors BOOLEAN,
parental_consent_confirmed BOOLEAN, -- Pflicht wenn contains_minors = true
-- Drittmaterial
contains_music BOOLEAN,
music_rights_confirmed BOOLEAN, -- Pflicht wenn contains_music = true
contains_third_party_content BOOLEAN,
third_party_rights_confirmed BOOLEAN, -- Pflicht wenn contains_third_party_content = true
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_mard_asset
ON media_asset_rights_declarations (media_asset_id);
CREATE INDEX IF NOT EXISTS idx_mard_profile
ON media_asset_rights_declarations (declared_by_profile_id);
CREATE INDEX IF NOT EXISTS idx_mard_action_type
ON media_asset_rights_declarations (action_type);
-- Schnellfelder in media_assets (kein Ersatz fuer den Log, nur fuer effiziente Abfragen)
ALTER TABLE media_assets
ADD COLUMN IF NOT EXISTS rights_status VARCHAR(32)
NOT NULL DEFAULT 'legacy_unreviewed'
CHECK (rights_status IN ('legacy_unreviewed', 'declared', 'blocked')),
ADD COLUMN IF NOT EXISTS rights_declared_for_visibility VARCHAR(32)
CHECK (rights_declared_for_visibility IN ('private', 'club', 'official')),
ADD COLUMN IF NOT EXISTS rights_declared_at TIMESTAMPTZ;
-- Bestehende Medien: explicit legacy_unreviewed setzen (redundant zum DEFAULT, zur Klarheit)
UPDATE media_assets
SET rights_status = 'legacy_unreviewed'
WHERE rights_status = 'legacy_unreviewed'; -- no-op, setzt Default explizit
COMMENT ON TABLE media_asset_rights_declarations IS
'P-06: Append-only Erklaerungslog fuer Upload-Einwilligungen. '
'Eintraege werden nie geaendert. Juristische Validierung der Felder und Texte steht aus.';
COMMENT ON COLUMN media_assets.rights_status IS
'P-06: legacy_unreviewed = Altbestand ohne P-06-Erklaerung; '
'declared = gueltige Erklaerung fuer rights_declared_for_visibility; '
'blocked = durch Admin gesperrt (P-11-Schnittstelle).';