This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/docs/ICD/profile.md
2026-03-13 16:09:16 +00:00

206 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# User Profile & Settings
User identity, preferences, and credentials.
**All endpoints require:** `Auth()` middleware (JWT bearer token).
---
### Get Profile
```
GET /profile
```
**Auth:** Authenticated user
Returns the current user's profile.
```json
{
"id": "uuid",
"username": "jdoe",
"email": "jdoe@example.com",
"display_name": "Jane Doe",
"role": "user",
"avatar": "data:image/png;base64,...",
"settings": { "theme": "dark" },
"created_at": "2025-06-15T14:30:00Z",
"last_login_at": "2025-06-15T14:30:00Z"
}
```
| Field | Type | Notes |
|-------|------|-------|
| `id` | string | UUIDv4 |
| `username` | string | Unique login name |
| `email` | string | Unique, lowercased |
| `display_name` | string \| null | Optional friendly name |
| `role` | `"user"` \| `"admin"` | Platform role |
| `avatar` | string \| null | Data URI (PNG, 128×128). Omitted if unset. |
| `settings` | object | User preferences (theme, keybindings, etc.) |
| `created_at` | string | ISO 8601 timestamp |
| `last_login_at` | string \| null | ISO 8601 timestamp. Null if never logged in. |
> **Note:** The profile endpoint returns `avatar` (not `avatar_url`) as a
> curated response shape. The `User` model uses `avatar_url` internally.
---
### Update Profile
```
PUT /profile
```
**Auth:** Authenticated user
```json
{
"display_name": "New Name",
"email": "new@example.com"
}
```
Both fields are optional (partial update). Returns the full profile
(same shape as `GET /profile`).
**Errors:**
- `409` — email already taken
---
### Upload Avatar
```
POST /profile/avatar
```
**Auth:** Authenticated user
**Content-Type:** `application/json`
```json
{
"image": "data:image/png;base64,..."
}
```
Accepts a base64 data URI or raw base64 string. The server decodes,
resizes to 128×128 PNG, and stores as a data URI. Max input: 2 MB.
**Response:**
```json
{
"avatar": "data:image/png;base64,..."
}
```
**Errors:**
- `400` — missing `image` field, invalid base64, unsupported format, too large
---
### Delete Avatar
```
DELETE /profile/avatar
```
**Auth:** Authenticated user
**Response:**
```json
{
"message": "avatar removed"
}
```
---
### Change Password
```
POST /profile/password
```
**Auth:** Authenticated user (builtin auth only)
```json
{
"current_password": "old-pass",
"new_password": "new-pass-min-8"
}
```
Validates `current_password` against stored bcrypt hash. `new_password`
must be 8128 characters.
On success, the UEK (User Encryption Key) is re-wrapped with the new
password so BYOK-encrypted provider keys remain accessible.
**Response:**
```json
{
"message": "password updated"
}
```
**Errors:**
- `400` — missing fields, password too short/long
- `401` — current password incorrect
---
### Get Settings
```
GET /settings
```
**Auth:** Authenticated user
Returns user-level preferences wrapped in a `settings` key.
```json
{
"settings": {
"theme": "dark",
"editor_keybindings": "vim",
"default_model": "claude-sonnet-4-5"
}
}
```
This is a **composite response** (named key wrapping a single object),
not a bare object. The `settings` key is always present; its value is
`{}` if the user has never saved preferences.
---
### Update Settings
```
PUT /settings
```
**Auth:** Authenticated user
```json
{
"theme": "light",
"new_key": "new_value"
}
```
Shallow merge: incoming keys overwrite existing, unmentioned keys are
preserved. Handles edge cases: SQL NULL, JSON `null`, and corrupted
array values are all normalized to `{}` before merge.
Returns the updated settings (same shape as `GET /settings`).
---