Changeset 0.28.2.2 (#185)

This commit is contained in:
2026-03-13 16:09:16 +00:00
parent 7803ba8adf
commit 8c4cb9bbeb
9 changed files with 1199 additions and 91 deletions

View File

@@ -1,55 +1,205 @@
# User Profile & Settings
### Profile
User identity, preferences, and credentials.
**All endpoints require:** `Auth()` middleware (JWT bearer token).
---
### Get Profile
```
GET /profile → profileResponse
PUT /profile ← { "display_name", "email" }
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|admin",
"avatar_url": "...",
"created_at": "...",
"last_login": "..."
"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"
}
```
### Avatar
| 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
```
POST /profile/avatar ← multipart/form-data (field: "avatar")
DELETE /profile/avatar
```
### Password
**Auth:** Authenticated user
**Response:**
```json
{
"message": "avatar removed"
}
```
---
### Change Password
```
POST /profile/password
```
**Auth:** Authenticated user (builtin auth only)
```json
{
"current_password": "...",
"new_password": "..."
"current_password": "old-pass",
"new_password": "new-pass-min-8"
}
```
On password change, the UEK is re-wrapped with the new password
(BYOK keys remain accessible without re-encryption).
Validates `current_password` against stored bcrypt hash. `new_password`
must be 8128 characters.
### App Settings
On success, the UEK (User Encryption Key) is re-wrapped with the new
password so BYOK-encrypted provider keys remain accessible.
```
GET /settings → { "settings": {...} }
PUT /settings ← { "theme", "editor_keybindings", ... }
**Response:**
```json
{
"message": "password updated"
}
```
User-level preferences (theme, keybindings, default model, etc.).
**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`).
---