---
module: claims.vendors
title: Vendors
tab: Claude
order: 40
audience: dev
---

> Act-without-guessing reference. All items code-confirmed in hiveops-claims (2026-07-01) unless marked (unverified).

## Ownership

- **Service:** hiveops-claims (`hiveiq-claims`, port 8092). Owns vendor read + write end to end.
- **Frontend:** `hiveiq-claims-frontend`, `claims.bcos.cloud`, port 5179. Page: `frontend/src/components/Vendors/VendorsPage.svelte`; create panel: `components/modals/AddVendorModal.svelte`; api: `lib/api.ts` → `vendorAPI`.
- No other service, no Kafka, no cross-service call in this feature.

## Endpoints (exact)

| METHOD | Path | Notes |
|--------|------|-------|
| GET | `/api/claims/vendors` | optional `?type=CIT` or `?type=SP` (binds `Vendor.VendorType`); no type → all |
| POST | `/api/claims/vendors` | body `{name*, type*, contactName?, contactEmail?, contactPhone?}`; returns `201` |

- External route: `https://api.bcos.cloud/claims/api/claims/vendors`.
- Auth: `Authorization: Bearer <JWT>` required. Scope key = JWT `institutionKey` claim.
- Required fields: `name` (`@NotBlank`), `type` (`@NotNull`, `CIT`|`SP`). Email validated **client-side only**.
- Response fields: `uuid, name, type, contactName, contactEmail, contactPhone, createdAt`.

## Storage

- **DB:** `hiveiq_claims` (Postgres, `10.10.10.188` via ProxyJump). **Table:** `vendors`.
- Columns: `id, uuid, name, type('CIT'|'SP'), contact_name, contact_email, contact_phone, institution_key(nullable, no index), created_at, updated_at`.
- FK in: `claims.cit_vendor_id`, `claims.sp_vendor_id` → `vendors(id)`.
- **Kafka topics:** none for this feature.

## Gotchas

- **No update / no delete endpoint** — `VendorController` has only GET + POST. Typos are fixable only via direct SQL `UPDATE vendors`.
- **No role gate** — `SecurityConfig` = `anyRequest().authenticated()`. Do NOT assume `hasAnyRole('MSP_ADMIN','BCOS_ADMIN')`; isolation is `institutionKey` only.
- **No dedup** — `(institution_key, name)` is not unique; POST twice = two rows.
- **Blank `institutionKey` JWT** pools vendors under a null key (nullable column) → apparent "missing" or cross-user leakage.
- Frontend splits CIT/SP **client-side**; `typeFilter` in `VendorsPage` is declared but not bound to any UI control, so `?type=` is currently unused.
- Deleting a vendor referenced by a claim fails the FK — unassign on the claim first.
- `dev` profile = H2 (`create-drop`, Flyway off); `prod` = Postgres + Flyway `validate`.

## Do NOT

- Do NOT tell users to edit or delete a vendor in the UI — no such action exists.
- Do NOT claim vendor changes emit Kafka events — they don't.
- Do NOT invent an MSP/all-institutions vendor view — every query is `institutionKey`-scoped.
- Do NOT expect a role/permission error path — auth failures are 401 (missing/invalid token), not 403 by role.
- Do NOT run `docker exec hiveiq-postgres` on the services VM — Postgres is on `10.10.10.188`.
- Do NOT reference this AI assistant as anything but "Adoons" externally.

## Cross-links

[claims.vendors] Overview · Internal · Architect. Service facts: [technical.claims]. Platform: [platform.service-ownership], [platform.kafka], [platform.data-architecture].
