feat: Sprint 5 — AI insights, webhooks/Slack, PWA, performance monitoring
AI-Powered Insights (G9): - Rule-based anomaly detection: budget burn rate, staffing gaps, utilization, timeline overruns across all active projects - AI narrative generation via existing Azure OpenAI integration - Cached in project dynamicFields to avoid regeneration - New /analytics/insights page with anomaly feed + project summaries - Sidebar nav: "AI Insights" under Analytics Webhook System + Slack (G10): - Webhook model in Prisma (url, secret, events, isActive) - HMAC-SHA256 signed payloads with 5s timeout fire-and-forget dispatch - Slack-aware: routes hooks.slack.com URLs through Slack formatter - 6 events integrated: allocation.created/updated/deleted, project.created/ status_changed, vacation.approved - Admin UI: /admin/webhooks with CRUD, test button, event checkboxes - webhook router: list, getById, create, update, delete, test PWA Support (G11): - manifest.json with standalone display, brand-colored icons (192+512px) - Service worker: cache-first for static, network-first for API, offline fallback - ServiceWorkerRegistration component with 60-min update checks - InstallPrompt banner with 30-day dismissal memory - Apple Web App meta tags + viewport theme color Performance Monitoring (A15): - Pino structured logging (JSON prod, pretty dev) via LOG_LEVEL env - tRPC logging middleware on all protectedProcedure calls - Request ID (UUID) per call for log correlation - Slow query warnings (>500ms) at warn level - GET /api/perf endpoint: memory, uptime, SSE connections, node version Fix: renamed scenario.apply to scenario.applyScenario (tRPC reserved word) Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -67,6 +67,9 @@ function ReportBuilderIcon() {
|
||||
function GraphIcon() {
|
||||
return <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><circle cx="6" cy="6" r="2.5" strokeWidth={1.8} /><circle cx="18" cy="6" r="2.5" strokeWidth={1.8} /><circle cx="12" cy="18" r="2.5" strokeWidth={1.8} /><path strokeLinecap="round" strokeWidth={1.8} d="M8.5 7.5l2 7M15.5 7.5l-2 7M8.5 6h7" /></svg>;
|
||||
}
|
||||
function InsightsIcon() {
|
||||
return <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.8} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" /></svg>;
|
||||
}
|
||||
function NotificationsIcon() {
|
||||
return <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.8} d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6 6 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" /></svg>;
|
||||
}
|
||||
@@ -146,6 +149,7 @@ const navSections: NavSection[] = [
|
||||
{ href: "/reports/chargeability", label: "Chargeability", icon: <ChargeabilityIcon />, roles: ["ADMIN", "MANAGER", "CONTROLLER"] },
|
||||
{ href: "/reports/builder", label: "Report Builder", icon: <ReportBuilderIcon />, roles: ["ADMIN", "MANAGER", "CONTROLLER"] },
|
||||
{ href: "/analytics/computation-graph", label: "Computation Graph", icon: <GraphIcon />, roles: ["ADMIN", "MANAGER", "CONTROLLER"] },
|
||||
{ href: "/analytics/insights", label: "AI Insights", icon: <InsightsIcon />, roles: ["ADMIN", "MANAGER", "CONTROLLER"] },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -184,6 +188,7 @@ const adminNavEntries: AdminEntry[] = [
|
||||
{ href: "/admin/settings", label: "Settings", icon: <AdminIcon /> },
|
||||
{ href: "/admin/skill-import", label: "Skill Import", icon: <AdminIcon /> },
|
||||
{ href: "/admin/notifications", label: "Broadcasts", icon: <BroadcastIcon /> },
|
||||
{ href: "/admin/webhooks", label: "Webhooks", icon: <AdminIcon /> },
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user