Files
trainingstagebuch/docs/benachrichtigungskonzept.md
2026-08-14 09:47:59 +02:00

14 KiB
Raw Blame History

Benachrichtigungssystem Konzept

Zielbild

Nutzer sollen relevante Vorgänge rechtzeitig sehen, ohne mit Meldungen überflutet zu werden. Jede Benachrichtigung ist einer konkreten Aufgabe oder Information zugeordnet und führt mit einem Klick direkt dorthin. Das System unterscheidet zwischen Vereinsverwaltung, Trainerbereich und Mitgliedern, respektiert Rollen und persönliche Einstellungen und bleibt auch dann zuverlässig, wenn jemand gerade nicht angemeldet ist.

Die zentrale Produktentscheidung lautet: Der Posteingang in der Anwendung ist die verlässliche Quelle; Live-Hinweise, E-Mail und später Push sind nur zusätzliche Zustellwege. Dadurch gehen Informationen nicht verloren, auch wenn ein Browser geschlossen ist oder ein Versand fehlschlägt.

Nutzergruppen und Grundregeln

Nutzergruppe Erhält Benachrichtigungen zu Darf nicht sehen
Vereinsverwaltung Vorgängen in ihren berechtigten Modulen, z. B. Anfragen, Freigaben, Aufgaben, Zahlungen Inhalte ohne Modulberechtigung oder außerhalb ihres Vereins
Trainer Eigene Trainings- und Mannschaftsprozesse, (Q)TTR-Änderungen relevanter Spieler sowie Freundschaftsspiel-Anfragen Verwaltungs- oder Mitgliedsdaten außerhalb der eigenen Berechtigung bzw. Zuordnung
Mitglied Eigenen Terminen, Nachrichten, Profilanfragen und Mitgliedschaftsthemen Daten anderer Mitglieder, interne Verwaltungsnotizen
Systemadministrator Technischen oder übergreifenden Systemereignissen Vereinsinhalte ohne expliziten Support-/Berechtigungsprozess

Empfänger werden immer auf dem Server bestimmt. Der Client erhält nur bereits autorisierte Einträge. Eine Rolle ist kein pauschaler Verteiler: Eine neue Probetrainingsanfrage geht beispielsweise an Nutzer mit requests:read oder eine künftig konfigurierbare zuständige Rolle, nicht automatisch an alle Vereinsnutzer.

Ereigniskatalog für die erste Ausbaustufe

Ereignis Empfänger Priorität Standardkanal Ziel
Neue Kontakt-, Probe-, Mitgliedschafts- oder Sponsoringanfrage Zuständige Nutzer für Anfragen hoch Posteingang, Live-Hinweis, E-Mail Anfrage öffnen
Neue oder fällige Aufgabe Zugewiesene Person; bei fehlender Zuweisung verantwortliche Rolle normal / hoch bei Überfälligkeit Posteingang, Live-Hinweis Aufgabe öffnen
Profiländerung beantragt Nutzer mit Berechtigung zur Mitgliederpflege normal Posteingang, Live-Hinweis Änderungsanfrage prüfen
Profiländerung genehmigt/abgelehnt betreffendes Mitglied normal Posteingang, Live-Hinweis Mitgliederbereich
Neue direkte Vereinsnachricht Empfänger-Mitglied normal Posteingang, Live-Hinweis, optional E-Mail Nachricht öffnen
Termin-/Trainingsänderung oder -absage betroffene, angemeldete Mitglieder hoch bei Absage, sonst normal Posteingang, Live-Hinweis, optional E-Mail Termin öffnen
(Q)TTR eines relevanten Spielers hat sich geändert Zugeordnete Trainer bzw. Trainer mit Lesezugriff auf den Spieler normal Posteingang, Live-Hinweis, optional Tagesbündelung Spieler-/Mannschaftsprofil öffnen
Eingehende Anfrage für ein Freundschaftsspiel Zuständige Trainer bzw. Nutzer mit schedule:read im Zielverein hoch Posteingang, Live-Hinweis, optional E-Mail Freundschaftsspiel öffnen
Freundschaftsspiel angenommen, abgelehnt oder wesentlich geändert Ersteller und zuständige Trainer beider Vereine normal / hoch bei kurzfristiger Absage Posteingang, Live-Hinweis Freundschaftsspiel öffnen
Zahlung offen, Mahnstufe oder Zahlungseingang Kasse bzw. betroffenes Mitglied, abhängig vom Vorgang hoch bei Frist/Mahnung Posteingang, optional E-Mail Forderung öffnen
Rolle oder Zugang geändert betroffener Nutzer hoch Posteingang, E-Mail Einstellungen bzw. Verein
Wichtige Produkt-/Sicherheitsinformation gezielte Nutzergruppe kritisch Posteingang, E-Mail; später Push Informationsdetail

