---
module: claims.dashboard
title: Claims Dashboard
tab: Claude
order: 40
audience: dev
---

Terse agent reference for the Claims Dashboard view. Owner service: **hiveops-claims** (`hiveiq-claims`, port 8092, image `hiveiq-claims`). Frontend: `Dashboard.svelte` in `hiveops-claims/frontend`.

## Owns this view
- Backend: `hiveops-claims` only. No cross-service call in the dashboard read path.
- DB: `hiveiq_claims` (PostgreSQL prod; H2 in dev profile).
- External route: `api.bcos.cloud/claims/…` → `hiveiq-claims:8092/api/claims/…`.

## Endpoints (this view)
| METHOD | Path | Notes |
|--------|------|-------|
| GET | `/api/claims/stats` | → `ClaimStatsResponse`; scoped by JWT `institutionKey` |
| GET | `/api/claims` | `Page<ClaimSummaryResponse>`; params below |

Query params for `GET /api/claims`:
- `status` — CSV of enum values (`OPEN,WAITING_CIT,…`); unknown value = 500
- `claimNumber` — case-insensitive substring
- `terminalId` — case-insensitive substring
- `page`, `size` (default 25), `sort` (default `createdAt`; e.g. `shortageAmount,asc`)

Sortable fields: `claimNumber`, `terminalId`, `lossStart`, `shortageAmount`, `status`, `submittedAt`, `updatedAt`, `createdAt`.

## Enums
- `ClaimStatus`: `OPEN`, `WAITING_CIT`, `WAITING_SP`, `WAITING_INSTITUTION`, `PENDING_PAYMENT`, `RESOLVED_PAID`, `RESOLVED_OFFAGE_FOUND`, `RESOLVED_DENIED`
- `ClaimType`: `DEPOSIT`, `WITHDRAW`

## Tables
- `claims` (read) · `claim_payments` (read; `amount_paid`, `amount_owed`) · `vendors` (read, join for names) · `device_summary` (read, only for `GET /api/claims/atms`, not the grid)

## Topics
- Dashboard read path: **none produced, none consumed.**
- Service-wide: consumes `hiveops.device.events` (group `hiveops-claims-device-sync`) → `device_summary`. Affects ATM picker only.

## Auth / roles
- JWT Bearer required; `anyRequest().authenticated()`.
- **No `hasAnyRole`** anywhere. Scope = `institutionKey` from `ClaimsPrincipal`.
- `permitAll`: `/actuator/health`, `/actuator/info`, swagger, `/h2-console/**`, `/error`, `/api/internal/**`.

## Gotchas
- `depositRecoveredYtd` / `withdrawRecoveredYtd` are **all-time**, not year-scoped (name is misleading — no year filter in `getStats`).
- `awaitingResponse` counts `OPEN` + all `WAITING_*` active claims (includes fresh OPEN).
- Exposure cards sum full `shortageAmount` of active claims — not remaining owed.
- `getStats` loads all institution claims and computes in-memory (no SQL aggregate).
- Filtering is two params (`claimNumber`, `terminalId`), **not** a single `search` param (older docs are stale).
- Stats errors are swallowed client-side (`catch {}`) → cards silently vanish; curl to see real error.
- DB env is split form `DB_HOST`/`DB_PORT`/`DB_NAME`/`DB_USERNAME`/`DB_PASSWORD` — **not** `DB_URL`.

## Do NOT
- Do NOT assume role gates protect claims data — only `institutionKey` scoping does.
- Do NOT add a claims endpoint/table to another service; hiveops-claims owns claims. See [platform.service-ownership].
- Do NOT trust "YTD" stat labels as year-bounded.
- Do NOT use a `search=` param on `/api/claims` — it is ignored.
- Do NOT expect Kafka/websocket push for the dashboard; refresh is 60s client polling.
- Do NOT pass unlisted `sort` fields or unknown `status` values — the latter 500s.
