Files
AutopilotMonitor/src/Backend/AutopilotMonitor.Functions/Services/Notifications
Oliver Kieselbach 8b266570cb feat(notifications): multi-channel notifications + per-rule notify
Phase 1 - named notification channels (1..N per tenant):
- NotificationChannel model (provider/url/headers/enabled + per-event
  opt-ins incl. single NotifyOnSlaEvents); stored as JSON column
  NotificationChannelsJson, cap 10, fail-soft ParseList
- No data migration: GetNotificationChannels() synthesizes one channel
  from the legacy single-webhook fields under stable id "legacy";
  web materializes on first save and clears legacy fields
- All dispatch sites (ingest success/failure/white-glove/ESP, SLA breach/
  resolved/consecutive, enrollment-start, hardware-rejected, test) route
  via SendToChannelsAsync with per-channel toggle filtering
- Per-channel secret redaction (structure stays visible to readers) with
  restore-by-id; save-time validation (dup ids, provider, https, headers)
- Settings UI: channel card list with add/remove, event pills, per-channel
  test button ({channelId} body, legacy-compatible without body)

Phase 2 - analyze-rule channel notifications:
- NotifyDefault (definition, false for all built-ins, test-guarded) +
  Notify/NotifyChannelIds tenant override in RuleStates (two-tier mirror
  of MarkSessionAsFailed); custom rules fold into the tenant-owned row
- Dispatch in AnalyzeOnEnrollmentEndHandler only: outcome.Results is
  new-findings-only (engine dedup) so no re-notification; manual
  "Analyze Now" reanalyze never dispatches
- BuildRuleFiredAlert (eventType analyze_rule_fired): device, serial,
  rule, severity, category, confidence, explanation + session deep link
- Rule card: notify toggle + channel target pills, bell header badge

2858/2858 Functions tests (19 new), web tsc + vitest clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 10:35:41 +02:00
..