Skip to content

Shooting Data Consent Go-Live Runbook

Dieses Runbook beschreibt den betrieblichen Wechsel fuer die Schiessdaten-Freigabe in der Hauptapp. Es deckt Backfill, Go-Live-Verifikation und den Support-Pfad fuer blockierte Nutzer ab.

Wichtig:

  • Die Consent-Logik blockiert Anzeige und verwaltete Sichten, nicht den technischen Ingest.
  • Altbestand darf nicht implizit freigeschaltet werden.
  • Minderjaehrige unter 16 duerfen nicht per Self-Consent freigeschaltet werden.

Ziel des Backfills

Fuer bestehende Nutzer mit sportpassId legen wir einen expliziten Consent-Record an, wenn noch keiner existiert.

Sichere Default-Regeln:

  • Erwachsene oder noch nicht sauber klassifizierte Nutzer:
  • status = PENDING
  • subjectType = UNKNOWN
  • blockedReason = backfill_missing_consent
  • verifiziert bekannte Minderjaehrige:
  • status = PARENTAL_CONSENT_REQUIRED
  • subjectType = MINOR
  • blockedReason = backfill_parental_consent_required

Damit bleibt der Bestand fail-closed, bis Nutzer selbst zustimmen oder eine verifizierte Elternfreigabe vorliegt.

Offener Freigabepunkt vor Produktivlauf

Vor dem echten Go-Live muss eine verlaessliche Quelle fuer Minderjaehrigkeit festgelegt sein.

Erlaubte Varianten:

  • Geburtsdatum oder Geburtsjahr aus einem verifizierten Stammdatenpfad
  • eine sportjahresbezogene DSB-Altersklassenzuordnung, wenn sie fuer den jeweiligen Sportbereich belastbar abgeleitet werden kann
  • eine kuratierte Override-Liste fuer den initialen Cutover

Nicht ausreichend:

  • pauschale Vermutungen aus frei interpretierten Wettkampfklassen
  • manuelle Einzelfallannahmen ohne dokumentierte Quelle

Bis diese Quelle final bestaetigt ist, darf der produktive Backfill nur mit einer kuratierten Minor-Override-Liste oder komplett fail-closed auf PENDING/UNKNOWN erfolgen.

Backfill-Skript

Das Backend bringt ein idempotentes Skript fuer den Bestand mit:

cd targetshot/backend
npm run shooting-data-consent:backfill -- --dry-run

Optionen:

  • --dry-run: nur Plan und Zaehler ausgeben
  • --sync-existing: bestehende PENDING/UNKNOWN-Records fuer bekannte Minderjaehrige auf MINOR/PARENTAL_CONSENT_REQUIRED hochstufen
  • --user-id=<id>: auf einen Benutzer eingrenzen
  • --sportpass-id=<id>: auf eine Sportpass-ID eingrenzen
  • --overrides-file=<path>: JSON-Datei mit bekannten Minderjaehrigen

Beispiel fuer eine Override-Datei:

{
  "minorUserIds": [
    "keycloak-user-id-1"
  ],
  "minorSportpassIds": [
    "41301343",
    "41309999"
  ]
}

Dry-Run mit Override-Datei:

cd targetshot/backend
npm run shooting-data-consent:backfill -- \
  --dry-run \
  --overrides-file=./tmp/shooting-data-minors.json

Echter Lauf:

cd targetshot/backend
npm run shooting-data-consent:backfill -- \
  --overrides-file=./tmp/shooting-data-minors.json

Spaeterer Nachlauf nach finaler Altersquellen-Freigabe:

cd targetshot/backend
npm run shooting-data-consent:backfill -- \
  --sync-existing \
  --overrides-file=./tmp/shooting-data-minors.json

Empfohlener Ablauf fuer Staging oder Prod

1. Vorab pruefen

  • DB-Backup oder Snapshot vorhanden
  • aktuelles App-Release mit Consent-Backend und Consent-Frontend ist bereits deployed
  • Support weiss, dass Altbestand ab dem Cutover blockiert sein kann
  • Minor-Quelle oder Override-Datei ist dokumentiert

2. Dry-Run fahren

Erwartung:

  • createCount groesser 0 fuer Nutzer ohne Consent-Record
  • updateCount nur dann groesser 0, wenn bewusst --sync-existing genutzt wird
  • items zeigen fuer bekannte Minderjaehrige PARENTAL_CONSENT_REQUIRED

3. Backfill anwenden

Nur ausfuehren, wenn Dry-Run plausibel ist.

