---
module: claims.claim-detail
title: Claim Detail
tab: Internal
order: 20
audience: internal
---

Ops/support reference for the **Claim Detail** panel (`ClaimPanel.svelte`, opens right-side over the claims list). Backend is **hiveops-claims** (`hiveiq-claims`, port 8092, DB `hiveiq_claims`). Frontend `claims.bcos.cloud`; API `api.bcos.cloud/claims/` → `hiveiq-claims:8092/api/claims/`.

## Who can do what

- **No role guards.** `SecurityConfig` is `anyRequest().authenticated()` — there is **no** `hasAnyRole('MSP_ADMIN','BCOS_ADMIN')` anywhere in this service. Any user with a valid HiveIQ JWT can open, edit, message, note, upload, and change payments on the panel.
- **Isolation is by `institutionKey`** carried in the JWT (`ClaimsPrincipal`). The *list* (`GET /api/claims`) filters to your institution — but the *detail* endpoints below do **not** (see failure modes). There is no admin-vs-user distinction inside claims.
- **Internal email-template endpoints** (`/api/internal/**`) are `permitAll()` at security level but gated by an `X-Internal-Secret` header (env `INTERNAL_SERVICE_SECRET`, default empty). Not used by this panel.

## What each tab calls (first things to check)

| Tab | Action | Call |
|-----|--------|------|
| (open) | Load claim + payments + vendor list | `GET /api/claims/{uuid}`, `GET /api/claims/vendors` |
| Overview | Save Edit | `PUT /api/claims/{uuid}` |
| Messages | Load / Send | `GET /api/claims/{uuid}/messages?vendorUuid=`, `POST …/messages` |
| Files | List / Upload / Download | `GET/POST …/attachments`, `GET …/attachments/{aUuid}/download` |
| 🔒 Notes | List / Add | `GET/POST …/notes` |
| Payment | (embedded) / Save card | payments come inside the claim; `PUT …/payments/{party}` |

`{party}` is `INSTITUTION` / `CIT` / `SP`.

## First things to check when it misbehaves

1. **Panel opens blank / "Could not load claim details"** — the open path fires `GET /api/claims/{uuid}` **and** `GET /api/claims/vendors` in parallel; if either 401/500s the whole panel shows the load-failed toast. Check the JWT (expired → 401) and that the vendors endpoint is healthy first.
2. **Messages/Files/Notes empty but you expect data** — these tabs lazy-load only on first open and only when the local array is empty. A failed load is swallowed silently (empty `catch {}`) — no toast. Check the network tab / `docker logs hiveiq-claims`, don't trust the empty state.
3. **Vendor email didn't arrive after sending a message or uploading a file** — messages and attachments trigger `EmailService` (SMTP `JavaMailSender`), **not** Kafka. If `mailSender` is null / SMTP unconfigured, or no recipient can be resolved, the email is **silently skipped** and the message/note/file still saves. Check `mail.from` / SMTP env and that the vendor has a `contactEmail` (or that an additional recipient email was supplied).
4. **CIT/SP vendor dropdown is empty in Edit** — depends on `GET /api/claims/vendors` returning vendors of that `type`; register vendors first (Vendors page). The Messages "to vendor" dropdown only lists vendors **assigned to this claim** (`citVendorUuid`/`spVendorUuid`).
5. **Download does nothing** — `GET …/attachments/{attachmentUuid}/download` streams from the local uploads dir (`UPLOADS_DIR`, default `/tmp/claims-uploads`). If the container was recreated and that dir isn't a persistent volume, the file rows exist but the bytes are gone.
6. **Terminal/location/ATM list looks stale or wrong** — device data (`device_summary`) is a Kafka mirror fed by `hiveops.device.events`. There is **no reconciler**; if the devices service didn't publish a change, claims shows stale data. Cross-check the devices service.

## Common failure modes + fixes

- **Cross-institution data visible / editable (IDOR).** `GET/PUT /api/claims/{uuid}` and all `/{claimUuid}/…` activity endpoints resolve by UUID with **no** `institutionKey` check. Anyone with a claim UUID from any institution can read/modify it. Treat claim UUIDs as sensitive; flagged as a real bug (see uncertainties). No config toggle — needs a code fix.
- **Save Edit clears a vendor unexpectedly.** The panel sends `clearCitVendor: true` / `clearSpVendor: true` whenever its dropdown is blank. Opening Edit and saving with a vendor field showing "— None —" **removes** that party (and deletes its payment row). Don't save the Overview edit unless the vendor selects are correct.
- **Payment balance looks wrong after assigning a vendor.** Assigning a CIT/SP vendor later adds that party's payment row at `amountOwed = 0` — it does **not** re-split the shortage. Adjust owed amounts manually on the Payment tab.
- **50MB upload rejected.** Multipart cap is 50MB/file, 52MB/request. Larger files 413.
- **Attachments lost after redeploy** — confirm `UPLOADS_DIR` is a mounted volume, not the container-local default.

## Where to look

- Logs: `docker logs hiveiq-claims` (or Loki, `localhost:3100` on services VM).
- Health: `GET /actuator/health` (permitAll).
- DB (separate VM `10.10.10.188` via ProxyJump): tables `claims`, `claim_payments`, `claim_messages`, `claim_notes`, `claim_attachments`, `vendors`, `device_summary`.

See [claims.claim-detail] Architect tab for how the pieces fit together.
