---
module: profile.profile
title: Profile
tab: Claude
order: 40
audience: dev
---

Terse agent reference for the **Profile** tab (`ProfileInfo.svelte`). Self-service edit of the caller's own `users` row.

## Owner
- **Backend owner:** hiveops-auth (port 8082, prod host 8001), DB `hiveiq_auth`, table `users`.
- **Frontend:** hiveops-profile SPA, `ProfileInfo.svelte`, port 5184, `profile.bcos.cloud`.
- **Cross-call:** hiveops-mgmt (institution label only).

## Endpoints (exact)
| Method | Path | Body / returns |
|---|---|---|
| GET | `/auth/api/users/me` | → `UserMeResponse` |
| PUT | `/auth/api/users/me` | `{ name?, phone?, jobTitle?, avatarData? }` → `UserMeResponse` |
| GET (internal, mgmt) | `/api/internal/customers/domain/{domain}/institution-keys` | header `X-Internal-Secret`; reads `companyName` |

- Via NGINX prod: prefix `https://api.bcos.cloud` → `.../auth/api/users/me`.
- Adjacent tabs (NOT this module): `GET|PUT /auth/api/users/me/preferences`, `POST /auth/api/change-password`.

## Auth / roles
- Identity = JWT subject email (`@AuthenticationPrincipal`). **No role annotation** — any authenticated user, own record only.
- Do NOT assume `hasAnyRole('MSP_ADMIN','BCOS_ADMIN')` here; that gate does **not** exist on these endpoints.

## Storage (table `users`, DB `hiveiq_auth`)
| Column | Notes |
|---|---|
| `name`, `phone`, `job_title` | editable; partial update (non-null only) |
| `avatar_data` | TEXT, base64 `data:image/jpeg;base64,...`; client crops 200×200, JPEG q0.85 |
| `institution` | column exists (V10) but **NOT** returned in `/me` response |
| `preferences` | jsonb; owned by preferences endpoints, not this tab |

- Migration: `V10__add_profile_fields.sql`.

## Kafka / executor
- **None.** No topics produced/consumed, no executor→Kafka→record-store pattern in this feature.

## Gotchas
- `UserMeResponse.institution` = **mgmt `companyName` resolved from email domain**, not `users.institution`. Blank institution ⇒ mgmt down / domain unmapped / bad `X-Internal-Secret`.
- 2 MB avatar limit is **client-side only** (`file.size > 2*1024*1024`); server does **not** validate avatar size — a direct `PUT` can store an arbitrarily large blob in `avatar_data` TEXT.
- Every `GET`/`PUT /users/me` makes a synchronous mgmt REST call (institution label). mgmt failure ⇒ institution `null`, not an error.
- `updateProfile` applies only non-null fields; sending `avatarData: ""` (empty string, as the "Remove" button does) clears the avatar; omitting the field leaves it unchanged.

## Do NOT
- Do NOT route profile reads/writes to any service other than hiveops-auth.
- Do NOT invent a per-user admin edit endpoint — none exists on this tab.
- Do NOT rely on `users.institution` for the displayed institution.
- Do NOT trust the 2 MB cap on the server side.
- Do NOT expect a Kafka event when a profile changes.
- Do NOT use this tab's endpoints for password/MFA changes (Security tab: `POST /auth/api/change-password`).