4. Direkt danach verifizieren

  • Consent-Route in der App blockiert Bestand ohne Zustimmung
  • persoenliche Dashboards liefern ohne Freigabe keine sensiblen Schiessdaten
  • Coach-/Club-/Jugendpfade liefern ohne Betroffenen-Freigabe keine sensiblen Daten
  • verifizierte Elternfreigabe entsperrt Minderjaehrige erst nach Link plus Code

Testmatrix fuer Go-Live

Mindestens diese Faelle einmal Ende-zu-Ende pruefen:

Selbstsicht

  • Erwachsener ohne Consent:
  • Login erfolgreich
  • App leitet auf Consent-Seite
  • Dashboard/Reports blockiert
  • Erwachsener mit Self-Consent:
  • persoenliche Schiessdaten sichtbar
  • Profil zeigt GRANTED
  • Erwachsener nach Widerruf:
  • persoenliche Schiessdaten sofort wieder blockiert

Minderjaehrige

  • Minderjaehriger ohne Elternfreigabe:
  • Login erfolgreich
  • Consent-Seite zeigt Elternfreigabe-Pfad
  • keine persoenlichen Schiessdaten sichtbar
  • Minderjaehriger nach Versand der Elternmail:
  • Status PARENTAL_PENDING
  • Mailversand allein schaltet nichts frei
  • Minderjaehriger nach verifizierter Elternfreigabe:
  • Status GRANTED
  • persoenliche Schiessdaten sichtbar

Verwaltete Sichten

  • Coach mit Club-Scope und freigegebenem Betroffenen:
  • Schiessdaten sichtbar
  • Coach mit Club-Scope, aber ohne Freigabe des Betroffenen:
  • consent_required oder guardian_consent_required
  • Jugendtrainer mit Jugendscope:
  • nur freigegebene Jugendschützen sichtbar
  • Clubfremder Zugriff:
  • immer forbidden, unabhaengig vom Consent

Support- und Betriebsleitfaden

Pruefen:

  • existiert ShootingDataConsent fuer den Nutzer?
  • welcher status liegt vor?
  • ist blockedReason plausibel?

Interpretation:

  • PENDING: erwachsener oder noch unklassifizierter Nutzer ohne Zustimmung
  • PARENTAL_CONSENT_REQUIRED: Minderjaehriger, Elternfreigabe noch nicht gestartet
  • PARENTAL_PENDING: Elternfreigabe gestartet, aber noch nicht verifiziert
  • REJECTED: Elternfreigabe explizit abgelehnt
  • REVOKED: frueher freigegeben, danach widerrufen

Fall: Coach sieht einen Schuetzen nicht

Pruefen:

  • Rolle und Club-Scope korrekt?
  • hat der Betroffene GRANTED?
  • falls minderjaehrig: wurde Elternfreigabe wirklich verifiziert?

Fall: Elternfreigabe-Mail kam nicht an

Pruefen:

  • Mailversandfehler im Backend-Log
  • guardian_delivery_failed oder guardian_verification_pending im Blockgrund
  • Guardian-Adresse im Consent-Record korrekt

Fall: Widerruf rueckgaengig machen

  • kein stilles Admin-Override im DB-Feld
  • Betroffener muss erneut zustimmen
  • fuer Minderjaehrige erneut ueber den verifizierten Elternpfad gehen

Operator-Notizen fuer den ersten Produktivlauf

  • Den ersten Lauf mit Dry-Run-JSON archivieren.
  • Nach dem Apply die Summenzaehler ebenfalls sichern.
  • Minor-Override-Datei als kontrolliertes Betriebsartefakt behandeln, nicht lose per Chat weiterreichen.
  • Wenn die verlaessliche Altersquelle spaeter feststeht, den Nachlauf mit --sync-existing explizit dokumentieren.

Falsche Minderjährigkeits-Einstufung korrigieren

Seit dem Eltern-Gate entsteht eine MINOR-Einstufung auch aus dem Geburtsdatum der Vereinssoftware. Ist dieses Datum falsch, hebt der Verein die Einstufung selbst auf — es gibt dafür keinen stillen Eingriff in der Datenbank.

Voraussetzung: Das Geburtsdatum muss zuerst in der Vereinssoftware korrigiert werden. Die Cloud schreibt es nie selbst; sie liest es. Solange dort ein Datum unter 16 steht, lehnt der Server die Korrektur mit correction_contradicts_birthdate ab — das ist der Riegel dagegen, dass der Elternschutz eines echten Jugendlichen abgeschaltet wird.

Wer: Vereinsadministration und Vorstand (admin, club_leader) für Mitglieder ihres eigenen Vereins. Der Trainer nicht.

