---
module: analytics.incidents
title: Incident Trends
tab: Claude
order: 40
audience: dev
---

> Terse agent reference. All facts confirmed in source 2026-07-01. `hiveops-ai` = "Adoons".

## Ownership
- **Endpoint owner:** `hiveops-analytics` (port 8089).
- **Data owner:** `hiveops-incident` (port 8080), table `journal_events`.
- This tab is a **live synchronous pull**, not a snapshot/Kafka read.

## Endpoints (METHOD + path)
| Method | Path | Service | Auth |
|--------|------|---------|------|
| GET | `/api/analytics/incident-trends` | analytics | JWT, **no role gate** |
| GET | `/api/journal-events/activity?hoursBack=24` | incident | JWT, institution-scoped |

- Frontend call: `analyticsAPI.getIncidentTrends()` → `GET {apiBase}/incident-trends`.
- Analytics forwards caller `Bearer` token verbatim to incident. No service account.

## Tables
- `journal_events` (read) — `hiveiq_incident` DB.
- `atms` (read, join + institution scope) — `hiveiq_incident` DB.
- **Not used by this tab:** `analytics_snapshots`, `ai_insights` (`hiveiq_analytics`).

## Kafka
- **None on this path.** (`hiveops.incidents.*`, `journal.file-parsed`, `analytics.snapshot-ready` feed the snapshot tab, not this one.)

## Response shape (`IncidentTrendsResponse`)
- `dailyCounts: [{date, count}]` — seeded today-only.
- `byCategory: {HARDWARE,CASH,NETWORK,POWER,AUTH,SYSTEM,OTHER: n}`.
- `recurringFailures: [{atmId, eventType, count}]` — 24h, count≥3, top 20.
- `peakHours: int[7][24]` — Mon=0, UTC hour.

## Roles / scoping
- `CUSTOMER` / `MSP_ADMIN` → scoped to granted institution keys (downstream `InstitutionContext.resolveScope()`).
- `BCOS_ADMIN` / `ADMIN` / `QDS_ADMIN` / `USER` → unrestricted.

## Config
- `INCIDENT_SERVICE_URL` default `http://hiveops-incident-backend:8080`.
- `hoursBack` hard-coded = 24 (not env-tunable).

## Gotchas (confirmed)
- Window is **24h**, despite chart titled "30-DAY INCIDENT TREND".
- `dailyCounts` always length 1 → frontend renders "Not enough data" (needs ≥2).
- `recurringFailures` always empty: service reads `atmId` as String but DTO serializes it as numeric `Long` → skipped.
- No "OPERATIONS" category emitted; operational types → `OTHER`.
- Downstream failure is swallowed → whole tab silently empties (grep analytics log `IncidentTrends: failed to fetch activity events`).

## Do NOT
- Do NOT query `analytics_snapshots`/`ai_insights` for this tab — wrong source.
- Do NOT expect this tab to read Kafka — it's a per-request HTTP pull.
- Do NOT assume role-gating on `/api/analytics/incident-trends` — any authenticated JWT passes.
- Do NOT add incident/journal endpoints to analytics — analytics computes, incident owns the data ([platform.service-ownership]).
- Do NOT trust "0 recurring failures" as fleet health — it's the atmId-type bug.
- Do NOT hand analytics a service token expecting broader data — scope follows the caller's JWT.
