# Концепция динамической генерации расписания Документ фиксирует актуальную концепцию после внедрения календарных учебных графиков. Подробная продуктовая модель описана в [`docs/ACADEMIC_CALENDAR.md`](docs/ACADEMIC_CALENDAR.md), REST API — в [`docs/API.md`](docs/API.md), схема БД — в [`docs/DATABASE.md`](docs/DATABASE.md). ## Базовая идея Фактические занятия не хранятся отдельными строками на каждую дату. Система хранит: - календарный учебный график по специальности, профилю, форме обучения и учебному году; - правила расписания дисциплин; - слоты правил: день недели, чётность, пара, преподаватель, аудитория, тип занятия, формат и опциональные подгруппы для лабораторных; - назначение конкретного календарного графика учебной группе на учебный год. При запросе `GET /api/schedule` backend рендерит расписание на диапазон дат. Если дата не является днём теоретического обучения по назначенному группе графику, обычные пары не выводятся и академические часы не списываются. ## Слои модели ### Календарный слой - `academic_years` и `semesters` задают границы учебного года и семестров. - `specialties` и `specialty_profiles` определяют образовательную программу группы. - `academic_calendars` хранит график профиля и формы обучения. - `academic_calendar_activity_types` хранит коды из Excel-графика: `Т`, `Э`, `К`, `У`, `П`, `Пд`, `Н`, `Г`, `Д`, `ПА`, `С`, `*`, `=`. - `academic_calendar_days` хранит дневную сетку по курсу и дате. - `student_group_calendar_assignments` выбирает график для группы на учебный год. ### Слой правил расписания - `time_slots` задаёт сетку пар для тенанта. - `schedule_rules` хранит дисциплину, семестр, отдельные лимиты часов и стартовые недели для лекций, лабораторных и практик. - `schedule_rule_groups` связывает правило с одной или несколькими группами. - `schedule_rule_slots` хранит шаблонные занятия правила, а `schedule_rule_slot_subgroups` связывает лабораторный слот с одной или несколькими подгруппами. ## Алгоритм генерации 1. Для даты определяется семестр. 2. Для группы находится назначенный календарный учебный график. 3. По году начала обучения вычисляется текущий курс группы. 4. По курсу и дате находится код активности. 5. Обычные пары генерируются только для кода, где `allow_schedule = true`; в seed-данных это `Т`. 6. Для разрешённого дня выбираются активные правила и слоты. 7. Лимит часов считается только по реально проведённым занятиям; для лабораторных подгрупп счётчик ведётся отдельно по каждой подгруппе. Лекции и практики нельзя делить на подгруппы. Если лабораторный слот привязан к нескольким подгруппам разных групп, он выводится как совместное занятие этих групп, а часы списываются отдельно по каждой подгруппе. Если назначение графика отсутствует, расписание группы возвращается пустым списком без ошибки. ## Административный сценарий Администратор создаёт специальность и профиль, затем создаёт группу с этой связкой. В разделе расписания он создаёт учебный год, семестры и календарный график, заполняет дневную сетку кодами активностей и назначает график группе. После сохранения графика или назначения кэш генератора очищается, поэтому следующие запросы расписания используют новые правила сразу.