Files
UniVerse/backend/UniVerse.Api/openapi.json
T
serega404 7761238719
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 11s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 36s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Successful in 14s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 8s
feat: Добавил генерацию api документации для git
2026-05-13 17:12:42 +03:00

5578 lines
154 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"
}
}
}
}
}
}
},
"/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/UserDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"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": "**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": "**Required:** any authenticated user",
"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"
}
}
}
},
"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": [ ]
}
]
}
},
"/api/v1/reviews/{id}": {
"get": {
"tags": [
"Reviews"
],
"summary": "Получить отзыв по ID.",
"description": "**Required:** any authenticated user",
"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"
}
}
}
},
"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/pending": {
"get": {
"tags": [
"Reviews"
],
"summary": "Получить список отзывов, ожидающих LLM-анализа.",
"description": "Только Admin. Используется для мониторинга очереди обработки.\n\n**Required roles:** Admin",
"parameters": [
{
"name": "Page",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "PageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Список отзывов со статусом Pending (пагинированный).",
"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/{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/{id}": {
"get": {
"tags": [
"Users"
],
"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/UserDto"
}
}
}
},
"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": "Разрешено только самому пользователю или Admin.\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/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": "**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/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/{id}/enrollments": {
"get": {
"tags": [
"Users"
],
"summary": "Получить список записей пользователя на лекции.",
"description": "Разрешено только самому пользователю или Admin.\n\n**Required:** any authenticated user",
"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": "Список записей (пагинированный)."
},
"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}/reviews": {
"get": {
"tags": [
"Users"
],
"summary": "Получить отзывы пользователя.",
"description": "**Required:** any authenticated user",
"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"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/{id}/achievements": {
"get": {
"tags": [
"Users"
],
"summary": "Получить достижения пользователя.",
"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": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserAchievementDto"
}
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/{id}/transactions": {
"get": {
"tags": [
"Users"
],
"summary": "Получить историю транзакций монет пользователя.",
"description": "Разрешено только самому пользователю или Admin.\n\n**Required:** any authenticated user",
"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
},
"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
},
"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"
}
},
"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
},
"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"
},
"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
},
"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"
}
},
"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"
}
]
}