Nicht als Benachrichtigung vorgesehen sind reine Lesesichtungen, normale Protokolländerungen und jede kleine Bearbeitung durch andere Personen. Diese gehören in die Historie/Aktivitätsprotokolle. Mehrere gleichartige Ereignisse werden zusammengefasst, etwa: „3 neue Probetrainingsanfragen“.

Prioritäten und Zustellregeln

  • Kritisch: Sicherheits- oder Zugangsereignisse. Nicht stumm schaltbar; zusätzlich E-Mail.
  • Hoch: Frist, neue externe Anfrage, Absage oder überfällige Aufgabe. Sofort im Produkt; E-Mail standardmäßig an.
  • Normal: Handlungsrelevante Information. Sofort im Produkt; E-Mail ist eine persönliche Einstellung.
  • Niedrig: Reine Information. Nur im Posteingang, standardmäßig gebündelt oder deaktiviert.

Sichtbarkeit in Hauptnavigation und Trainerbereich

Die Anwendung zeigt die Glocke mit dem globalen Zähler ungelesener Einträge immer sichtbar im authentifizierten Hauptkopf, unmittelbar neben dem Nutzer-Menü. Sie bleibt damit sichtbar, unabhängig davon, ob der Nutzer gerade die Vereins-, Trainer- oder Mitgliederansicht geöffnet hat. Auf kleinen Bildschirmen bleibt mindestens das Glocken-Icon mit Badge erhalten; der Text kann entfallen.

Ein Klick öffnet einen kompakten Auszug der neuesten Einträge; „Alle anzeigen“ führt zum persönlichen Posteingang. Dieser Posteingang wird nicht als separater, leerer „Trainer-Posteingang“ dupliziert: Er ist ein gemeinsamer persönlicher Eingang mit klaren Filtern bzw. Bereichen Alle, Trainer, Verein und Mitglied. Im Trainerprodukt ist der Filter Trainer voreingestellt und zusätzlich als eigener Navigationspunkt „Posteingang“ in der Hauptnavigation sichtbar. Die Glocke zählt aber stets alle für den angemeldeten Nutzer relevanten ungelesenen Einträge.

Ein neuer Live-Eintrag zeigt einen unaufdringlichen Toast, aber keinen blockierenden Dialog. Ton ist standardmäßig aus.

Ein Eintrag bleibt ungelesen, bis der Nutzer ihn bewusst öffnet oder einzeln/alle als gelesen markiert. Das Öffnen des Dropdowns allein markiert nichts als gelesen. Wird das Zieldokument archiviert oder die Berechtigung entzogen, bleibt der Eintrag als Hinweis erhalten, zeigt aber eine sichere, erklärende Zielseite.

Fachliches Datenmodell

Die Benachrichtigung wird als immutable Ereignis plus nutzerspezifischer Zustellstatus modelliert. Dadurch kann ein Ereignis mehreren Personen zugestellt werden, ohne Inhalte zu duplizieren.

notification_events
  id, club_id?, type, priority, actor_user_id?,
  resource_type, resource_id, title_key, body_key, payload,
  dedupe_key?, created_at, expires_at?

notification_recipients
  id, event_id, user_id, read_at?, archived_at?,
  delivery_state, email_state, email_sent_at?, created_at

notification_preferences
  user_id, club_id?, event_category,
  in_app_enabled, email_enabled, push_enabled, digest_frequency,
  quiet_hours_from?, quiet_hours_to?

payload enthält nur die für Darstellung und Navigation erforderlichen Daten, etwa { "clubId": 12, "requestId": 44, "route": "/club-requests?requestId=44" }. Es enthält keine sensiblen Freitexte, Adressen oder internen Notizen. Titel und Texte werden über Übersetzungsschlüssel erzeugt; das erlaubt Spracheinstellungen und spätere Textanpassungen.