Wie: Mitgliederverwaltung → Mitglied öffnen → „Einstufung als minderjährig aufheben". Der Grund ist Pflicht (mindestens 10 Zeichen) und wird im Einwilligungs-Protokoll als Ereignis SUBJECT_TYPE_CORRECTED festgehalten, zusammen mit der handelnden Person, dem Vorher/Nachher und dem Befund der Altersprüfung.

Was dabei passiert:

  • Die Einstufung geht auf UNKNOWN zurück — die Korrektur nimmt eine Behauptung zurück, sie stellt keine neue auf.
  • Der Status geht auf PENDING. Eine zuvor erteilte Eltern-Freigabe wird damit zurückgenommen: sie stammt nicht von der betroffenen Person. Bis zu deren eigener Zustimmung bleiben die Schießdaten zurückgehalten.
  • Offene und erteilte Eltern-Anfragen werden auf INVALIDATED gesetzt. Entwertet heißt nicht gelöscht: Zeitstempel und Kontaktangaben bleiben als Beleg stehen. Ein noch kursierender Bestätigungslink kann die Einstufung danach nicht zurückholen.
  • Die betroffene Person bekommt eine Mitteilung in der App.

Was danach zu tun ist: Die Person meldet sich an und gibt die Schießdaten selbst frei (Profil → Schießdaten-Freigabe). Vorher erscheint sie in Berichten und Ranglisten weiterhin nicht.

Was ausdrücklich nicht geht:

  • Ein Widerruf (REVOKED) wird nicht angetastet (revoked_consent_not_correctable). Daran hängt der physische Löschlauf, und ob ein unter falscher Einstufung erklärter Widerruf aufhebbar ist, ist eine Rechtsfrage.
  • Ist die Person gar nicht als minderjährig eingestuft, passiert nichts (subject_type_not_minor) — ein zweiter Klick ist folgenlos.
  • Lässt sich das Geburtsdatum gerade nicht prüfen, wird nicht korrigiert (correction_check_unavailable, HTTP 503). Erneut versuchen.

Hinweis zur Automatik: Eine Zeile in PENDING × UNKNOWN darf der Einwilligungs-Backfill neu einstufen. Taucht später doch ein belegbar minderjähriges Geburtsdatum auf, kommt der Elternschutz also zurück — das ist gewollt und der Grund, warum die Korrektur nicht auf ADULT stellt.

Nach einer Korrektur: wie der Eltern-Weg wieder aufgeht

Eine Korrektur ist eine begründete, protokollierte Entscheidung. Sie lässt sich zurücknehmen — aber auf derselben Stufe, auf der sie getroffen wurde:

Aufheben (Korrektur) Wieder öffnen
Rolle Administration, Vorstand Administration, Vorstand
Begründung Pflicht Pflicht
Protokoll SUBJECT_TYPE_CORRECTED Ereignis der Eltern-Anfrage

Konkret: Nach einer Korrektur überspringen Einladung und „Elternanfrage erneut senden" den Eltern-Weg, wenn die auslösende Person nur Trainerin ist (guardianConsent.reason = subject_type_corrected) oder keine Begründung mitgibt (…_reason_required). Vorstand und Administration öffnen ihn mit Begründung wieder; der Trainer-Klick allein genügt nicht mehr.

Warum nicht gesperrt? Weil eine Sperre eine Fehlbedienung unreparierbar machte: eine zweite Korrektur ist ausgeschlossen (der Dienst arbeitet nur auf MINOR-Zeilen), und eine wirklich minderjährige Person ohne Geburtsdatum in der Vereinssoftware hätte dann gar keinen Eltern-Weg mehr. Das Missverhältnis lag nie im Weg selbst, sondern in der Hürde.

Warum nicht an das Geburtsdatum geknüpft? Weil die Bedingung zirkulär wäre: die Korrektur gelingt nur, wenn das Geburtsdatum nicht minderjährig sagt — dieselbe Quelle könnte danach nie das Gegenteil belegen, ohne dass sich die Stammdaten ändern. Aus einer Bedingung wäre eine Dauersperre geworden.

Störfall: Lässt sich nicht feststellen, ob eine Korrektur vorliegt, wird der Eltern-Weg NICHT ausgelöst (guardian_gate_check_unavailable). Der Vorgang ist wiederholbar; geschrieben wurde nichts.

Der Einwilligungs-Backfill (--sync-existing) hebt eine Korrektur nicht mehr auf: eine Zeile mit Korrektur-Vermerk wird übersprungen, auch wenn eine Minderjährigen-Override-Liste sie nennt. Vorher traf seine Vorbedingung (PENDING × UNKNOWN) genau den Zustand, den die Korrektur hinterlässt.