first commit
This commit is contained in:
367
docs/API.md
Normal file
367
docs/API.md
Normal file
@@ -0,0 +1,367 @@
|
||||
# ShbUtils Core API
|
||||
|
||||
Локальный справочник по API сервиса `https://api.shlakoblock.com`.
|
||||
|
||||
- Источник: `https://api.shlakoblock.com/api.json`
|
||||
- OpenAPI: `3.1.0`
|
||||
- Версия сервиса: `2.1.3-SNAPSHOT`
|
||||
- Дата снимка: `2026-07-22`
|
||||
- Формат запросов и ответов, если не указано иное: `application/json`
|
||||
|
||||
Документ является снимком контракта. В OpenAPI не описаны rate limits, гарантии идемпотентности и формат JSON-тел для большинства ошибок.
|
||||
|
||||
## Авторизация
|
||||
|
||||
### Internal endpoints
|
||||
|
||||
Все пути `/internal/*` требуют заголовок:
|
||||
|
||||
```http
|
||||
X-Internal-Secret: <shared-secret>
|
||||
```
|
||||
|
||||
При отсутствующем или неверном секрете возвращается `401 invalid_internal_secret`.
|
||||
|
||||
### Player endpoints
|
||||
|
||||
Пути `/api/*` требуют bearer-токен, выданный `POST /internal/auth/start`:
|
||||
|
||||
```http
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
Хотя схема `BearerAuth` присутствует в OpenAPI, требования `security` не проставлены у самих операций. Необходимость токена следует из ответов `401 missing/invalid token`; для этих endpoint также возможен `403 player_offline`.
|
||||
|
||||
## Basic
|
||||
|
||||
### `GET /`
|
||||
|
||||
Маркер сервиса. Возвращает `200` и название сервиса простым текстом.
|
||||
|
||||
### `GET /health`
|
||||
|
||||
Проверяет соединения с БД и Redis.
|
||||
|
||||
| Код | Значение |
|
||||
| --- | --- |
|
||||
| `200` | `status: ok` |
|
||||
| `503` | `status: degraded` |
|
||||
|
||||
## Internal
|
||||
|
||||
### `POST /internal/join`
|
||||
|
||||
Регистрирует вход игрока.
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "11111111-1111-1111-1111-111111111111",
|
||||
"playerName": "Player"
|
||||
}
|
||||
```
|
||||
|
||||
`playerName` необязателен и может быть `null`. Успех: `200 ApiMessage`. Ошибки: `400 invalid_body / invalid_uuid`, `401 invalid_internal_secret`.
|
||||
|
||||
### `POST /internal/quit`
|
||||
|
||||
Регистрирует выход игрока. Тело: `UuidRequest`. Успех: `200 ApiMessage`. Ошибки: `400 invalid_body / invalid_uuid`, `401`.
|
||||
|
||||
### `POST /internal/auth/start`
|
||||
|
||||
Выдаёт bearer-токен для игрока. Игрок должен быть онлайн.
|
||||
|
||||
- Тело: `UuidRequest`.
|
||||
- Успех: `200 TokenResponse`.
|
||||
- Ошибки: `400 invalid_body / invalid_uuid`, `401`, `403 player_offline`.
|
||||
|
||||
### `POST /internal/verification/code`
|
||||
|
||||
Создаёт verification-код для Minecraft UUID. Это направление «Minecraft → внешний клиент», поэтому ShbDiscordBot не использует endpoint для своего `/auth`.
|
||||
|
||||
- Тело: `VerificationCodeRequest`.
|
||||
- Успех: `200 VerificationCodeResponse`.
|
||||
- Ошибки: `400 invalid_body / invalid_uuid`, `401`.
|
||||
|
||||
### `POST /internal/verification/verify`
|
||||
|
||||
Проверяет ранее созданный код и привязывает Telegram и/или Discord.
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "123456",
|
||||
"telegramId": 123456789,
|
||||
"telegramTag": "example",
|
||||
"discordId": "123456789012345678"
|
||||
}
|
||||
```
|
||||
|
||||
Кроме `code`, поля необязательны и nullable. Успех: `200 VerificationVerifyResponse`. Ошибки: `400 invalid_body`, `401`, `404 invalid_or_expired_code`.
|
||||
|
||||
### `POST /internal/auth/password`
|
||||
|
||||
Проверяет пароль игрока без передачи хэша наружу.
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "11111111-1111-1111-1111-111111111111",
|
||||
"password": "plain-text-password"
|
||||
}
|
||||
```
|
||||
|
||||
Успех: `200 PasswordVerifyResponse`. Ошибки: `400 invalid_body / invalid_uuid`, `401`.
|
||||
|
||||
### `POST /internal/auth/password/change`
|
||||
|
||||
Заменяет пароль игрока.
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "11111111-1111-1111-1111-111111111111",
|
||||
"newPassword": "new-plain-text-password"
|
||||
}
|
||||
```
|
||||
|
||||
Успех: `200 ApiMessage`. Ошибки: `400 invalid_body / invalid_uuid / invalid_password`, `401`, `404 player_not_found`.
|
||||
|
||||
### `POST /internal/players/password/reset`
|
||||
|
||||
Удаляет сохранённый пароль игрока. Тело: `PasswordResetRequest`. Успех: `200 ApiMessage`. Ошибки: `400 invalid_body / invalid_uuid`, `401`, `404 player_not_found`.
|
||||
|
||||
### `POST /internal/players/unlink`
|
||||
|
||||
Отвязывает Telegram и/или Discord. Оба флага по умолчанию равны `true`.
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "11111111-1111-1111-1111-111111111111",
|
||||
"telegram": true,
|
||||
"discord": true
|
||||
}
|
||||
```
|
||||
|
||||
Успех: `200 ApiMessage`. Ошибки: `400 invalid_body / invalid_uuid`, `401`, `404 player_not_found`.
|
||||
|
||||
### `POST /internal/players/status`
|
||||
|
||||
Ищет игрока и возвращает состояние регистрации/привязок. В теле должно присутствовать ровно одно из полей `uuid`, `name`, `telegramId`, `discordId`.
|
||||
|
||||
```json
|
||||
{
|
||||
"discordId": "123456789012345678"
|
||||
}
|
||||
```
|
||||
|
||||
Успех: `200 PlayerStatusResponse`; если совпадение отсутствует, возвращается объект с `exists: false`, а не `404`. Ошибки: `400 invalid_body / invalid_uuid / exactly_one_identifier_required`, `401`.
|
||||
|
||||
### `GET /internal/players/{uuid}`
|
||||
|
||||
Возвращает полный `PlayerProfile` по UUID. Ошибки: `400 invalid_uuid`, `401`, `404 player_not_found`.
|
||||
|
||||
### `GET /internal/players/by-name/{name}`
|
||||
|
||||
Ищет полный `PlayerProfile` по Minecraft-нику без учёта регистра. Ошибки: `401`, `404 player_not_found`.
|
||||
|
||||
### `GET /internal/players/by-telegram/{telegramId}`
|
||||
|
||||
Ищет полный `PlayerProfile` по Telegram ID. Ошибки: `400 invalid_telegram_id`, `401`, `404 player_not_found`.
|
||||
|
||||
### `POST /internal/players/{uuid}/telegram`
|
||||
|
||||
Устанавливает либо очищает Telegram-привязку.
|
||||
|
||||
```json
|
||||
{
|
||||
"telegramId": 123456789,
|
||||
"telegramTag": "example"
|
||||
}
|
||||
```
|
||||
|
||||
Оба поля nullable; `null` используется для отвязки. Успех: `200 PlayerProfile`. Ошибки: `400 invalid_body / invalid_uuid`, `401`, `404 player_not_found`.
|
||||
|
||||
### `POST /internal/players/{uuid}/discord`
|
||||
|
||||
Устанавливает либо очищает Discord-привязку. Это endpoint, используемый ShbDiscordBot после погашения локального кода.
|
||||
|
||||
```json
|
||||
{
|
||||
"discordId": "123456789012345678"
|
||||
}
|
||||
```
|
||||
|
||||
`discordId: null` означает отвязку. Успех: `200 PlayerProfile`. Ошибки: `400 invalid_body / invalid_uuid`, `401`, `404 player_not_found`.
|
||||
|
||||
## Player API
|
||||
|
||||
### `GET /api/players/online`
|
||||
|
||||
Возвращает массив `Player` со всеми онлайн-игроками. Ошибки: `401 missing/invalid token`, `403 player_offline`.
|
||||
|
||||
### `GET /api/players/registered`
|
||||
|
||||
Возвращает массив `Player` со всеми зарегистрированными игроками. Ошибки: `401 missing/invalid token`, `403 player_offline`.
|
||||
|
||||
### `GET /api/players/me/state`
|
||||
|
||||
Возвращает `MyPlayerStateResponse` для владельца bearer-токена. Ошибки: `401 missing/invalid token`, `403 player_offline`.
|
||||
|
||||
### `GET /api/players/{uuid}`
|
||||
|
||||
Возвращает зарегистрированного игрока как `Player`.
|
||||
|
||||
Ошибки: `400 invalid_uuid`, `401 missing/invalid token`, `403 player_offline`, `404 player_not_found`.
|
||||
|
||||
## Схемы данных
|
||||
|
||||
`required` ниже означает обязательность по OpenAPI. Nullable-поле может явно содержать `null`.
|
||||
|
||||
### `ApiMessage`
|
||||
|
||||
| Поле | Тип | required |
|
||||
| --- | --- | --- |
|
||||
| `message` | string | да |
|
||||
|
||||
### `JoinRequest`
|
||||
|
||||
| Поле | Тип | required |
|
||||
| --- | --- | --- |
|
||||
| `uuid` | string | да |
|
||||
| `playerName` | string или null | нет |
|
||||
|
||||
### `UuidRequest`, `VerificationCodeRequest`, `PasswordResetRequest`
|
||||
|
||||
Каждая схема содержит одно обязательное поле `uuid: string`.
|
||||
|
||||
### `TokenResponse`
|
||||
|
||||
| Поле | Тип | required |
|
||||
| --- | --- | --- |
|
||||
| `token` | string | да |
|
||||
|
||||
### `VerificationCodeResponse`
|
||||
|
||||
| Поле | Тип | required |
|
||||
| --- | --- | --- |
|
||||
| `code` | string | да |
|
||||
| `expiresAt` | int64 | да |
|
||||
|
||||
OpenAPI не уточняет единицу `expiresAt`; клиенту следует согласовать её с реализацией сервиса.
|
||||
|
||||
### `VerificationVerifyRequest`
|
||||
|
||||
| Поле | Тип | required |
|
||||
| --- | --- | --- |
|
||||
| `code` | string | да |
|
||||
| `telegramId` | int64 или null | нет |
|
||||
| `telegramTag` | string или null | нет |
|
||||
| `discordId` | string или null | нет |
|
||||
|
||||
### `VerificationVerifyResponse`
|
||||
|
||||
| Поле | Тип | required |
|
||||
| --- | --- | --- |
|
||||
| `uuid` | string | да |
|
||||
| `name` | string | да |
|
||||
|
||||
### `PasswordVerifyRequest`
|
||||
|
||||
Обязательные поля: `uuid: string`, `password: string`.
|
||||
|
||||
### `PasswordVerifyResponse`
|
||||
|
||||
Обязательное поле: `valid: boolean`.
|
||||
|
||||
### `PasswordChangeRequest`
|
||||
|
||||
Обязательные поля: `uuid: string`, `newPassword: string`.
|
||||
|
||||
### `UnlinkAccountsRequest`
|
||||
|
||||
| Поле | Тип | required |
|
||||
| --- | --- | --- |
|
||||
| `uuid` | string | да |
|
||||
| `telegram` | boolean | нет |
|
||||
| `discord` | boolean | нет |
|
||||
|
||||
### `PlayerStatusRequest`
|
||||
|
||||
Все поля необязательны/nullable, но сервер требует ровно один идентификатор:
|
||||
|
||||
| Поле | Тип |
|
||||
| --- | --- |
|
||||
| `uuid` | string или null |
|
||||
| `name` | string или null |
|
||||
| `telegramId` | int64 или null |
|
||||
| `discordId` | string или null |
|
||||
|
||||
### `PlayerStatusResponse`
|
||||
|
||||
Только `exists` обязательно по схеме. Остальные поля могут отсутствовать при `exists: false`.
|
||||
|
||||
| Поле | Тип |
|
||||
| --- | --- |
|
||||
| `exists` | boolean |
|
||||
| `uuid` | string или null |
|
||||
| `name` | string или null |
|
||||
| `registered` | boolean |
|
||||
| `telegramLinked` | boolean |
|
||||
| `telegramId` | int64 или null |
|
||||
| `telegramTag` | string или null |
|
||||
| `discordLinked` | boolean |
|
||||
| `discordId` | string или null |
|
||||
|
||||
### `PlayerProfile`
|
||||
|
||||
Все поля обязательны; идентификаторы внешних аккаунтов nullable.
|
||||
|
||||
| Поле | Тип |
|
||||
| --- | --- |
|
||||
| `uuid` | string |
|
||||
| `name` | string |
|
||||
| `registered` | boolean |
|
||||
| `online` | boolean |
|
||||
| `telegramId` | int64 или null |
|
||||
| `telegramTag` | string или null |
|
||||
| `discordId` | string или null |
|
||||
|
||||
### `TelegramLinkRequest`
|
||||
|
||||
Необязательные nullable-поля: `telegramId: int64`, `telegramTag: string`.
|
||||
|
||||
### `DiscordLinkRequest`
|
||||
|
||||
Необязательное nullable-поле: `discordId: string`.
|
||||
|
||||
### `Player`
|
||||
|
||||
| Поле | Тип | required |
|
||||
| --- | --- | --- |
|
||||
| `uuid` | string | да |
|
||||
| `name` | string или null | да |
|
||||
|
||||
### `MyPlayerStateResponse`
|
||||
|
||||
Обязательные поля: `uuid: string`, `name: string`.
|
||||
|
||||
## Пример привязки Discord напрямую
|
||||
|
||||
Проверка текущей связи:
|
||||
|
||||
```http
|
||||
POST /internal/players/status HTTP/1.1
|
||||
Host: api.shlakoblock.com
|
||||
X-Internal-Secret: <secret>
|
||||
Content-Type: application/json
|
||||
|
||||
```
|
||||
|
||||
Запись Discord ID игроку:
|
||||
|
||||
```http
|
||||
POST /internal/players/11111111-1111-1111-1111-111111111111/discord HTTP/1.1
|
||||
Host: api.shlakoblock.com
|
||||
X-Internal-Secret: <secret>
|
||||
Content-Type: application/json
|
||||
|
||||
```
|
||||
{"discordId":"123456789012345678"}
|
||||
```
|
||||
Reference in New Issue
Block a user