shinkan-jinkendo/docs/compliance-audit.md
Lars aff3020b13
Some checks failed
Deploy Development / deploy (push) Successful in 39s
Test Suite / pytest-backend (push) Successful in 33s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 18s
Test Suite / playwright-tests (push) Failing after 58s
docs(compliance): Dokumentation auf Stand P-01b und P-01c aktualisiert (0.8.74)
- compliance-implementation.md: P-01c um copy-as-draft (0.8.72) und jsPDF
  + Abschnitts-Sortierung/-Einfuegen (0.8.74) ergaenzt; Testzusammenfassung
  auf 17 Playwright-Tests aktualisiert; Versionheader 0.8.74
- compliance-roadmap.md: App-Version 0.8.74; P-01-Blocker-Beschreibung
  vollstaendig (alle technischen Faehigkeiten); P-01c-Erweiterungen in
  Abschlussliste; Schnellreferenz aktualisiert
- compliance-package-register.md: P-01 Letzter Stand auf 0.8.74; Verweise
  und Hinweise ergaenzt (copy-as-draft, jsPDF, Sortierung); Fortschritt 0.8.74
- compliance-audit.md: Amendment §14.2 und §14.3 mit aktuellem Umsetzungsstand
  P-01/P-01b/P-01c; historische Befunde unveraendert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 22:17:51 +02:00

45 KiB
Raw Blame History

Compliance-Audit Shinkan Jinkendo

Status: Entwurf — technischer Audit, kein Rechtsanwalt
Datum: 2026-05-09
Auditor: Claude Code
App-Version: 0.8.65
Rechtlicher Hinweis: Dieses Dokument ist eine technische Analyse. Es ersetzt keine Rechtsberatung. Alle als „juristisch zu prüfen" markierten Punkte müssen durch einen Rechtsanwalt oder Datenschutzbeauftragten bewertet werden. Kein Code wurde verändert.


1. Executive Summary

Die Shinkan Jinkendo App ist technisch solide aufgebaut: robuste Mandantentrennung (TenantContext), mehrstufiges Löschkonzept für Medien, serverseitig erzwungene Zugriffskontrolle. Die Kernarchitektur der Datenschicht ist gut.

Kritische Compliance-Lücken:

  • Keine Rechtstexte (Impressum, Datenschutzerklärung, Nutzungsbedingungen, Medienrichtlinie)
  • Kein DSA-konformes Meldeverfahren für rechtswidrige Inhalte (UGC-Plattform)
  • Kein Recht-am-eigenen-Bild/Minderjährigen-Check beim Medienupload
  • Kein Self-Service-Löschrecht für Nutzer (nur Admin kann Konten löschen)
  • Auth-Token im localStorage (XSS-Risiko, TDDDG-Dokumentationspflicht)
  • HSTS-Header fehlt in der Nginx-Konfiguration
  • Papierkorb-Retention-Job nicht automatisch geplant
  • Passwort-Mindestlänge inkonsistent (Register: 8, PIN-Änderung: 4 Zeichen)

Vor öffentlichem Betrieb sind die kritischen Findings (KRIT-01 bis KRIT-07) zu adressieren.


2. Scope

