feat(meldungen): Benachrichtigungen per Mail und Webhook (#54)
Ein zugewiesener Lauf fiel bisher nur auf, wenn jemand die Uebersicht oeffnete; ein ueberfaelliger ueberhaupt nicht. Vier Anlaesse gehen jetzt hinaus — zugewiesen, ueberfaellig, abgeschlossen und Verzeichnisabgleich fehlgeschlagen —, je Person abschaltbar. Niemand bekommt Post ueber die eigene Tat: das ist der haeufigste Grund, Benachrichtigungen ganz abzuschalten, und deshalb faellt der Handelnde immer aus der Empfaengerliste. Eingereiht wird im Anfrage-Pfad, gesendet wird es nicht. Ein haengender Mailserver darf kein Abhaken blockieren, also schreibt der Dienst eine Zeile in `Zustellung` und ein eigener Zeitplan schickt sie. Betreff und Rumpf stehen fertig darin: eine Meldung sagt, was *damals* war. In keiner Nachricht steht ein Schrittinhalt, und damit auch kein erzeugtes Passwort. Darueber wacht src/lib/meldungen.ts — die Funktionen dort nehmen nur Kopfdaten, der Typ laesst nichts anderes zu. Geprueft wird es zusaetzlich ueber alle Rumpftexte, die wirklich verschickt wurden, so wie #012 es fuer die Druckansicht tat. Zwei Dinge haetten ohne Datenbank nicht gehalten. Die Einmaligkeit der Ueberfaelligkeitsmeldung liegt in einem partiellen eindeutigen Index: der Zeitplan sieht jede Minute nach, und ohne ihn bekaeme der Zustaendige fuer einen Lauf, der ueber das Wochenende steht, 2880 Mails — jede fuer sich korrekt, kein Test rot. Und die Sperre der Warteschlange liegt in derselben Tabelle wie die des Abgleichs, denn hinter einem Lastverteiler laufen zwei Instanzen. Eine stille Warteschlange ist schlimmer als keine: Verwaltung → Zustellungen zeigt mit Grund, was hinausging und was nicht. Geprueft gegen einen echten SMTP-Faenger (mailpit) statt gegen eine abgefangene Funktion — und `mailpit` gehoert damit ins Tor vor dem Commit, sonst ueberspringt die Suite 3 Tests und sieht gruen aus. Closes #54 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1be73b266c
commit
a417426f43
@@ -232,6 +232,39 @@ versucht es nicht wieder, und der Client fällt von sich aus auf Polling zurück
|
||||
Sonderfall und keinen eigenen Fehlercode.
|
||||
Die Hülle unter `src/app/(app)/layout.tsx` deckt `src/app/api/` nicht ab.
|
||||
|
||||
### Warum die Benachrichtigungen in einer Warteschlange liegen
|
||||
|
||||
Vier Anlässe gehen seit #034 hinaus: zugewiesen, überfällig, abgeschlossen, Abgleich fehlgeschlagen.
|
||||
Drei Entscheidungen prägen das.
|
||||
|
||||
**Eingereiht wird im Anfrage-Pfad, gesendet wird es nicht.** Ein hängender Mailserver darf kein
|
||||
Abhaken blockieren. Der Dienst schreibt eine Zeile in `Zustellung` — eine Einfügung in dieselbe
|
||||
Datenbank, die der Vorgang ohnehin anfasst —, und ein Zeitplan im selben Prozess schickt sie. Das
|
||||
Einreihen passiert **nach** der Transaktion und mit abgefangenem Fehler: ein Abhaken darf nicht
|
||||
daran scheitern, dass eine Benachrichtigung nicht eingereiht werden konnte.
|
||||
|
||||
**Betreff und Rumpf stehen fertig in der Zeile.** Das kostet Platz und ist es wert: eine Meldung
|
||||
sagt, was *damals* war. Baute der Zeitplan den Text erst beim Senden, stünde in einer Mail von heute
|
||||
der Stand von jetzt — und in einer aufgegebenen Zustellung von nächster Woche etwas völlig anderes.
|
||||
|
||||
**In keiner Meldung steht ein Schrittinhalt.** Darüber wacht `src/lib/meldungen.ts`: die Funktionen
|
||||
dort nehmen **nur** Kopfdaten, der Typ lässt nichts anderes zu. Eine Mail mit dem Lauf-Inhalt wäre
|
||||
genau die Lücke, die dieses Projekt an jeder anderen Stelle geschlossen hat — das erzeugte Passwort
|
||||
wird nirgends gespeichert, aber eine Mail liegt für immer in einem Postfach, oft auf einem Server,
|
||||
der nicht im Haus steht. `tests/benachrichtigungen.test.ts` prüft es zusätzlich über **alle**
|
||||
Rumpftexte, die wirklich verschickt wurden, so wie #012 es für die Druckansicht tat.
|
||||
|
||||
Zwei Dinge, die ohne Datenbank nicht gehalten hätten. Die **Einmaligkeit der
|
||||
Überfälligkeitsmeldung** liegt in einem partiellen eindeutigen Index: der Zeitplan sieht jede Minute
|
||||
nach, und ohne ihn bekäme der Zuständige für einen Lauf, der über das Wochenende steht, 2880 Mails —
|
||||
jede davon für sich korrekt, kein Test rot. Und die **Sperre** der Warteschlange liegt in derselben
|
||||
Tabelle wie die des Abgleichs: hinter einem Lastverteiler laufen zwei Instanzen, und ein `let laeuft
|
||||
= false` im Modul wüsste nichts von der zweiten.
|
||||
|
||||
**Das Polling-Prinzip gilt auch hier nicht umgekehrt:** ein Kommentar und ein angehängtes Foto lösen
|
||||
*keine* Mail aus. Beides sieht die Live-Aktualisierung sofort (Abschnitt 5d); eine Mail dafür wäre
|
||||
Lärm. Mehr Anlässe wären ein Benachrichtigungsbaukasten, und der ist eine Phase für sich.
|
||||
|
||||
## 5e. Der Aufkleber ist die Schnittstelle
|
||||
|
||||
Jedes Objekt traegt einen QR-Aufkleber mit einem `tagCode`, der **nie geaendert
|
||||
|
||||
Reference in New Issue
Block a user