14 KiB
14 KiB
📋 Задачи: Динамическая генерация расписания
Декомпозиция
SCHEDULE_PROPOSAL.mdна подзадачи для доски планирования. Категории: Backend, Frontend, DevOps/DB
DevOps / Database
Flyway-миграция: Временные слоты
- Создать миграцию: таблица
time_slots(id, order_number, start_time, end_time, duration_minutes) - Добавить CHECK-ограничения (start_time < end_time, duration_minutes > 0, order_number > 0)
Flyway-миграция: Учебные годы и семестры
- Создать миграцию: таблица
academic_years(id, title, start_date, end_date) - Создать миграцию: таблица
semesters(id, academic_year_id FK, semester_type ENUM, start_date, end_date) - Добавить CHECK-ограничения и индексы
Flyway-миграция: Праздники
- Создать миграцию: таблица
holidays(id, date, academic_year_id FK, description) - Добавить уникальный индекс на (date, academic_year_id)
Flyway-миграция: Матрица учебного графика
- Создать миграцию: таблица
academic_calendar_matrix(id, semester_id FK, course_number, specialty_id FK, week_number, activity_type ENUM) - Добавить ENUM:
THEORY,EXAM,VACATION,PRACTICE - Добавить уникальный индекс на (semester_id, course_number, specialty_id, week_number)
Flyway-миграция: Правила расписания
- Создать миграцию: таблица
schedule_rules(id, subject_id FK, semester_id FK, active_from_date, total_academic_hours) - Создать миграцию: связующая таблица
schedule_rule_groups(schedule_rule_id FK, group_id FK, PK составной) - Создать миграцию: таблица
schedule_rule_slots(id, schedule_rule_id FK, day_of_week, parity ENUM, time_slot_id FK, subgroup_id FK NULL, teacher_id FK, classroom_id FK, lesson_type_id FK, lesson_format) - Добавить CHECK на day_of_week (1–7)
- Добавить ENUM:
BOTH,EVEN,ODD
ETL-миграция данных
- Написать SQL/Java скрипт миграции
schedule_data→schedule_rules+schedule_rule_groups- Маппинг
number_of_hours→total_academic_hours - Маппинг привязок групп
- Маппинг
- Написать SQL/Java скрипт миграции
lessons→schedule_rule_slots- Трансформация
day(строка) →day_of_week(INT 1–6) - Трансформация
time(строка) →time_slot_id(FK) - Трансформация
week(строка) →parity(ENUM) - Группировка записей с одинаковым (subject_id, group_id) в одно правило
- Трансформация
- Верификация мигрированных данных (количество записей, целостность FK)
- Создать миграцию на удаление устаревших таблиц
lessonsиschedule_data(после верификации)
Backend (Java + Spring Boot)
JPA-сущности (Model)
- Создать Entity:
TimeSlot - Создать Entity:
AcademicYear - Создать Entity:
Semester(связь ManyToOne → AcademicYear) - Создать Entity:
Holiday(связь ManyToOne → AcademicYear) - Создать Entity:
AcademicCalendarMatrix(связи на Semester, Specialty) - Создать Entity:
ScheduleRule(связи на Subject, Semester) - Создать Entity:
ScheduleRuleSlot(связи на ScheduleRule, TimeSlot, Teacher, Classroom, LessonType) - Настроить ManyToMany-связь ScheduleRule ↔ StudentGroup через
schedule_rule_groups
DTO
- Создать DTO:
TimeSlotDto - Создать DTO:
AcademicYearDto,SemesterDto - Создать DTO:
HolidayDto - Создать DTO:
AcademicCalendarMatrixDto - Создать DTO:
ScheduleRuleDto,ScheduleRuleSlotDto - Создать DTO:
RenderedLessonDto(ответ генератора расписания)
Repository
- Создать
TimeSlotRepository - Создать
AcademicYearRepository - Создать
SemesterRepository(метод findByDateRange) - Создать
HolidayRepository(метод findByAcademicYearId) - Создать
AcademicCalendarMatrixRepository(метод findBySemesterAndCourseAndSpecialty) - Создать
ScheduleRuleRepositoryс JOIN FETCH (решение N+1 проблемы)- Метод: findByGroupIdAndSemesterId (через schedule_rule_groups)
- Метод: findByTeacherIdAndSemesterId (через schedule_rule_slots.teacher_id)
Сервис: AcademicDateService
- Метод: перевод произвольной даты → номер недели семестра
- Метод: определение чётности недели с учётом настройки тенанта
- Метод: проверка попадания даты в справочник
holidays - Метод: вычисление текущего курса группы (
текущий_учебный_год - year_start_study + 1) - Метод: определение семестра по дате
- Написать юнит-тесты для AcademicDateService
Сервис: ScheduleGeneratorService
- Метод:
buildScheduleForGroup(groupId, startDate, endDate)— расписание группы- Определение семестра по диапазону дат
- Вычисление номера недели и курса группы
- Проверка типа деятельности через матрицу графика
- Загрузка активных правил для группы
- Симуляция прогона часов (подсчёт consumed_hours)
- Пропуск праздников при подсчёте часов
- Проекция слотов на запрошенную неделю с учётом чётности и подгрупп
- Метод:
buildScheduleForTeacher(teacherId, startDate, endDate)— расписание преподавателя- Поиск правил по teacher_id в слотах
- Обогащение ответа списком групп из schedule_rule_groups
- Написать юнит-тесты для ScheduleGeneratorService
- Написать интеграционные тесты (полный цикл с тестовой БД)
Кеширование
- Реализовать кеш списка праздников по учебному году
- Реализовать кеш матрицы учебного графика по ключу (course, specialty_id, semester_id)
- Реализовать кеш consumed_hours для каждого правила
- Реализовать инвалидацию кеша праздников при CRUD-операциях с holidays
- Реализовать инвалидацию кеша consumed_hours при изменении правил или праздников
Валидация
- Адаптировать валидатор пересечения аудиторий (симуляция всего семестра при сохранении правила)
- Валидация пересечения преподавателей (один преподаватель не может вести две пары одновременно)
- Валидация пересечения групп (одна группа не может быть на двух занятиях одновременно, кроме подгрупп)
REST API: Контроллеры
GET /api/schedule— Новый эндпоинт расписания (параметры: groupId/teacherId + startDate + endDate)- Пометить
GET /api/users/lessonsкак@Deprecated(обратная совместимость) - CRUD:
POST/GET/PUT/DELETE /api/admin/time-slots - CRUD:
POST/GET/PUT/DELETE /api/admin/calendar/years - CRUD:
GET/PUT /api/admin/calendar/semesters(вложены в years) - CRUD:
POST/GET/PUT/DELETE /api/admin/calendar/holidays - CRUD:
GET/PUT /api/admin/calendar/matrix(массовое сохранение матрицы) - CRUD:
POST/GET/PUT/DELETE /api/admin/schedule-rules- Включая вложенные слоты и привязку групп
- Написать интеграционные тесты для API
Удаление устаревшего кода
- Удалить/рефакторить старый
LessonsController(после миграции фронтенда) - Удалить/рефакторить старый
ScheduleDataController - Удалить старые Entity:
Lesson,ScheduleData - Удалить старые Repository и Service для lessons/schedule_data
Frontend (Vanilla JS + HTML/CSS)
Просмотр расписания: Студенты
- Реализовать переключатель дат (Date Picker / кнопки-стрелки по неделям)
- Переключить API-запросы на новый
GET /api/schedule?groupId=...&startDate=...&endDate=... - Рендеринг расписания по дням и временным слотам
- Отображение статуса периода (Каникулы / Практика / Экзамены), если неделя не учебная
- Отображение информации о подгруппах (два занятия рядом для разных подгрупп)
Просмотр расписания: Преподаватели
- Реализовать переключатель дат (Date Picker / кнопки-стрелки по неделям)
- Переключить API-запросы на новый
GET /api/schedule?teacherId=...&startDate=...&endDate=... - Отображение всех групп, привязанных к каждому занятию
- Отображение подгрупп, если преподаватель ведёт у подгруппы
Панель администратора: Вкладка «Временные слоты»
- Создать UI-страницу настройки временных слотов
- CRUD-интерфейс: добавление/редактирование/удаление пар
- Отображение таблицы: номер пары → время начала → время окончания → длительность
- Валидация на фронтенде (пересечение времён, корректность данных)
Панель администратора: Вкладка «Учебный график»
- Создать UI: выбор учебного года и семестра
- Создать UI: CRUD учебных годов и семестров
- Создать UI: CRUD праздников (список дат с описанием)
- Создать визуальную сетку-матрицу:
- Горизонтальная ось — номера недель
- Вертикальная ось — Курс + Специальность
- Цветовая кодировка ячеек: Теория/Экзамены/Каникулы/Практика
- Клик/драг для массового назначения статуса
- Сохранение матрицы через API
PUT /api/admin/calendar/matrix
Панель администратора: Вкладка «Конструктор Правил»
- Создать UI: список существующих правил с фильтрацией (по группе, предмету, семестру)
- Форма создания/редактирования правила:
- Мультиселект групп (для потоковых лекций)
- Выбор дисциплины (subject)
- Выбор семестра
- Ввод totalHours (академические часы)
- Ввод даты начала (active_from_date)
- Динамический массив слотов (кнопка «Добавить занятие»):
- Select: День недели
- Select: Временной слот (из таблицы time_slots)
- Select: Чётность (Обе/Чётная/Нечётная)
- Select: Подгруппа (опционально)
- Select: Преподаватель
- Select: Аудитория
- Select: Тип занятия (Лекция/Практика/Лаба)
- Select: Формат (Очно/Онлайн)
- Визуальное предупреждение при конфликтах (аудитория/преподаватель уже заняты)
- Удаление правила с подтверждением