Files
vidconf/docs/api/users.md

309 lines
10 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.
# Профиль и аватар пользователя
Эндпоинты управления профилем, загрузкой аватаров и поиска пользователей.
## Быстрый старт
```bash
# 1. Получить профиль
curl http://localhost:8000/api/v1/users/me \
-H "Authorization: Bearer $TOKEN"
# 2. Обновить ФИО и команду
curl -X PATCH http://localhost:8000/api/v1/users/me \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name_user":"Новое имя","team_id":"uuid-team"}'
# 3. Загрузить аватар
curl -X POST http://localhost:8000/api/v1/users/me/avatar \
-H "Authorization: Bearer $TOKEN" \
-F "file=@/path/to/photo.jpg"
# 4. Удалить аватар
curl -X DELETE http://localhost:8000/api/v1/users/me/avatar \
-H "Authorization: Bearer $TOKEN"
# 5. Сменить пароль
curl -X POST http://localhost:8000/api/v1/users/me/password \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"current_password":"oldPassword123","new_password":"newSecurePassword456"}'
# 6. Поиск пользователей (для пикера участников)
curl 'http://localhost:8000/api/v1/users?q=john' \
-H "Authorization: Bearer $TOKEN"
# 7. Получить справочник команд
curl http://localhost:8000/api/v1/teams \
-H "Authorization: Bearer $TOKEN"
```
## Эндпоинты
### GET /api/v1/users/me
**Получить профиль текущего аутентифицированного пользователя.**
**Требует auth:** JWT Bearer token
**Response (200 OK):**
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"name_user": "Иван Петров",
"team_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"team_name": "Backend",
"avatar_path": "avatars/550e8400-e29b-41d4-a716-446655440000.jpg",
"avatar_url": "/media/avatars/550e8400-e29b-41d4-a716-446655440000.jpg",
"created_at": "2026-07-16T12:00:00Z"
}
```
**Поля:**
- `email` — адрес электронной почты (read-only)
- `name_user` — отображаемое имя (редактируемое)
- `team_id` — UUID команды (опционально, редактируемое)
- `team_name` — имя команды (null если не привязан)
- `avatar_path` — путь к файлу аватара (null если нет)
- `avatar_url` — готовый URL для отображения; при отсутствии аватара фронтенд показывает заглушку с инициалами
---
### PATCH /api/v1/users/me
**Изменить ФИО и/или команду текущего пользователя; email — read-only.**
**Требует auth:** JWT Bearer token
**Request body:** (все поля опциональны)
```json
{
"name_user": "Новое имя",
"team_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
}
```
**Поля:**
- `name_user` (str, 1..255) — новое ФИО
- `team_id` (UUID или null) — переназначить команду; явное `null` снимает привязку; отсутствие поля команду не трогает
**Response (200 OK):** обновленный профиль (как GET /me)
**Коды ошибок:**
- `404` — team_not_found (если передан несуществующий `team_id`)
- `422` — Unprocessable Entity (валидация: name_user пуст и т.д.)
---
### POST /api/v1/users/me/avatar
**Загрузить аватар текущего пользователя.**
**Требует auth:** JWT Bearer token
**Request body:** `multipart/form-data`
- `file` — файл изображения (обязателен)
**Требования:**
- **Формат:** JPEG, PNG или WebP (проверяется по magic bytes, не по расширению)
- **Максимальный размер:** 2 МБ
- Старый аватар автоматически удаляется при загрузке нового
**Response (200 OK):** обновленный профиль (как GET /me, с новым `avatar_url`)
**Коды ошибок:**
- `413` — avatar_too_large (файл больше 2 МБ)
- `415` — avatar_invalid_type (не JPEG/PNG/WebP; проверяется по magic bytes)
- `422` — Unprocessable Entity (невалидный multipart и т.д.)
**Примеры:**
```bash
# JPEG
curl -X POST http://localhost:8000/api/v1/users/me/avatar \
-H "Authorization: Bearer $TOKEN" \
-F "file=@photo.jpg"
# PNG
curl -X POST http://localhost:8000/api/v1/users/me/avatar \
-H "Authorization: Bearer $TOKEN" \
-F "file=@photo.png"
# WebP
curl -X POST http://localhost:8000/api/v1/users/me/avatar \
-H "Authorization: Bearer $TOKEN" \
-F "file=@photo.webp"
```
---
### DELETE /api/v1/users/me/avatar
**Удалить аватар текущего пользователя.**
**Требует auth:** JWT Bearer token
**Response (204 No Content)** — без тела
**Примечание:** После удаления `avatar_path` становится `null`, фронтенд отображает заглушку с инициалами.
---
### POST /api/v1/users/me/password
**Сменить пароль текущего пользователя.**
**Требует auth:** JWT Bearer token
**Request body:**
```json
{
"current_password": "oldPassword123",
"new_password": "newSecurePassword456"
}
```
**Поля:**
- `current_password` (str) — текущий пароль (обязательно, для верификации)
- `new_password` (str, ≥8) — новый пароль (политика как при регистрации: минимум 8 символов)
**Response (204 No Content)** — без тела
**Коды ошибок:**
- `400` — invalid_current_password (текущий пароль не совпадает)
- `422` — Unprocessable Entity (новый пароль короче 8 символов)
**Примечание:** Refresh-сессии сознательно **не отзываются** (см. ADR-005 `docs/architecture/adr/005-password-reset-deferred.md`) — пользователь останется залогинен на других устройствах. Массовый отзыв всех сессий появится вместе со сбросом пароля по email (v0.1.0).
---
### GET /api/v1/users
**Поиск пользователей для пикера участников конференции.**
**Требует auth:** JWT Bearer token
**Query параметры:**
- `q` (str, опционально) — текст для поиска (по имени и email)
**Поведение:**
- Без `q` — возвращает полный список (с ограничением ~20 результатов)
- С `q` — полнотекстовый поиск (также ~20 результатов)
- Поиск регистронезависим
**Response (200 OK):**
```json
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "ivan@example.com",
"name_user": "Иван Петров",
"avatar_url": "/media/avatars/550e8400-e29b-41d4-a716-446655440000.jpg"
},
{
"id": "6ba7b811-9dad-11d1-80b4-00c04fd430c8",
"email": "maria@example.com",
"name_user": "Мария Сидорова",
"avatar_url": null
}
]
```
**Примеры:**
```bash
# Полный список
curl http://localhost:8000/api/v1/users \
-H "Authorization: Bearer $TOKEN"
# Поиск по имени
curl 'http://localhost:8000/api/v1/users?q=ivan' \
-H "Authorization: Bearer $TOKEN"
# Поиск по email
curl 'http://localhost:8000/api/v1/users?q=example.com' \
-H "Authorization: Bearer $TOKEN"
```
---
## Аватары
### Хранение
Аватары хранятся в каталоге `MEDIA_ROOT/avatars/`:
```
MEDIA_ROOT/
└── avatars/
├── 550e8400-e29b-41d4-a716-446655440000.jpg
├── 6ba7b811-9dad-11d1-80b4-00c04fd430c8.png
└── ...
```
**Адресация:**
- Backend сохраняет: `user.avatar_path = "avatars/{user_id}.{ext}"`
- Frontend отображает: `avatar_url = "/media/avatars/{user_id}.{ext}"`
- Nginx раздаёт напрямую (location `/media/` → alias `MEDIA_ROOT`)
### Валидация
**Magic bytes (не расширение):**
- JPEG: `FF D8 FF`
- PNG: `89 50 4E 47`
- WebP: `52 49 46 46 ... 57 45 42 50`
**Размер:** max 2 МБ (413 Payload Too Large)
### Заглушка (дефолт)
Если `avatar_path` = `null`:
- Фронтенд отображает цветную заглушку с инициалами (2 буквы ФИО)
- Цвет выбирается детерминированно по хэшу `user_id` (всегда одинаковый для пользователя)
---
## Типы данных
### UserProfileOut
```json
{
"id": "uuid",
"email": "string",
"name_user": "string",
"team_id": "uuid or null",
"team_name": "string or null",
"avatar_path": "string or null",
"avatar_url": "string or null",
"created_at": "datetime"
}
```
### UserListItemOut
```json
{
"id": "uuid",
"email": "string",
"name_user": "string",
"avatar_url": "string or null"
}
```
---
## Примечания
- **Email read-only:** адрес электронной почты менять нельзя (требует переверификации, которая не реализована в v0.0.1)
- **Таймзона:** все `created_at` сохраняются в UTC (ISO 8601)
- **Команда опциональна:** пользователь может работать без привязки к команде (`team_id` = null)
- **Безопасность:** пароли никогда не передаются в API; для смены пароля используйте `POST /api/v1/users/me/password`. Сброс пароля по email появится в v0.1.0 (см. ADR-005)
---
## Ссылки
- [Справочник команд](./teams.md) — GET /api/v1/teams
- [Администраторский API](./admin.md) — GET/PATCH /api/v1/admin/users/{id}, POST /api/v1/admin/users/{id}/avatar
- [Аутентификация](./auth.md) — регистрация, логин
- [Конференции](./conferences.md) — параметр `participants` при создании/редактировании