dedupe_key verhindert Doppelungen durch wiederholte Jobs oder parallele Requests, zum Beispiel club:12:request:44:created. Für Sammelmeldungen wird ein kurzer Zeitraum verwendet, etwa zehn Minuten je Verein, Typ und Empfängergruppe.

Regel für (Q)TTR-Änderungen

Ein Import, Sync oder erneuter Abruf erzeugt keine Benachrichtigung allein deshalb, weil er gelaufen ist. Vor dem Speichern vergleicht der Server je Spieler die normalisierten bisherigen und neuen Werte (ttr, qttr) sowie den zugehörigen Stichtag/Stand. Nur wenn mindestens ein fachlicher Wert tatsächlich abweicht, wird genau ein Ereignis erzeugt, z. B. „Max Mustermann: QTTR 1.487 → 1.512“.

Für denselben Spieler und Stichtag verhindert eine eindeutige dedupe_key wie club:12:member:44:qttr:2026-08-11 weitere Meldungen. Trifft ein korrigierter Wert für denselben Stichtag ein, wird der bestehende ungelesene Eintrag aktualisiert statt eine zweite Meldung zu erzeugen. Fehlt der alte Wert oder ist der neue Wert ungültig, wird kein Änderungsalarm versendet; die Änderung bleibt im Importprotokoll nachvollziehbar. Bei vielen Änderungen werden sie pro Trainer und Abruf gebündelt, etwa „12 (Q)TTR-Änderungen in deinen Mannschaften“.

Empfohlene Indizes: (user_id, read_at, created_at DESC) auf notification_recipients, (club_id, created_at DESC) auf notification_events und ein eindeutiger Index auf dedupe_key, soweit gesetzt.

Technische Architektur

  1. Eine fachliche Aktion wird erfolgreich in der Datenbank gespeichert, etwa eine neue Vereinsanfrage.
  2. Im selben Datenbank-Commit erzeugt ein NotificationService das Ereignis und die berechtigten Empfänger. So existiert kein Hinweis auf einen Vorgang, der später zurückgerollt wird.
  3. Nach dem Commit wird ein neutrales Echtzeitereignis an den persönlichen Nutzerraum gesendet, z. B. notification:created mit Empfänger-ID und Zähler. Bestehendes Socket.IO kann dafür erweitert werden.
  4. Der Client lädt den Eintrag über die API nach und aktualisiert Glocke und Posteingang. Bei fehlender Socket-Verbindung wird beim App-Start, beim Tab-Fokus und periodisch moderat abgeglichen.
  5. Ein Hintergrund-Worker verarbeitet E-Mail und später Web-Push anhand der Zustellpräferenzen. Wiederholversuche und Fehler landen in einem Zustellprotokoll.

Die bisherigen Club-Socket-Räume eignen sich für Aktualisierungen gemeinsamer Ansichten, sind aber für persönliche Hinweise nicht ausreichend sicher. Ergänzung: Socket-Authentifizierung mit dem bestehenden Zugangstoken und persönliche Räume wie user:{userId}; der Client darf keine frei wählbaren Nutzer- oder Clubräume betreten.

API-Schnittstellen (Vorschlag)

Methode Endpunkt Zweck
GET /notifications?clubId=&cursor=&unreadOnly= Posteingang paginiert laden
GET /notifications/unread-count?clubId= Zähler für Glocke laden
POST /notifications/:recipientId/read Eintrag als gelesen markieren
POST /notifications/read-all Gefilterte Einträge als gelesen markieren
POST /notifications/:recipientId/archive Persönlich ausblenden/archivieren
GET / PUT /notification-preferences persönliche Kanal- und Kategorieeinstellungen

Es gibt bewusst keinen allgemeinen Client-Endpunkt zum Erzeugen einer Benachrichtigung. Fachliche Endpunkte (Anfrage anlegen, Aufgabe zuweisen, Termin absagen) rufen den serverseitigen Dienst auf. Manuell verfasste Vereinskommunikation bleibt im Kommunikationsmodul und erzeugt für Empfänger ihren passenden Posteingangseintrag.

