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
4aa79c93ff
commit
2d3325ef20
@@ -38,6 +38,7 @@ Der Auftrag nennt englische Modelle. Verbindlich gilt:
|
||||
| DeviceTemplateDefault | `GeraetetypVorlage` | Comment | `Kommentar` |
|
||||
| — (ergänzt) | `AbgleichSperre` | AuditLog | `Protokoll` |
|
||||
| — (ergänzt) | `BenutzerKunde` | — (ergänzt) | `TagCodeVergabe` |
|
||||
| — (ergänzt) | `Zustellung` | | |
|
||||
|
||||
Enums: `Rolle {ADMIN REDAKTEUR TECHNIKER LESER}` · `Betriebsmodus {INTERN DIENSTLEISTUNG}` ·
|
||||
`LaufStatus {OFFEN IN_ARBEIT ABGESCHLOSSEN ARCHIVIERT}` ·
|
||||
@@ -45,7 +46,9 @@ Enums: `Rolle {ADMIN REDAKTEUR TECHNIKER LESER}` · `Betriebsmodus {INTERN DIENS
|
||||
`SchrittTyp {HAKEN TEXT ZAHL AUSWAHL DATUM BEFEHL}` (später `AKTION`) ·
|
||||
`VariablenTyp {TEXT ZAHL AUSWAHL DATUM}` ·
|
||||
`GeraeteTyp {PC NOTEBOOK SERVER FIREWALL SWITCH DRUCKER RAUM SONSTIGES}` ·
|
||||
`VersionStatus {ENTWURF VEROEFFENTLICHT}` · `Herkunft {ABGLEICH MANUELL}`.
|
||||
`VersionStatus {ENTWURF VEROEFFENTLICHT}` · `Herkunft {ABGLEICH MANUELL}` ·
|
||||
`Zustellweg {MAIL WEBHOOK}` · `Zustellzustand {OFFEN GESENDET FEHLGESCHLAGEN AUFGEGEBEN}` ·
|
||||
`Meldeanlass {LAUF_ZUGEWIESEN LAUF_UEBERFAELLIG LAUF_ABGESCHLOSSEN ABGLEICH_FEHLGESCHLAGEN}`.
|
||||
|
||||
`SEED_MODE` akzeptiert `DIENSTLEISTUNG` und `SERVICE` als Alias.
|
||||
|
||||
@@ -98,9 +101,11 @@ Dreizeiler: Recht prüfen, Zod-Schema anwenden, Service rufen.
|
||||
wird. `SchrittTyp` bekommt später `AKTION`, `konfig` und `wert` sind Json, und
|
||||
`Lauf.erstelltVonId` wie `Schrittergebnis.aktualisiertVonId` dürfen leer sein — ein Systemlauf
|
||||
ist darstellbar.
|
||||
- **Regeln stehen in der Datenbank, nicht nur im Service.** Zwölf CHECK-Bedingungen, zwei
|
||||
partielle Eindeutigkeitsindizes und vier zusammengesetzte Fremdschlüssel halten fest, was auch
|
||||
dann gelten muss, wenn jemand an der Service-Schicht vorbei schreibt. Die Mandantengrenze ist
|
||||
- **Regeln stehen in der Datenbank, nicht nur im Service.** CHECK-Bedingungen, partielle
|
||||
Eindeutigkeitsindizes, zusammengesetzte Fremdschlüssel und Trigger halten fest, was auch
|
||||
dann gelten muss, wenn jemand an der Service-Schicht vorbei schreibt.
|
||||
`tests/datenbankregeln.test.ts` zählt sie **namentlich** auf — dort steht die jeweils aktuelle
|
||||
Liste, und genau deshalb steht hier keine Zahl mehr: sie lief dreimal der Wirklichkeit nach. Die Mandantengrenze ist
|
||||
einer davon: ein Lauf kann strukturell kein Gerät, keine Person und keine Abteilung eines
|
||||
fremden Kunden wählen. Der Service prüft dasselbe noch einmal, nur mit besserer Meldung.
|
||||
|
||||
@@ -122,6 +127,12 @@ Zwei Obergrenzen, die nicht angehoben werden dürfen:
|
||||
Build-Skripte von Abhängigkeiten sind in `pnpm-workspace.yaml` unter `allowBuilds` freigegeben
|
||||
(pnpm 12 liest das `pnpm`-Feld in `package.json` nicht mehr).
|
||||
|
||||
**`minimumReleaseAgeExclude` bleibt leer.** pnpm 12 nimmt Pakete erst nach einer Wartezeit an — ein
|
||||
Schutz gegen ein kompromittiertes Release, das Stunden später zurückgezogen wird. Trägt `pnpm add`
|
||||
dort von sich aus eine Ausnahme ein, ist das kein Formfehler, sondern die Meldung „diese Version ist
|
||||
frisch von heute“. Dann gehört **eine abgelagerte Version** gepinnt, nicht die Ausnahme committet.
|
||||
`nodemailer` steht deshalb exakt auf `10.0.10` und nicht auf der neuesten Fassung (#034).
|
||||
|
||||
## Next 16
|
||||
|
||||
`middleware.ts` heißt **`proxy.ts`** und exportiert `proxy()`, Node-Laufzeit. `cookies()`,
|
||||
@@ -177,15 +188,21 @@ speichern, neu laden, und nachsehen, ob es wirklich in der Datenbank steht.
|
||||
## Vor jedem Commit
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.test.yml up -d --wait ldap
|
||||
docker compose -f docker-compose.test.yml up -d --wait ldap mailpit
|
||||
pnpm lint && pnpm typecheck && pnpm format:pruefen && pnpm test && pnpm pruefe:doku
|
||||
```
|
||||
|
||||
**Der LDAP-Container gehört in die erste Zeile.** Ohne ihn überspringt die Suite **22 Tests** — den
|
||||
ganzen Verzeichnis-Abgleich (nachgezählt: 81 statt 59 in `tests/abgleich.test.ts` und
|
||||
`tests/verzeichnis.test.ts`). Sie sagt das auf stderr, aber der Lauf sieht grün aus, und wer nur
|
||||
diesem Abschnitt folgte, hat den Abgleich nie geprüft. In CI bricht sie stattdessen ab, absichtlich.
|
||||
Aufgefallen bei der Abnahme zu #019.
|
||||
**Die beiden Container gehören in die erste Zeile.** Ohne sie überspringt die Suite Tests, sagt das
|
||||
auf stderr — und sieht trotzdem grün aus. Wer nur diesem Abschnitt folgte, hätte das Betroffene nie
|
||||
geprüft. In CI bricht sie stattdessen ab, absichtlich.
|
||||
|
||||
| Container | Fehlt er, fehlen | Betroffen |
|
||||
|---|---|---|
|
||||
| `ldap` | **22 Tests** (nachgezählt: 81 statt 59) | der ganze Verzeichnis-Abgleich, `tests/abgleich.test.ts` und `tests/verzeichnis.test.ts` |
|
||||
| `mailpit` | **3 Tests** (nachgezählt: 36 statt 33) | der echte SMTP-Versand in `tests/benachrichtigungen.test.ts` — die vier Anlässe, die Passwort-Prüfung über alle Rumpftexte und „nichts zweimal“ |
|
||||
|
||||
`ldap` fiel bei der Abnahme zu #019 auf, `mailpit` kam mit #034 dazu. Beide Zahlen sind **gemessen**,
|
||||
nicht geschätzt — in #040 hätte beinahe eine geratene in dieser Datei gestanden.
|
||||
|
||||
`format:pruefen` gehört dazu, seit der Review in #010 darauf gestoßen ist: `lint-staged` formatiert
|
||||
beim Commit automatisch nach, und das Ergebnis wäre ein Commit mit Änderungen, die niemand gesehen
|
||||
|
||||
Reference in New Issue
Block a user