Files
UniVerse/backend/UniVerse.Api/openapi.json
T
serega404 99d25adbb1
Backend CI / build-and-test (push) Failing after 13m11s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Failing after 10m12s
Frontend CI / build-and-check (push) Failing after 16m9s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Failing after 14m6s
🚀 Create and publish a Docker image / Build & publish backend image (push) Failing after 14m58s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Failing after 14m58s
feat: перелопатил синхронизацию преподавателей
2026-05-24 21:06:03 +03:00

6282 lines
174 KiB
JSON
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.
{
"openapi": "3.0.4",
"info": {
"title": "UniVerse API",
"description": "REST API веб-платформы UniVerse.\n\nАутентификация: JWT Bearer (получить через `POST /api/v1/auth/login/microsoft` или `POST /api/v1/auth/login/dev` в Development).",
"contact": {
"name": "UniVerse Dev"
},
"version": "v1"
},
"paths": {
"/api/v1/achievements": {
"get": {
"tags": [
"Achievements"
],
"summary": "Получить список всех достижений.",
"description": "Возвращает определения достижений (без информации о получении конкретным пользователем).\n Для достижений конкретного пользователя используйте GET /api/v1/users/{id}/achievements.\n\n**Required:** any authenticated user",
"responses": {
"200": {
"description": "Список достижений.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/AchievementDto"
}
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"post": {
"tags": [
"Achievements"
],
"summary": "Создать новое достижение.",
"description": "Только Admin. Достижения автоматически присваиваются студентам при выполнении условий.\n\n**Required roles:** Admin",
"requestBody": {
"description": "Название, описание, иконка, награда в XP/монетах и условие получения.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateAchievementRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/CreateAchievementRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/CreateAchievementRequest"
}
}
}
},
"responses": {
"201": {
"description": "Достижение создано.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AchievementDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/achievements/{id}": {
"get": {
"tags": [
"Achievements"
],
"summary": "Получить достижение по ID.",
"description": "**Required:** any authenticated user",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID достижения.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Данные достижения.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AchievementDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Достижение не найдено.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"put": {
"tags": [
"Achievements"
],
"summary": "Обновить достижение по ID.",
"description": "Только Admin.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID достижения.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"description": "Обновляемые поля достижения.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateAchievementRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/UpdateAchievementRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/UpdateAchievementRequest"
}
}
}
},
"responses": {
"200": {
"description": "Обновлённые данные достижения.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AchievementDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Достижение не найдено.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"delete": {
"tags": [
"Achievements"
],
"summary": "Удалить достижение по ID.",
"description": "Только Admin. Удаление не отзывает достижение у уже получивших его пользователей.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID достижения.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"204": {
"description": "Достижение удалено."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Достижение не найдено.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/auth/login/microsoft": {
"post": {
"tags": [
"Auth"
],
"summary": "Вход через Microsoft Entra ID (SPA/PKCE flow).",
"description": "Фронтенд самостоятельно обрабатывает редирект к Microsoft и передаёт сюда\nполученный authorization code. В ответ возвращается пара JWT-токенов;\nrefresh token устанавливается в HttpOnly cookie.",
"requestBody": {
"description": "Authorization code и redirect URI из Microsoft OAuth2.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginMicrosoftRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/LoginMicrosoftRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/LoginMicrosoftRequest"
}
}
}
},
"responses": {
"200": {
"description": "Успешный вход — возвращает access token и данные пользователя.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthResponse"
}
}
}
},
"400": {
"description": "Неверный или просроченный authorization code.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
}
},
"get": {
"tags": [
"Auth"
],
"summary": "Инициация server-driven входа через Microsoft (редирект-flow).",
"description": "Браузер переходит на этот URL; backend строит Microsoft authorize URL с CSRF state\nи редиректит пользователя на `login.microsoftonline.com`.\nПосле успешного входа Microsoft редиректит на `GET /api/v1/auth/callback/microsoft`.",
"parameters": [
{
"name": "returnUrl",
"in": "query",
"description": "URL для редиректа после успешного входа (опционально).",
"schema": {
"type": "string"
}
}
],
"responses": {
"302": {
"description": "Редирект на Microsoft authorize endpoint."
},
"500": {
"description": "Microsoft authentication не настроен (AzureAd:TenantId/ClientId отсутствуют)."
}
}
}
},
"/api/v1/auth/callback/microsoft": {
"get": {
"tags": [
"Auth"
],
"summary": "OAuth2 callback — обмен code на токены (server-driven flow).",
"description": "Microsoft редиректит браузер сюда после успешного входа.\nBackend валидирует CSRF state, обменивает code на токены,\nустанавливает refresh token cookie и редиректит на `returnUrl` с access token в URL-фрагменте.",
"parameters": [
{
"name": "code",
"in": "query",
"description": "Authorization code от Microsoft.",
"schema": {
"type": "string"
}
},
{
"name": "state",
"in": "query",
"description": "CSRF state для верификации.",
"schema": {
"type": "string"
}
},
{
"name": "error",
"in": "query",
"description": "Код ошибки от Microsoft (если вход не удался).",
"schema": {
"type": "string"
}
},
{
"name": "error_description",
"in": "query",
"description": "Описание ошибки от Microsoft.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Если returnUrl не задан — возвращает JSON с токенами (удобно для тестирования).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthResponse"
}
}
}
},
"302": {
"description": "Успешный вход — редирект на returnUrl с токеном в URL-фрагменте."
},
"400": {
"description": "Отсутствует authorization code.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"401": {
"description": "Ошибка от Microsoft или невалидный CSRF state.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
}
}
},
"/api/v1/auth/login/dev": {
"post": {
"tags": [
"Auth"
],
"summary": "Dev-only вход без OAuth (только в Development-окружении).",
"description": "Создаёт или находит пользователя по email без реального OAuth flow.\nВозвращает 404 в Production и Staging.",
"requestBody": {
"description": "Email, отображаемое имя и роль тестового пользователя.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DevLoginRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/DevLoginRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/DevLoginRequest"
}
}
}
},
"responses": {
"200": {
"description": "Успешный вход.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthResponse"
}
}
}
},
"404": {
"description": "Endpoint недоступен вне Development.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
}
}
},
"/api/v1/auth/refresh": {
"post": {
"tags": [
"Auth"
],
"summary": "Обновление access token по refresh token из HttpOnly cookie.",
"description": "Refresh token читается из HttpOnly cookie `refreshToken` (устанавливается при входе).\nВозвращает новую пару токенов и обновляет cookie.",
"responses": {
"200": {
"description": "Новая пара токенов.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthResponse"
}
}
}
},
"401": {
"description": "Refresh token отсутствует, просрочен или отозван.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Аккаунт деактивирован или refresh token недействителен.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
}
}
},
"/api/v1/auth/logout": {
"post": {
"tags": [
"Auth"
],
"summary": "Выход из системы — отзыв refresh token.",
"description": "Инвалидирует текущий refresh token в БД и удаляет cookie.\nПосле этого вызова access token остаётся валидным до истечения его TTL (30 минут).\n\n**Required:** any authenticated user",
"responses": {
"204": {
"description": "Выход выполнен успешно."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/auth/me": {
"get": {
"tags": [
"Auth"
],
"summary": "Получение профиля текущего авторизованного пользователя.",
"description": "**Required:** any authenticated user",
"responses": {
"200": {
"description": "Данные текущего пользователя.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CurrentUserDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Пользователь не найден в БД (рассинхронизация токена).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/courses": {
"get": {
"tags": [
"Courses"
],
"summary": "Получить список курсов с фильтрацией и пагинацией.",
"description": "**Required:** any authenticated user",
"parameters": [
{
"name": "TagId",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "Search",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "IsSynced",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список курсов (пагинированный).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CourseDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"post": {
"tags": [
"Courses"
],
"summary": "Создать новый курс.",
"description": "Только Admin.\n\n**Required roles:** Admin",
"requestBody": {
"description": "Название и описание курса.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateCourseRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/CreateCourseRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/CreateCourseRequest"
}
}
}
},
"responses": {
"201": {
"description": "Курс создан.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CourseDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/courses/{id}": {
"get": {
"tags": [
"Courses"
],
"summary": "Получить курс по ID (включая теги).",
"description": "**Required:** any authenticated user",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID курса.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Данные курса с тегами.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CourseDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Курс не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"put": {
"tags": [
"Courses"
],
"summary": "Обновить курс по ID.",
"description": "Только Admin.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID курса.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"description": "Новое название и/или описание.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateCourseRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/UpdateCourseRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/UpdateCourseRequest"
}
}
}
},
"responses": {
"200": {
"description": "Обновлённые данные курса.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CourseDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Курс не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"delete": {
"tags": [
"Courses"
],
"summary": "Удалить курс по ID.",
"description": "Только Admin. Удаление курса каскадно удаляет связанные лекции.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID курса.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"204": {
"description": "Курс удалён."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Курс не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/courses/{id}/tags": {
"post": {
"tags": [
"Courses"
],
"summary": "Привязать тег к курсу.",
"description": "Только Admin. Тег должен существовать в системе.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID курса.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"description": "ID тега.",
"content": {
"application/json": {
"schema": {
"type": "integer",
"format": "int32"
}
},
"text/json": {
"schema": {
"type": "integer",
"format": "int32"
}
},
"application/*+json": {
"schema": {
"type": "integer",
"format": "int32"
}
}
}
},
"responses": {
"204": {
"description": "Тег привязан."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Курс или тег не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"409": {
"description": "Тег уже привязан к курсу.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/courses/{id}/tags/{tagId}": {
"delete": {
"tags": [
"Courses"
],
"summary": "Отвязать тег от курса.",
"description": "Только Admin.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID курса.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "tagId",
"in": "path",
"description": "ID тега.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"204": {
"description": "Тег отвязан."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Курс или тег не найден, либо связь не существует.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/lectures": {
"get": {
"tags": [
"Lectures"
],
"summary": "Получить каталог лекций с фильтрацией и пагинацией.",
"description": "Включает флаг `isEnrolled` — записан ли текущий пользователь на лекцию.\n\n**Required:** any authenticated user",
"parameters": [
{
"name": "DateFrom",
"in": "query",
"schema": {
"type": "string",
"format": "date"
}
},
{
"name": "DateTo",
"in": "query",
"schema": {
"type": "string",
"format": "date"
}
},
{
"name": "CourseId",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "TeacherId",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "Format",
"in": "query",
"schema": {
"$ref": "#/components/schemas/LectureFormat"
}
},
{
"name": "IsOpen",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "TagId",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "Search",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список лекций (пагинированный).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LectureDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"post": {
"tags": [
"Lectures"
],
"summary": "Создать новую лекцию.",
"description": "Только Admin. Курс задаётся при создании и не может быть изменён.\n\n**Required roles:** Admin",
"requestBody": {
"description": "Данные лекции: курс, преподаватель, локация, время, формат, вместимость.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateLectureRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/CreateLectureRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/CreateLectureRequest"
}
}
}
},
"responses": {
"201": {
"description": "Лекция создана.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LectureDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/lectures/{id}": {
"get": {
"tags": [
"Lectures"
],
"summary": "Получить детальную карточку лекции по ID.",
"description": "Включает флаг `isEnrolled` — записан ли текущий пользователь на эту лекцию.\n\n**Required:** any authenticated user",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID лекции.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Детальные данные лекции.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LectureDetailDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Лекция не найдена.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"put": {
"tags": [
"Lectures"
],
"summary": "Обновить лекцию по ID.",
"description": "Admin или Teacher. CourseId изменить нельзя.\n\n**Required roles:** Admin, Teacher",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID лекции.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"description": "Обновляемые поля: преподаватель, локация, время, формат, описание.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateLectureRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/UpdateLectureRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/UpdateLectureRequest"
}
}
}
},
"responses": {
"200": {
"description": "Обновлённые данные лекции.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LectureDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin или Teacher.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Лекция не найдена.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"delete": {
"tags": [
"Lectures"
],
"summary": "Удалить лекцию по ID.",
"description": "Только Admin. Каскадно удаляет записи и отзывы.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID лекции.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"204": {
"description": "Лекция удалена."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Лекция не найдена.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/lectures/{id}/enroll": {
"post": {
"tags": [
"Lectures"
],
"summary": "Записаться на лекцию.",
"description": "Только Student. Проверяет наличие свободных мест и отсутствие повторной записи.\nПосле посещения начисляются монеты через gamification.\n\n**Required roles:** Student",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID лекции.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"204": {
"description": "Запись выполнена."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Student.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Лекция не найдена.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"409": {
"description": "Студент уже записан или мест нет.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"delete": {
"tags": [
"Lectures"
],
"summary": "Отменить запись на лекцию.",
"description": "Только Student. Отменить можно только свою запись.\n\n**Required roles:** Student",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID лекции.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"204": {
"description": "Запись отменена."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Student.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Лекция или запись не найдена.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/lectures/{id}/attendance/{userId}": {
"patch": {
"tags": [
"Lectures"
],
"summary": "Отметить посещение студента на лекции.",
"description": "Admin или Teacher. При отметке `attended=true` начисляются монеты за посещение\nчерез gamification service.\n\n**Required roles:** Admin, Teacher",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID лекции.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "userId",
"in": "path",
"description": "ID студента.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"description": "true — посетил, false — не посетил.",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
},
"text/json": {
"schema": {
"type": "boolean"
}
},
"application/*+json": {
"schema": {
"type": "boolean"
}
}
}
},
"responses": {
"204": {
"description": "Посещение отмечено."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin или Teacher.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Лекция или запись студента не найдена.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/lectures/{id}/enrollments": {
"get": {
"tags": [
"Lectures"
],
"summary": "Получить список записавшихся студентов на лекцию.",
"description": "Только Admin или Teacher. Включает флаг посещения (`attended`).\n\n**Required roles:** Admin, Teacher",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID лекции.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список записей (пагинированный).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EnrollmentDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin или Teacher.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Лекция не найдена.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/lectures/{id}/reviews": {
"get": {
"tags": [
"Lectures"
],
"summary": "Получить отзывы к лекции.",
"description": "Только Admin или Teacher.\n\n**Required roles:** Admin, Teacher",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID лекции.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список отзывов (пагинированный).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReviewDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin или Teacher.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Лекция не найдена.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/locations": {
"get": {
"tags": [
"Locations"
],
"summary": "Получить список всех локаций.",
"description": "**Required:** any authenticated user",
"responses": {
"200": {
"description": "Список локаций.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/LocationDto"
}
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"post": {
"tags": [
"Locations"
],
"summary": "Создать новую локацию.",
"description": "Только Admin. Локации также создаются автоматически при синхронизации с Modeus.\n\n**Required roles:** Admin",
"requestBody": {
"description": "Название, корпус, аудитория и/или адрес.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateLocationRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/CreateLocationRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/CreateLocationRequest"
}
}
}
},
"responses": {
"201": {
"description": "Локация создана.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LocationDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/locations/{id}": {
"get": {
"tags": [
"Locations"
],
"summary": "Получить локацию по ID.",
"description": "**Required:** any authenticated user",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID локации.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Данные локации.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LocationDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Локация не найдена.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"put": {
"tags": [
"Locations"
],
"summary": "Обновить локацию по ID.",
"description": "Только Admin.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID локации.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"description": "Обновляемые поля: название, корпус, аудитория, адрес.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateLocationRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/UpdateLocationRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/UpdateLocationRequest"
}
}
}
},
"responses": {
"200": {
"description": "Обновлённые данные локации.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LocationDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Локация не найдена.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"delete": {
"tags": [
"Locations"
],
"summary": "Удалить локацию по ID.",
"description": "Только Admin. При удалении локации у связанных лекций поле `locationId` становится null.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID локации.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"204": {
"description": "Локация удалена."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Локация не найдена.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/notifications": {
"get": {
"tags": [
"Notifications"
],
"summary": "Получить уведомления текущего пользователя.",
"description": "**Required:** any authenticated user",
"parameters": [
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список уведомлений.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserNotificationDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/notifications/read-all": {
"patch": {
"tags": [
"Notifications"
],
"summary": "Отметить все уведомления текущего пользователя как прочитанные.",
"description": "**Required:** any authenticated user",
"responses": {
"204": {
"description": "Уведомления отмечены прочитанными."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/notifications/send": {
"post": {
"tags": [
"Notifications"
],
"summary": "Отправить уведомление немедленно.",
"description": "Канал задаётся строкой, например `email`. Новые провайдеры добавляются через `INotificationProvider`.\n\n**Required roles:** Admin",
"requestBody": {
"description": "Канал, получатель, тема и текст уведомления.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SendNotificationRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/SendNotificationRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/SendNotificationRequest"
}
}
}
},
"responses": {
"202": {
"description": "Уведомление принято к отправке."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/notifications/schedule": {
"post": {
"tags": [
"Notifications"
],
"summary": "Запланировать отложенную отправку уведомления через Quartz.NET.",
"description": "**Required roles:** Admin",
"requestBody": {
"description": "Уведомление и момент отправки.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ScheduleNotificationRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/ScheduleNotificationRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/ScheduleNotificationRequest"
}
}
}
},
"responses": {
"202": {
"description": "Уведомление поставлено в очередь Quartz.NET.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ScheduledNotificationResponse"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/reviews": {
"post": {
"tags": [
"Reviews"
],
"summary": "Создать отзыв к лекции.",
"description": "Только Student. После создания отзыв отправляется на LLM-анализ\n(статус `Pending`). LLM оценивает содержательность и начисляет монеты\nскрытно от пользователя.\n\n**Required roles:** Student",
"requestBody": {
"description": "ID лекции, оценка (Like/Neutral/Dislike) и текст отзыва.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateReviewRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/CreateReviewRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/CreateReviewRequest"
}
}
}
},
"responses": {
"201": {
"description": "Отзыв создан и поставлен в очередь на LLM-анализ.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReviewDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Student.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Лекция не найдена.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"409": {
"description": "Студент уже оставил отзыв к этой лекции.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"get": {
"tags": [
"Reviews"
],
"summary": "Получить список всех отзывов.",
"description": "Только Admin. Возвращает все отзывы независимо от LLM-статуса.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "LlmStatus",
"in": "query",
"schema": {
"$ref": "#/components/schemas/ReviewLlmStatus"
}
},
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список всех отзывов (пагинированный).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReviewDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/reviews/llm-prompt": {
"get": {
"tags": [
"Reviews"
],
"summary": "Получить текущий промпт LLM-анализа отзывов.",
"description": "Только Admin. Если настройка ещё не сохранена, возвращает базовый промпт.\n\n**Required roles:** Admin",
"responses": {
"200": {
"description": "Текущий шаблон промпта.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReviewPromptDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"put": {
"tags": [
"Reviews"
],
"summary": "Обновить промпт LLM-анализа отзывов.",
"description": "Только Admin. Промпт применяется к следующим анализам и ручным повторам.\n\n**Required roles:** Admin",
"requestBody": {
"description": "Новый шаблон с плейсхолдерами {lectureContext} и {reviewText}.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateReviewPromptRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/UpdateReviewPromptRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/UpdateReviewPromptRequest"
}
}
}
},
"responses": {
"200": {
"description": "Сохранённый шаблон промпта.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReviewPromptDto"
}
}
}
},
"400": {
"description": "Промпт пустой или не содержит обязательные плейсхолдеры.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/reviews/{id}": {
"get": {
"tags": [
"Reviews"
],
"summary": "Получить отзыв по ID.",
"description": "Только Admin или Teacher.\n\n**Required roles:** Admin, Teacher",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID отзыва.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Данные отзыва (включая LLM-статус и сентимент).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReviewDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin или Teacher.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Отзыв не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"put": {
"tags": [
"Reviews"
],
"summary": "Обновить отзыв.",
"description": "Разрешено любому авторизованному пользователю, но сервис проверяет владельца.\nИзменение текста сбрасывает LLM-статус в `Pending` (повторный анализ).\n\n**Required:** any authenticated user",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID отзыва.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"description": "Новая оценка и/или текст.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateReviewRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/UpdateReviewRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/UpdateReviewRequest"
}
}
}
},
"responses": {
"200": {
"description": "Обновлённые данные отзыва.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReviewDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Отзыв принадлежит другому пользователю.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Отзыв не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"delete": {
"tags": [
"Reviews"
],
"summary": "Удалить отзыв.",
"description": "Владелец может удалить свой отзыв. Admin может удалить любой.\n\n**Required:** any authenticated user",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID отзыва.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"204": {
"description": "Отзыв удалён."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Нет прав на удаление (не владелец и не Admin).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Отзыв не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/reviews/{id}/reanalyze": {
"post": {
"tags": [
"Reviews"
],
"summary": "Запустить повторный LLM-анализ отзыва.",
"description": "Только Admin. Сбрасывает статус отзыва на `Pending` и отправляет его\nна повторную обработку.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID отзыва.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"204": {
"description": "Повторный анализ запланирован."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Отзыв не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/sync/schedule": {
"post": {
"tags": [
"Sync"
],
"summary": "Запустить синхронизацию расписания лекций из Modeus.",
"description": "Только Admin. Выполняет upsert лекций и связанных курсов на основе данных\nиз внешнего API `schedule.rdcenter.ru`. Поддерживает фильтрацию по специальности,\nпериоду и типу занятий.\n\n**Required roles:** Admin",
"requestBody": {
"description": "Параметры синхронизации: specialtyCode, timeMin/timeMax, typeId.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SyncScheduleRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/SyncScheduleRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/SyncScheduleRequest"
}
}
}
},
"responses": {
"200": {
"description": "Результат синхронизации: кол-во созданных, обновлённых и пропущенных записей.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SyncResultDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/sync/status": {
"get": {
"tags": [
"Sync"
],
"summary": "Получить статус последней синхронизации.",
"description": "Только Admin. Возвращает время и результат последней успешной синхронизации.\n\n**Required roles:** Admin",
"responses": {
"200": {
"description": "Статус синхронизации.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SyncStatusDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/sync/rooms": {
"post": {
"tags": [
"Sync"
],
"summary": "Синхронизировать аудитории (локации) из Modeus.",
"description": "Только Admin. Импортирует аудитории из `schedule.rdcenter.ru` и создаёт\nсоответствующие записи в таблице locations.\n\n**Required roles:** Admin",
"responses": {
"200": {
"description": "Результат синхронизации аудиторий.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SyncResultDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/sync/employees": {
"post": {
"tags": [
"Sync"
],
"summary": "Поиск преподавателей в Modeus по ФИО.",
"description": "Только Admin. Ищет преподавателей через внешнее API и возвращает список\nдля ручного импорта. Найденные преподаватели не создаются автоматически.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "fullname",
"in": "query",
"description": "Полное имя или часть имени преподавателя для поиска.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Список найденных преподавателей.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/EmployeeDto"
}
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/tags": {
"get": {
"tags": [
"Tags"
],
"summary": "Получить список тегов с опциональной фильтрацией по типу и родителю.",
"description": "**Required:** any authenticated user",
"parameters": [
{
"name": "type",
"in": "query",
"description": "Тип тега: Institute, Faculty, Subject, Organization, Topic, Other.",
"schema": {
"$ref": "#/components/schemas/TagType"
}
},
{
"name": "parentId",
"in": "query",
"description": "ID родительского тега (фильтрация дочерних).",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список тегов.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/TagDto"
}
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"post": {
"tags": [
"Tags"
],
"summary": "Создать новый тег.",
"description": "Только Admin.\n\n**Required roles:** Admin",
"requestBody": {
"description": "Название, тип и опциональный родительский тег.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateTagRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/CreateTagRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/CreateTagRequest"
}
}
}
},
"responses": {
"201": {
"description": "Тег создан.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TagDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/tags/{id}": {
"get": {
"tags": [
"Tags"
],
"summary": "Получить тег по ID.",
"description": "**Required:** any authenticated user",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID тега.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Данные тега.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TagDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Тег не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"put": {
"tags": [
"Tags"
],
"summary": "Обновить тег по ID.",
"description": "Только Admin.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID тега.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"description": "Новое название, тип и/или родительский тег.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateTagRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/UpdateTagRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/UpdateTagRequest"
}
}
}
},
"responses": {
"200": {
"description": "Обновлённые данные тега.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TagDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Тег не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"delete": {
"tags": [
"Tags"
],
"summary": "Удалить тег по ID.",
"description": "Только Admin. Удаление тега каскадно удаляет привязки к курсам (`course_tags`).\nДочерние теги остаются, но их `parentId` становится null.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID тега.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"204": {
"description": "Тег удалён."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Тег не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/tags/tree": {
"get": {
"tags": [
"Tags"
],
"summary": "Получить иерархическое дерево всех тегов.",
"description": "Возвращает корневые теги с вложенными дочерними тегами.\nПолезно для построения фильтрующих UI-компонентов.\n\n**Required:** any authenticated user",
"responses": {
"200": {
"description": "Иерархический список тегов.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/TagTreeDto"
}
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/me": {
"get": {
"tags": [
"Users"
],
"summary": "Получить профиль текущего пользователя.",
"description": "**Required:** any authenticated user",
"responses": {
"200": {
"description": "Данные текущего пользователя.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CurrentUserDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Пользователь не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"put": {
"tags": [
"Users"
],
"summary": "Обновить профиль текущего пользователя (displayName, avatarUrl).",
"description": "**Required:** any authenticated user",
"requestBody": {
"description": "Обновляемые поля профиля.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateUserRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/UpdateUserRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/UpdateUserRequest"
}
}
}
},
"responses": {
"200": {
"description": "Обновлённые данные текущего пользователя.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CurrentUserDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Пользователь не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/me/stats": {
"get": {
"tags": [
"Users"
],
"summary": "Получить статистику текущего пользователя.",
"description": "**Required:** any authenticated user",
"responses": {
"200": {
"description": "Статистика текущего пользователя.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserStatsDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Пользователь не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/me/enrollments": {
"get": {
"tags": [
"Users"
],
"summary": "Получить список записей текущего пользователя на лекции.",
"description": "**Required:** any authenticated user",
"parameters": [
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список записей (пагинированный).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LectureDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Пользователь не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/me/reviews": {
"get": {
"tags": [
"Users"
],
"summary": "Получить отзывы текущего пользователя.",
"description": "**Required:** any authenticated user",
"parameters": [
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список отзывов (пагинированный).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReviewDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/me/achievements": {
"get": {
"tags": [
"Users"
],
"summary": "Получить достижения текущего пользователя.",
"description": "**Required:** any authenticated user",
"responses": {
"200": {
"description": "Список полученных достижений.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserAchievementDto"
}
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/me/transactions": {
"get": {
"tags": [
"Users"
],
"summary": "Получить историю транзакций монет текущего пользователя.",
"description": "**Required:** any authenticated user",
"parameters": [
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "История транзакций (пагинированная).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CoinTransactionDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/{id}": {
"get": {
"tags": [
"Users"
],
"summary": "Получить профиль пользователя по ID.",
"description": "Только Admin. Для текущего пользователя используйте GET /api/v1/users/me.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID пользователя.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Данные пользователя.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Пользователь не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
},
"put": {
"tags": [
"Users"
],
"summary": "Обновить профиль пользователя (displayName, avatarUrl).",
"description": "Только Admin. Для текущего пользователя используйте PUT /api/v1/users/me.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID пользователя.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"description": "Обновляемые поля профиля.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateUserRequest"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/UpdateUserRequest"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/UpdateUserRequest"
}
}
}
},
"responses": {
"200": {
"description": "Обновлённые данные пользователя.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Пользователь не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/{id}/stats": {
"get": {
"tags": [
"Users"
],
"summary": "Получить статистику пользователя (XP, монеты, уровень, посещения).",
"description": "Только Admin. Для текущего пользователя используйте GET /api/v1/users/me/stats.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID пользователя.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Статистика пользователя.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserStatsDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Пользователь не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/{id}/enrollments": {
"get": {
"tags": [
"Users"
],
"summary": "Получить список записей пользователя на лекции.",
"description": "Только Admin. Для текущего пользователя используйте GET /api/v1/users/me/enrollments.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID пользователя.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список записей (пагинированный).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LectureDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Пользователь не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/{id}/reviews": {
"get": {
"tags": [
"Users"
],
"summary": "Получить отзывы пользователя.",
"description": "Только Admin. Для текущего пользователя используйте GET /api/v1/users/me/reviews.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID пользователя.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список отзывов (пагинированный).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReviewDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/{id}/achievements": {
"get": {
"tags": [
"Users"
],
"summary": "Получить достижения пользователя.",
"description": "Только Admin. Для текущего пользователя используйте GET /api/v1/users/me/achievements.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID пользователя.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список полученных достижений.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserAchievementDto"
}
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/{id}/transactions": {
"get": {
"tags": [
"Users"
],
"summary": "Получить историю транзакций монет пользователя.",
"description": "Только Admin. Для текущего пользователя используйте GET /api/v1/users/me/transactions.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID пользователя.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "История транзакций (пагинированная).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CoinTransactionDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users": {
"get": {
"tags": [
"Users"
],
"summary": "Получить список всех пользователей с фильтрацией и пагинацией.",
"description": "Только Admin.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "Search",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "Role",
"in": "query",
"schema": {
"$ref": "#/components/schemas/UserRole"
}
},
{
"name": "IsActive",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список пользователей (пагинированный).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserDtoPagedResult"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/{id}/role": {
"patch": {
"tags": [
"Users"
],
"summary": "Изменить набор ролей пользователя.",
"description": "Только Admin. Доступные роли: Student, Teacher, Admin.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID пользователя.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"description": "Новый набор ролей пользователя.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserRole"
}
}
},
"text/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserRole"
}
}
},
"application/*+json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserRole"
}
}
}
}
},
"responses": {
"204": {
"description": "Роли успешно изменены."
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Пользователь не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/{id}/active": {
"patch": {
"tags": [
"Users"
],
"summary": "Активировать или деактивировать аккаунт пользователя.",
"description": "Только Admin. Деактивированный пользователь не может войти в систему.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID пользователя.",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"description": "true — активировать, false — деактивировать.",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
},
"text/json": {
"schema": {
"type": "boolean"
}
},
"application/*+json": {
"schema": {
"type": "boolean"
}
}
}
},
"responses": {
"204": {
"description": "Статус успешно изменён."
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"404": {
"description": "Пользователь не найден.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
}
},
"components": {
"schemas": {
"AchievementDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"name": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
},
"iconUrl": {
"type": "string",
"nullable": true
},
"xpReward": {
"type": "integer",
"format": "int32"
},
"coinReward": {
"type": "integer",
"format": "int32"
},
"condition": {
"type": "string",
"nullable": true
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"AuthResponse": {
"type": "object",
"properties": {
"accessToken": {
"type": "string",
"nullable": true
},
"expiresAt": {
"type": "string",
"format": "date-time"
},
"user": {
"$ref": "#/components/schemas/UserAuthDto"
}
},
"additionalProperties": false
},
"CoinTransactionDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"amount": {
"type": "integer",
"format": "int32"
},
"type": {
"$ref": "#/components/schemas/CoinTransactionType"
},
"reviewId": {
"type": "integer",
"format": "int32",
"nullable": true
},
"achievementId": {
"type": "integer",
"format": "int32",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"CoinTransactionDtoPagedResult": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CoinTransactionDto"
},
"nullable": true
},
"totalCount": {
"type": "integer",
"format": "int32"
},
"page": {
"type": "integer",
"format": "int32"
},
"pageSize": {
"type": "integer",
"format": "int32"
},
"totalPages": {
"type": "integer",
"format": "int32"
}
},
"additionalProperties": false
},
"CoinTransactionType": {
"enum": [
"ReviewReward",
"AchievementReward",
"AttendanceReward",
"AdminAdjustment"
],
"type": "string"
},
"CourseDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"name": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
},
"isSynced": {
"type": "boolean"
},
"tags": {
"type": "array",
"items": {
"$ref": "#/components/schemas/TagDto"
},
"nullable": true
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"CourseDtoPagedResult": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CourseDto"
},
"nullable": true
},
"totalCount": {
"type": "integer",
"format": "int32"
},
"page": {
"type": "integer",
"format": "int32"
},
"pageSize": {
"type": "integer",
"format": "int32"
},
"totalPages": {
"type": "integer",
"format": "int32"
}
},
"additionalProperties": false
},
"CreateAchievementRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
},
"iconUrl": {
"type": "string",
"nullable": true
},
"xpReward": {
"type": "integer",
"format": "int32"
},
"coinReward": {
"type": "integer",
"format": "int32"
},
"condition": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"CreateCourseRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"CreateLectureRequest": {
"type": "object",
"properties": {
"courseId": {
"type": "integer",
"format": "int32"
},
"teacherId": {
"type": "integer",
"format": "int32",
"nullable": true
},
"locationId": {
"type": "integer",
"format": "int32",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
},
"format": {
"$ref": "#/components/schemas/LectureFormat"
},
"startsAt": {
"type": "string",
"format": "date-time"
},
"endsAt": {
"type": "string",
"format": "date-time"
},
"isOpen": {
"type": "boolean"
},
"maxEnrollments": {
"type": "integer",
"format": "int32"
},
"onlineUrl": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"CreateLocationRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"nullable": true
},
"building": {
"type": "string",
"nullable": true
},
"room": {
"type": "string",
"nullable": true
},
"address": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"CreateReviewRequest": {
"type": "object",
"properties": {
"lectureId": {
"type": "integer",
"format": "int32"
},
"rating": {
"$ref": "#/components/schemas/ReviewRating"
},
"text": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"CreateTagRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"nullable": true
},
"type": {
"$ref": "#/components/schemas/TagType"
},
"parentId": {
"type": "integer",
"format": "int32",
"nullable": true
}
},
"additionalProperties": false
},
"CurrentUserDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"email": {
"type": "string",
"nullable": true
},
"displayName": {
"type": "string",
"nullable": true
},
"avatarUrl": {
"type": "string",
"nullable": true
},
"roles": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserRole"
},
"nullable": true
},
"xp": {
"type": "integer",
"format": "int32"
},
"coins": {
"type": "integer",
"format": "int32"
},
"level": {
"type": "integer",
"format": "int32"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"DevLoginRequest": {
"type": "object",
"properties": {
"email": {
"type": "string",
"nullable": true
},
"displayName": {
"type": "string",
"nullable": true
},
"roles": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserRole"
},
"nullable": true
}
},
"additionalProperties": false
},
"EmployeeDto": {
"type": "object",
"properties": {
"id": {
"type": "string",
"nullable": true
},
"fullName": {
"type": "string",
"nullable": true
},
"department": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"EnrollmentDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"userId": {
"type": "integer",
"format": "int32"
},
"userName": {
"type": "string",
"nullable": true
},
"userEmail": {
"type": "string",
"nullable": true
},
"attended": {
"type": "boolean"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"EnrollmentDtoPagedResult": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/components/schemas/EnrollmentDto"
},
"nullable": true
},
"totalCount": {
"type": "integer",
"format": "int32"
},
"page": {
"type": "integer",
"format": "int32"
},
"pageSize": {
"type": "integer",
"format": "int32"
},
"totalPages": {
"type": "integer",
"format": "int32"
}
},
"additionalProperties": false
},
"EnrollmentSlotRuleDto": {
"type": "object",
"properties": {
"level": {
"type": "integer",
"format": "int32"
},
"slots": {
"type": "integer",
"format": "int32"
}
},
"additionalProperties": false
},
"LectureDetailDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"courseId": {
"type": "integer",
"format": "int32"
},
"courseName": {
"type": "string",
"nullable": true
},
"teacherId": {
"type": "integer",
"format": "int32",
"nullable": true
},
"teacherName": {
"type": "string",
"nullable": true
},
"locationId": {
"type": "integer",
"format": "int32",
"nullable": true
},
"locationName": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
},
"format": {
"$ref": "#/components/schemas/LectureFormat"
},
"startsAt": {
"type": "string",
"format": "date-time"
},
"endsAt": {
"type": "string",
"format": "date-time"
},
"isOpen": {
"type": "boolean"
},
"maxEnrollments": {
"type": "integer",
"format": "int32"
},
"enrollmentsCount": {
"type": "integer",
"format": "int32"
},
"onlineUrl": {
"type": "string",
"nullable": true
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"isEnrolled": {
"type": "boolean"
}
},
"additionalProperties": false
},
"LectureDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"courseId": {
"type": "integer",
"format": "int32"
},
"courseName": {
"type": "string",
"nullable": true
},
"teacherId": {
"type": "integer",
"format": "int32",
"nullable": true
},
"teacherName": {
"type": "string",
"nullable": true
},
"locationId": {
"type": "integer",
"format": "int32",
"nullable": true
},
"locationName": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
},
"format": {
"$ref": "#/components/schemas/LectureFormat"
},
"startsAt": {
"type": "string",
"format": "date-time"
},
"endsAt": {
"type": "string",
"format": "date-time"
},
"isOpen": {
"type": "boolean"
},
"maxEnrollments": {
"type": "integer",
"format": "int32"
},
"enrollmentsCount": {
"type": "integer",
"format": "int32"
},
"onlineUrl": {
"type": "string",
"nullable": true
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"isEnrolled": {
"type": "boolean"
}
},
"additionalProperties": false
},
"LectureDtoPagedResult": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/components/schemas/LectureDto"
},
"nullable": true
},
"totalCount": {
"type": "integer",
"format": "int32"
},
"page": {
"type": "integer",
"format": "int32"
},
"pageSize": {
"type": "integer",
"format": "int32"
},
"totalPages": {
"type": "integer",
"format": "int32"
}
},
"additionalProperties": false
},
"LectureFormat": {
"enum": [
"Online",
"Offline"
],
"type": "string"
},
"LocationDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"name": {
"type": "string",
"nullable": true
},
"building": {
"type": "string",
"nullable": true
},
"room": {
"type": "string",
"nullable": true
},
"address": {
"type": "string",
"nullable": true
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"LoginMicrosoftRequest": {
"type": "object",
"properties": {
"authorizationCode": {
"type": "string",
"nullable": true
},
"redirectUri": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"ProblemDetails": {
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"type": "integer",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
}
},
"additionalProperties": { }
},
"ReviewDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"lectureId": {
"type": "integer",
"format": "int32"
},
"lectureTitle": {
"type": "string",
"nullable": true
},
"userId": {
"type": "integer",
"format": "int32"
},
"userName": {
"type": "string",
"nullable": true
},
"rating": {
"$ref": "#/components/schemas/ReviewRating"
},
"text": {
"type": "string",
"nullable": true
},
"llmStatus": {
"$ref": "#/components/schemas/ReviewLlmStatus"
},
"sentiment": {
"$ref": "#/components/schemas/ReviewSentiment"
},
"qualityScore": {
"type": "number",
"format": "double",
"nullable": true
},
"isInformative": {
"type": "boolean",
"nullable": true
},
"llmTags": {
"type": "array",
"items": {
"type": "string"
},
"nullable": true
},
"llmRawOutput": {
"type": "string",
"nullable": true
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"ReviewDtoPagedResult": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ReviewDto"
},
"nullable": true
},
"totalCount": {
"type": "integer",
"format": "int32"
},
"page": {
"type": "integer",
"format": "int32"
},
"pageSize": {
"type": "integer",
"format": "int32"
},
"totalPages": {
"type": "integer",
"format": "int32"
}
},
"additionalProperties": false
},
"ReviewLlmStatus": {
"enum": [
"Pending",
"Analyzed",
"Rejected"
],
"type": "string"
},
"ReviewPromptDto": {
"type": "object",
"properties": {
"prompt": {
"type": "string",
"nullable": true
},
"updatedAt": {
"type": "string",
"format": "date-time",
"nullable": true
}
},
"additionalProperties": false
},
"ReviewRating": {
"enum": [
"Like",
"Neutral",
"Dislike"
],
"type": "string"
},
"ReviewSentiment": {
"enum": [
"Positive",
"Neutral",
"Negative"
],
"type": "string"
},
"ScheduleNotificationRequest": {
"type": "object",
"properties": {
"channel": {
"type": "string",
"nullable": true
},
"recipient": {
"type": "string",
"nullable": true
},
"subject": {
"type": "string",
"nullable": true
},
"body": {
"type": "string",
"nullable": true
},
"sendAt": {
"type": "string",
"format": "date-time"
},
"recipientName": {
"type": "string",
"nullable": true
},
"metadata": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"nullable": true
}
},
"additionalProperties": false
},
"ScheduledNotificationResponse": {
"type": "object",
"properties": {
"jobId": {
"type": "string",
"nullable": true
},
"sendAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"SendNotificationRequest": {
"type": "object",
"properties": {
"channel": {
"type": "string",
"nullable": true
},
"recipient": {
"type": "string",
"nullable": true
},
"subject": {
"type": "string",
"nullable": true
},
"body": {
"type": "string",
"nullable": true
},
"recipientName": {
"type": "string",
"nullable": true
},
"metadata": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"nullable": true
}
},
"additionalProperties": false
},
"SyncResultDto": {
"type": "object",
"properties": {
"created": {
"type": "integer",
"format": "int32"
},
"updated": {
"type": "integer",
"format": "int32"
},
"skipped": {
"type": "integer",
"format": "int32"
},
"error": {
"type": "string",
"nullable": true
},
"details": {
"type": "array",
"items": {
"type": "string"
},
"nullable": true
}
},
"additionalProperties": false
},
"SyncScheduleRequest": {
"type": "object",
"properties": {
"specialtyCode": {
"type": "string",
"nullable": true
},
"timeMin": {
"type": "string",
"format": "date-time",
"nullable": true
},
"timeMax": {
"type": "string",
"format": "date-time",
"nullable": true
},
"typeId": {
"type": "array",
"items": {
"type": "string"
},
"nullable": true
}
},
"additionalProperties": false
},
"SyncStatusDto": {
"type": "object",
"properties": {
"lastSyncAt": {
"type": "string",
"format": "date-time",
"nullable": true
},
"status": {
"type": "string",
"nullable": true
},
"lastResult": {
"$ref": "#/components/schemas/SyncResultDto"
}
},
"additionalProperties": false
},
"TagDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"name": {
"type": "string",
"nullable": true
},
"type": {
"$ref": "#/components/schemas/TagType"
},
"parentId": {
"type": "integer",
"format": "int32",
"nullable": true
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"TagTreeDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"name": {
"type": "string",
"nullable": true
},
"type": {
"$ref": "#/components/schemas/TagType"
},
"children": {
"type": "array",
"items": {
"$ref": "#/components/schemas/TagTreeDto"
},
"nullable": true
}
},
"additionalProperties": false
},
"TagType": {
"enum": [
"Institute",
"Faculty",
"Subject",
"Organization",
"Topic",
"Other"
],
"type": "string"
},
"UpdateAchievementRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
},
"iconUrl": {
"type": "string",
"nullable": true
},
"xpReward": {
"type": "integer",
"format": "int32"
},
"coinReward": {
"type": "integer",
"format": "int32"
},
"condition": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"UpdateCourseRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"UpdateLectureRequest": {
"type": "object",
"properties": {
"teacherId": {
"type": "integer",
"format": "int32",
"nullable": true
},
"locationId": {
"type": "integer",
"format": "int32",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
},
"format": {
"$ref": "#/components/schemas/LectureFormat"
},
"startsAt": {
"type": "string",
"format": "date-time"
},
"endsAt": {
"type": "string",
"format": "date-time"
},
"isOpen": {
"type": "boolean"
},
"maxEnrollments": {
"type": "integer",
"format": "int32"
},
"onlineUrl": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"UpdateLocationRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"nullable": true
},
"building": {
"type": "string",
"nullable": true
},
"room": {
"type": "string",
"nullable": true
},
"address": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"UpdateReviewPromptRequest": {
"type": "object",
"properties": {
"prompt": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"UpdateReviewRequest": {
"type": "object",
"properties": {
"rating": {
"$ref": "#/components/schemas/ReviewRating"
},
"text": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"UpdateTagRequest": {
"type": "object",
"properties": {
"name": {
"type": "string",
"nullable": true
},
"type": {
"$ref": "#/components/schemas/TagType"
},
"parentId": {
"type": "integer",
"format": "int32",
"nullable": true
}
},
"additionalProperties": false
},
"UpdateUserRequest": {
"type": "object",
"properties": {
"displayName": {
"type": "string",
"nullable": true
},
"avatarUrl": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"UserAchievementDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"achievement": {
"$ref": "#/components/schemas/AchievementDto"
},
"awardedAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"UserAuthDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"email": {
"type": "string",
"nullable": true
},
"displayName": {
"type": "string",
"nullable": true
},
"roles": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserRole"
},
"nullable": true
}
},
"additionalProperties": false
},
"UserDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"email": {
"type": "string",
"nullable": true
},
"displayName": {
"type": "string",
"nullable": true
},
"avatarUrl": {
"type": "string",
"nullable": true
},
"roles": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserRole"
},
"nullable": true
},
"isActive": {
"type": "boolean"
},
"xp": {
"type": "integer",
"format": "int32"
},
"coins": {
"type": "integer",
"format": "int32"
},
"level": {
"type": "integer",
"format": "int32"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"UserDtoPagedResult": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserDto"
},
"nullable": true
},
"totalCount": {
"type": "integer",
"format": "int32"
},
"page": {
"type": "integer",
"format": "int32"
},
"pageSize": {
"type": "integer",
"format": "int32"
},
"totalPages": {
"type": "integer",
"format": "int32"
}
},
"additionalProperties": false
},
"UserNotificationDto": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"body": {
"type": "string",
"nullable": true
},
"isRead": {
"type": "boolean"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"UserNotificationDtoPagedResult": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserNotificationDto"
},
"nullable": true
},
"totalCount": {
"type": "integer",
"format": "int32"
},
"page": {
"type": "integer",
"format": "int32"
},
"pageSize": {
"type": "integer",
"format": "int32"
},
"totalPages": {
"type": "integer",
"format": "int32"
}
},
"additionalProperties": false
},
"UserRole": {
"enum": [
"Student",
"Teacher",
"Admin"
],
"type": "string"
},
"UserStatsDto": {
"type": "object",
"properties": {
"totalLectures": {
"type": "integer",
"format": "int32"
},
"attendedLectures": {
"type": "integer",
"format": "int32"
},
"totalReviews": {
"type": "integer",
"format": "int32"
},
"xp": {
"type": "integer",
"format": "int32"
},
"coins": {
"type": "integer",
"format": "int32"
},
"level": {
"type": "integer",
"format": "int32"
},
"achievementsCount": {
"type": "integer",
"format": "int32"
},
"currentLevelXp": {
"type": "integer",
"format": "int32"
},
"nextLevelXp": {
"type": "integer",
"format": "int32",
"nullable": true
},
"activeEnrollments": {
"type": "integer",
"format": "int32"
},
"enrollmentSlotLimit": {
"type": "integer",
"format": "int32"
},
"enrollmentSlotRules": {
"type": "array",
"items": {
"$ref": "#/components/schemas/EnrollmentSlotRuleDto"
},
"nullable": true
}
},
"additionalProperties": false
}
},
"securitySchemes": {
"Bearer": {
"type": "http",
"description": "Введите JWT access token, полученный из `/api/v1/auth/login/microsoft`.\n\nПример: `eyJhbGci...`",
"scheme": "bearer",
"bearerFormat": "JWT"
}
}
},
"tags": [
{
"name": "Achievements"
},
{
"name": "Auth"
},
{
"name": "Courses"
},
{
"name": "Lectures"
},
{
"name": "Locations"
},
{
"name": "Notifications"
},
{
"name": "Reviews"
},
{
"name": "Sync"
},
{
"name": "Tags"
},
{
"name": "Users"
}
]
}