156 lines
3.6 KiB
Markdown
156 lines
3.6 KiB
Markdown
# Control-plane API
|
||
|
||
## Аутентификация
|
||
|
||
### POST /api/auth/register
|
||
|
||
```json
|
||
{
|
||
"username": "john",
|
||
"email": "john@example.com",
|
||
"password": "Secret123"
|
||
}
|
||
```
|
||
|
||
| Поле | Описание |
|
||
|------|----------|
|
||
| `username` | 3–30 символов |
|
||
| `email` | Валидный email |
|
||
| `password` | От 8 символов, заглавная + строчная + цифра |
|
||
|
||
`201` — `{ "token": "...", "refresh_token": "...", "user": { "id": "...", "username": "...", "email": "...", "created_at": "..." } }`
|
||
`400` — ошибка валидации
|
||
`409` — email уже занят
|
||
|
||
### POST /api/auth/login
|
||
|
||
```json
|
||
{ "email": "john@example.com", "password": "Secret123" }
|
||
```
|
||
|
||
`200` — `{ "token": "...", "refresh_token": "...", "user": { ... } }`
|
||
`401` — неверный email или пароль
|
||
`429` — превышен лимит (10 попыток/мин с IP)
|
||
|
||
### POST /api/auth/refresh
|
||
|
||
Обновить токены. Старый refresh_token удаляется, выдаётся новая пара.
|
||
|
||
```json
|
||
{ "refresh_token": "..." }
|
||
```
|
||
|
||
`200` — `{ "token": "...", "refresh_token": "...", "user": { ... } }`
|
||
`401` — токен невалиден или умер
|
||
|
||
### POST /api/auth/logout
|
||
|
||
Удалить refresh_token из БД.
|
||
|
||
```json
|
||
{ "refresh_token": "..." }
|
||
```
|
||
|
||
`200` — `{ "message": "logged out successfully" }`
|
||
|
||
---
|
||
|
||
## Защищённые (требуют Bearer-токен)
|
||
|
||
Заголовок: `Authorization: Bearer <access_token>`
|
||
|
||
### GET /api/auth/me
|
||
|
||
Профиль текущего пользователя.
|
||
|
||
`200` — `{ "user": { "id": "...", "username": "...", "email": "...", "created_at": "..." } }`
|
||
|
||
### PUT /api/auth/me
|
||
|
||
Обновить username.
|
||
|
||
```json
|
||
{ "username": "john_updated" }
|
||
```
|
||
|
||
`200` — `{ "user": { "id": "...", "username": "john_updated", ... } }`
|
||
|
||
### PUT /api/auth/password
|
||
|
||
Сменить пароль. Старый пароль обязателен для подтверждения.
|
||
|
||
```json
|
||
{ "old_password": "Secret123", "new_password": "NewSecret456!" }
|
||
```
|
||
|
||
`200` — `{ "message": "password changed successfully" }`
|
||
`400` — неверный старый пароль, слабый новый или совпадают
|
||
|
||
---
|
||
|
||
## Организации (все Bearer)
|
||
|
||
### POST /api/organizations
|
||
|
||
```json
|
||
{ "name": "My Corp", "slug": "my-corp" }
|
||
```
|
||
|
||
`201` — `{ "organization": { "id": "...", "name": "My Corp", "slug": "my-corp", "created_at": "...", "updated_at": "..." } }`
|
||
`409` — slug уже занят
|
||
|
||
### GET /api/organizations
|
||
|
||
`200` — `{ "organizations": [...], "total": 1 }`
|
||
|
||
### GET /api/organizations/:id
|
||
|
||
`200` — `{ "organization": { ... } }`
|
||
`404` — не найдена
|
||
|
||
### PUT /api/organizations/:id
|
||
|
||
```json
|
||
{ "name": "Updated Corp" }
|
||
```
|
||
|
||
`200` — `{ "organization": { ... } }`
|
||
|
||
### DELETE /api/organizations/:id
|
||
|
||
`200` — `{ "message": "organization deleted" }`
|
||
|
||
---
|
||
|
||
## Формат JWT
|
||
|
||
```json
|
||
{
|
||
"user_id": "uuid",
|
||
"email": "john@example.com",
|
||
"sub": "uuid",
|
||
"exp": 1718000000,
|
||
"iat": 1717913600
|
||
}
|
||
```
|
||
|
||
- `user_id` / `sub` — UUID пользователя
|
||
- `exp` — timestamp истечения (24ч)
|
||
- `iat` — timestamp выпуска
|
||
|
||
## Ошибки
|
||
|
||
```json
|
||
{ "error": "описание" }
|
||
```
|
||
|
||
| Статус | Описание |
|
||
|--------|----------|
|
||
| 400 | Ошибка валидации |
|
||
| 401 | Неверные данные, токен протух или невалиден |
|
||
| 404 | Пользователь или организация не найдены |
|
||
| 409 | Email или slug уже заняты |
|
||
| 429 | Превышен лимит попыток логина |
|
||
| 500 | Внутренняя ошибка |
|
||
|