задачи 2 и 8

This commit is contained in:
Zuev
2026-08-11 18:18:08 +03:00
parent 519864b962
commit 18a97b293a
59 changed files with 6237 additions and 276 deletions

View File

@@ -265,8 +265,32 @@ constraint. При чтении API разворачивает периоды о
- **Жизненный цикл:** архивные преподаватели, аудитории, группы и дисциплины не принимаются в новых правилах.
- **Правило расписания:** `status=ARCHIVED` или дата вне `valid_from` / `valid_to` исключают правило из генерации.
- **Доступность аудитории:** `is_available=false` запрещает новые назначения, но не удаляет историю.
- **Конфликты слотов:** сначала попарно проверяются слоты самого нового payload, включая точные дубли, затем — активные правила того же семестра. Конфликт возникает при пересечении дня, базового временного слота, чётности (`BOTH` пересекается с любой чётностью) и активных недель слота, если совпадает преподаватель, аудитория или учебная группа. `ODD` и `EVEN` между собой не конфликтуют. Активные недели считаются из лимита часов типа занятия, недели начала, чётности и порядка слотов внутри правила; например, занятие на 1-3 неделях не конфликтует с тем же ресурсом с 4 недели. Для лабораторных занятий разные подгруппы одной группы могут идти параллельно, но занятие для всей группы конфликтует с любой её подгруппой. Backend возвращает `409 Conflict`; `conflictRule` присутствует только для конфликта с сохранённым правилом, а внутренний конфликт описывается полями и русскими причинами без искусственной записи.
- **Конкурентная запись:** публичные методы `ScheduleRuleService` являются транзакционными. Создание сначала блокирует строку семестра, а update блокирует правило и старый/новый семестры в стабильном порядке, поэтому два backend-pod не могут одновременно пройти проверку одного семестра по устаревшему снимку.
- **Конфликты слотов:** сначала попарно проверяются слоты самого нового payload, включая точные дубли, затем — активные правила той же версии. Конфликт возникает при пересечении дня, базового временного слота, чётности (`BOTH` пересекается с любой чётностью) и активных недель слота, если совпадает преподаватель, аудитория или учебная группа. `ODD` и `EVEN` между собой не конфликтуют. Активные недели считаются из лимита часов типа занятия, недели начала, чётности и порядка слотов внутри правила; например, занятие на 1-3 неделях не конфликтует с тем же ресурсом с 4 недели. Для лабораторных занятий разные подгруппы одной группы могут идти параллельно, но занятие для всей группы конфликтует с любой её подгруппой. Backend возвращает `409 Conflict`; `conflictRule` присутствует только для конфликта с сохранённым правилом, а внутренний конфликт описывается полями и русскими причинами без искусственной записи.
- **Конкурентная запись:** публичные методы `ScheduleRuleService` являются транзакционными. Создание блокирует строку семестра и выбранную версию, а update — правило, версию и старый/новый семестры в стабильном порядке. Публикация блокирует версию до завершения полной проверки, поэтому другой backend-pod не может дописать правило после валидации черновика.
### Черновики, версии и публикация
Правила каждого семестра принадлежат явной версии расписания. Жизненный цикл версии:
1. `DRAFT` создаётся пустым или как полная копия выбранной версии.
2. Конструктор добавляет, изменяет и архивирует правила только в выбранном черновике.
3. Полная проверка выявляет внутренние конфликты правил; diff сопоставляет правила по
стабильному `version_group_id` и отдельно сравнивает сформированные занятия семестра.
4. Публикация требует причины и в одной транзакции архивирует прежнюю публикацию, затем
переводит проверенный черновик в `PUBLISHED`.
5. Ранее опубликованная версия получает `ARCHIVED` и может быть восстановлена такой же
атомарной операцией с обязательной причиной.
На уровне БД частичный уникальный индекс допускает только одну `PUBLISHED`-версию на
семестр. Блокировки версии и набора версий семестра не позволяют публикации пересечься с
редактированием черновика или конкурентной публикацией. Каждое создание, архивирование,
публикация и восстановление записывается в неизменяемый журнал с автором, временем и
причиной.
Обычная генерация для студентов, преподавателей и кабинетов просмотра всегда выбирает
только опубликованные правила. Точечные изменения привязаны к слотам конкретной версии:
после новой публикации overrides прежней версии сохраняются как аудит, но не влияют на
актуальное расписание и не показываются в его операционном реестре.
### Точечные изменения расписания
@@ -386,6 +410,41 @@ constraint. При чтении API разворачивает периоды о
отозвать только собственную ожидающую заявку. История содержит автора, время, статус и
комментарий каждого перехода.
### Анализ качества и локальная оптимизация расписания
Анализатор качества работает без собственной таблицы и не меняет правила расписания.
Пользователь выбирает конкретную версию семестра. Для `PUBLISHED` он строит фактические
занятия через `ScheduleQueryService`, поэтому в расчёт входят переносы, замены и отмены из
`schedule_overrides`. `DRAFT` и `ARCHIVED` генерируются напрямую по собственным правилам,
без точечных изменений текущей публикации. Семестр загружается частями не более 120 дней,
но оценка рассчитывается единообразно по всему периоду.
Итоговая оценка от 0 до 100 формируется из объяснимых штрафов:
- окна групп и преподавателей между занятиями одного дня;
- пятая и последующие пары группы или преподавателя за день;
- нехватка мест и заметно избыточная вместимость аудитории;
- занятие в подтверждённый строго недоступный или нежелательный интервал;
- занятие вне предпочтительного интервала преподавателя на выбранный день недели;
- нарушение пожеланий `NO_GAPS` и `CONSECUTIVE`.
Неравномерность дневной нагрузки выводится отдельной диагностической метрикой в процентах
и не добавляет скрытого штрафа к итоговой оценке.
В ответе сохраняются исходный штраф, вклад каждого критерия и конкретные проблемы с
датой, занятием и затронутой сущностью. Это делает оценку воспроизводимой и позволяет
фильтровать проблемы по типу и серьёзности.
Для проблемы опубликованной версии помощник перебирает другие слоты эффективной сетки того же дня и
активные аудитории достаточной вместимости. Каждый вариант повторно проходит
`ScheduleOverrideService`, затем анализатор моделирует его влияние на общую оценку и
показывает улучшения и компромиссы. Занятия с ручным override считаются закреплёнными и не
получают рекомендаций. Применение возможно только после подтверждения пользователя через
обычный механизм `schedule_overrides`; автоматической публикации и полного solver в MVP
нет. Для черновика доступны те же оценка, метрики и объяснимые проблемы, но рекомендации
не создаются: пользователь исправляет правила в изолированном конструкторе и повторяет
проверку до публикации. Архив анализируется только для чтения.
## Привязка преподаватель ↔ дисциплина
Связь Many-to-Many через таблицу `teacher_subjects`: