# Формат ошибок и загрузка файлов

Источник: https://docs.novapoker.ru/dev/api-conventions/
Дорожка: разработка
Сверено с кодом: Mon Aug 24
Код: repos/poker-api/apps/server/src/common, repos/poker-api/apps/server/src/uploads

---

Два сквозных механизма, которые встречаются в каждом разделе.

## Формат ошибок

Все ошибки API приходят одной формой:

```json
{ "error": { "code": "SNAKE_CASE", "message": "..." } }
```

**Коды стабильны, и на них завязаны фронты** — по коду они выбирают текст и
поведение, а не по `message`. Менять код — ломающее изменение, даже если
сообщение осталось прежним.

Что бывает сейчас:

| Область | Коды |
|---|---|
| Общее | `VALIDATION_ERROR`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND` |
| Вход | `INVALID_OTP`, `OTP_RATE_LIMITED`, `INVALID_REFRESH_TOKEN`, `USER_BANNED` |
| Запись | `REGISTRATION_CLOSED`, `REGISTRATION_BANNED`, `ALREADY_REGISTERED`, `INVALID_STATUS` |
| Live | `NOT_ENOUGH_PLAYERS`, `TOURNAMENT_ALREADY_STARTED`, `TOURNAMENT_NOT_RUNNING`, `TOURNAMENT_NOT_FINISHED`, `ALREADY_ELIMINATED`, `NOTHING_TO_UNDO`, `SEAT_TAKEN`, `INVALID_LEVEL`, `INVALID_LEVELS` |
| Результаты | `RESULTS_ALREADY_CONFIRMED` |

## Загрузка картинок

`POST /uploads`, multipart, поле `file`. Кладёт файл в S3-совместимое хранилище
и возвращает `{ url, key }`.

**Presigned URL не используются — файл идёт через сервер.** Это осознанный
выбор: так проверка прав и ограничений остаётся в одном месте.

Доступ даёт `UploadAccessGuard`. Загрузить может:

- платформенный админ с правом `content.manage` **или** `tournaments.manage`;
- **либо** любой `owner`/`td` какого-нибудь клуба.

Ограничения — белый список MIME-типов и лимит размера, оба в `storage.ts`.

## Что рядом

- [Аутентификация и роли](https://docs.novapoker.ru/dev/auth.md) — откуда берутся права.
- [Ландшафт и границы](https://docs.novapoker.ru/dev.md) — где лежит контракт целиком.
