---
module: claims.settings
title: Settings
tab: Internal
order: 20
audience: internal
---

Ops/support view of the Claims **Settings** screen. The screen is a **read-only** display of the *effective* vendor-email template for the logged-in user's institution. Template management is **API-only** — there is no create/edit UI wired into this page (the SPA calls only the `effective` endpoint).

## What the screen actually does

- Frontend: `hiveops-claims/frontend/src/components/Settings/EmailTemplatesSection.svelte` calls `emailTemplateAPI.effective()` on mount and renders one of three states.
- Backend: `GET /api/claims/settings/email-templates/effective` (owner service `hiveops-claims`, image `hiveiq-claims`, port 8092).
- Resolution order (from `EmailTemplateController.effective`):
  1. This institution's own default (`is_default = true`, `institution_key = <JWT institutionKey>`)
  2. Global default (`institution_key = '__GLOBAL__'`, `is_default = true`) → shown as **Global Template (inherited)**
  3. Neither → HTTP **204** → UI shows **No template configured** (built-in fallback body is used at send time)

## Roles required

- **None beyond authentication.** `SecurityConfig` ends in `anyRequest().authenticated()` — there is **no** `hasAnyRole('MSP_ADMIN','BCOS_ADMIN')` guard anywhere in this service. Any user with a valid HiveIQ JWT can read the effective template and (via API) manage their own institution's templates.
- Isolation is purely by `institutionKey` taken from the JWT principal (`ClaimsPrincipal`), not by role. A user only ever sees/edits templates where `institution_key` matches their own JWT.

## Admin-only actions (how templates get created)

There is no in-app editor, so templates are created one of two ways:

1. **Authenticated API (per-institution)** — acting as a user of that institution:
   - `POST /api/claims/settings/email-templates` `{ name, subject, bodyHtml, isDefault }`
   - `PUT /api/claims/settings/email-templates/{uuid}`
   - `DELETE /api/claims/settings/email-templates/{uuid}`
2. **Internal service API (cross-institution / global)** — `/api/internal/email-templates`, gated by an `X-Internal-Secret` header (see failure modes). Requires `?institutionKey=` query param. Use `institutionKey=__GLOBAL__` to set the shared default that every institution inherits.

Setting `isDefault: true` on create/update runs `clearDefaultForInstitution` first, so **only one default per institution** is ever active — you don't have to clear the old one manually.

## First things to check when it misbehaves

- **User sees "No template configured" but a template exists** → the template's `is_default` is `false`. Only the default is resolved. Set one template's `isDefault=true`.
- **User sees the Global template instead of their own** → their institution has no row with `is_default=true`; only `__GLOBAL__` does. Create/mark an institution-specific default.
- **Wrong institution's template appears** → check the JWT's `institutionKey` claim; scoping is entirely JWT-driven. A mis-issued token = wrong template.
- **Vendor emails go out with the wrong wording** → the *send path* (`EmailService.sendMessageNotification`) re-resolves the default the same way (own → `__GLOBAL__` → hardcoded fallback). If the Settings screen shows template X, message emails use X. Attachment notification emails do **not** use templates (hardcoded body) — that's expected.
- **204/500 on the endpoint** → confirm the service is up: `curl http://localhost:8092/actuator/health` on the services VM; route externally as `api.bcos.cloud/claims/settings/email-templates/effective` with a real Bearer token.

## Common failure modes + fixes

| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| Screen stuck on "Loading…" or shows fallback | `effective` request failed (network/401); the component catches errors and sets `template=null` | Check JWT validity + nginx `claims/` route; look at `hiveiq-claims` logs |
| `/api/internal/email-templates` → 401 "Invalid service secret" | `INTERNAL_SERVICE_SECRET` env unset (default blank) or header mismatch | Set `INTERNAL_SERVICE_SECRET` on the container **and** send matching `X-Internal-Secret`. If blank, ALL internal calls are rejected |
| PUT/DELETE → 403 | Template's `institution_key` ≠ caller's JWT institutionKey | Edit only your own institution's templates; use the internal API for cross-institution |
| PUT/DELETE → 404 "Template not found" | Wrong `uuid` (this uses the `uuid` column, not the numeric `id`) | Use the `uuid` from the list response |
| Vendor emails never arrive | `MAIL_USERNAME`/`MAIL_PASSWORD` unset → `JavaMailSender` bean absent → send silently skipped (logged at DEBUG) | Configure `MAIL_*` env; check logs for "Mail not configured — skipping" |

## Where the data lives

- Table `email_templates` in DB `hiveiq_claims` (PostgreSQL, prod). Columns: `id`, `uuid`, `institution_key`, `name`, `subject`, `body_html`, `is_default`, `created_at`, `updated_at` (migration `V2__email_templates.sql`).
- Dev profile is H2 in-memory (`create-drop`, Flyway disabled) — templates reset on restart.

See the customer-facing Overview tab for the end-user description, and the Architect tab for the build.
