добавил файл с задачами по денамической генерации занятий

This commit is contained in:
Zuev
2026-04-07 17:42:58 +03:00
parent c7145de95a
commit 48e8d4e631

218
SCHEDULE_TASKS.md Normal file
View File

@@ -0,0 +1,218 @@
# 📋 Задачи: Динамическая генерация расписания
> Декомпозиция [`SCHEDULE_PROPOSAL.md`](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 (17)
- [ ] Добавить 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 16)
- [ ] Трансформация `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: Формат (Очно/Онлайн)
- [ ] Визуальное предупреждение при конфликтах (аудитория/преподаватель уже заняты)
- [ ] Удаление правила с подтверждением