# 🔌 REST API Все эндпоинты имеют префикс `/api/`. Ответы возвращаются в формате JSON. --- ## Аутентификация ### `POST /api/auth/login` Вход в систему. **Тело запроса:** ```json { "username": "admin", "password": "admin" } ``` **Успешный ответ (200):** ```json { "success": true, "message": "OK", "token": "550e8400-e29b-41d4-a716-446655440000", "role": "ADMIN", "redirect": "/admin/", "departmentId": 1, "userId": 1 } ``` **Ошибка (401):** ```json { "success": false, "message": "Неверное имя пользователя или пароль", "token": null, "role": null, "redirect": null, "departmentId": null, "userId": null } ``` > После получения токена клиент должен передавать его в заголовке: `Authorization: Bearer ` --- ## Пользователи ### `GET /api/users` Список всех пользователей. **Ответ:** ```json [ { "id": 1, "username": "admin", "role": "ADMIN", "fullName": "Иванов Админ Иванович", "jobTitle": "Доцент", "departmentName": "Кафедра ИБ" }, { "id": 2, "username": "Тестовый преподаватель", "role": "TEACHER", "fullName": "Петров Препод Петрович", "jobTitle": "Профессор", "departmentName": "Кафедра ВТ" } ] ``` ### `GET /api/users/teachers` Список только преподавателей (роль `TEACHER`). ### `GET /api/users/teachers/{departmentId}` Список преподавателей привязанных к конкретной кафедре (роль `TEACHER`, код кафедры `departmentId`). ### `POST /api/users` Создание пользователя. **Тело запроса:** ```json { "username": "teacher1", "password": "password", "role": "TEACHER", "fullName": "Test Teacher", "jobTitle": "Proffessor", "departmentId": 1 } ``` **Валидация:** - `username` — обязателен и уникален - `password` — минимум 4 символа - `role` — `ADMIN`, `TEACHER` или `STUDENT` - `fullName` — обязателен - `departmentId` — обязателен ### `DELETE /api/users/{id}` Удаление пользователя. --- ## Динамическое расписание Новая модель расписания строится из правил (`schedule_rules`) и слотов (`schedule_rule_slots`). Фактические занятия рендерятся на диапазон дат. ### `GET /api/schedule` Получение расписания группы или преподавателя за период. **Параметры:** | Параметр | Обязателен | Описание | |----------|------------|----------| | `groupId` | Да, если нет `teacherId` | ID учебной группы | | `teacherId` | Да, если нет `groupId` | ID преподавателя | | `startDate` | Да | Начало периода в формате `YYYY-MM-DD` | | `endDate` | Да | Конец периода в формате `YYYY-MM-DD` | Передаётся ровно один параметр: `groupId` или `teacherId`. Максимальный диапазон — 120 дней. **Пример:** ```http GET /api/schedule?groupId=1&startDate=2026-04-27&endDate=2026-05-03 ``` **Ответ:** ```json [ { "scheduleRuleId": 10, "scheduleRuleSlotId": 31, "date": "2026-04-27", "dayOfWeek": 1, "dayName": "Понедельник", "weekNumber": 13, "parity": "ODD", "timeSlotId": 3, "timeSlotOrder": 3, "startTime": "11:40:00", "endTime": "13:10:00", "subjectId": 1, "subjectName": "Высшая математика", "teacherId": 2, "teacherName": "Петров Препод Петрович", "classroomId": 1, "classroomName": "101 Ленинская", "lessonTypeId": 1, "lessonTypeName": "Лекция", "lessonFormat": "Очно", "subgroupId": null, "groupIds": [1], "groupNames": ["ИВТ-21-1"], "activityType": "THEORY", "totalAcademicHours": 72, "consumedAcademicHoursBeforeLesson": 24, "remainingAcademicHoursAfterLesson": 46 } ] ``` ### `GET /api/admin/time-slots` Список временных слотов занятий. CRUD доступен по: | Метод | URL | Назначение | |-------|-----|------------| | `GET` | `/api/admin/time-slots` | Список слотов | | `POST` | `/api/admin/time-slots` | Создать слот | | `PUT` | `/api/admin/time-slots/{id}` | Обновить слот | | `DELETE` | `/api/admin/time-slots/{id}` | Удалить слот | **Тело создания/обновления:** ```json { "orderNumber": 1, "startTime": "08:00:00", "endTime": "09:30:00", "durationMinutes": 90 } ``` ### Календарный график администратора | Метод | URL | Назначение | |-------|-----|------------| | `GET` | `/api/admin/calendar/years` | Учебные годы с семестрами | | `POST` | `/api/admin/calendar/years` | Создать учебный год | | `PUT` | `/api/admin/calendar/years/{id}` | Обновить учебный год | | `DELETE` | `/api/admin/calendar/years/{id}` | Удалить учебный год | | `GET` | `/api/admin/calendar/years/{academicYearId}/semesters` | Семестры учебного года | | `POST` | `/api/admin/calendar/years/{academicYearId}/semesters` | Создать семестр | | `PUT` | `/api/admin/calendar/semesters/{id}` | Обновить семестр | | `GET` | `/api/admin/calendar/holidays?academicYearId=1` | Праздники учебного года | | `POST` | `/api/admin/calendar/holidays` | Создать праздник | | `PUT` | `/api/admin/calendar/holidays/{id}` | Обновить праздник | | `DELETE` | `/api/admin/calendar/holidays/{id}` | Удалить праздник | | `GET` | `/api/admin/calendar/matrix?semesterId=1&courseNumber=1&specialtyId=2` | Матрица учебного графика | | `PUT` | `/api/admin/calendar/matrix` | Массовое сохранение матрицы | ### `POST /api/admin/schedule-rules` Создание правила динамического расписания. ```json { "subjectId": 1, "semesterId": 1, "activeFromDate": "2026-02-01", "totalAcademicHours": 72, "groupIds": [1, 2], "slots": [ { "dayOfWeek": 1, "parity": "BOTH", "timeSlotId": 3, "subgroupId": null, "teacherId": 2, "classroomId": 1, "lessonTypeId": 1, "lessonFormat": "Очно" } ] } ``` CRUD доступен по: | Метод | URL | Назначение | |-------|-----|------------| | `GET` | `/api/admin/schedule-rules` | Список правил, фильтры `semesterId`, `groupId` | | `GET` | `/api/admin/schedule-rules/{id}` | Одно правило | | `POST` | `/api/admin/schedule-rules` | Создать правило | | `PUT` | `/api/admin/schedule-rules/{id}` | Обновить правило | | `DELETE` | `/api/admin/schedule-rules/{id}` | Удалить правило | ### `GET /api/lesson-types` Справочник типов занятий для конструктора правил расписания. **Ответ:** ```json [ { "id": 1, "name": "Лекция" }, { "id": 2, "name": "Практика" } ] ``` --- ## Кафедры и специальности ### Кафедры | Метод | URL | Назначение | |-------|-----|------------| | `GET` | `/api/departments` | Список кафедр | | `POST` | `/api/departments` | Создать кафедру | | `PUT` | `/api/departments/{id}` | Обновить кафедру | | `DELETE` | `/api/departments/{id}` | Удалить кафедру | **Тело создания/обновления:** ```json { "departmentName": "Кафедра ИБ", "departmentCode": 1 } ``` ### Специальности | Метод | URL | Назначение | |-------|-----|------------| | `GET` | `/api/specialties` | Список специальностей | | `POST` | `/api/specialties` | Создать специальность | | `PUT` | `/api/specialties/{id}` | Обновить специальность | | `DELETE` | `/api/specialties/{id}` | Удалить специальность | **Тело создания/обновления:** ```json { "specialityName": "Программная инженерия", "specialityCode": "09.03.04" } ``` --- ## Группы ### `GET /api/groups` Список всех групп. **Ответ:** ```json [ { "id": 1, "name": "ИВТ-21-1", "groupSize": 25, "educationFormId": 1, "educationFormName": "Бакалавриат", "departmentId": 1, "course": 3, "specialityCode": 1 } ] ``` ### `GET /api/groups/{departmentId}` Список всех групп привязанных к конкретной кафедре. ### `POST /api/groups` Создание группы. ```json { "name": "ИВТ-11", "groupSize": 12, "educationFormId": 1, "departmentId": 1, "yearStartStudy": 2026, "specialityCode": 1 } ``` `specialityCode` исторически содержит ID записи из `/api/specialties`; текущий курс вычисляется из `yearStartStudy`. ### `DELETE /api/groups/{id}` Удаление группы. --- ## Аудитории ### `GET /api/classrooms` Список аудиторий с привязанным оборудованием. **Ответ:** ```json [ { "id": 1, "name": "101 Ленинская", "capacity": 120, "isAvailable": true, "equipments": [ { "id": 1, "name": "Проектор" }, { "id": 4, "name": "Интерактивная доска" } ] } ] ``` ### `POST /api/classrooms` Создание аудитории. ```json { "name": "404 Лаборатория", "capacity": 30, "isAvailable": true, "equipmentIds": [1, 2, 3] } ``` ### `PUT /api/classrooms/{id}` Обновление аудитории (partial update). ### `DELETE /api/classrooms/{id}` Удаление аудитории. --- ## Дисциплины ### `GET /api/subjects` Список всех дисциплин. ```json { "name": "Физика", "code": null, "departmentId": 1 } ``` ### `GET /api/subjects/{departmentId}` Список всех дисциплин привязанных к кафедре. ### `POST /api/subjects` ```json { "name": "Физика", "code": null, "departmentId": 1 } ``` ### `DELETE /api/subjects/{id}` Удаление дисциплины. --- ## Оборудование ### `GET /api/equipments` Список всего оборудования. ### `POST /api/equipments` ```json { "name": "3D-принтер" } ``` ### `DELETE /api/equipments/{id}` Удаление оборудования. --- ## Формы обучения ### `GET /api/education-forms` Список форм обучения. **Ответ:** ```json [ { "id": 1, "name": "Бакалавриат" }, { "id": 2, "name": "Магистратура" } ] ``` ### `POST /api/education-forms` ```json { "name": "Аспирантура" } ``` ### `DELETE /api/education-forms/{id}` Удаление формы обучения. **Невозможно**, если к ней привязаны группы. --- ## Привязка «Преподаватель ↔ Дисциплина» ### `GET /api/teacher-subjects` Список всех привязок. **Ответ:** ```json [ { "userId": 2, "userName": "Тестовый преподаватель", "subjectId": 1, "subjectName": "Высшая математика" } ] ``` ### `POST /api/teacher-subjects` ```json { "userId": 2, "subjectId": 3 } ``` ### `DELETE /api/teacher-subjects` ```json { "userId": 2, "subjectId": 3 } ``` --- ## Управление тенантами (Базы данных) ### `GET /api/database/status` Статус текущего подключения (определяется по домену запроса). **Ответ:** ```json { "tenant": "default", "connected": true, "configured": true, "name": "Default", "url": "jdbc:postgresql://db:5432/app_db" } ``` ### `GET /api/database/tenants` Список всех тенантов. ### `POST /api/database/tenants` Добавление нового тенанта. ```json { "name": "СВФУ", "domain": "swsu", "url": "jdbc:postgresql://db-host:5432/swsu_db", "username": "dbuser", "password": "dbpass" } ``` **Логика:** 1. Создаёт HikariCP пул для нового тенанта 2. Запускает Flyway миграции на его БД 3. Обновляет Kubernetes ConfigMap ### `DELETE /api/database/tenants/{domain}` Удаление тенанта. ### `POST /api/database/test` Тест подключения к произвольной БД (без регистрации тенанта). ```json { "url": "jdbc:postgresql://host:5432/testdb", "username": "user", "password": "pass" } ``` **Ответ:** ```json { "success": true, "message": "Подключение успешно!" } ``` --- ## Коды ответов | Код | Описание | |-----|----------| | `200` | Успех | | `400` | Ошибка валидации (с `message` в теле) | | `401` | Неверные учётные данные | | `404` | Ресурс / тенант не найден | | `500` | Внутренняя ошибка сервера |