32 KiB
План реализации задач после созвона с научным руководителем
Дата: 2026-05-19
1. Короткий вывод
В проекте уже есть основа для большей части требований: справочники, пользователи, кафедры, дисциплины, аудитории, динамическое расписание на базе schedule_rules, календарный учебный график, временные сетки и экран загруженности аудиторий. Главные недостающие архитектурные слои:
- нормальная ролевая модель и серверная авторизация;
- темпоральность: история принадлежности, версионирование связей и запрет ретроактивного изменения прошлого расписания;
- мягкое удаление справочников вместо физического удаления;
- отдельные рабочие места для кафедры и учебного отдела;
- расширенные просмотры расписания и загруженности по преподавателям, аудиториям, кафедрам, парам и периодам.
Рекомендуемый порядок: сначала ввести темпоральный слой, жизненный цикл записей и роли, затем уже строить новые кабинеты и редакторы. Если начать с экранов, старые связи будут продолжать теряться при удалениях, переносах преподавателей и правках расписания.
2. Расшифровка задач руководителя в терминах системы
| Формулировка | Что реализуем |
|---|---|
| Загруженность по паре или преподавателю | Аналитика занятости по временным слотам, преподавателям, аудиториям, кафедрам, дисциплинам и периодам. |
| Темпоральные базы данных | Не отдельная БД, а темпоральная модель внутри текущей PostgreSQL БД каждого тенанта: периоды действия записей, история связей, версионирование расписания. |
| Сделать удаление аудиторий и т.д., чтобы нельзя было использовать в дальнейшем | Мягкое удаление/архивация справочников. Исторические записи остаются, новые назначения на архивные сущности запрещены. |
| Перенос преподавателей с одной кафедры в другую без потери связи с прошлыми записями | История принадлежности преподавателя к кафедрам через интервалы действия, а не простое перезаписывание users.department_id. |
| Уровни пользователей | Расширение ролей и прав: администратор, кафедра, учебный отдел, преподаватель, студент. Проверки должны быть на backend, не только в UI. |
| Администратор: создание аудиторий, специальностей, кафедр и т.д. | Довести справочники до полного CRUD + архив/восстановление + фильтр архивных записей. |
| Кафедра: смотреть предметы кафедры, грузить, связывать предметы, разделять, комментарии, расписания и загруженность | Новый кабинет кафедры: дисциплины кафедры, импорт, описание дисциплин, привязки преподавателей и типов занятий, комментарии, расписание и нагрузка кафедры. |
| Учебный отдел: закреплять время и аудитории, редактировать расписание, закреплять предметы и преподавателей в аудитории в определённое время | Новый кабинет учебного отдела: редактор расписания, фиксация времени/аудиторий/преподавателей, точечные переносы и отмены, проверка конфликтов. |
| Просмотр расписания разных аудиторий, преподавателей, кафедр | Универсальный просмотр расписания с фильтрами по аудитории, преподавателю, группе, кафедре, дисциплине и периоду. |
3. Текущее состояние проекта
Уже есть
- Backend: Java 17, Spring Boot, JPA, Flyway, мультитенантность через отдельную БД на тенант.
- Frontend: Vanilla JS, отдельные интерфейсы
/admin/,/teacher/,/student/. - Роли сейчас ограничены
ADMIN,TEACHER,STUDENT. - Авторизация возвращает UUID-токен и роль, но полноценной серверной проверки прав по эндпоинтам пока нет.
- Динамическое расписание строится из:
schedule_rules;schedule_rule_groups;schedule_rule_slots;schedule_rule_slot_subgroups;time_slots;academic_years/semesters;academic_calendars.
GET /api/scheduleсейчас принимает ровно один фильтр:groupIdилиteacherId.- Экран загруженности аудиторий уже есть и использует реальные аудитории, временные слоты и сгенерированное расписание.
- У аудиторий есть
is_available, ноDELETE /api/classrooms/{id}физически удаляет запись. - Преподаватель сейчас имеет одно поле
users.department_id; история переводов не хранится. - Дисциплины связаны с кафедрой через
subjects.department_id; история смены кафедры дисциплины не хранится. - Привязка преподавателей к дисциплинам есть через
teacher_subjects, но это простая текущая связь без периода действия, комментариев и разбиения по ответственности.
Основные проблемы текущей модели
- Физическое удаление справочников опасно для истории расписания и отчётов.
- Обновление текущих связей перезаписывает контекст прошлого.
- Динамическое расписание пересчитывается из текущих правил, поэтому изменение правила может изменить отображение прошлого периода.
- Ролевая модель не отражает учебный отдел и кафедру как самостоятельных пользователей.
- Просмотр расписания и загруженности завязан на частные сценарии, а не на единый фильтруемый слой.
4. Целевая архитектурная идея
Ввести три базовых понятия:
- Жизненный цикл записи: активна, архивирована, недоступна для новых назначений.
- Период действия связи: преподаватель относится к кафедре не "навсегда", а с даты по дату.
- Версия расписания: прошлое расписание должно оставаться воспроизводимым, даже если текущие правила изменились.
После этого все новые экраны работают с одной логикой:
- активные справочники доступны для выбора;
- архивные записи видны в истории, но не выбираются для будущих назначений;
- отчёты за прошлый период используют связи, действовавшие на дату занятия;
- правки будущего расписания не ломают прошлые отчёты.
5. Этап 1. Роли и права доступа
Новые роли
| Роль | Назначение |
|---|---|
ADMIN |
Полный доступ внутри тенанта: справочники, пользователи, роли, настройки. |
EDUCATION_OFFICE |
Учебный отдел: расписание, аудитории, временные слоты, закрепления, конфликты. |
DEPARTMENT |
Кафедра: дисциплины своей кафедры, преподаватели, комментарии, нагрузка, просмотр расписания. |
TEACHER |
Преподаватель: личное расписание и, позже, заявки на изменения. |
STUDENT |
Просмотр расписания. |
ADMIN можно оставить как суперроль внутри одной БД тенанта. Управление тенантами через /api/database стоит разрешить только ADMIN.
Backend
- Расширить
Role. - Обновить
AuthController.ROLE_REDIRECTS:ADMIN->/admin/;EDUCATION_OFFICE->/edu-office/;DEPARTMENT->/department/;TEACHER->/teacher/;STUDENT->/student/.
- Добавить серверную авторизацию:
- хранение активных сессий/токенов или проверяемый токен;
- фильтр/интерцептор, который получает пользователя по
Authorization; - аннотации или централизованные проверки прав в контроллерах.
- Не полагаться на
localStorage.roleкак на источник прав.
Frontend
- Добавить оболочки
/department/и/edu-office/. - В админке скрывать пункты меню по роли, но считать это только UX-ограничением.
- Все ошибки доступа показывать на русском:
Недостаточно прав для выполнения операции.
6. Этап 2. Темпоральный слой и жизненный цикл справочников
Базовые поля жизненного цикла
Для справочников, которые могут участвовать в расписании или отчётах, добавить:
status(ACTIVE,ARCHIVED);active_from;active_to;archived_at;archived_by;archive_reason.
Минимальный набор для первого внедрения:
classrooms;equipments;departments;specialties;specialty_profiles;education_forms;student_groups;subgroups;subjects;users.
Для сущностей, где достаточно простого вывода из эксплуатации, можно начать с status, archived_at, archive_reason, а active_from/active_to добавить там, где требуется отчётность по датам.
Правила использования
GETпо умолчанию возвращает только активные записи.- Для админских экранов добавить
includeArchived=true. DELETEзаменить на архивирование.- Физическое удаление оставить только для записей, которые точно нигде не используются, либо убрать из публичных API.
- В формах будущего расписания нельзя выбирать архивные аудитории, дисциплины, группы, подгруппы, кафедры и пользователей.
- В историческом расписании архивные записи отображаются с пометкой, например
Аудитория 101 (архив).
Аудитории
is_available и архивирование должны означать разные вещи:
is_available=false— аудитория временно недоступна, но может вернуться в работу;status=ARCHIVED— аудитория выведена из эксплуатации и не может использоваться в новых назначениях.
UI-кнопку Удалить лучше заменить на Вывести из эксплуатации. Для администратора можно добавить отдельное действие Восстановить.
7. Этап 3. История переводов преподавателей между кафедрами
Модель данных
Добавить таблицу:
teacher_department_assignments
Поля:
id;teacher_id;department_id;valid_from;valid_to;is_primary;comment;created_at;created_by.
Текущий users.department_id можно временно оставить как денормализованное поле "текущая кафедра", но источником правды для отчётов должна стать таблица истории.
Правила
- У преподавателя должна быть ровно одна основная кафедра на дату.
- При переводе преподавателя:
- закрывается старая запись
valid_to; - создаётся новая запись
valid_from; - старые расписания и отчёты используют кафедру, актуальную на дату занятия.
- закрывается старая запись
- Привязки
teacher_subjectsне удаляются автоматически при переводе, иначе потеряется история. Для будущих назначений можно показывать предупреждение, если дисциплина не относится к текущей кафедре преподавателя.
API
GET /api/users/{id}/department-historyPOST /api/users/{id}/department-transferGET /api/departments/{id}/teachers?date=YYYY-MM-DDGET /api/users/teachers?departmentId=&date=
8. Этап 4. Версионирование расписания и точечные изменения
Текущая модель schedule_rules хороша для генерации будущего расписания, но недостаточна для неизменяемого прошлого и точечных переносов.
Версии правил
Добавить к правилам и слотам период действия:
valid_from;valid_to;status;version_group_idилиparent_rule_id;created_by;change_reason.
При редактировании правила:
- если правка относится к будущему периоду, закрывать старую версию и создавать новую;
- если правка исправляет ошибку текущего будущего правила, разрешить обновление только до даты начала действия;
- прошлые периоды не пересчитывать по новым данным.
Точечные изменения расписания
Добавить таблицу:
schedule_overrides
Назначение: перенос, отмена или замена конкретной сгенерированной пары.
Поля:
id;base_rule_slot_id;lesson_date;action(MOVE,CANCEL,REPLACE);new_time_slot_id;new_classroom_id;new_teacher_id;new_lesson_format;comment;created_by;created_at.
Генератор расписания должен сначала строить базовые пары из правил, затем применять точечные изменения.
Закрепление времени, аудитории, преподавателя
В schedule_rule_slots или отдельной таблице закреплений добавить признаки:
time_locked;classroom_locked;teacher_locked;locked_by;locked_at;lock_comment.
Учебный отдел сможет фиксировать назначения, а автоматические или массовые операции не должны менять закреплённые поля без явного подтверждения.
9. Этап 5. Проверка конфликтов
Перед сохранением правила, версии или override проверять:
- преподаватель не занят в другом месте в тот же день/пару;
- аудитория не занята другой парой;
- вместимость аудитории не меньше суммы групп/подгрупп;
- преподаватель привязан к дисциплине и нужному типу занятия;
- выбранная аудитория активна и доступна на дату;
- группа/подгруппа активна на дату;
- кафедральные ограничения не нарушены, если дисциплина принадлежит другой кафедре.
Конфликты делить на:
ERROR— сохранение запрещено;WARNING— можно сохранить с комментарием, если роль имеет право.
API:
POST /api/admin/schedule-rules/validatePOST /api/edu-office/schedule/validateGET /api/schedule/conflicts?startDate=&endDate=
10. Этап 6. Кабинет кафедры
Функции
- Просмотр дисциплин своей кафедры.
- Создание и редактирование описания дисциплины.
- Импорт дисциплин из файла. Формат нужно согласовать отдельно: CSV/XLSX, обязательные колонки, правила обновления.
- Разделение данных дисциплины:
- карточка дисциплины: название, код, кафедра, описание, комментарии;
- преподаватели дисциплины;
- типы занятий, которые может вести каждый преподаватель;
- история изменений.
- Комментарии к дисциплине, привязке или расписанию.
- Просмотр расписания кафедры.
- Просмотр загруженности кафедры:
- по преподавателям;
- по дисциплинам;
- по неделям;
- по типам занятий.
Backend
Новые или расширенные сущности:
subject_comments;subject_department_assignmentsили темпоральные поля уsubjects;- версионированные
teacher_subjects; teacher_lesson_typesвывести в полноценный API, если таблица уже есть в схеме.
API:
GET /api/department/subjectsPOST /api/department/subjects/importGET /api/department/subjects/{id}PUT /api/department/subjects/{id}GET /api/department/subjects/{id}/teachersPUT /api/department/subjects/{id}/teachersGET /api/department/scheduleGET /api/department/workloadPOST /api/department/comments
Frontend
Создать /department/ как отдельный кабинет:
subjects— дисциплины кафедры;teachers— преподаватели кафедры и их дисциплины;schedule— расписание кафедры;workload— нагрузка;commentsили встроенные комментарии в карточках.
11. Этап 7. Кабинет учебного отдела
Функции
- Просмотр расписания по группам, аудиториям, преподавателям и кафедрам.
- Редактирование правил расписания.
- Точечный перенос пары.
- Отмена пары.
- Замена преподавателя.
- Замена аудитории.
- Закрепление времени, аудитории и преподавателя.
- Работа с конфликтами.
- Просмотр загруженности аудиторий и преподавателей.
Backend
API:
GET /api/edu-office/schedulePOST /api/edu-office/schedule/overridesPUT /api/edu-office/schedule/overrides/{id}DELETE /api/edu-office/schedule/overrides/{id}POST /api/edu-office/schedule/locksDELETE /api/edu-office/schedule/locks/{id}GET /api/edu-office/workload/classroomsGET /api/edu-office/workload/teachersGET /api/edu-office/conflicts
Frontend
Создать /edu-office/ с вкладками:
Расписание;Редактор;Конфликты;Загруженность аудиторий;Загруженность преподавателей;Закрепления.
Текущий админский конструктор расписания можно переиспользовать, но его нужно отделить от справочников и адаптировать под роль учебного отдела.
12. Этап 8. Универсальный просмотр расписания
Сейчас GET /api/schedule требует ровно groupId или teacherId. Для новых требований нужен отдельный эндпоинт или расширение текущего.
Рекомендуется добавить новый эндпоинт:
GET /api/schedule/search
Фильтры:
startDate;endDate;groupId;teacherId;classroomId;departmentId;subjectId;lessonTypeId;timeSlotId;parity;includeArchived.
Правило: можно передавать один или несколько фильтров. Если фильтров нет, доступ зависит от роли:
ADMINиEDUCATION_OFFICEмогут видеть всё;DEPARTMENTвидит свою кафедру;TEACHERвидит себя;STUDENTвидит доступные группы или свою группу, когда появится привязка студента к группе.
Форматы отображения:
- недельная сетка;
- табличный список;
- вид по аудиториям;
- вид по преподавателям;
- вид по кафедрам.
13. Этап 9. Загруженность по паре, преподавателю и кафедре
Показатели
- занятость аудитории по дате и паре;
- занятость преподавателя по дате и паре;
- часы преподавателя за период;
- часы кафедры за период;
- распределение по дисциплинам;
- распределение по типам занятий;
- свободные аудитории на выбранную дату/пару;
- перегрузки и конфликты.
API
GET /api/workload/classroomsGET /api/workload/teachersGET /api/workload/departmentsGET /api/workload/time-slotsGET /api/workload/free-classrooms
Общие параметры:
startDate;endDate;date;timeSlotId;teacherId;departmentId;classroomId;groupId;lessonTypeId.
Реализация
На первом этапе считать загруженность из ScheduleGeneratorService и фильтровать уже сгенерированные пары. Если отчёты станут тяжёлыми, добавить кэш или материализованную таблицу фактических занятий на период.
Важно: после внедрения schedule_overrides отчёты должны считать уже итоговое расписание, а не только базовые правила.
14. Миграции Flyway
Существующие миграции не изменять. Новые изменения оформлять новыми файлами:
V2__roles_and_lifecycle.sql- новые роли;
- поля жизненного цикла для справочников;
- индексы по
status,active_from,active_to.
V3__teacher_department_history.sql- история принадлежности преподавателей к кафедрам;
- перенос текущих
users.department_idв первую историческую запись.
V4__subject_and_teacher_temporal_links.sql- комментарии;
- версионированные связи преподавателей и дисциплин;
- связь преподаватель + дисциплина + тип занятия с периодом действия.
V5__schedule_versions_and_overrides.sql- версии правил;
- точечные изменения расписания;
- закрепления.
V6__workload_indexes.sql- индексы под отчёты и фильтры расписания.
Нумерация может измениться, если в проекте появятся другие миграции до начала реализации.
15. Изменения документации
После каждого этапа обновлять:
docs/DATABASE.md;docs/API.md;docs/BUSINESS_LOGIC.md;docs/FRONTEND.md;docs/ARCHITECTURE.md, если меняются роли, авторизация или темпоральная модель.
Для больших этапов лучше добавлять отдельные документы:
docs/RBAC.md;docs/TEMPORAL_MODEL.md;docs/SCHEDULE_EDITING.md;docs/WORKLOAD_ANALYTICS.md.
16. Проверка и критерии готовности
Backend
docker run --rm -v /mnt/HDD/magistr/magistr/backend:/app -w /app maven:3.9-eclipse-temurin-17 mvn -q clean compile- Прогон Flyway на чистой PostgreSQL БД.
- Проверка, что старые данные мигрировали в темпоральные таблицы.
- Тесты или ручные проверки:
- архивная аудитория не выбирается для будущей пары;
- старая пара с архивной аудиторией отображается;
- перевод преподавателя не меняет кафедру в отчёте за прошлый период;
- правка будущего правила не меняет прошлое расписание;
- конфликт преподавателя/аудитории блокируется или предупреждается.
Frontend
node --checkдля изменённых JS-файлов.git diff --check.- Ручной smoke-test в браузере:
- вход под каждой ролью;
- видимость нужных вкладок;
- запрет доступа к чужим эндпоинтам;
- создание/архивирование/восстановление справочников;
- редактирование расписания учебным отделом;
- просмотр расписания и загруженности по разным фильтрам.
17. Риски и вопросы, которые нужно уточнить
- Что именно руководитель имеет в виду под "темпоральными базами данных": только история изменений или полноценная bitemporal-модель с
valid_timeиtransaction_time. - Нужно ли хранить фактические проведённые занятия отдельно от планового расписания.
- Какие форматы файлов кафедра должна "грузить": XLSX, CSV, шаблон учебного плана, свободная таблица.
- Кто именно является пользователем роли
DEPARTMENT: заведующий кафедрой, оператор кафедры или несколько сотрудников. - Нужна ли студентам привязка к конкретной группе. Сейчас студент выбирает группу вручную.
- Должно ли удаление/архивирование кафедры запрещаться при наличии активных преподавателей, групп и дисциплин или разрешаться с каскадной архивацией.
- Нужно ли вести журнал всех действий пользователя для юридически значимой истории изменений.
18. Рекомендуемый порядок внедрения
- Роли и серверная авторизация.
- Мягкое удаление аудиторий и справочников.
- История переводов преподавателей.
- Версионирование расписания и точечные изменения.
- Проверка конфликтов.
- Универсальный
schedule/search. - Загруженность преподавателей, кафедр и пар.
- Кабинет кафедры.
- Кабинет учебного отдела.
- Финальная синхронизация документации и регрессионный smoke-test.
Такой порядок закрывает базовую целостность данных до того, как появятся новые роли и экраны, которые начнут массово создавать и менять расписание.