Compliance-Checks (Notification-Engine)
| Modell | Modul-Route | Zweck |
|---|---|---|
ComplianceCheck (NEU, hier dokumentiert) | /compliance-checks (BE-API) | Generische Notification-Engine für 5 Use-Cases mit Severity + Snooze |
EmployeeComplianceCheck (älter) | /employees-compliance-checks | Pflicht-Schulungs-/Bescheinigungs-Tracking pro Mitarbeiter (Erste-Hilfe, Brandschutzhelfer, …) |
Beide Modelle existieren parallel und decken unterschiedliche Use-Cases ab. Diese Seite dokumentiert das neue generische System.
- Notification-Popup im Header (zeigt eigene pending Checks via
GET /api/compliance-checks/me/pending) - Compliance-History-Page unter
/employees/:id/compliance-history(zeigt beide Subsysteme zusammen) - Dashboard-Tile mit pending-Check-Count
Der Endpoint-Frontmatter dieser Seite (/compliance-checks) bezieht sich daher auf die BE-API-Routenfamilie, nicht auf eine FE-Page.
Zweck
ComplianceCheck ist eine generische Notification-Engine mit 5 vorbereiteten Use-Cases. Pro Mitarbeiter und Tag erzeugt der Daily-Cron (02:30 Uhr) Einträge, die der Empfänger in einem Notification-Popup mit Severity-Klassifikation (info / warning / violation) zu sehen bekommt. Anwender können Checks acknowledgen (gesehen) oder snoozen (auf später verschieben).
Voraussetzungen
Berechtigungen (CASL)
Frontend-Page-Guard: view:FE_ComplianceCheck, view:ComplianceCheck
API-Datenzugriff:
| Action | Subject | Wirkung |
|---|---|---|
view | ComplianceCheck | Liste / Detail (mit recipientEmployeeId-Filter typisch) |
create | ComplianceCheck | typisch nur System-Engine |
update | ComplianceCheck | Status-Wechsel via Endpoints |
do | AcknowledgeComplianceCheck | POST /:id/acknowledge |
do | SnoozeComplianceCheck | POST /:id/snooze |
do | RunDailyComplianceChecks | POST /run-daily (Power-Action für Admin) |
Use-Cases (checkType)
Die Engine kennt aktuell 5 vordefinierte Use-Cases. Jeder hat eine eigene Logik, wann er getriggert wird, und einen passenden Severity-Default:
checkType | Wann? | Default-Severity | payload-Beispiel |
|---|---|---|---|
vacationExpiryNotice | BAG-Hinweispflicht: Resturlaub verfällt am Übertragungs-Stichtag (typisch 31.03.) | warning | { daysLeft, expiryDate, vacationItemId } |
probationEndNotice | Probezeit endet in N Tagen | info | { probationEndDate, probationDurationMonths } |
jubileeNotice | Jubiläum (5/10/25/40 Jahre Betriebszugehörigkeit) erreicht | info | { years, employmentStartDate } |
contractEndNotice | Befristeter Vertrag endet in N Tagen | info oder warning | { contractEndDate, fixedTerm } |
arbzgViolation | §3 ArbZG-Tageshöchstgrenze überschritten | violation | { date, workedMinutes, capMinutes } |
Mehr zu §3 ArbZG: Konzept §3 ArbZG-Cap.
Severity-Skala
| Severity | UI-Wirkung | Bedeutung |
|---|---|---|
info | Blauer Popup, geringe Dringlichkeit | informative Hinweise (z. B. Jubiläum) |
warning | Gelber Popup, mittlere Dringlichkeit | rechtlich relevant aber nicht kritisch (z. B. BAG-Urlaubshinweis) |
violation | Roter Popup, hohe Dringlichkeit | rechtlich-relevanter Verstoß, sofort behandeln (z. B. §3 ArbZG-Cap) |
Status-Lifecycle
| Status | Bedeutung |
|---|---|
pending | Frisch erzeugt, wartet auf User-Aktion |
snoozed | User hat snooze geklickt; wird nach snoozedUntil wieder pending |
acknowledged | User hat bestätigt — wird nicht mehr im Popup gezeigt |
expired | Trigger-Datum überschritten ohne Aktion (z. B. Urlaub ist tatsächlich verfallen) |
Löschen von Checks (Welle 134)
Seit Welle 134 ist das Löschen eines ComplianceCheck auch dann erlaubt, wenn das triggerDate bereits erreicht oder überschritten ist (Status expired). Vorher hat der Service in diesem Fall mit einem Validierungs-Fehler abgebrochen — was bei jährlichen Bereinigungs-Läufen oder beim manuellen Aufräumen ungewollt blockierend war. Quelle: BE-Commit 8c48dc07.
Datenmodell
| Feld | Typ | Bedeutung |
|---|---|---|
id | UUID | Primary Key |
checkType | String | Use-Case-Schlüssel (5 vordefinierte; siehe oben) |
severity | enum | info | warning | violation |
recipientEmployeeId | UUID | wer sieht den Check |
contextType / contextId | String / UUID nullable | z. B. EmployeeContract / contract.id für Bezug |
payload | JSON nullable | Use-Case-spezifische Daten |
triggerDate | Date | wann wird das Ereignis akut |
status | enum | pending | snoozed | acknowledged | expired |
snoozedUntil | Date nullable | bei status=snoozed |
acknowledgedAt / acknowledgedByEmployeeId / acknowledgedFromIp | DateTime/UUID/String nullable | Audit-Trail der Bestätigung |
API-Endpoints
| Methode | Endpoint | Zweck |
|---|---|---|
GET | /api/compliance-checks | Liste, typisch gefiltert nach recipientEmployeeId und Status |
GET | /api/compliance-checks/me/pending | eigene pending Checks (Notification-Popup-Quelle) |
GET | /api/compliance-checks/:id | Detail |
POST | /api/compliance-checks/:id/acknowledge | als gesehen markieren |
POST | /api/compliance-checks/:id/snooze | snoozen mit snoozedUntil |
POST | /api/compliance-checks/run-daily | manueller Trigger (Admin) |
POST | /api/compliance-checks/simulate | Simulations-Modus für Konfigurations-Tests |
Cron + Engine
- Daily-Cron 02:30 Uhr (
api.speamcore.com/src/server.ts) ruftrunDailyComplianceChecksauf — pro aktivem Use-Case wird die Engine ausgeführt. - Idempotenz: mehrfache Läufe an einem Tag erzeugen keine Duplikate (Check pro
recipientEmployeeId+checkType+triggerDate). - Einmal-pro-Vorgang (seit Juni 2026): Für wiederkehrende Hinweise wie das Leasingende eines Fahrzeugs (Stufen 12 / 6 / 3 Monate vor Vertragsende) gilt zusätzlich
onlyNotifyNewItems— ein Hinweis wird pro (Fahrzeug, Stufe) genau einmal erzeugt und nicht mehr täglich neu, selbst wenn er schon quittiert/gesnoozed wurde. Neue Fahrzeuge und Stufen-Eskalationen lösen weiterhin aus. - Notification-Service: Bei neuen pending Checks erfolgt zusätzlich ein Push über die Notification-Channels (sofern Subscriptions konfiguriert).
ComplianceCheckHistory
Pro Status-Wechsel eines Checks wird ein Eintrag in der separaten Tabelle ComplianceCheckHistory (Migration 20260501113010) erzeugt — Audit-Trail wer wann was bestätigt/gesnoozed/expired hat. So bleibt die Historie nachvollziehbar, auch wenn der Check selbst längst acknowledged ist.
Verknüpfungen
- Notification-System — Push-Versand der Checks (Konzept)
- §3 ArbZG-Cap — Trigger-Quelle für
arbzgViolation-Checks → erzeugt automatischWorkTimeOvertimeApproval - EmployeeContract / EmployeeContractVacation — Quelle für probationEnd, contractEnd, vacationExpiry
- Settings — pro Mandant aktivierbare Use-Cases (
enableVacationExpiryNotice,enableProbationEndNotice, …)
Versionshinweise
-
2026-06-30 (temporär): Die beiden Fahrzeug-Kilometerstand-Hinweise (
vehicleMileageMissingPrompt„Kilometerstand bitte eintragen" undvehicleMileageImplausibleFlag„Kilometerstand prüfen") werden clientseitig ausgeblendet, weil sie täglich beim Login als Pflicht-Popup erschienen und so den Einstieg blockierten. Alle übrigen Compliance-Hinweise (Probezeit, Vertragsende, Resturlaub, ArbZG, Jubiläum, Leasingende) bleiben unverändert aktiv. Reaktivierung durch Entfernen der beiden Einträge aus derSUPPRESSED-Liste inComplianceNotificationPopUp.tsx. Verifiziert anComplianceNotificationPopUp.tsx. -
2026-06-12:
onlyNotifyNewItems-Mechanik dokumentiert — Leasingende-Fahrzeug-Hinweise (Stufen 12/6/3 Monate) werden pro Vorgang einmalig erzeugt statt täglich neu. Verifiziert ancomplianceNotification.service.ts(generateVehicleContractEndNotices). -
2026-05-20 (Welle 134): Löschen von Checks auch nach Erreichen des
triggerDateerlaubt — vorher blockierte der Service expired Checks. Quelle: BE-Commit8c48dc07. -
2026-05 (Welle 99): Initiale Doku des neuen
ComplianceCheck-Modells. Eingeführt mit Migrations20260501113006-initial-compliance-check-model.js+20260501113010-initial-compliance-check-history-model.js. ServicecomplianceNotification.service.ts(613 Zeilen). Daily-Cron inserver.ts. Simulations-Endpoint für Konfigurations-Tests. -
Vorgänger-Doku: Diese Seite hatte bis Welle 98 fälschlich den
EmployeeComplianceCheck-Inhalt — der gehört nach/employees-compliance-checks.