L6 Benachrichtigungen & Audit: Empfängerregeln, In-App-Benachrichtigungen und Craftvia-Mails

- handleEvent (Signatur unverändert) löst alle 17 Domain-Events auf: Team/Assignees,
  Backoffice (read_all + report:approve), Teamleiter-Freigaben, Ersteller, Abrechnung,
  Notdienst, Import, Sync; Akteur ausgenommen, alle IDs über ctx.db neu aufgelöst.
- In-App-Notification über ctx.db (ungelesene gleiche Meldung wird aufgefrischt),
  E-Mail über enqueueMail mit dedupeKey event:entity:user (+ optional occurrenceId),
  Opt-out je Typ, Notdienst als Pflichtmail, feste Empfänger ohne Doppelmail.
- Mail-Templates craftvia_* (de/en) inkl. Notdienst-Format Spec §19.4 und Craftvia-Fußzeile.
- Migration tenant_mail_settings: mailFromName, mailReplyTo, emergencyRecipients,
  billingRecipients an tenant_settings (keine neue Tabelle).
- Texte aus messages/{de,en}/notifications.json.
- Test scripts/test-benachrichtigungen-events.ts (63 Prüfungen).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-14 12:11:53 +02:00
co-authored by Claude Opus 5
parent bf4456718e
commit 7b37c41a83
9 changed files with 1452 additions and 4 deletions
+5
View File
@@ -70,6 +70,11 @@ model TenantSettings {
timezone String @default("Europe/Berlin")
securityPolicy Json @default("{}") @map("security_policy") // pw/mfa/session
smtp Json @default("{}")
// Craftvia §33.2 — tenant mail settings (sender address stays the platform domain for SPF/DKIM).
mailFromName String? @map("mail_from_name")
mailReplyTo String? @map("mail_reply_to")
emergencyRecipients String[] @default([]) @map("emergency_recipients")
billingRecipients String[] @default([]) @map("billing_recipients")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")