feat(helpdesk): add Risk Radar dashboard with customer risk scoring

New portfolio view scoring customers 0-100 across five dimensions:
- Open pressure (30%): open + critical ticket count
- Trend (25%): net ticket flow (created - closed) in period
- SLA overdue (20%): tickets exceeding escalation targets
- Resolution time (15%): median hours to close (null = neutral)
- Inactivity (10%): age of oldest open ticket

Card grid with score badges (color-coded high/medium/low), metric
pills, driver bars. Click opens detail dialog with all dimensions
and open ticket list. Clientside search filter.

PBI_LV_Tickets with client-driven paging ($skip/$top, hardcap 5000).
Escalation definitions cached separately (30min TTL). Truncated
banner when data is capped.

New: RiskRadarService, getTicketsForRiskRadar(), 13 PHPUnit tests,
permission helpdesk.risk-radar.view, 2 routes, i18n de+en.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-06 00:24:48 +02:00
parent c6c5d06936
commit 5a4974909b
17 changed files with 1487 additions and 5 deletions

View File

@@ -305,5 +305,23 @@
"trend_tooltip_up": "Mehr Tickets erhalten als gelöst im Zeitraum — Rückstau wächst.",
"trend_tooltip_down": "Mehr Tickets gelöst als erhalten im Zeitraum — Rückstau wird abgebaut.",
"Download file": "Datei herunterladen",
"Trend based on last {days} days": "Trend basiert auf den letzten {days} Tagen"
"Trend based on last {days} days": "Trend basiert auf den letzten {days} Tagen",
"Trend": "Trend",
"Risk radar": "Risiko-Radar",
"Risk score": "Risiko-Score",
"High risk": "Hohes Risiko",
"Medium risk": "Mittleres Risiko",
"Low risk": "Niedriges Risiko",
"SLA overdue": "SLA überfällig",
"Net flow": "Netto-Zufluss",
"Open pressure": "Offene Tickets",
"Inactivity": "Inaktivität",
"No risk data available.": "Keine Risikodaten verfügbar.",
"Could not load risk radar.": "Risiko-Radar konnte nicht geladen werden.",
"Data may be incomplete. Not all tickets could be loaded.": "Daten möglicherweise unvollständig. Nicht alle Tickets konnten geladen werden.",
"Why at risk": "Warum kritisch",
"open": "offen",
"overdue": "überfällig",
"net": "netto",
"Search customers...": "Kunden suchen..."
}

View File

@@ -305,5 +305,23 @@
"trend_tooltip_up": "More tickets received than resolved in the period — backlog is growing.",
"trend_tooltip_down": "More tickets resolved than received in the period — backlog is shrinking.",
"Download file": "Download file",
"Trend based on last {days} days": "Trend based on last {days} days"
"Trend based on last {days} days": "Trend based on last {days} days",
"Trend": "Trend",
"Risk radar": "Risk radar",
"Risk score": "Risk score",
"High risk": "High risk",
"Medium risk": "Medium risk",
"Low risk": "Low risk",
"SLA overdue": "SLA overdue",
"Net flow": "Net flow",
"Open pressure": "Open pressure",
"Inactivity": "Inactivity",
"No risk data available.": "No risk data available.",
"Could not load risk radar.": "Could not load risk radar.",
"Data may be incomplete. Not all tickets could be loaded.": "Data may be incomplete. Not all tickets could be loaded.",
"Why at risk": "Why at risk",
"open": "open",
"overdue": "overdue",
"net": "net",
"Search customers...": "Search customers..."
}