Bereich Geprüft
Backend-Router (alle .py)
Datenbankmigrationen (001046)
Frontend App.jsx, Routing, Auth
API-Authentifizierung und Autorisierung
Mandanten-/Zugriffschicht (TenantContext, club_tenancy)
Medien-Archiv (media_assets, lifecycle)
PWA-Konfiguration (manifest.webmanifest)
Nginx-Konfiguration (nginx.conf)
Docker-Compose (docker-compose.yml)
Vorhandene Tests (backend/tests/*.py)
LocalStorage / SessionStorage Nutzung
Rechtstexte (Impressum, DSGVO, AGB)
CSP / Security-Header
Passwort-Handling, Session-Management

3. Annahmen

  • App ist öffentlich im Internet erreichbar unter shinkan.jinkendo.de (HTTPS)
  • SSL/TLS-Terminierung erfolgt am externen Reverse-Proxy vor dem Nginx-Container
  • Betreiber ist im EU-Raum ansässig (DSGVO anwendbar)
  • Minderjährige können sich registrieren (keine Altersverifikation vorhanden)
  • Die Plattform erlaubt Upload und Anzeige von Bildern und Videos mit Personenabbildungen

4. Nicht geprüfte Bereiche

  • Produktions-Infrastruktur (Synology NAS, Raspberry Pi 5) nur Konfigurationsdateien
  • Netzwerkinfrastruktur (Fritz!Box) außerhalb des Repos
  • SMTP-Anbieter im Detail (Anbieter unbekannt aus Umgebungsvariablen)
  • Aktive Penetrationstests
  • Backup-Prozess und Restore-Test (kein Skript im Repository)

5. Technische Bestandsaufnahme

5.1 Architektur

Komponente Technologie Sicherheitsrelevanz
Frontend React 18 + Vite, SPA Routing, Token-Speicherung
Backend FastAPI Python 3.12 Zugriffskontrolle, Validierung
Datenbank PostgreSQL 16 Alpine Datenhaltung, Mandantentrennung
Proxy Nginx (Docker) CSP, Security-Header, Upload-Limit
Storage Lokaler Bind-Mount via Docker Medienspeicherung
Auth Token-basiert (Sessions-Tabelle) Session-Management
PWA Web App Manifest + Icons Offline-Caching (kein Service Worker!)
E-Mail SMTP (konfigurierbar) Registrierung, Passwort-Reset
KI OpenRouter (optional, nicht MVP) KI-Features

5.2 Authentifizierung

  • Token: secrets.token_urlsafe(32) (kryptografisch sicher)
  • Hashing: bcrypt mit auto-Upgrade von Legacy SHA256
  • Session-Ablauf: 30 Tage (konfigurierbar per session_days)
  • Rate-Limiting: Login 30/min, Forgot-Password 3/min, Register 3/hour (slowapi)
  • No-Enumeration: /forgot-password gibt keine Info über E-Mail-Existenz preis

5.3 Rollen (global)

Rolle Rechte
trainer Standard-Nutzer; Upload, private Übungen, Planung
admin Plattform-Admin; alle Vereine, alle Profile einsehbar
superadmin Vollzugriff; Official-Promotion, physische Löschung, Admin-Konfiguration

5.4 Vereinsrollen (pro Verein)

Rolle Rechte
club_admin Vereinsstruktur, Mitglieder, Vereins-Medien/Übungen
trainer Training planen, Übungen verwalten
content_editor Inhalte bearbeiten
division_lead Spartenleitung

5.5 PWA / Service Worker

  • Kein Service Worker im Repository vorhanden
  • Keine Workbox- oder sw.js-Datei gefunden
  • Bedeutung: Das Hauptrisiko (private Medien im PWA-Cache) entfällt mangels Service Worker

5.6 Browser-Storage-Nutzung

Speicherart Inhalt TDDDG-Klassifikation
localStorage['authToken'] Auth-Session-Token Technisch notwendig
localStorage['shinkan_active_club'] Aktiver Verein (ID) Technisch notwendig
localStorage['shinkan_active_profile'] Profil-ID Technisch notwendig
sessionStorage[storageStepKey] Trainingsschritt (Coach-Page) Session-temporär, nicht personenbezogen
sessionStorage[storageDeltasKey] Trainingsdeltas JSON Session-temporär
sessionStorage[storageDebriefKey] Debrief-Status Session-temporär
Cookies keine
IndexedDB keine

6. Datenflussanalyse

6.1 Registrierung / Login

Nutzer → POST /api/auth/register → Profil (inaktiv) + Verifikations-E-Mail
Nutzer → E-Mail-Link → GET /api/auth/verify/{token}
 → Profil aktiv, Session-Token in Response
 → Frontend: localStorage.setItem('authToken', token)

Nutzer → POST /api/auth/login → Token in Response
 → Frontend: localStorage.setItem('authToken', token)

Gespeicherte Daten: Name, E-Mail, bcrypt-Hash, Rolle, Tier, trial_ends_at, email_verified, verification_token (temporär, wird nach Verifikation gelöscht)

6.2 Medienupload

Nutzer → POST /api/exercises/{id}/media (multipart) [50 MB Limit]
 → MIME-Type-Prüfung (magic bytes)
 → SHA256-Hash (Deduplizierung)
 → Dateispeicherung: library/{scope}/{kind}/{sha256}{ext}
 → DB-Eintrag: media_assets + exercise_media

Admin → POST /api/media-assets/bulk-upload [1 GB Limit]
 → gleicher Pfad; Sichtbarkeit + Verein als Formular-Parameter

6.3 Medienpromotion

Vereins-Admin → PATCH /api/media-assets/{id}
 → assert_valid_governance_visibility() → Mitgliedschaftsprüfung
 → Bei visibility=club: club_id Pflicht + Mitgliedschaft
 → Bei visibility=official: NUR Superadmin
 → copyright_notice: KEIN Pflichtfeld (nur im exercises-Router für official)

PROBLEM: Copyright-Pflicht ist NICHT im media_assets-Router für alle Promotions implementiert

6.4 Medienlöschung

Stufe 1 (Soft-Trash, lifecycle_state='trash_soft'):
 → Manuell durch Eigentümer / Vereins-Admin / Superadmin
 → Datei bleibt auf Disk; weiterhin sichtbar (je nach Exercise-Implementierung)

Stufe 2 (Hidden, lifecycle_state='trash_hidden'):
 → Nach 30 Tagen (Job) oder manuell
 → Nicht mehr in normalen Abfragen sichtbar

Stufe 3 (Purge):
 → Nach weiteren 30 Tagen (Job) oder Superadmin manuell
 → Datei physisch gelöscht

PROBLEM: media_retention_job.py ist NICHT automatisch geplant

6.5 Rechteprüfung

Jeder Request → require_auth() → Token aus X-Auth-Token-Header → Session aus DB
Vereinsdaten → get_tenant_context() → TenantContext (profile_id, role, effective_club_id)
Listenabfragen → library_content_visibility_sql() → SQL WHERE-Baustein
Schreibzugriffe → assert_valid_governance_visibility() → 403 bei Verstoß

7. Rollen- und Rechteanalyse

7.1 Mandantentrennung Stärken

  • TenantContext konsequent in allen vereinsrelevanten Routern via Depends(get_tenant_context)
  • library_content_visibility_sql() als zentraler Sichtbarkeits-Filter (SQL-Ebene)
  • effective_club_id aus Header nur für Mitglieder, beliebig nur für Plattform-Admins
  • Integrationstests vorhanden: test_access_layer_integration.py

7.2 Klarstellung: Wer kann Vereinsmedien bearbeiten?

Die Audit-Anforderung „alle Vereinsnutzer können bearbeiten" trifft auf die tatsächliche Implementierung nicht zu. In _item_permissions() (media_assets.py) ist edit_metadata nur für club_admin-Rolle oder Plattform-Admin True normale Mitglieder können Vereinsmedien nicht bearbeiten. Dies ist ein positiver Befund.

7.3 Profil-Löschung (DSGVO-Lücke)

DELETE /api/profiles/{pid} nur Plattform-Admin. Nutzer können ihr eigenes Konto nicht selbst löschen. Potenzielle DSGVO-Verletzung (Art. 17).


8. Medienrechteanalyse

  • Vorhanden: copyright_notice (max. 8000 Zeichen) in media_assets
  • Pflichtfeld bei exercise_media mit visibility='official' (exercises-Router)
  • NICHT Pflichtfeld beim direkten Upload in das Medienarchiv
  • NICHT Pflichtfeld bei Promotion von private zu club
  • NICHT dokumentiert: Wer hat erklärt? Wann? Welche Lizenzversion?

8.2 Rechteerklärung beim Upload

  • Keine Einwilligungserklärung beim Upload: „Ich bestätige, alle Rechte an dieser Datei zu besitzen"
  • Kein Upload-Dialog mit Pflicht-Checkbox
  • Kein Hinweis auf verbotene Inhalte (Rechte Dritter, Persönlichkeitsrechte)

8.3 Recht am eigenen Bild

  • Keine Abfrage, ob erkennbare Personen abgebildet sind
  • Keine Abfrage, ob Minderjährige enthalten sind
  • Keine Abfrage nach Einwilligung der abgebildeten Personen
  • Juristisch zu prüfen: Anforderungen nach §22 KUG

9. Löschkonzeptanalyse

9.1 Stärken

  • Klares 3-Stufen-Lifecycle-Modell (active → trash_soft → trash_hidden → purged)
  • Superadmin-Direktlöschung als Sofortmaßnahme
  • SHA256-Deduplizierung verhindert doppelte physische Dateien
  • Datei-Relokation bei Sichtbarkeitsänderung implementiert

9.2 Lücken

Problem Risiko
Papierkorb-Job nicht automatisch geplant Dateien bleiben physisch nach Ablauf der Fristen
Keine Löschung aus Backups dokumentiert DSGVO Art. 17: Backup-Retention oder Löschprozess nötig
Kein Legal-Hold-Status Bei Rechtsverletzung dauert es 30 Tage bis zur vollständigen Unsichtbarkeit
Kein Audit-Log für Löschgründe Keine Nachvollziehbarkeit für DSA/DSGVO
Kein Uploader-Benachrichtigungssystem Bei Sperrung / Löschung kein Feedback an Uploader

10. PWA- / Storage-Analyse

10.1 Positiv

  • Kein Service Worker → kein PWA-Cache-Risiko für Medien
  • Keine Cookies → kein Cookie-Banner nötig (für Cookies)
  • CSP-Header gesetzt: script-src 'self' (XSS-Mitigation)

10.2 LocalStorage-Bewertung

Die localStorage-Nutzung ist technisch notwendig (Auth, Mandantenkontext). Nach TDDDG §25 ist technisch notwendige Speicherung ohne Einwilligung zulässig. Dokumentation in der Datenschutzerklärung ist Pflicht.

10.3 Token-Sicherheit

  • Auth-Token in localStorage: vulnerabel bei XSS
  • CSP script-src 'self' reduziert XSS-Risiko erheblich
  • Kein CSRF-Problem (Token im Header, nicht in Cookie)
  • HttpOnly-Cookie wäre sicherer, erfordert Architekturanpassung

11. Datenschutzanalyse (DSGVO)

11.1 Identifizierte Verarbeitungsvorgänge

Vorgang Rechtsgrundlage (technisch) VVT-Status
Registrierung (Name, E-Mail, Passwort-Hash) Vertrag (Art. 6 Abs. 1 lit. b) Kein VVT
Login / Session-Management Berechtigtes Interesse Kein VVT
E-Mail-Versand Vertragserfüllung Kein VVT, SMTP-Anbieter unbekannt
Medienupload (Bilder/Videos) Einwilligung oder Vertragserfüllung Keine Einwilligung abgeholt
Vereinszugehörigkeit Vertragserfüllung Kein VVT
Training-Logging Berechtigtes Interesse Kein VVT
Backup (implizit) Berechtigtes Interesse Keine Retention dokumentiert

11.2 Betroffenenrechte

Recht Status
Auskunft (Art. 15) Kein Self-Service-Export
Berichtigung (Art. 16) ⚠ Nur eigener Name/E-Mail über Einstellungen
Löschung (Art. 17) Kein Self-Service-Löschung
Einschränkung (Art. 18) Nicht implementiert
Datenübertragbarkeit (Art. 20) Kein Export-Endpoint
Widerspruch (Art. 21) Kein Mechanismus

11.3 Auftragsverarbeiter (identifiziert)

Dienst Anbieter AV-Vertrag
Hosting Selbstbetrieb (Raspberry Pi) Entfällt
SMTP / E-Mail Unbekannt (Env-Variable) Nicht dokumentiert
MediaWiki-Import karatetrainer.net Nicht dokumentiert
OpenRouter (KI) OpenRouter.ai Nicht dokumentiert

11.4 Minderjährige

  • Keine Altersverifikation bei Registrierung
  • Keine besondere Schutzmaßnahme
  • Juristisch zu prüfen: §8 DSGVO

12. DSA-/UGC-Analyse

12.1 Einordnung

Die App erlaubt Upload von User Generated Content (Bilder, Videos). Inhalte können öffentlich sichtbar sein (official-Stufe: plattformweit). Dies ist UGC im Sinne des DSA.

Juristisch zu prüfen: Ab welcher Nutzerzahl und unter welchen Voraussetzungen der DSA für diese Plattform gilt.

12.2 Fehlende Mechanismen

DSA-Anforderung Status
Meldeverfahren für rechtswidrige Inhalte
„Inhalt melden"-Funktion
Moderations-Backend mit Statuswerten
Benachrichtigung des Uploaders bei Sperrung
Begründung für Moderationsentscheidungen
Beschwerdemechanismus
Eskalation für schwere Inhalte (CSAM, Straftaten)
Audit-Log für Meldungen und Entscheidungen

12.3 Was vorhanden ist (Notfall-Maßnahmen)

  • Superadmin kann Inhalte sofort physisch löschen (superadmin_hard_delete)
  • Lifecycle-System ermöglicht schrittweise Deaktivierung
  • official-Promotion nur durch Superadmin (redaktioneller Prozess)

13. Sicherheitsanalyse

13.1 Positiv bewertete Maßnahmen

Maßnahme Status
HTTPS (Produktion via Reverse-Proxy)
bcrypt Passwort-Hashing mit Legacy-SHA256-Upgrade
Rate-Limiting (slowapi)
CSRF-Schutz (Token im Header, nicht Cookie)
SQL-Injection-Schutz (parameterisierte Queries)
CSP-Header (nginx)
X-Content-Type-Options: nosniff (nginx + FastAPI-Middleware)
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy (camera/mic/geo)
OpenAPI in Produktion deaktiviert
DB-Port nur localhost exponiert
MIME-Type-Validierung beim Upload
SHA256-Integritätsprüfung + Deduplizierung
Secrets in .env (nicht im Code)
User-Enumeration verhindert (forgot-password, resend-verification)
Path-Traversal-Schutz in media_storage.py (path_under_media_root + .relative_to())
Club-Name-Slugify: nur [a-z0-9-] im Dateipfad
CORS: Origins eingeschränkt (ALLOWED_ORIGINS aus Env)

13.2 Sicherheitslücken

ID Titel Schwere Datei/Nachweis
SEC-01 Kein HSTS-Header Hoch frontend/nginx.conf kein Strict-Transport-Security
SEC-02 Auth-Token in localStorage Mittel frontend/src/context/AuthContext.jsx:47
SEC-03 style-src 'unsafe-inline' in CSP Niedrig frontend/nginx.conf:23
SEC-04 Passwort-Mindestlänge inkonsistent: Backend 3 Stellen, Frontend-Feld minLength=6, Backend-Register-Minimum=8 Mittel backend/routers/auth.py:104 (< 4), frontend/src/pages/LoginPage.jsx:175 (minLength="6")
SEC-05 ALLOW_PUBLIC_MEDIA_STATIC umgeht Auth für alle Medien Hoch backend/main.py:222-223
SEC-06 Kein MFA für Superadmins Mittel Kein TOTP/OTP implementiert
SEC-07 Kein Audit-Log für Admin-Aktionen Mittel Keine admin_audit_log-Tabelle
SEC-08 Password-Reset-Token in sessions-Tabelle (Präfix reset_) Niedrig backend/routers/auth.py:143
SEC-09 Kein Backup-Konzept dokumentiert Mittel Kein Backup-Skript im Repo
SEC-10 Kein Anti-Virus-Scan für Uploads Niedrig Kein ClamAV o.ä.
SEC-11 Kein genereller HTML-Sanitizer für Rich-Text-Felder Mittel backend/exercise_rich_text.py nur Inline-Media-Normalisierung, kein bleach/nh3
SEC-12 minLength="6" im Login-Formular, Backend fordert 8 Zeichen Niedrig frontend/src/pages/LoginPage.jsx:175
SEC-13 Hartcodierte Versionsangabe v0.1.0 • Development auf Login-Seite (falsch + Info-Leak) Niedrig frontend/src/pages/LoginPage.jsx:242
SEC-14 CORS: allow_methods=["*"] und allow_headers=["*"] breiter als nötig Niedrig backend/main.py:84-87

13.3 Ergänzende Befunde aus Restprüfung

main.py — CORS-Konfiguration

app.add_middleware(
    CORSMiddleware,
    allow_origins=ALLOWED_ORIGINS,   # ✓ aus Env, keine Wildcard-Origins
    allow_credentials=True,          # ✓ korrekt (kein * + credentials)
    allow_methods=["*"],             # ⚠ breiter als nötig
    allow_headers=["*"],             # ⚠ breiter als nötig
)

allow_credentials=True in Kombination mit allow_origins=["*"] wäre ein kritischer Fehler (FastAPI würde ihn aber abweisen). Durch die explizite Origin-Liste ist das Risiko gering. allow_methods=["*"] und allow_headers=["*"] könnten auf die tatsächlich benötigten Methoden (GET, POST, PUT, PATCH, DELETE) und Header (X-Auth-Token, X-Active-Club-Id, Content-Type) eingeschränkt werden.

media_storage.py — Path-Traversal-Schutz (positiv)

path_under_media_root() kombiniert zwei unabhängige Prüfungen:

  1. String-Prüfung: ".." in key.split("/")
  2. Filesystem-Prüfung: p.relative_to(media_root.resolve())

Die Dateiendung wird auf 16 Zeichen begrenzt. Club-Namen werden auf [a-z0-9-] normalisiert. SHA256 als Dateiname ist manipulationssicher. Bewertung: Gut implementiert, kein Path-Traversal-Risiko erkennbar.

exercise_rich_text.py — Fehlender genereller HTML-Sanitizer

Das Modul normalisiert ausschließlich das Inline-Media-Markup ({{exerciseMedia:id}}<span>). Es enthält keinen generellen HTML-Sanitizer (kein bleach, lxml-cleaner, nh3 o.ä.).

Felder in RICH_HTML_EXERCISE_FIELDS (summary, goal, execution, preparation, trainer_notes) können beliebiges HTML enthalten. Risikominderung:

  • CSP script-src 'self' verhindert <script>-Ausführung
  • React's dangerouslySetInnerHTML muss im Frontend für XSS genutzt werden — zu prüfen
  • Betroffene Felder sind nur für eingeloggte Nutzer sichtbar (kein öffentlicher Angriffspfad)

Empfehlung: bleach oder nh3 für Allowlist-basierte HTML-Sanitierung einsetzen.

LoginPage.jsx — Weitere Befunde

  1. Keine Rechtstexte-Links: Kein Link auf Impressum oder Datenschutzerklärung (bestätigt KRIT-01)
  2. minLength="6": Browser-seitig 6 Zeichen, Backend erzwingt 8 → UX-Bruch, Nutzer sieht kein Frontend-Feedback
  3. Hartcodierter Versionsstring: v0.1.0 • Development ist öffentlich sichtbar, falsch (App ist 0.8.65) und leakt Umgebungsinfo

13.5 Warnung: ALLOW_PUBLIC_MEDIA_STATIC (SEC-05)

Das Flag ALLOW_PUBLIC_MEDIA_STATIC=1 würde bei Aktivierung alle Mediendateien ohne Auth unter /media/ ausliefern und das gesamte Sichtbarkeitskonzept (privat, Verein, offiziell) für alle gespeicherten Mediendateien unterlaufen. Bestätigt in backend/main.py:222-223:

if os.getenv("ALLOW_PUBLIC_MEDIA_STATIC", "").strip().lower() in ("1", "true", "yes"):
    app.mount("/media", StaticFiles(directory=_media_dir), name="media")

Dieses Flag darf in Produktionsumgebungen niemals gesetzt sein. Muss in der Betriebsdokumentation explizit verboten und per Release-Checkliste überprüft werden.


14. Dokumentationsanalyse

14.1 Vorhandene technische Dokumentation

  • .claude/docs/technical/ACCESS_LAYER_AND_GOVERNANCE_PLAN.md
  • .claude/docs/technical/MEDIA_ASSETS_AND_ARCHIVE_SPEC.md
  • backend/version.py mit CHANGELOG ✓
  • backend/scripts/check_access_layer_hints.py

14.2 Fehlende rechtliche Dokumentation

Dokument Status (Audit 2026-05-09) Stand 2026-05-10
Impressum Keine Seite, kein Inhalt, keine Route ⚠️ Route + Platzhalter vorhanden; Inhalt durch Betreiber/Rechtsanwalt ausstehend
Datenschutzerklärung ⚠️ Route + Platzhalter vorhanden; Inhalt ausstehend
Nutzungsbedingungen / AGB ⚠️ Route + Platzhalter vorhanden; Inhalt ausstehend
Medienrichtlinie / Community-Regeln ⚠️ Route + Platzhalter vorhanden; Inhalt ausstehend
Verzeichnis der Verarbeitungstätigkeiten (VVT) offen (Betreiber-Aufgabe)
AV-Verträge mit Auftragsverarbeitern offen (Betreiber-Aufgabe)
Backup-Konzept schriftlich offen (Betreiber-Aufgabe)

Amendment 2026-05-10: Routen und Platzhalterseiten implementiert (P-01, 0.8.69); Mobile/PWA via /settings/legal (P-01b, 0.8.70); Admin-konfigurierbare Rechtstexte mit DB-Versionierung, Superadmin-UI, PDF-Download, Abschnitts-Editor (P-01c, 0.8.710.8.74). KRIT-01 bleibt offen bis zur Veröffentlichung juristisch geprüfter Inhalte.

14.3 Fehlende Frontend-Routen

In frontend/src/App.jsx fehlen (Stand Audit 2026-05-09):

  • /impressum
  • /datenschutz
  • /nutzungsbedingungen
  • /medienrichtlinie

Alle müssen vor der Authentifizierung erreichbar und in der PWA verfügbar sein.

Amendment 2026-05-10 (P-01, Version 0.8.69): Alle vier Routen sind implementiert und ohne Auth erreichbar. Links in LoginPage-Footer, DesktopSidebar-Footer und /settings/legal (P-01b). Migrationsnummer der Datenbank: bis 046 geprüft (Audit-Scope). Migration 047 (legal_documents) wurde außerhalb des Audit-Zeitfensters angelegt — siehe docs/compliance-implementation.md §P-01c.


15. Testanalyse

15.1 Vorhandene Tests

Test-Datei Inhalt
test_access_layer.py Sichtbarkeits-SQL-Logik
test_access_layer_integration.py Cross-Tenant-Isolation mit echter DB
test_exercises_delete_policy.py DELETE-Logik
test_exercise_media_download.py Download-Zugriffsschutz
test_official_exercise_media_rules.py Official-Promotion + Copyright
test_media_assets_archive.py Deduplizierung, Lifecycle
test_club_exercise_media_copyright.py Copyright bei Vereinsübungen
test_exercise_inline_post.py Inline-Medien-Validierung
test_exercise_rich_text.py HTML-Sanitizer
test_security_release.py OpenAPI/Health in Produktion
test_profiles_read_access.py Profil-Zugriffsrechte

15.2 Testlücken

Bereich Status
DSA-Meldeverfahren Funktion fehlt
DSGVO-Betroffenenrechte (Löschung, Export) Funktion fehlt
Minderjährigen-Check beim Upload Funktion fehlt
Einwilligungs-Check beim Upload Funktion fehlt
ALLOW_PUBLIC_MEDIA_STATIC=1 aktiviert Nicht getestet
Admin-Audit-Log Funktion fehlt
Passwort-Mindestlänge bei PIN-Änderung Nicht getestet
Copyright-Pflicht bei Archiv-Promotion Nicht getestet

16. Risiko-Matrix

KRITISCH

ID Titel Beschreibung Betroffene Dateien Juristisch prüfen Aufwand
KRIT-01 Keine Rechtstexte Keine Impressum-, Datenschutz-, AGB- oder Medienrichtlinien-Seite. Öffentlich erreichbare App ohne Impressum ist Ordnungswidrigkeit (TMG §5, TDDDG). frontend/src/App.jsx keine Routen Ja 25 Tage (Technik) + Rechtsanwalt
KRIT-02 Kein Self-Service-Löschrecht Nutzer können ihr Konto nicht selbst löschen (DSGVO Art. 17). Nur Plattform-Admin kann Konten löschen. backend/routers/profiles.py:414 Ja 58 Tage
KRIT-03 Kein DSA-Meldeverfahren Keine Möglichkeit, rechtswidrige Inhalte zu melden. Kein Moderationssystem für UGC-Plattform. Kein Router vorhanden Ja 1020 Tage
KRIT-04 Kein Recht-am-eigenen-Bild-Check Keine Abfrage bei Medienupload, ob Personen oder Minderjährige abgebildet sind. backend/routers/exercises.py, backend/routers/media_assets.py Ja 37 Tage
KRIT-05 Kein DSGVO-Self-Service (Auskunft, Export) Keine Datenauskunft, kein Datenexport, keine Berichtigungsmöglichkeit (DSGVO Art. 15, 16, 20). Kein Endpoint Ja 510 Tage
KRIT-06 Copyright-Pflicht inkonsistent Copyright ist Pflichtfeld nur im exercises-Router für official. Im media_assets-Router (Archiv) kann ohne Copyright zu club/official promoted werden. backend/routers/media_assets.py:766784 Ja 12 Tage
KRIT-07 Papierkorb-Job nicht geplant media_retention_job.py existiert, aber kein Cron-Job konfiguriert. Medien bleiben physisch nach Ablauf der DSGVO-Fristen auf dem Server. backend/media_retention_job.py Nein 1 Tag

HOCH

ID Titel Beschreibung Aufwand
HOCH-01 ALLOW_PUBLIC_MEDIA_STATIC Wenn gesetzt, sind alle Mediendateien ohne Auth abrufbar untergräbt gesamtes Sichtbarkeitskonzept Dokumentation + Test
HOCH-02 Kein HSTS Kein Strict-Transport-Security-Header in nginx.conf Dokumentation (Reverse-Proxy)
HOCH-03 Auth-Token in localStorage XSS könnte Token extrahieren; CSP reduziert, eliminiert nicht Dokumentation (HttpOnly als Langfrist-Plan)
HOCH-04 Kein MFA für Superadmins Superadmin hat unbegrenzten Systemzugriff ohne zweiten Faktor 58 Tage
HOCH-05 Kein Admin-Audit-Log Profil-Löschungen, Lifecycle-Aktionen nicht geloggt 35 Tage
HOCH-06 Keine Mindestalter-Abfrage Keine Schranke gegen Registrierung Minderjähriger 12 Tage

MITTEL

ID Titel Beschreibung Aufwand
MITT-01 Passwort-Mindestlänge inkonsistent Register: 8 Zeichen, PUT /api/auth/pin: 4 Zeichen 30 Min
MITT-02 Keine Sofortsperrung bei Rechtsverletzung Stufe-1-Papierkorb dauert 30 Tage bis zur vollständigen Unsichtbarkeit 23 Tage
MITT-03 Kein VVT Kein Verzeichnis der Verarbeitungstätigkeiten (DSGVO Art. 30) Betreiber
MITT-04 SMTP-Anbieter unbekannt Kein AV-Vertrag; E-Mail-Dienstleister nicht dokumentiert Betreiber
MITT-05 sessionStorage nicht bei Logout bereinigt TrainingCoachPage-Fortschritt bleibt nach Logout im sessionStorage 0,5 Tage
MITT-06 Keine Löschung aus Backups DSGVO-Löschungsanfragen greifen nicht auf Backups Betreiber (Policy)
MITT-07 MediaWiki-Integration ohne AV-Vertrag Datentransfer zu karatetrainer.net nicht dokumentiert Betreiber
MITT-08 OpenRouter ohne AV-Vertrag Erst aktivieren wenn AV-Vertrag vorhanden Betreiber

NIEDRIG

ID Titel Beschreibung Aufwand
NIED-01 style-src 'unsafe-inline' Inline-Styles in CSP erlaubt Nonce/Hash
NIED-02 Kein Anti-Virus-Scan Malware-Dateien hochladbar ClamAV-Integration
NIED-03 Reset-Token in sessions-Tabelle Token mit reset_-Präfix in Auth-Tabelle Separate Tabelle
NIED-04 SHA256-Hash in API-Response Datei-Fingerprinting möglich Response-Filterung
NIED-05 Kein Passwort-Complexity-Check Nur Mindestlänge geprüft zxcvbn o.ä.
NIED-06 minLength="6" im Login-Formular Inkonsistent mit Backend (8 Zeichen); Browser lässt 6-7-char-Passwörter zu, Backend lehnt sie dann ab frontend/src/pages/LoginPage.jsx:175
NIED-07 Hartcodierter Versionsstring auf Login-Seite v0.1.0 • Development sichtbar ohne Auth; falsche Version (0.8.65) + Umgebungsinfo frontend/src/pages/LoginPage.jsx:242
NIED-08 CORS allow_methods/headers=["*"] Breiter als nötig; Origins sind korrekt eingeschränkt, aber Methoden/Header nicht backend/main.py:84-87
NIED-09 Kein genereller HTML-Sanitizer für Rich-Text exercise_rich_text.py bereinigt nur Inline-Media-Markup; beliebiges HTML in summary, goal, execution etc. möglich (CSP schützt gegen Script-Execution) backend/exercise_rich_text.py

17. Umsetzungsplan

Empfohlene Reihenfolge

Etappe 1 Pflicht vor öffentlichem Betrieb (Kritische Blocker)

Paket-ID Titel Findings Aufwand
P-01 Rechtstexte (Seiten + Routen, Inhalte durch Rechtsanwalt) KRIT-01 25 Tage Technik
P-02 Self-Service-Kontolöschung + Datenexport KRIT-02, KRIT-05 58 Tage
P-03 Papierkorb-Retention-Job aktivieren KRIT-07 1 Tag
P-04 Copyright-Pflicht für Archiv-Promotion vereinheitlichen KRIT-06 1 Tag
P-05 Passwort-Mindestlänge angleichen MITT-01 30 Min
P-06 Upload-Einwilligungsdialog (Personen, Minderjährige, Rechte) KRIT-04 24 Tage

Etappe 2 Sicherheit und Datenschutz (dringend empfohlen)

Paket-ID Titel Findings Aufwand
P-07 ALLOW_PUBLIC_MEDIA_STATIC dokumentieren + Test HOCH-01, SEC-05 0,5 Tage
P-08 HSTS und externe Proxy-Sicherheit dokumentieren HOCH-02, SEC-01 0,5 Tage
P-09 Admin-Audit-Log HOCH-05, SEC-07 35 Tage
P-10 Mindestalter-Abfrage HOCH-06 12 Tage
P-11 Legal-Hold Lifecycle-Status MITT-02 23 Tage
P-12 sessionStorage bei Logout bereinigen MITT-05 0,5 Tage
P-22 HTML-Sanitizer für Rich-Text-Felder (bleach/nh3) NIED-09, SEC-11 12 Tage
P-23 LoginPage: minLength angleichen + Version entfernen NIED-06, NIED-07, SEC-12, SEC-13 1 Stunde
P-24 CORS einschränken (Methoden + Header) NIED-08, SEC-14 1 Stunde

Etappe 3 DSA-Meldeverfahren (mittelfristig, nach juristischer Klärung)

Paket-ID Titel Findings Aufwand
P-13 Content-Melde-Backend (content_reports-Tabelle + Endpoints) KRIT-03 58 Tage
P-14 Moderations-UI (Frontend) KRIT-03 35 Tage
P-15 Uploader-Benachrichtigung bei Sperrung KRIT-03 12 Tage
P-16 Beschwerdeverfahren KRIT-03 24 Tage

Etappe 4 Langfristige Optimierungen

Paket-ID Titel Aufwand
P-17 MFA für Superadmins (TOTP) 58 Tage
P-18 HttpOnly-Cookie als Auth-Alternative 35 Tage
P-19 Anti-Virus-Scan (ClamAV) 35 Tage
P-20 VVT erstellen Betreiber
P-21 AV-Verträge abschließen Betreiber

Technische Änderung Backend: In backend/routers/media_assets.py, Funktionen patch_media_asset() und bulk_media_patch():

  • Bei Visibility-Wechsel zu club oder official: copyright_notice muss vorhanden und min. 3 Zeichen lang sein
  • Fehler: HTTP 422 mit klarer Fehlermeldung

Test: Promotion ohne copyright_notice → HTTP 422; mit copyright_notice → OK


P-05 im Detail: Passwort-Mindestlänge angleichen

Technische Änderung:

  • backend/routers/auth.py:104: if len(new_pin) < 8: statt < 4
  • Fehlermeldung: „Passwort muss mindestens 8 Zeichen lang haben"

P-13 im Detail: Content-Melde-Backend

Neue DB-Migration (backend/migrations/047_content_reports.sql):

CREATE TABLE content_reports (
    id SERIAL PRIMARY KEY,
    reporter_profile_id INTEGER REFERENCES profiles(id) ON DELETE SET NULL,
    target_type VARCHAR(20) NOT NULL CHECK (target_type IN ('exercise', 'media_asset')),
    target_id INTEGER NOT NULL,
    reason VARCHAR(50) NOT NULL
        CHECK (reason IN ('illegal_content', 'copyright', 'personal_rights',
                          'minor_protection', 'hate_speech', 'spam', 'other')),
    description TEXT,
    status VARCHAR(20) NOT NULL DEFAULT 'pending'
        CHECK (status IN ('pending', 'under_review', 'resolved_removed',
                          'resolved_kept', 'rejected')),
    moderator_profile_id INTEGER REFERENCES profiles(id) ON DELETE SET NULL,
    moderator_note TEXT,
    resolved_at TIMESTAMP,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

Neue Endpoints:

  • POST /api/reports Meldung einreichen (require_auth)
  • GET /api/admin/reports Moderations-Queue (Admin/Superadmin)
  • PATCH /api/admin/reports/{id} Status setzen + Notiz

18. Dauerhafter Auditplan

18.1 Audit-Frequenzen

Typ Frequenz
Mini-Audit Bei jedem PR mit Compliance-Relevanz
Release-Audit Vor jedem Produktions-Deployment
Quartalsaudit Alle 3 Monate
Jahresaudit Einmal jährlich (mit Rechtsanwalt/Datenschutzbeauftragtem)

18.2 Sonderaudit-Auslöser

  • Neue öffentlich sichtbare Features
  • Neue Upload-Funktionen (Medientypen, Quellen)
  • Neue Rollen oder Rechteänderungen
  • Neue externe Dienstleister
  • Einführung von Analytics oder Tracking
  • Änderungen am Minderjährigenschutz
  • Sicherheitsvorfall oder Datenpanne
  • Datenschutzanfrage eines Nutzers
  • Meldung rechtswidriger Inhalte
  • Größere Architekturänderungen
  • Gesetzesänderungen (DSGVO, DSA, TDDDG)

18.3 Checkliste: Mini-Audit bei Feature-PR

[ ] Betrifft der PR personenbezogene Daten? → DSGVO-Check
[ ] Betrifft der PR Medienupload oder -anzeige? → Rechte-Check + DSA-Check
[ ] Betrifft der PR Rollen oder Sichtbarkeit? → Access-Layer-Check
[ ] Betrifft der PR Storage oder Caching? → TDDDG-Check
[ ] Betrifft der PR externe Dienste? → AV-Vertrag prüfen
[ ] Betrifft der PR Auth oder Session? → Sicherheits-Check
[ ] Neuer Endpoint → require_auth / get_tenant_context vorhanden?
[ ] Neue Datenspalte → Migration + Lösch-Cascade korrekt?
[ ] Neue Frontend-Speicherung → TDDDG-Klassifikation dokumentiert?
[ ] ACCESS_LAYER: python backend/scripts/check_access_layer_hints.py

18.4 Checkliste: Release-Audit

[ ] Versions-Bump (backend/version.py + frontend/src/version.js)
[ ] ALLOW_PUBLIC_MEDIA_STATIC nicht in Prod-Env gesetzt
[ ] OpenAPI/Swagger nicht öffentlich (ENVIRONMENT=production)
[ ] HSTS am externen Reverse-Proxy konfiguriert (manuell prüfen)
[ ] Papierkorb-Retention-Job läuft (Logs prüfen)
[ ] SSL-Zertifikat gültig
[ ] DB-Backup der letzten 24h vorhanden
[ ] Rechtstexte aktuell (kein Placeholder, kein veraltetes Datum)
[ ] pytest -m "not slow" grün
[ ] ACCESS_LAYER_INTEGRATION=1 pytest tests/test_access_layer_integration.py grün
[ ] test_security_release.py grün
[ ] pip-audit (keine kritischen CVEs)
[ ] npm audit --audit-level=high (keine kritischen CVEs)

18.5 Checkliste: Neues Feature

[ ] Verarbeitet das Feature personenbezogene Daten? → VVT aktualisieren
[ ] Neue DB-Tabellen → Lösch-Cascade und Retention definiert?
[ ] Neue API-Endpoints → Access Layer korrekt?
[ ] Feature mit UGC? → DSA-Meldeverfahren abgedeckt?
[ ] Feature mit Medien? → Lifecycle, Sichtbarkeit, Copyright?
[ ] Feature für Minderjährige relevant? → Schutzmaßnahmen?
[ ] Neue localStorage/sessionStorage-Nutzung → TDDDG + Datenschutzerklärung?
[ ] Neue externe Abhängigkeit → AV-Vertrag?
[ ] Keine sensitiven Daten in Fehlerausgaben?
[ ] api.js für alle Frontend API-Calls?
[ ] Tests geschrieben und grün?

18.6 Checkliste: Änderung am Medienmodell

[ ] Neue Medientypen → MIME-Type-Validierung aktualisiert?
[ ] Neue Sichtbarkeitsstufen → library_content_visibility_sql() aktualisiert?
[ ] Lifecycle-Änderungen → Papierkorb-Job angepasst?
[ ] Copyright-Anforderungen konsistent für alle Promotions-Wege?
[ ] ALLOW_PUBLIC_MEDIA_STATIC explizit: In Prod verboten (dokumentiert)?
[ ] Neue Download-Endpoints → require_auth_flexible implementiert?
[ ] Recht-am-eigenen-Bild-Abfragen aktualisiert?

18.7 Checkliste: Änderung am Rollenmodell

[ ] Neue Rollen → assert_valid_governance_visibility() berücksichtigt?
[ ] EXEMPT-Liste in check_access_layer_hints.py aktualisiert?
[ ] test_access_layer*.py angepasst?
[ ] MFA-Anforderung für neue Admin-Rollen geprüft?
[ ] Audit-Log für neue Aktionen?

18.8 Pflichttests vor Release

# Zugriffskontrolle
pytest backend/tests/test_access_layer.py -v

# Cross-Tenant-Integration (mit PostgreSQL)
ACCESS_LAYER_INTEGRATION=1 pytest backend/tests/test_access_layer_integration.py -v

# Mediensicherheit
pytest backend/tests/test_exercise_media_download.py -v
pytest backend/tests/test_official_exercise_media_rules.py -v
pytest backend/tests/test_media_assets_archive.py -v
pytest backend/tests/test_club_exercise_media_copyright.py -v

# Sicherheits-Release-Checks
pytest backend/tests/test_security_release.py -v

# Access Layer Script (Strict Mode)
ACCESS_LAYER_STRICT=1 python backend/scripts/check_access_layer_hints.py

# Abhängigkeits-Scan
cd backend && pip-audit
cd frontend && npm audit --audit-level=high

18.9 Vorlage: Quartalsaudit-Bericht

# Compliance-Quartalsaudit Q[X]/[Jahr]

Datum: [DATUM] | Auditor: [NAME]

## 1. Status offener Findings
[Tabelle: ID  Titel  Status]

## 2. Neue Findings dieser Periode
[Tabelle: ID  Titel  Schwere  Aufwand]

## 3. Rechtstexte
[ ] Impressum geprüft: [DATUM]
[ ] Datenschutzerklärung geprüft: [DATUM]
[ ] AGB/Nutzungsbedingungen geprüft: [DATUM]
[ ] Medienrichtlinie geprüft: [DATUM]

## 4. DSGVO-Status
[ ] VVT aktuell
[ ] AV-Verträge vollständig
[ ] Backup-Retention-Policy dokumentiert
[ ] Betroffenenrechte-Mechanismen getestet

## 5. DSA-Status
[ ] Meldeverfahren Test-Meldung durchgeführt: [DATUM]
[ ] Offene Meldungen: [X] (alle bearbeitet: Ja/Nein)
[ ] Eskalationspfad dokumentiert: Ja/Nein

## 6. Technische Sicherheit
[ ] Abhängigkeits-Scan: [DATUM]  Kritische CVEs: [X]
[ ] SSL gültig bis: [DATUM]
[ ] HSTS konfiguriert: Ja/Nein
[ ] Alle Pflichttests grün: Ja/Nein

## 7. Empfehlungen
[Liste]

19. Entscheidungsvorlage

19.1 Was ist aktuell kritisch?

  1. Keine Rechtstexte App ist öffentlich ohne Impressum (Ordnungswidrigkeit)
  2. Kein Löschrecht für Nutzer DSGVO Art. 17 verletzt
  3. Kein DSA-Meldeverfahren bei UGC-Plattform möglicherweise Pflicht
  4. Copyright-Lücke Archiv-Upload ohne Copyright-Pflicht bei Promotion
  5. Kein Recht-am-eigenen-Bild-Check bei Upload

19.2 Was blockiert sicheren öffentlichen Betrieb (technisch)?

  1. KRIT-01: Rechtstexte fehlen vollständig
  2. KRIT-02: Kein Self-Service-Löschrecht
  3. KRIT-07: Papierkorb-Job läuft nicht automatisch
  4. HOCH-01: ALLOW_PUBLIC_MEDIA_STATIC muss in Prod-Doku explizit verboten sein
  5. HOCH-02: HSTS am externen Reverse-Proxy überprüfen

19.3 Mindest-Paket vor erstem öffentlichem Betrieb

  • P-05 (30 Min): Passwort-Mindestlänge angleichen
  • P-04 (1 Tag): Copyright-Pflicht vereinheitlichen
  • P-03 (1 Tag): Papierkorb-Job aktivieren
  • P-06 (2 Tage): Upload-Einwilligungsdialog
  • P-01 (2 Tage Technik + Rechtsanwalt): Rechtstexte-Seiten
  • P-02 (5 Tage): Self-Service-Kontolöschung

19.4 Was kann zurückgestellt werden?

  • P-17 (HttpOnly-Cookie): Größere Architekturänderung, kein unmittelbarer Compliance-Bedarf
  • P-19 (Anti-Virus-Scan): Hoher Aufwand, Risiko bei lokalem Storage gering
  • P-13 bis P-16 (DSA-Meldeverfahren): Erst juristisch klären ob und in welchem Umfang erforderlich

19.5 Juristisch zu prüfende Fragen

Thema Frage
DSGVO Art. 17 Wie muss Löschung aus Backups gehandhabt werden?
DSA Ab welcher Nutzerzahl gilt der DSA? Welche Pflichten für Kleinplattformen?
§22 KUG Welche Einwilligungen für Personenbilder im Vereinskontext?
§8 DSGVO Mindestalter für die Registrierung?
TDDDG §25 Muss für localStorage eine Einwilligung eingeholt werden?
Impressum-Pflicht Vollständige Angaben des Verantwortlichen?
AV-Verträge Welche Dienstleister benötigen einen AVV?
MediaWiki Lizenzanforderungen für Übungsinhalte aus karatetrainer.net?

19.6 Organisatorische Aufgaben für den Betreiber

  1. Rechtsanwalt beauftragen (Rechtstexte)
  2. VVT erstellen (DSGVO Art. 30)
  3. AV-Verträge abschließen (SMTP-Anbieter, ggf. MediaWiki)
  4. Backup-Prozess dokumentieren und Restore-Tests durchführen
  5. Moderationsprozess definieren
  6. Notfallkontakt für Datenpannen benennen
  7. HSTS am externen Reverse-Proxy sicherstellen
  8. Papierkorb-Job-Monitoring einrichten

19.7 Verbleibende Risiken nach technischer Umsetzung

  • HSTS liegt außerhalb des Repos (Betreiber-Verantwortung)
  • Backup-Löschung bei DSGVO-Anfragen erfordert manuelle Prozesse
  • Minderjährige können Altersangabe fälschen (kein verlässlicher Online-Altersnachweis)
  • Rechtswidrige Inhalte können zwischen Upload und Moderationsentscheidung sichtbar sein
  • SMTP-Anbieter kann E-Mail-Inhalte verarbeiten

19.8 Freigabe-Formulierungen

Verwende diese exakten Formulierungen zur Freigabe einzelner Pakete:

Paket Freigabe-Formulierung
P-05 „Freigabe zur Umsetzung P-05: Passwort-Mindestlänge angleichen"
P-04 „Freigabe zur Umsetzung P-04: Copyright-Pflicht vereinheitlichen"
P-03 „Freigabe zur Umsetzung P-03: Papierkorb-Retention-Job aktivieren"
P-06 „Freigabe zur Umsetzung P-06: Upload-Einwilligungsdialog"
P-01 „Freigabe zur Umsetzung P-01: Rechtstexte-Seiten technisch anlegen"
P-02 „Freigabe zur Umsetzung P-02: Self-Service-Kontolöschung und Datenexport"
P-09 „Freigabe zur Umsetzung P-09: Admin-Audit-Log"
P-13 „Freigabe zur Umsetzung P-13: Content-Melde-Backend"
Etappe 1 komplett „Freigabe zur Umsetzung Etappe 1"
Etappe 1+2 „Freigabe zur Umsetzung Etappen 1 und 2"

Audit abgeschlossen. Keine Codeänderungen vorgenommen. Umsetzung erst nach ausdrücklicher Freigabe.


20. Regel zur Paket-ID-Stabilität

Ergänzt: 2026-05-10 — Kanonisches Referenzdokument: docs/compliance-package-register.md

20.1 Grundsatz

Paket-IDs (P-01 bis P-24 und alle künftigen) werden nach ihrer ersten Vergabe in diesem Dokument nie wieder umnummeriert, gelöscht oder wiederverwendet. Die in §17 (Umsetzungsplan) vergebenen IDs sind dauerhaft stabil.

20.2 Regeln im Einzelnen

Regel Beschreibung
ID-Stabilität Eine einmal vergebene Paket-ID bleibt für immer mit dem ursprünglichen fachlichen Inhalt verknüpft.
Titel-Präzisierung erlaubt Der Titel eines Pakets darf präzisiert werden, wenn die fachliche Substanz unverändert bleibt. Die ID ändert sich dabei nicht.
Neue Pakete Künftige Arbeitspakete erhalten aufsteigende neue IDs (P-25, P-26 …). Keine Wiedervergabe von IDs abgeschlossener oder gelöschter Pakete.
Nacharbeiten mit Suffix Nacharbeiten, Korrekturen oder Teilprobleme eines bestehenden Pakets werden mit alphabetischen Suffixen dokumentiert (P-03b, P-05b, …), nicht als eigenständige Hauptpakete.
Freigabe-Formulierung Freigaben müssen immer die Paket-ID und den kanonischen Titel aus diesem Dokument oder aus docs/compliance-package-register.md nennen, um Verwechslungen auszuschließen.
Kanonisches Register docs/compliance-package-register.md ist die verbindliche Quelle für alle Umsetzungsberichte, Re-Audit-Dokumente und Freigaben. Bei Widerspruch zwischen Dokumenten gilt dieses Audit als ursprüngliche Quelle; das Register als aktuell gepflegte Wahrheit.

20.3 Umgang mit Drift in nachgelagerten Dokumenten

Falls ein nachgelagertes Dokument (Umsetzungsbericht, Re-Audit, Mini-Fix) eine abweichende Beschreibung für eine bekannte ID verwendet, gilt:

  1. Die abweichende Beschreibung ist ein Dokumentationsfehler, kein neues Paket.
  2. Das betroffene Dokument ist auf die kanonische ID und den kanonischen Titel zu korrigieren.
  3. Der Drift und die Korrektur sind im Konsistenzbericht des Paketregisters zu vermerken.
  4. Kein fachlicher Inhalt darf bei der Korrektur verloren gehen — er wird ggf. dem richtigen Paket-Eintrag zugeordnet.

20.4 Freigabe-Vorlagen (aktualisiert)

Verwende diese exakten Formulierungen zur Freigabe einzelner Pakete:

Paket Freigabe-Formulierung
P-01 „Freigabe zur Umsetzung P-01: Rechtstexte"
P-02 „Freigabe zur Umsetzung P-02: Self-Service-Kontolöschung und Datenexport"
P-03 „Freigabe zur Umsetzung P-03: Papierkorb-Retention-Job aktivieren"
P-04 „Freigabe zur Umsetzung P-04: Copyright-Pflicht für Archiv-Promotion vereinheitlichen"
P-05 „Freigabe zur Umsetzung P-05: Passwort-Mindestlänge angleichen"
P-06 „Freigabe zur Umsetzung P-06: Upload-Einwilligungsdialog"
P-07 „Freigabe zur Umsetzung P-07: ALLOW_PUBLIC_MEDIA_STATIC dokumentieren und testen"
P-08 „Freigabe zur Umsetzung P-08: HSTS und externe Proxy-Sicherheit dokumentieren"
P-09 „Freigabe zur Umsetzung P-09: Admin-Audit-Log"
P-10 „Freigabe zur Umsetzung P-10: Mindestalter-Abfrage"
P-11 „Freigabe zur Umsetzung P-11: Legal-Hold Lifecycle-Status"
P-12 „Freigabe zur Umsetzung P-12: sessionStorage bei Logout bereinigen"
P-13 „Freigabe zur Umsetzung P-13: Content-Melde-Backend"
P-17 „Freigabe zur Umsetzung P-17: MFA für Superadmins"
P-18 „Freigabe zur Umsetzung P-18: HttpOnly-Cookie als Auth-Alternative"
P-22 „Freigabe zur Umsetzung P-22: HTML-Sanitizer für Rich-Text-Felder"
Etappe 1 komplett „Freigabe zur Umsetzung Etappe 1"
Etappe 1+2 „Freigabe zur Umsetzung Etappen 1 und 2"

Die ursprüngliche Freigabe-Tabelle in §19.8 bleibt erhalten und zeigt den Stand des Initial-Audits. §20.4 ist die aktuellere, vollständigere Version.


Dokument erstellt: 2026-05-09 | Auditor: Claude Code | Kein Rechtsanwalt; alle rechtlichen Einschätzungen sind juristisch zu prüfen.