{"openapi":"3.1.0","info":{"title":"ESEATV.PRO API","version":"1.0.0","description":"Первичный API портала ESEA Season 59 Europe (CS2). Ответ успеха: `{ data, meta? }`; ошибки: `{ error: { code, message, details? } }`. Все времена — ISO 8601 UTC. Статистика игроков по картам — эндпоинты /matches/{id}/stats и /players/{slug}/stats (D-015)."},"servers":[{"url":"/api/v1"}],"tags":[{"name":"public"},{"name":"admin"}],"components":{"securitySchemes":{"session":{"type":"apiKey","in":"cookie","name":"eseatv_admin","description":"HttpOnly cookie сессии, выдаётся POST /admin/auth/login"},"csrf":{"type":"apiKey","in":"header","name":"x-csrf-token","description":"CSRF-токен сессии; обязателен для всех admin-мутаций (+ проверка Origin)"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}}}}},"PageMeta":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"},"pageCount":{"type":"integer"}}},"MatchStatus":{"type":"string","enum":["scheduled","live","completed","postponed","cancelled","unknown"]}}},"paths":{"/health":{"get":{"tags":["public"],"summary":"Живость приложения и БД","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"503":{"description":"БД недоступна","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/seasons":{"get":{"tags":["public"],"summary":"Сезоны (текущий S59 EU)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}}}}},"/divisions":{"get":{"tags":["public"],"summary":"Дивизионы с этапами и счётчиками","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}}}}},"/divisions/{slug}":{"get":{"tags":["public"],"summary":"Дивизион + таблицы этапов","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"404":{"description":"Не найден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/standings":{"get":{"tags":["public"],"summary":"Таблица этапа (official | calculated)","parameters":[{"name":"stage","in":"query","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Нет stage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Этап не найден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/matches":{"get":{"tags":["public"],"summary":"Матчи с фильтрами и пагинацией","parameters":[{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["upcoming","results","live","all"]}},{"name":"status","in":"query","required":false,"schema":{"$ref":"#/components/schemas/MatchStatus"}},{"name":"division","in":"query","required":false,"schema":{"type":"string"}},{"name":"stage","in":"query","required":false,"schema":{"type":"integer"}},{"name":"team","in":"query","required":false,"schema":{"type":"integer"}},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":64},"description":"Название команды (в т.ч. прежнее)"},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1}},{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Некорректные параметры","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/matches/{id}":{"get":{"tags":["public"],"summary":"Матч: карты, вето (если есть), личные встречи, ссылки на источник","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"404":{"description":"Не найден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/matches/{id}/stats":{"get":{"tags":["public"],"summary":"Статистика игроков матча: byMap[0] — все карты, далее по картам (K, D, A, ADR, HS%, K/D, MVP)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"404":{"description":"Не найден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/teams":{"get":{"tags":["public"],"summary":"Команды","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string"}},{"name":"division","in":"query","required":false,"schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["name","wins","elo"]}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1}},{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}}}}},"/teams/{slug}":{"get":{"tags":["public"],"summary":"Профиль команды: состав, история, матчи, карты, место","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"404":{"description":"Не найдена","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/players":{"get":{"tags":["public"],"summary":"Игроки (рейтинг FACEIT)","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["nickname","elo"]}},{"name":"team","in":"query","required":false,"schema":{"type":"integer"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1}},{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}}}}},"/players/{slug}":{"get":{"tags":["public"],"summary":"Профиль игрока: команды, история рейтинга FACEIT","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"404":{"description":"Не найден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/players/{slug}/stats":{"get":{"tags":["public"],"summary":"Статистика игрока за сезон и последние карты","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"404":{"description":"Не найден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/maps":{"get":{"tags":["public"],"summary":"Справочник карт","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}}}}},"/maps/statistics":{"get":{"tags":["public"],"summary":"Статистика карт (сыграно, доля, пики/баны если есть, результаты команд)","parameters":[{"name":"division","in":"query","required":false,"schema":{"type":"string"}},{"name":"map","in":"query","required":false,"schema":{"type":"string","pattern":"^de_[a-z0-9]+$"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}}}}},"/maps/veto":{"get":{"tags":["public"],"summary":"Статистика вето по подтверждённым данным: баны, первые баны, пики, десайдеры по картам (FACEIT последовательность не отдаёт — только ручной ввод)","parameters":[{"name":"division","in":"query","required":false,"schema":{"type":"string"}},{"name":"team","in":"query","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}}}}},"/search":{"get":{"tags":["public"],"summary":"Поиск по БД: команды, игроки, матчи, дивизионы, этапы","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}}}}},"/data-status":{"get":{"tags":["public"],"summary":"Свежесть данных по источникам","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}}}}},"/compare":{"get":{"tags":["public"],"summary":"Сравнение двух команд","parameters":[{"name":"a","in":"query","required":true,"schema":{"type":"string"}},{"name":"b","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"404":{"description":"Не найдены","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/openapi.json":{"get":{"tags":["public"],"summary":"Это описание","responses":{"200":{"description":"OpenAPI 3.1"}}}},"/auth/register":{"post":{"tags":["users"],"summary":"Регистрация пользователя сайта (для чата): ник 3–20 символов, пароль от 8; ставит HttpOnly cookie. Лимит 5 регистраций в час с адреса","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ username, password }","additionalProperties":true}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Неверный ник/пароль (код в error.code)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Чужой Origin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Ник занят","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Слишком много регистраций","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/login":{"post":{"tags":["users"],"summary":"Вход пользователя сайта (лимит 8 неудач за 15 мин)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ username, password }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"401":{"description":"Неверные данные","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Чужой Origin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Слишком много попыток","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/logout":{"post":{"tags":["users"],"summary":"Выход (нужен заголовок x-csrf-token)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"401":{"description":"Не выполнен вход","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/me":{"get":{"tags":["users"],"summary":"Текущий пользователь и CSRF-токен его сессии (без кэша)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}}}}},"/chat":{"get":{"tags":["users"],"summary":"Сообщения чата (публично): room=global|match-{id}, after — только новые; deleted — скрытые модератором за 10 мин","parameters":[{"name":"room","in":"query","required":false,"schema":{"type":"string"}},{"name":"after","in":"query","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Неизвестная комната","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["users"],"summary":"Написать в чат (вход + x-csrf-token; до 300 символов; не чаще раза в 3 с и 12 в минуту)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ room, body }","additionalProperties":true}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Пустое/длинное сообщение","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Не выполнен вход","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF или блокировка","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Слишком часто","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/auth/login":{"post":{"tags":["admin"],"summary":"Вход (лимит: 5 неудач за 15 мин на клиента+логин)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ username, password }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"401":{"description":"Неверные данные","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Чужой Origin / слабый пароль в production","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Слишком много попыток","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/auth/logout":{"post":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Выход","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/auth/password":{"post":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Смена пароля","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ current, next }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/overview":{"get":{"security":[{"session":[]}],"tags":["admin"],"summary":"Обзор: счётчики, прогоны, ошибки, проблемы данных, привязки, кандидаты","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/audit-logs":{"get":{"security":[{"session":[]}],"tags":["admin"],"summary":"Журнал действий","parameters":[{"name":"entityType","in":"query","required":false,"schema":{"type":"string"}},{"name":"entityId","in":"query","required":false,"schema":{"type":"integer"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/ingestion/runs":{"get":{"security":[{"session":[]}],"tags":["admin"],"summary":"Прогоны синхронизации","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/ingestion/errors":{"get":{"security":[{"session":[]}],"tags":["admin"],"summary":"Ошибки синхронизации","parameters":[{"name":"run","in":"query","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/ingestion/run":{"post":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Запустить задачу (в фоне, 202)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ job: discover|matches|live|details|standings|participants|players }","additionalProperties":true}}}},"responses":{"202":{"description":"Принято","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Неизвестная задача","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/bindings":{"post":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Подтвердить привязку этапа к championship FACEIT","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ stageId, externalId, reason? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Удалить привязку","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ id, reason? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/locks":{"delete":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Снять ручную блокировку поля","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ entity: match|match_map|team|player|roster_membership|standings_entry, id, field, reason? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/matches":{"post":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Создать матч вручную","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ stageId, team1Id, team2Id, scheduledAt, bestOf, reason? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/matches/{id}":{"patch":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Исправить матч (статус, счёт, победитель, формат, время, команды)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"MatchPatch","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/matches/{id}/maps/{n}":{"put":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Создать/исправить карту матча","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}},{"name":"n","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ mapCode?, team1Rounds?, team2Rounds?, winner?, pickedBy?, isPlayed?, reason? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/matches/{id}/veto":{"put":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Ручное подтверждённое вето","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ events: [{ action, mapCode, side }], reason? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/teams":{"post":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Создать команду","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ name, tag?, country?, avatarUrl?, faceitTeamId? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/teams/{id}":{"patch":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Исправить команду","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"TeamInput","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/players":{"post":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Создать игрока","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ nickname, country?, faceitPlayerId?, faceitUrl? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/players/{id}":{"patch":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Исправить игрока","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"PlayerInput","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/roster":{"post":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Добавить игрока в состав","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ teamId, playerId, seasonId, role, joinedAt? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/roster/{id}":{"patch":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Исправить период состава (роль, даты)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ role?, joinedAt?, leftAt? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/standings/{id}":{"patch":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Исправить строку официальной таблицы","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ position?, played?, wins?, losses?, draws?, points?, statusNote? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/stages":{"post":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Создать этап","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ seasonId, divisionId, name, kind, groupLabel?, sortOrder? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/stages/{id}":{"patch":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Исправить этап и правила очков","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"StagePatch","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/divisions/{id}":{"patch":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Исправить дивизион (подтверждение, правила повышения)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"DivisionPatch","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/maps/{code}":{"patch":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Карта в активном пуле","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ inActivePool }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/chat":{"get":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Последние сообщения чата (модерация)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/chat/{id}":{"delete":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Скрыть сообщение чата (с записью в журнал)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ reason? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/users/{id}/ban":{"post":{"security":[{"session":[],"csrf":[]}],"tags":["admin"],"summary":"Заблокировать/разблокировать пользователя чата (с записью в журнал)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"{ banned, reason? }","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Ошибка валидации","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Нет сессии","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"CSRF не пройден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Не найдено","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Конфликт","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}