Datenschutz, Sicherheit und Betrieb

  • Berechtigungen werden beim Erzeugen und beim Abruf bzw. Öffnen der Zielressource geprüft.
  • E-Mails enthalten möglichst keine vertraulichen Daten; sie nennen Anlass und Verein und verlinken nach Anmeldung auf das Ziel.
  • Für E-Mail, Push und Telemetrie werden Einwilligung, Widerruf und Versandzeitpunkt protokolliert. Kritische Sicherheitsmails folgen der erforderlichen Rechtsgrundlage und sind nicht abwählbar.
  • Standardaufbewahrung: gelesene/archivierte Einträge 180 Tage, ungelesene 365 Tage; kritische Sicherheitsereignisse gemäß Sicherheits- und Löschkonzept länger. Die Fristen müssen mit dem finalen Datenschutzkonzept abgestimmt werden.
  • E-Mail-Versand ist asynchron, idempotent und hat begrenzte Wiederholversuche. Ein Versandfehler verändert nie den In-App-Status.

Umsetzung in Stufen

MVP

  • Datenmodell, serverseitiger NotificationService, REST-API und Posteingang mit Glocke.
  • Live-Aktualisierung über authentifizierte persönliche Socket-Räume plus Polling-Fallback.
  • Globale Glocke mit Badge im authentifizierten Hauptkopf und sichtbarer Navigationspunkt „Posteingang“ im Trainerbereich.
  • Ereignisse: neue Vereinsanfragen, zugewiesene/fällige Aufgaben, Profiländerungen, direkte Vereinsnachrichten, tatsächlich geänderte (Q)TTR-Werte sowie eingehende Freundschaftsspiel-Anfragen.
  • Gelesen/ungelesen, Navigation zum Kontext und persönliche In-App-Einstellung.

Ausbaustufe 2

  • E-Mail-Worker mit Vorlagen, Zustellprotokoll, Bündelung und Ruhezeiten.
  • Termin-/Trainingsänderungen, Finanzen, Rollen- und Zugangsmeldungen.
  • Zuständigkeiten je Ereignistyp im Verein konfigurierbar.

Ausbaustufe 3

  • Web-Push/PWA, tägliche oder wöchentliche Zusammenfassungen, Eskalationen bei unbehandelten kritischen Vorgängen.
  • Auswertung: Zustellung, Öffnung, Bearbeitungszeit ausschließlich aggregiert und datensparsam.

Akzeptanzkriterien für das MVP

  • Eine neue Probetrainingsanfrage erscheint für alle zuständigen Nutzer innerhalb weniger Sekunden in Glocke und Posteingang, aber nicht bei Unberechtigten.
  • Im Trainerbereich ist der Posteingang über Hauptnavigation und Glocke ohne Seitenwechsel sichtbar erreichbar; die Glocke zeigt auch dort zuverlässig den ungelesenen Zähler.
  • Ein erneuter (Q)TTR-Import mit identischen Werten erzeugt keinen Eintrag. Ändert sich ein TTR- oder QTTR-Wert, sehen nur berechtigte bzw. zugeordnete Trainer eine nachvollziehbare Meldung mit Alt- und Neuwert.
  • Eine eingehende Freundschaftsspiel-Anfrage wird im Zielverein den zuständigen Trainern zugestellt und führt direkt zur Entscheidung in „Freundschaftsspiele“.
  • Ein Mitglied sieht die Entscheidung über seine Profiländerung und kann direkt zum passenden Bereich navigieren.
  • Nach Ab- und erneutem Anmelden bleiben ungelesene Einträge und der Zähler korrekt erhalten.
  • Bei unterbrochener Echtzeitverbindung werden neue Einträge beim nächsten Abgleich sichtbar.
  • Ein Nutzer kann normale Kategorien abschalten; kritische Sicherheitsinformationen bleiben sichtbar.
  • Ein Empfänger kann keine Benachrichtigung oder Zielressource eines anderen Vereins oder Nutzers über manipulierte IDs abrufen.

Offene Produktentscheidungen

  1. Welche Rollen sind pro Ereignistyp anfänglich zuständig (z. B. Anfragen: Vorstand, Mitgliederverwaltung oder frei konfigurierbar)?
  2. Soll E-Mail bereits im MVP enthalten sein oder erst nach dem belastbaren In-App-Posteingang?
  3. Müssen Mitglieder in der ersten Version individuelle Trainings-/Terminpräferenzen erhalten oder genügt „bei allen für mich relevanten Änderungen“?
  4. Welche Aufbewahrungsfrist wird mit Datenschutz/Vertrag final festgelegt?