Расписание НГУЭУ Документы системы расписания
Веб-приложение для составления и ведения расписания

Техническое задание: веб-система составления и ведения учебного расписания§

Идентификатор: ТЗ-RSP-WEB-001
Версия: 0.3 — календарное расписание, точечные переносы и онлайн-занятия; проект для редактирования заказчиком
Дата: 9 сентября 2026 года
Назначение: основа для обсуждения, оценки и разработки новой системы с возможностью последующего расширения.
Целевая установка: автономное веб-приложение на сервере заказчика, основная СУБД — PostgreSQL.
Основание: исследование файлов и экранов существующей системы «Расписание занятий и экзаменов» и Политика составления расписания, построенная по полному снимку БД и уточнениям владельца.

Документ задаёт поведение будущего продукта. Формулировка «система должна» относится к новой реализации. Подтверждённые возможности старой программы, проектные решения и ещё не выясненные правила обозначены отдельно. ТЗ не утверждает, что все предлагаемые операции были выполнены или проверены в старой программе.

Версия 0.3 предназначена для дополнений заказчика. Все требования базового объёма действуют как рабочая редакция до изменения документа; открытые вопросы не дают исполнителю права молча выбирать способ преобразования неоднозначных данных. Сроки, стоимость, состав команды и окончательный перечень расширений определяются после согласования объёма. Обновление этого ТЗ не означает, что описанные функции уже реализованы в работающем просмотрщике.

В редакции 0.2 уточнены совместные проведения по нескольким планам, классификация обучения, временные профили, ограничения ресурсов и условия публикации. Добавлены FR-061–FR-068: управление правилами, объяснимые показатели качества, проверяемое объединение исходных строк и контроль готовности политики. Все 20 правил POL-01–POL-20 сопоставлены с требованиями и приёмкой. Наблюдаемые частоты используются как основания для обсуждения настроек; они не становятся автоматически обязательными нормами или коэффициентами оптимизатора.

Редакция 0.3 уточняет обязательную базовую версию по сообщению владельца: создание занятий на конкретные числа, просмотр по дням, перенос одного проведения без изменения остальных повторений и явное назначение онлайн-формата. Новый FR-069 позволяет перенести только выбранную группу из общего занятия. Добавлены пять сценариев AP-19–AP-23. Выбранный стек React/TypeScript, Django/DRF и PostgreSQL сохраняется; работа нового приложения не зависит от Delphi, BDE и Paradox.

Оглавление§

Назначение и ожидаемый результат§

Цель продукта§

Создать веб-приложение для подготовки, ручного составления, проверки, согласования, публикации и просмотра расписания занятий, экзаменов, зачётов и консультаций. Перенести в него учебные справочники, планы, связи групп, занятия и ограничения из исследованной системы. Организовать совместную работу сотрудников в браузере с контролем прав и сохранением истории.

Результат — устанавливаемая на инфраструктуре заказчика система: исходный код, PostgreSQL со схемой и миграциями, интерфейс, API, механизм импорта, автоматические проверки, установочный комплект, инструкции и проверенная процедура восстановления. Рабочие действия выполняются через браузер; установка Delphi, BDE, Paradox или клиентского SQL-приложения пользователям не требуется.

Что означает «такая же система»§

Под эквивалентностью понимается покрытие предметных возможностей: справочники, группы и подгруппы, учебные планы и виды нагрузки, объединённые занятия, назначение времени и ресурсов, список неназначенных занятий, перестановки и замены, ограничения, поиск свободных аудиторий и виды расписания по группе, преподавателю и аудитории.

Побайтовая совместимость с Paradox, повторение всех пиктограмм, цветов и окон Windows, а также воспроизведение недоступного алгоритма старой программы в базовый объём не входят. Новый интерфейс должен решать те же задачи понятными веб-формами. Там, где старое поведение не установлено, ниже задано самостоятельное проектное правило или указан вопрос, который нужно разрешить.

Разграничение материалов и будущего продукта§

Материал Роль в проекте
Исходная настольная программа и её Paradox-файлы Источник предметной области, данных и наблюдаемых интерфейсных возможностей
Технический отчёт и текущий просмотрщик SQLite на rsp.nsuemdev.ru Исследовательский инструмент: помогает изучать снимок, искать записи и сверять импорт
Политика составления расписания и защищённые профили Аналитическая реконструкция правил по готовому результату; основания, частоты и неопределённости, а не исходный код алгоритма
Веб-приложение по настоящему ТЗ Новый продукт для многопользовательского редактирования и эксплуатации на PostgreSQL

Нынешний просмотрщик не является готовым редактором расписания. Его API, учётные записи HTTP Basic и файловая SQLite не должны автоматически становиться архитектурой нового продукта. Допускается повторное использование документированных правил чтения и проверки источников, русских описаний полей и проверочных наборов данных.

PostgreSQL и файловое хранение§

SYS-001. Основной источник рабочих данных — отдельная серверная PostgreSQL. Это не один файл, который приложение открывает как SQLite: доступ идёт по протоколу СУБД, а данные сохраняются в управляемом PostgreSQL каталоге/томе. Браузер обращается только к API приложения.

Файл exports/schedule.sqlite используется для первоначального импорта и сверки. Переносимость установки обеспечивается резервной копией PostgreSQL, архивом приватных файлов и конфигурацией приложения. Простое копирование работающего каталога PostgreSQL средствами файлового менеджера не является предусмотренным способом резервного копирования.

Приёмка SYS-001: после удаления контейнеров приложения и их повторного создания рабочие данные сохраняются; новая установка восстанавливается из документированного комплекта резервной копии без доступа к старой машине.

Основания, исходные данные и границы достоверности§

Материалы исследования§

Код источника Материал Назначение
SRC-01 Технический отчёт Сводная архитектура, словарь 88 полей, 59 интерфейсных возможностей, оговорки
SRC-02 Анализ экранов и screen/Screenshot_1.jpg … Screenshot_15.jpg Наблюдаемые формы, поля и команды
SRC-03 Анализ связей Проверенные отношения, значения -1/0/NULL, групповые выборки
SRC-04 Схема экспорта (локальный материал), SQLite Точные имена и типы полей, доступные строки
SRC-05 Анализ форматов, анализ индексов Paradox, CP866, индексы и ограничения источников
SRC-06 Проверка групповых выборок (локальный материал), независимая сверка pxlib (локальный материал) Контрольные данные для миграции
SRC-07 Проверка текущего просмотрщика (локальный материал) Проверка чтения снимка через HTTPS; не подтверждает работу нового редактора
SRC-08 Политика составления расписания, редакция 0.1 от 2026-09-09, POL-01–POL-20 Полный анализ 15 111 строк, наблюдаемые предпочтения, ограничения применимости и каталог правил
SRC-09 Уточнения владельца от 2026-09-09, воспроизведённые в разделе 3 политики Расшифровка формы, уровня обучения, онлайн- и билингвального признаков; не подтверждает календарь и строгость временных норм
SRC-10 Уточнение владельца и согласованный план редакции 0.3 от 2026-09-09 Старая система использует периодическую сетку без полноценного подневного редактирования на конкретные числа; перенос одного занятия требует менять сетку. Назначение и отображение онлайн-занятий поддерживаются некорректно. Для новой версии подтверждён перенос только выбранной группы из общего проведения

SRC-10 фиксирует опыт владельца, а не результат выполнения команд старой программы в рамках исследования. Слово «очные» в исходном сообщении уточнено владельцем как «онлайн-занятия». Обязательное отличие новой версии: календарные проведения можно создавать и менять непосредственно, а повторяющаяся сетка служит шаблоном их первоначального заполнения. Само это уточнение не раскрывает формулу старого DayNo и не разрешает угадывать даты при импорте.

Контрольная SHA-256 источника SRC-08: ed4ca4c44b69a4e2b2f9510cc4912fe90593797b8f5a90f2b30b91af019cf29d. Расчётные основания находятся в скриптах и агрегатах research/analyze_policy_*.py, research/policy-*.json, перечисленных в разделе 12 политики. При следующем снимке пересчитываются и показатели, и границы охвата; старые числа не являются целевыми нормативами нового расписания.

Исходники основной настольной программы и её основной исполняемый файл в исследованном наборе отсутствуют. Функциональность исследовалась по файлам и скриншотам; не проводилось выполнение всех команд старой программы. Связанная утилита Reorder.EXE подтверждает Windows x86, Delphi/VCL и BDE для этой утилиты; использование того же стека всей программой остаётся обоснованной гипотезой.

Контрольный объём снимка§

Показатель Значение
Основные таблицы Paradox 19
Все доступные строки 19 таблиц, включая вспомогательные 75 909
Строки Classes 15 111
Группы 554
Преподаватели 866
Аудитории 184
Дисциплины 5 068
Позиции плана 4 748
Связи групп с планами 21 419
Объекты текущей SQLite 19 исходных таблиц + 2 представления + _source_manifest

Контрольная SHA-256 SQLite: c9754cd457d4902429ccfcbf85cdf54c7307b0cfdf74f3ed6b6ead0f8ca207b0. Для следующего снимка значения и хеш должны вычисляться заново. 15 111 исходных записей нельзя заранее считать 15 111 отдельными календарными событиями: одна запись может кодировать повторение, и смысл периода ещё нужно подтвердить.

Особенности, влияющие на реализацию§

  1. Скриншоты относятся к сентябрю 2024 года; имя папки — 1_sem_2026_2027. Название каталога не устанавливает дату начала семестра.
  2. Classes.DayNo содержит 72 непустых кода в диапазоне 0–299. Формула даты, начало отсчёта, сочетание EachWeek и OddWeek не подтверждены.
  3. У 3 458 строк занятий GroupNo=-1; участники определяются по соответствующей позиции плана через GRPPLAN. Объединение не должно размножать одно занятие в нескольких физических копиях.
  4. ClassesInf имеет 15 111 доступных строк при счётчике 15 124 в заголовке источника. CLASSINF — другая, пустая таблица. Расхождение не разрешается добавлением 13 фиктивных записей.
  5. Assigned=True не означает полноту ресурсов: 2 339 таких записей не имеют аудитории. В новой модели временное размещение, полнота сведений и разрешение на публикацию разделяются.
  6. CourseNo и CourseCount нельзя превращать в номер фактического года обучения. Все прямые GROUPS.StreamNo равны -1; состав объединённых занятий не восстанавливается из справочника STREAMS.
  7. Свободные заметки могут содержать внутренние сведения и реквизиты онлайн-занятий. Для внешнего просмотра необходим отдельный разрешённый состав полей; значения заметок в это ТЗ не копируются.
  8. В двух кафедрах встречаются ссылки на факультеты 46 и 48, отсутствующие в справочнике. Импорт должен показывать такие связи как требующие сопоставления, а не создавать вымышленные факультеты.
  9. Все 638 многозаписных клеток преподавателей согласованы по полному названию предмета и виду занятия; 572 многозаписные клетки аудиторий — также по преподавателю. Только 236 из этих 572 имеют один PlanNo; равенство плана не является обязательным признаком совместного проведения. Это основание для проверки кандидатов объединения, а не разрешение автоматически схлопнуть строки.
  10. Формы обучения, уровни, онлайн-формат и билингвальность — разные признаки. У заочных назначено только 745 из 3 817 участий (19,52%): по такому охвату нельзя восстановить общий режим сессий или считать недостающие занятия отменёнными.
  11. В строгой выборке целых групп 1 121 из 4 396 строк имеют справочную численность выше вместимости помещения. Историческое расхождение не разрешает превышение в новой системе; требуются проверка данных и утверждение режима контроля.

Состав базовой версии и порядок изменения ТЗ§

Приоритеты и происхождение требований§

Обозначение Значение
B / базовое Обязательное требование первой полноценной рабочей версии
E / расширение Кандидат дальнейшего развития; не включается в стоимость и приёмку B автоматически
Q / уточнение Неопределённость источника или решение заказчика; указано допустимое поведение до её разрешения
Подтверждено данными Сущность, поле или связь действительно обнаружены в файлах
Наблюдается на экране Форма или команда видна; её выполнение не проверено
Проектное решение Требование к новой системе, независимо от устройства старой
АП / аналитика политики Наблюдение или гипотеза SRC-08; степень поддержки не равна утверждённой обязательности
УВ / уточнение владельца Подтверждённые владельцем сведения SRC-09/SRC-10; применяются в своей явно заданной области

Требования SYS, FR, DATA, CAL, MIG, API, SEC, NFR, OPS и ACC, если явно не помечены E, относятся к базовому объёму. Идентификаторы LEG обозначают пункты сопоставления старого и нового интерфейсов, а не дополнительные требования. Пункт Q не отменяет необходимость сохранить исходные данные и дать пользователю доступ к их исследованию.

Базовый объём B§

Направление Результат
Пользователи и права Индивидуальные учётные записи, роли, области ответственности, журнал действий
Учебная организация Справочники, группы и подгруппы, аудитории, преподаватели, дисциплины
Планирование Учебные периоды, календарь, звонки, планы, виды и объёмы нагрузки
Расписание Ручной редактор событий и повторений, неназначенные занятия, изменения ресурсов, обмен местами
Проверка Пересечения участников и ресурсов, жёсткие ограничения, полнота и предупреждения
Политика и качество Версии правил, временные профили, матрица помещений, раздельные показатели качества и объяснение последствий ручных изменений
Совместная работа Защита от перезаписи чужих изменений, разграничение кафедральных предложений и общего плана
Выдача результата Утверждённые версии, просмотр по группе/преподавателю/аудитории, печатный вид и контролируемая выгрузка
Перенос Воспроизводимый импорт SQLite, сохранение исходных значений, протокол расхождений и сопоставлений
Эксплуатация Автономная установка, резервное копирование, восстановление, мониторинг и обновления

Рабочие решения для версии 0.3§

  • Одна образовательная организация в одной установке; её подразделения и несколько учебных периодов. Полноценный коммерческий SaaS с арендаторами — расширение.
  • Русский интерфейс; часовой пояс организации по умолчанию Asia/Novosibirsk. Фактические даты нового расписания задаются явно.
  • Единственный редактируемый черновик в пределах учебного периода. История публикаций неизменяема. Несколько параллельных веток расписания — расширение.
  • Один основной преподаватель и одна аудитория на экземпляр занятия в B; отсутствие ресурса в черновике допускается с замечанием о неполноте. Несколько одновременно занятых аудиторий/преподавателей требуют отдельного расширения и проверки.
  • Состояния экземпляра: unplaced, scheduled, cancelled. «Опубликовано» относится к версии расписания, а «передано кафедре» — к отдельному процессу согласования.
  • Жёсткие пересечения ресурсов и участников внутри одной редакции нельзя сохранить как нормальное размещение. Черновики разных периодов независимы; пересечения с действующими публикациями других периодов отмечаются и блокируют новую публикацию, но не сохранение черновика. Вместимость и совместимость помещений проверяются по FR-033 и FR-066; произвольная причина диспетчера не разрешает превышение вместимости.
  • Одно совместное проведение может обеспечивать несколько компонентов разных планов в одной редакции. Состав участников объединяется, преподаватель и помещение бронируются по одному разу; выполнение каждого плана учитывается отдельной подтверждённой связью.
  • Читатель по умолчанию входит в систему. Анонимное опубликованное расписание — явно включаемая настройка с отдельным составом выдаваемых полей.
  • Ручное составление является обязательным. Автоматический оптимизатор, интеграции с вузовскими системами, мессенджерами и внешней идентификацией в B не входят.

Как дополнять документ§

Изменять требования следует по идентификаторам: сохранять старый ID при уточнении смысла, выдавать новый при добавлении самостоятельной функции, а исключённое требование помечать как снятое с причиной. Для каждой новой функции обязательно определить роль, входные данные, влияние на существующие занятия и версии, ошибки, права, критерий приёмки и необходимость миграции схемы. Одной строки «добавить интеграцию» или «сделать автосоставление» недостаточно для оценки разработки.

Если новое решение конфликтует с рабочим правилом текущей редакции, менять нужно также связанные разделы данных, API, миграции и приёмки. Список открытых решений и шаблон карточки расширения приведены в конце документа.

Функциональные требования к новой веб-системе расписания§

Этот раздел задает поведение нового продукта, а не утверждает, что перечисленные проверки выполнялись в настольной программе. Основание: техническое описание (локальный материал), анализ 15 экранов, исходные таблицы и подготовленная SQLite-выгрузка.

Текущая редакция дополнительно использует SRC-08–SRC-10: АП — аналитика политики, УВ — уточнения владельца. Всего 69 требований FR: 67 базовых и два расширения (FR-059, FR-060). Сами основания не определяют строгость рабочих правил: она задаётся утверждённой конфигурацией.

Для прослеживаемости используются обозначения: ИД — соответствующие данные подтверждены в файлах; ИЭ — экран, поле или подписанная команда видны на скриншоте; НП — новое проектное правило, нужное веб-приложению. Наличие ИД или ИЭ подтверждает источник функции, но не весь алгоритм ее выполнения. Например, Stable найден в данных, а запрет редактирования закрепленного занятия вводится настоящим ТЗ. B — обязательная базовая поставка; E — последующее расширение, не являющееся условием приемки базовой поставки. Все требования ниже имеют приоритет B, кроме явно отмеченных E.

Система предназначена для учебных диспетчеров: вести справочники, формировать учебную потребность, вручную размещать занятия и экзамены, проверять занятость ресурсов, согласовывать изменения и выпускать версии расписания. Автоматическое построение полного расписания не включается в обязательную поставку. Не требуется воспроизведение визуального оформления Windows: требуется функциональная преемственность и понятная работа в браузере.

Термины и границы поведения§

  • Позиция плана — отдельная учебная потребность по дисциплине, подразделению и составу участников. Одна дисциплина может иметь несколько позиций плана.
  • Вид нагрузки — лекция, практика/семинар, лабораторная, зачет, экзамен или консультация. Код и название согласуются отдельно от старых буквенных обозначений.
  • Экземпляр занятия — одно конкретное занятие, которое после размещения имеет календарную дату и интервал начала/окончания. В базовой поставке у экземпляра один основной преподаватель и, для очного занятия, одна аудитория.
  • Серия — связанный набор экземпляров, созданных по правилу повторения. Серия не заменяет даты отдельных экземпляров.
  • Учебный поток занятия — явно выбранный набор групп/подгрупп, совместно участвующих в нагрузке. Административный поток — именованный классификационный набор групп; его членство само по себе не назначает группы на занятия.
  • Рабочее расписание — изменяемый вариант семестра. Публикация — отдельная неизменяемая версия, которую видят читатели. Редактирование рабочего варианта не изменяет опубликованный.
  • Назначение — активное размещение с состоянием scheduled; неназначенность — unplaced; отмена проведения — cancelled. Закрепление, кафедральное согласование и опубликованность не являются альтернативными значениями этого статуса.

Пользователи, доступ и рабочее пространство§

FR-001. Вход и завершение сеанса — B, НП§

Внутренние разделы доступны после входа в личную учетную запись. Пользователь может завершить сеанс; администратор — заблокировать учетную запись и отозвать ее активные сеансы. Пароль общего доступа уже развернутого просмотрщика не переносится в качестве системы прав нового продукта. При наличии публичного просмотра он действует только для опубликованных безопасных полей.

Приемка: пользователь входит и выходит; после блокировки ранее открытый сеанс перестает выполнять защищенные запросы. Прямой URL карточки или API без действующего сеанса не раскрывает внутренние данные.

FR-002. Роли и совмещение полномочий — B, НП§

Предусмотреть роли: администратор системы, центральный диспетчер, сотрудник кафедры, утверждающий/публикатор и читатель. Роли можно совмещать. Администратор управляет учетными записями, правами и техническими настройками; изменение учебных данных требует дополнительно назначенной роли диспетчера. Публикатор выпускает версии, но без роли диспетчера не меняет занятия. Читатель не изменяет данные.

Приемка: одна учетная запись с двумя ролями получает объединение разрешенных действий; снятие роли убирает соответствующие команды и API-права. Технический администратор без предметной роли не сохраняет изменение расписания.

FR-003. Область полномочий — B, НП§

Каждая предметная роль получает явно заданную область: все подразделения либо определенные кафедры/факультеты. Центральный диспетчер работает со всем назначенным ему контуром. Сотрудник кафедры ведет потребность своей кафедры, предлагает преподавателей и ограничения, обрабатывает переданные заявки; окончательное размещение и межкафедральные изменения выполняет центральный диспетчер. Для проверки занятости можно показывать занятые интервалы ресурсов вне области без закрытых комментариев.

Приемка: сотрудник кафедры A не изменяет план кафедры B, подменив идентификатор в запросе. Участие группы другого факультета в общем занятии не дает сотруднику прав редактирования всей этой группы.

FR-004. Матрица основных действий — B, НП§

Следующая матрица является обязательной исходной политикой; доступ дополнительно ограничивается областью FR-003.

Действие Администратор Диспетчер Кафедра Публикатор Читатель
Учетные записи и права Да Нет Нет Нет Нет
Общие справочники и семестры Только с ролью диспетчера Да Нет Нет Нет
Планы кафедры и предложения преподавателей Нет Да В своей области Просмотр Нет
Назначение, перенос, обмен, отмена Нет Да Заявка Нет Нет
Ограничения преподавателей Нет Да Предложение в своей области Просмотр Нет
Подготовка правил политики и временных профилей Нет Да Предложение в своей области Просмотр Нет
Утверждение и активация политики Нет Только при совмещении Нет Да, по отдельному праву policy.approve Нет
Отчёты качества и проверка совместных проведений Нет В своей области Агрегаты своей области В своей области Нет
Закрепление и снятие закрепления Нет Да Нет Нет Нет
Утверждение и публикация Нет Только при совмещении Нет Да Нет
Закрытые заметки Отдельное предметное право По области По области По области при предоставленном праве Нет
Просмотр опубликованного расписания Да Да Да Да Да
Технический просмотр данных Отдельное право Отдельное право Нет Нет Нет

Приемка: для каждой строки выполняются положительный тест разрешенной роли и отрицательный тест запрещенной; скрытие кнопки без серверного запрета не считается выполнением требования.

FR-005. Контроль доступа к выгрузкам и журналам — B, НП§

Те же права действуют для таблиц, карточек, поиска, выгрузок, печати, фоновых заданий и истории. Журнал действий доступен диспетчеру по его области и специально уполномоченному аудитору; чтение журнала не должно открывать закрытые старые значения пользователю без права чтения заметок. Объем прав экспортирующего проверяется при формировании файла и получении результата.

Приемка: пользователь без доступа к кафедре не получает ее закрытые строки через CSV или поиск; после снятия права не скачивает ранее созданную защищенную выгрузку по сохраненной ссылке.

FR-006. Навигация и контекст — B, ИЭ + НП§

Основные разделы: обзор, расписание, неназначенные занятия, учебный план, справочники, ограничения, согласование, публикации, импорт/диагностика и просмотр данных. В заголовке постоянно видны семестр и режим «рабочий вариант»/«опубликованная версия». Фильтры списка и выбранная неделя сохраняются при возврате из карточки; пустая выдача отличается от ошибки загрузки.

Приемка: переход из расписания в преподавателя и обратно сохраняет неделю и группу. При переключении семестра интерфейс очищает несовместимые фильтры и не показывает данные старого семестра под новым заголовком.

Справочники и учебные ресурсы§

FR-007. Единое поведение справочников — B, ИД + ИЭ + НП§

Справочники имеют поиск без учета регистра русских букв, фильтры, сортировку, страницы результатов, карточку, создание, изменение и архивирование. Использованные записи не удаляются физически через обычный интерфейс. У каждой записи есть устойчивый идентификатор; переименование не разрывает связи. Повторяющиеся названия допускаются только там, где это содержательно возможно, и различаются дополнительными реквизитами.

Приемка: поиск «ИВАН» находит «Иванов»; архивная аудитория сохраняется в старой версии, но недоступна для нового назначения. Удаление используемого справочника отклоняется с перечнем зависимостей.

FR-008. Факультеты — B, ИД + ИЭ§

Вести полное и краткое название факультета, действительность и внешний код при наличии. Факультет используется для группировки кафедр, групп и фильтров. Пустые названия и буквальные артефакты импорта вроде HTML-сущностей отмечаются для проверки; система не создает подразделение из такого значения молча.

Приемка: переименование меняет актуальное отображение связанных карточек без потери связей. Архивирование факультета с активными группами требует предварительного решения о них; автоматического переноса в произвольный факультет нет.

FR-009. Кафедры — B, ИД + ИЭ§

Вести название, сокращение, факультет или явно обозначенную независимую принадлежность. Отображать связанные планы, преподавателей и закрепленные аудитории. Перед сменой принадлежности показывать затрагиваемые области прав и требовать выполнения операции пользователем, уполномоченным на обе области.

Приемка: кафедра с неизвестной ссылкой на факультет при импорте попадает в диагностику. Изменение факультета не дает прежним кафедральным пользователям права на новое подразделение и не меняет автоматически владельца исторической публикации.

FR-010. Курсы и уровни обучения — B, ИД + ИЭ§

Вести название курса, уровень обучения и, если заполнен, фактический год обучения как отдельное значение. Числовой идентификатор не показывать вместо курса. В старых данных CourseNo=6 может соответствовать первому курсу магистратуры; такие записи отображаются по названию и согласованному сопоставлению.

Приемка: группа с указанным классификатором показывается как «1-й курс магистратуры», а не «6-й курс». Отсутствие подтвержденного фактического года не заполняется номером старого ключа.

FR-011. Учебные группы — B, ИД + ИЭ + УВ§

Карточка группы включает обозначение, факультет, курс/уровень, учебный период действительности, численность и состав подгрупп. Предусмотреть просмотр плана и расписания группы. Численность — целое неотрицательное число либо отдельное состояние «неизвестна»; неизвестность отличается от нуля. Для совпадающих обозначений показывать период и факультет.

Отдельно хранить форму full_time/part_time/correspondence/unknown, уровень vocational/bachelor_specialist/master/postgraduate/unknown, онлайн-признак и билингвальность. Для признаков доступны источник, версия классификатора, статус подтверждения и ручная корректировка с причиной. Онлайн-признак группы задаёт исходное предложение формата её занятий, но окончательный формат проведения хранится у серии/экземпляра. При импорте применять подтверждённую владельцем таблицу из раздела «Классификация групп»; незнакомое обозначение направлять на проверку. Изменение названия не меняет признаки уже опубликованного расписания.

Приемка: отрицательная численность отклоняется. Архивирование группы не удаляет ее занятия; для будущих активных занятий интерфейс требует сначала решить состав участников или отменить эти занятия.

FR-012. Подгруппы и пересечения участников — B, ИД + ИЭ + НП§

В базовой версии группа имеет одно разбиение на подгруппы с явным признаком подтверждения непересекаемости. Для подгруппы задаются обозначение и численность либо неизвестное значение. Занятие всей группы пересекается с любой ее подгруппой; занятия разных подгрупп могут идти одновременно только внутри подтвержденного непересекающегося разбиения. Если непересекаемость неизвестна, система консервативно считает такие подгруппы пересекающимися. Индивидуальные списки студентов и несколько пересекающихся схем деления — отдельное расширение.

Приемка: параллельные занятия подгрупп 1 и 2 разрешаются при подтвержденной непересекаемости и разных преподавателях/аудиториях; при неизвестной непересекаемости либо участии всей группы в том же интервале сохранение блокируется. Сумма известных численностей подгрупп не превышает численность группы без явной диагностики.

FR-013. Преподаватели — B, ИД + ИЭ§

Вести отображаемое ФИО, кафедру, должность, степень, звание, состояние действительности и закрытую служебную заметку. Из карточки открываются нагрузка, расписание и ограничения. Полные тезки допустимы; различаются кафедрой и устойчивым идентификатором. Учетная запись преподавателя, если появится позднее, не заменяет его предметную карточку.

ФИО используется для поиска и сверки, устойчивый ID — для занятости и расчётов. Нельзя назначать особый приоритет, запрет времени или внешнюю занятость по фамилии, должности, кафедре либо наблюдаемому вечернему профилю. Такие условия вводятся отдельным подтверждённым правилом доступности с областью и сроком действия (POL-16).

Приемка: можно создать двух тезок без слияния. Архивный преподаватель остается в истории, но не назначается на новое занятие; заметка не появляется в публичной карточке расписания.

FR-014. Дисциплины — B, ИД + ИЭ§

Вести полное и краткое название дисциплины, внешний код и признак действительности. Сетка использует краткое название с доступным полным названием в карточке. Несколько позиций плана одной дисциплины допустимы; их объединение по совпадению текста запрещено без специальной операции с предварительным просмотром последствий.

Приемка: две позиции одной дисциплины для разных кафедр сохраняются независимо; изменение сокращения не меняет объем и участников. Пустое полное название отклоняется.

FR-015. Аудитории — B, ИД + ИЭ + НП§

Вести обозначение, корпус/адрес как реквизит, вместимость, назначение, закрепленную кафедру, действительность и закрытую заметку. Различать тип аудитории и вид занятия. Поддержать как минимум лекционные, практические, лаборатории, компьютерные и лингафонные аудитории; соответствие старым кодам согласовать при импорте. Для ресурса доступны расписание и ограничения.

Приемка: аудитория с отсутствующей вместимостью имеет пометку «неизвестна», а не нулевую вместимость. Одинаковые номера в разных корпусах различимы; выбор «Любая» существует в фильтре и не сохраняется как тип помещения.

FR-016. Административные потоки — B, ИД + ИЭ + НП§

Разрешить создать именованный набор групп, добавить/исключить группу и использовать набор для фильтрации или первоначального выбора участников. Изменение административного потока не изменяет состав уже созданных позиций плана и занятий. Название с учебным годом является текстом, а не источником календарных дат.

Приемка: исключение группы из административного потока меняет фильтр, но оставляет ее участником ранее сформированной общей лекции до отдельного изменения этой лекции. Пустой поток не создает фиктивных участников.

FR-017. Классификаторы видов нагрузки — B, ИД + ИЭ + НП§

Базовый набор включает лекцию, практику/семинар, лабораторную, зачет, экзамен и консультацию с явными кодами и названиями. Для вида задается базовая единица учета и допустимость деления на подгруппы. Старые с, л, п, з, э, к сохраняются в происхождении записи, а перевод в новый вид выполняется по утвержденной таблице соответствий.

Приемка: неизвестный код попадает в очередь сопоставления; сходный код аудитории не используется для автоматической расшифровки вида занятия. Архивирование вида не меняет уже опубликованное расписание.

FR-018. Дни и сетки звонков — B, ИД + ИЭ + НП§

Показывать локализованные дни недели и вести именованные сетки звонков. Каждый слот имеет порядковую метку, время начала и окончания; длительность задается явно. Сетка может действовать для выбранного периода/кампуса. В основной поставке для одного экземпляра применяется одна сетка, допускается индивидуальный интервал по явному действию диспетчера.

Приемка: слот 08:00–09:30 сохраняется, окончание раньше начала отклоняется. Время окончания не вычисляется как начало следующей пары; изменение сетки не сдвигает существующие датированные занятия молча.

Семестр и учебная потребность§

FR-019. Параметры семестра — B, ИЭ + НП§

Семестр имеет название, учебный год, даты начала/окончания, часовой пояс Asia/Novosibirsk по умолчанию, начало нумерации учебных недель, рабочие дни, периоды занятий/экзаменов и исключения календаря. Семестр можно перевести в архив с запретом обычного редактирования. Изменение календаря после появления расписания выполняется через предварительный отчет последствий.

Приемка: нельзя сохранить окончание раньше начала. Сокращение периода не удаляет занятия за новыми границами: показывает их и блокирует подтверждение до согласованного решения.

FR-020. Позиция учебного плана — B, ИД + ИЭ§

Создавать отдельную позицию по дисциплине, ответственной кафедре, семестру и описанию. Карточка содержит участников, виды/объемы нагрузки, требования к аудиториям, закрепление и связи с экземплярами. Копирование позиции допускается с предварительным выбором переносимых полей; исторические назначения, публикации и согласования не копируются как завершенные.

Приемка: две позиции с одинаковой дисциплиной, но разными участниками сохраняются. Копия имеет новый идентификатор и не делит изменяемые занятия с оригиналом.

FR-021. Состав учебного потока — B, ИД + ИЭ + НП§

Для каждого вида нагрузки явно выбирать группы целиком либо отдельные подгруппы. Общая лекция нескольких групп является одним занятием с несколькими участниками. Выбор всей группы и ее подгруппы одновременно нормализуется до всей группы после предупреждения; численность не суммируется повторно. Состав не выводится автоматически из административного потока после создания.

Совместное проведение допускается и для нескольких компонентов разных планов по FR-065. Каждая исходная потребность сохраняет идентичность, участников и учётный объём. Совпадение PlanNo, SubjectNo, времени или текста названия по отдельности не создаёт такое объединение. В карточке видны одно фактическое проведение и все обеспечиваемые им планы; совместность подтверждается диспетчером.

Приемка: общая лекция двух групп отображается у каждой группы по одному разу и занимает одного преподавателя один раз. Повторный выбор той же подгруппы не удваивает состав и объем нагрузки.

FR-022. Виды, объемы и деление нагрузки — B, ИД + ИЭ + НП§

Для каждого вида указывать общий объем за период, при необходимости недельную норму, число/состав подгрупп и ожидаемую длительность одного занятия. Недельная норма служит плановым ориентиром, а не скрытым правилом автоматического умножения. Экзамены, зачеты и консультации используют тот же механизм явного объема с собственными длительностями.

Приемка: план может иметь лекции без лабораторных и отдельный экзамен. Отрицательные объемы запрещены; несовместимый набор «проводить по подгруппам» без выбранных подгрупп не проходит сохранение.

FR-023. Единицы учета — B, НП§

В настройках семестра указать длительность академического часа, например 45 минут, и допустимый шаг объема. Отличать академические часы, астрономическую длительность и число экземпляров. В карточке явно показывать используемую единицу. Механизм расчета объема экземпляра определяется длительностью учебной части; перерыв не засчитывается автоматически.

Приемка: два академических часа по 45 минут дают 90 минут учебного времени; наличие перерыва между слотами не увеличивает нагрузку. Импортированное PlanQty с невыясненной единицей не объявляется подтвержденным количеством пар.

FR-024. Формирование неназначенных занятий из плана — B, НП§

Диспетчер выбирает позицию, вид, состав участников, объем и длительность. Система показывает число создаваемых экземпляров и остаток, затем создает unplaced. При недельном шаблоне предварительный просмотр учитывает фактические недели и исключенные дни. Повторный запуск предлагает только недостающий объем либо явно отмеченное создание сверх плана.

Приемка: из 18 академических часов при длительности 2 часа формируются 9 экземпляров; неподелившийся остаток требует решения и не округляется молча. Повтор одного подтвержденного запроса не создает дубликаты.

FR-025. Изменение плана с существующим расписанием — B, НП§

Изменение объема, участников или длительности сначала показывает затронутые экземпляры, конфликты и опубликованные ссылки. Можно применить изменение к будущим выбранным экземплярам либо оставить их и зафиксировать расхождение. Сокращение объема не удаляет проведенные/прошедшие или опубликованные экземпляры; избыток решается отдельными отменами или корректировкой плана.

Приемка: уменьшение с 20 до 16 часов при 20 размещенных часах дает предупреждение об избытке и перечень занятий. Без подтвержденного выбора четыре часа не исчезают автоматически.

FR-026. Требования к помещениям и ресурсам — B, ИД + ИЭ + НП§

Для вида нагрузки позиции плана задавать типы помещений через матрицу совместимости, обязательное и желательное оборудование, подтверждённую потребность в местах и, при необходимости, допустимый перечень помещений. Перечень может быть пустым и означать отсутствие отдельного ограничения, а не отсутствие допустимых аудиторий. Обязательность каждого условия задана явно; равенство старых буквенных кодов не заменяет матрицу. Базовый экземпляр использует одного преподавателя и одну аудиторию; комиссионные экзамены, смешанное одновременное проведение очно/онлайн и несколько помещений относятся к расширению.

Приемка: план без перечня помещений позволяет обычный поиск по типу/вместимости. При заданном обязательном перечне аудитория вне него не назначается; правило не подменяется вероятным смыслом пустой старой PLANROOM.

FR-027. Баланс учебной нагрузки — B, НП§

Показывать по плану, виду и участнику: требуемый объем, созданный, размещенный, неназначенный, отмененный и отклонение. Общий поток считается одним проведением для преподавателя, но участием для каждой включенной группы; эти показатели подписываются раздельно. Отмененные экземпляры не входят в обеспеченный объем, а публикация сама по себе не означает проведение занятия.

Приемка: отмена одной двухчасовой лекции уменьшает размещенный объем на два часа и показывает дефицит; не удваивает преподавательскую нагрузку из-за двух групп. Статистика содержит переход к исходным занятиям.

Календарь, состояния и ограничения§

FR-028. Явные даты и интервалы — B, УВ + НП§

Размещенное занятие имеет конкретную календарную дату, время начала и окончания в часовом поясе семестра. Интервалы рассматриваются как [начало, окончание): соседние занятия без пересечения допустимы. Переход через полночь в базовом редакторе запрещен; нестандартное вечернее занятие должно завершаться в те же локальные сутки. Старый DayNo не является датой нового события.

Диспетчер может создать разовое занятие непосредственно на выбранное число, например 15 марта 2027 года, без предварительного создания периодической сетки. Каждое проведение имеет самостоятельный ID, включая полученные из шаблона. Для разового занятия внутренняя одиночная серия допустима как техническая связь модели; пользователь не обязан настраивать повторение. Дата всегда включает год и относится к выбранному учебному периоду.

Приемка: 08:00–09:30 и 09:30–11:00 не конфликтуют; 08:00–09:30 и 09:20–10:50 конфликтуют. Неоднозначная импортированная дата не появляется на календаре по предположению.

FR-029. Повторяющиеся серии — B, ИЭ + НП§

Поддержать еженедельное повторение, повторение через неделю от выбранной опорной даты и явный набор дат в пределах семестра. До сохранения показывать все создаваемые экземпляры, исключения и конфликты. Метки «четная/нечетная» вычисляются из настроек учебных недель, а не из номера ISO-недели без соглашения.

Периодическая сетка является шаблоном генерации реальных календарных проведений, а не единственным редактируемым расписанием. Разовые занятия и серии совместно отображаются в календаре и проходят одинаковые проверки. Перенос отдельного проведения не изменяет правило серии и не запускает пересоставление остальных занятий.

Приемка: правило «каждые две недели от 7 сентября» дает проверяемый список дат; изменение опорной даты обновляет предпросмотр. Система не создает экземпляры после окончания семестра и не размещает только бесконечное абстрактное правило.

FR-030. Исключения и области изменения серии — B, НП§

При редактировании серии выбирать «только это занятие», «это и последующие» либо «вся серия в выбранном диапазоне». Праздник и нерабочий день исключаются по календарю; восстановление отдельного дня выполняется явно. Индивидуально измененный экземпляр помечается исключением и не теряет изменения при последующем редактировании шаблона без подтвержденного решения.

По умолчанию выбрано «только это занятие». Повторная генерация сохраняет переносы даты, изменения формата и состава участников. Возврат к шаблону — отдельное явное действие с предпросмотром; для выделенной по FR-069 группы нужно также разрешить связанное новое проведение, чтобы не восстановить двойное участие.

Приемка: перенос одной лекции не переносит остальные. Массовое изменение показывает ранее измененные исключения и предлагает сохранить их либо включить; молчаливого сброса исключений нет.

FR-031. Состояния экземпляра — B, ИД + ИЭ + НП§

unplaced означает отсутствие активного размещения и может содержать отдельные пожелания даты/ресурсов; занятость не создает. scheduled в рабочем варианте требует участников, даты, интервала и формата; преподаватель и аудитория могут временно отсутствовать. Размещение занимает только известные ресурсы. Перед публикацией для обычного учебного занятия обязателен преподаватель, для физического проведения onsite — также аудитория; для подтверждённого дистанционного online аудитория не требуется независимо от формы обучения группы. Иные исключения допускаются только утвержденной политикой вида занятия, без произвольного обхода. cancelled сохраняет прежнее размещение для истории, причину и автора, но не занимает ресурсы. Состояние не определяется заполненностью одного поля; отсутствие комнаты не заполняет delivery_mode=online.

В форме назначения доступны явные значения «В аудитории» (onsite) и «Онлайн» (online). Формат виден текстом в календаре, карточке, API и печати. Для отдельного проведения серии его можно изменить независимо от остальных с записью исключения и повторной проверкой ресурсов. При переходе в онлайн снятие прежнего бронирования комнаты показывается в предпросмотре; сохранение физической комнаты допускается только явным выбором и продолжает занимать её. Обратный переход требует аудиторию для публикации. Реквизиты подключения остаются защищёнными по FR-045/SEC-006; интеграция с видеоплатформой не требуется.

Приемка: неназначенная запись с желаемым временем не блокирует аудиторию. Черновое размещение без преподавателя сохраняется с замечанием, занимает участвующие группы и известную аудиторию, но блокирует публикацию. Отсутствие аудитории в старой назначенной записи не объявляется доказанной ошибкой исходной системы; импорт проверяет достаточность для новой политики.

FR-032. Жесткие конфликты — B, НП§

Перед размещением, переносом, обменом и изменением участников проверять пересечения одного преподавателя, аудитории и пересекающихся групп/подгрупп, обязательные ограничения ресурса, действительность справочников и границы семестра. Жесткое пересечение внутри той же рабочей редакции блокирует сохранение и показывает оба объекта и причину. Другие рабочие черновики независимы и не блокируют сохранение. Пересечение с активной публикацией другого учебного периода показывается как замечание, блокирующее публикацию, но допускающее сохранение черновика. Перед активацией публикации выполняется повторная атомарная проверка жестких пересечений по кандидату и всем действующим публикациям других периодов.

Приемка: два диспетчера не сохраняют разные занятия одному преподавателю на один интервал в одной редакции даже при одновременной отправке. Независимый черновик другого периода не мешает сохранению. Пересечение с опубликованным занятием другого периода видно вне зависимости от фильтра, допускает сохранение черновика и блокирует его публикацию; одновременная активация конфликтующих публикаций не проходит. Закрытые примечания конфликтующего занятия не раскрываются.

FR-033. Предупреждения и обоснованные исключения — B, НП§

Различать жёсткую ошибку, препятствие публикации, мягкое предупреждение и справочное наблюдение. Нежелательный допустимый тип помещения, отклонение от явно заданного ориентира и мягкое пожелание преподавателя показываются раздельно. Принятие предупреждения возможно только если действующая версия политики разрешает исключение для этой области и роли; нужны причина, срок и конкретные затронутые занятия. Подтверждение не отключает правило для остальных записей. Неизвестная численность не считается нулём.

Для вместимости применяется отдельный порядок FR-066. Пока он не утверждён, недостаточная или неизвестная вместимость позволяет исследовать вариант в черновике, но блокирует публикацию физического занятия. После утверждения недостаточная вместимость по умолчанию является жёсткой ошибкой; иной порядок возможен только как явное решение владельца с основанием и регламентом, а не как перенос исторического нарушения. Неизвестные данные требуют проверки и не приравниваются к допустимому превышению. Обязательное оборудование, запрещённый тип и обязательный перечень FR-026 не обходятся обычным предупреждением.

Приемка: для 30 подтверждённых участников и 24 мест простой комментарий диспетчера не разрешает выпуск; при утверждённом жёстком контроле назначение отклоняется. Разрешённое мягкое предпочтение принимается с причиной, но не отключает жёсткие пересечения или обязательное оборудование.

FR-034. Недоступность и пожелания — B, ИД + НП§

Для преподавателя и аудитории создавать разовый или повторяющийся интервал недоступности с периодом действия, видом «жесткий запрет»/«пожелание» и закрытой причиной. После изменения ограничения показывать затронутые занятия; жесткое ограничение, пересекающееся с размещением, не активируется до решения конфликтов. Предложения кафедры требуют принятия диспетчером для включения в действующие ограничения.

Импортированные TCHRRSTR и ROOMRSTR первоначально имеют состояние «требует расшифровки»: отдельно подтверждаются слой Week, календарный диапазон, продолжительность и строгость. Произвольный Reason хранится текстом и не исполняется как правило. Четыре преподавательских и три аудиторных совпадения из политики являются объектами предметной проверки, а не автоматическими разрешениями или доказанными нарушениями. Неразрешённые применимые ограничения блокируют выпуск затронутых ресурсов до документированного сопоставления либо решения об их неприменимости.

Приемка: принятый жесткий запрет исключает помещение из свободных; пожелание дает предупреждение. Просмотр занятости другим подразделением сообщает факт недоступности без служебной причины.

Ручное составление и изменение расписания§

FR-035. Основной редактор — B, ИЭ + НП§

Все операции доступны через кнопки и форму карточки: дата, слот/интервал, участники, преподаватель, формат, аудитория, комментарии и область изменения серии. Форма показывает текущие значения, несохраненные изменения и результат проверки. Сохранение завершается явным подтверждением факта записи; сетка обновляется после успешного ответа.

В режиме «День» команда «Добавить занятие» сразу подставляет выбранную дату и открывает обычную форму. Создание разового проведения, назначение из списка и редактирование календарного экземпляра доступны без изменения недельного шаблона. Отдельная команда «Перенести выбранную группу» выполняет FR-069, а не скрытый перенос всего потока.

Приемка: диспетчер составляет расписание полностью клавиатурой без перетаскивания мышью. При ошибке проверки введенные значения сохраняются в форме, а основная сетка не изображает неподтвержденное назначение как сохраненное.

FR-036. Назначение из списка — B, ИЭ + НП§

При выборе неназначенного занятия открывать его учебную потребность и предлагаемые параметры. Диспетчер выбирает время и ресурсы, просматривает проверки и назначает. После сохранения экземпляр перемещается из неназначенных в календарь без создания второго экземпляра. Можно сначала подобрать аудиторию и вернуться в форму с выбранным ресурсом.

Приемка: число экземпляров не меняется при назначении; баланс перемещает объем из неназначенного в размещенный. Двойное нажатие «Назначить» не создает две записи.

FR-037. Перенос занятия — B, ИЭ + НП§

По умолчанию команда изменяет дату и время только выбранного календарного экземпляра, сохраняя его идентичность, длительность, план и участников, если не выбрано другое явное изменение. До подтверждения показывать старую и новую календарные даты с годом, затронутое проведение, область «только это занятие», конфликты и статус публикации. Причина обязательна для изменения уже опубликованного или прошедшего занятия. Другие повторения серии и самостоятельные занятия остальных групп не меняются, автоматического перемещения мешающих занятий нет. Для переноса только части участников общего проведения используется FR-069.

Приемка: перенос проведения с 15 на 17 марта 2027 года освобождает старый интервал и занимает новый в одной операции; повторения 8 и 22 марта остаются прежними. При конфликте сохраняется исходное состояние. История связывает обе позиции с одним экземпляром; повторная генерация не возвращает его на 15 марта.

FR-038. Обмен местами — B, ИЭ + НП§

Диспетчер выбирает два занятия и предварительно просматривает обмен датами и временем начала. По умолчанию каждое сохраняет свою длительность, преподавателя, аудиторию и участников; обмен аудиториями является отдельным явным флажком. Проверки вычисляются для итогового состояния сразу двух занятий. Операция выполняется целиком либо не выполняется.

Приемка: промежуточная занятость второго участника обмена не дает ложный конфликт с самим обменом. При реальном конфликте с третьим занятием обе исходные позиции остаются прежними.

FR-039. Смена аудитории — B, ИЭ + НП§

Показать свободные и подходящие помещения на полный интервал выбранного занятия с учетом текущей вместимости участников и требований плана. Смена может касаться одного экземпляра или выбранных экземпляров серии. Для нескольких дат выдача различает помещение, подходящее для всех дат, и частично подходящее.

Приемка: аудитория, занятая хотя бы 10 минут интервала, не обозначается свободной. Массовая смена не применяется частично без отдельного выбранного режима и перечня пропущенных экземпляров.

FR-040. Замена преподавателя — B, ИЭ + НП§

Команда заменяет основного преподавателя экземпляра или выбранного диапазона серии. Показывать текущую занятость кандидата, ограничения и последствия для нагрузки. Замена в расписании не меняет автоматически кафедру плана или автора его подготовки. Для опубликованных и прошедших занятий фиксировать причину.

Приемка: новый преподаватель получает занятие в своем рабочем расписании, прежний перестает быть занят этим экземпляром. Занятый или архивный кандидат не сохраняется в scheduled.

FR-041. Снять назначение и отменить проведение — B, ИЭ + НП§

Разделить две команды. «Снять назначение» переводит экземпляр в unplaced, освобождает ресурсы и возвращает объем в очередь планирования; прежние значения остаются в истории. «Отменить проведение» переводит в cancelled, сохраняет карточку с причиной и не создает автоматически замену. «Восстановить» заново проходит обычные проверки; физического удаления использованного занятия нет.

Приемка: после снятия экземпляр есть в неназначенных; после отмены — в отмененных, но не в обычной очереди. Восстановление на уже занятый интервал отклоняется.

FR-042. Закрепление — новое правило для Stable — B, ИД + ИЭ + НП§

В новом продукте «Закреплено» означает защиту от изменения времени, преподавателя, аудитории, участников, формата и состояния без предварительного снятия закрепления диспетчером с причиной. Закрепление позиции плана распространяется на выбранные связанные экземпляры через явный предпросмотр. Оно не означает опубликованность или факт проведения. Старый Stable до согласования хранится как исходный признак и не включает эту блокировку автоматически.

Приемка: закрепленный экземпляр нельзя перенести ни из формы, ни массовым API. После снятия закрепления с причиной перенос разрешен при отсутствии других конфликтов; оба действия видны в истории.

FR-043. История и восстановление — B, НП§

Для предметных изменений сохранять автора, время, причину, предыдущие и новые значения, затронутые экземпляры и ссылку на общую операцию. Карточка показывает историю. Восстановление прежнего значения является новой операцией с проверкой текущих прав и конфликтов; история не переписывается. Изменения защищенных заметок не отображаются в обычном журнале читателя.

Приемка: видны назначение, перенос и отмена в правильной последовательности. Попытка вернуть прежнюю аудиторию, уже занятую другим занятием, отклоняется, сохраняя историю попытки согласно политике аудита.

FR-044. Одновременная и массовая работа — B, НП§

Форма сохраняется только относительно версии записи, которую пользователь открыл. Если запись изменил коллега, показывать различия и предлагать перечитать/повторить операцию; молчаливое сохранение поверх запрещено. Массовое действие сначала показывает состав и результат проверки, затем по умолчанию выполняется целиком. Альтернативное частичное применение допускается только после явного выбора с протоколом успешных и отклоненных строк.

Приемка: две открытые формы не теряют первое сохранение. Устаревший предварительный просмотр массовой операции перепроверяется при подтверждении; возникший конфликт не приводит к частично скрытому результату.

FR-045. Публичные комментарии и закрытые заметки — B, ИД + ИЭ + НП§

В карточке разделить публичный комментарий расписания и закрытую служебную заметку. Причины ограничений, заметки преподавателей/аудиторий и импортированные свободные тексты по умолчанию закрыты. Участник с правом заметок видит все исходные поля в защищенном просмотре; перенос текста в публичный комментарий выполняется явным отдельным действием. HTML и код из текста не исполняются.

Приемка: закрытый текст отсутствует в публичной версии, печати, подсказках и сетевых ответах читателя. Вставка HTML-разметки выводится безопасным текстом; изменение публичности записывается в историю.

Просмотры и поиск§

FR-046. Общее расписание — B, ИЭ + НП§

Предусмотреть режимы «День», «Неделя» и «Список» с фильтрами по периоду, факультету, кафедре, курсу, группе, преподавателю, аудитории, дисциплине, виду, формату проведения и состоянию. В режиме «День» доступны выбор даты с годом, предыдущий/следующий календарный день и переход к сегодняшней дате в часовом поясе периода. Пустой день явно показывает отсутствие занятий; выходной не пропускается автоматически. За границей выбранного периода показывать пояснение и запрет создания до выбора подходящего периода. Все режимы читают одни и те же календарные экземпляры, а не независимо вычисляют сетку по шаблону. Ячейка показывает дату/время, сокращение дисциплины, вид, преподавателя, текстовый формат «В аудитории»/«Онлайн», аудиторию при её наличии и обозначение участников. Цвет дополнен текстом/значком, чтобы смысл не зависел только от цвета. Детали доступны нажатием и клавиатурой.

Приемка: общее занятие видно во всех выбранных группах, но карточка указывает единый экземпляр. Переключение в список сохраняет фильтры; конфликтный или неназначенный объект не маскируется цветом без подписи.

FR-047. Расписания группы, преподавателя и аудитории — B, ИЭ + НП§

Из карточки занятия открывать три ресурсных представления с сохранением выбранной даты и режима «День»/«Неделя»/«Список». Группа видит занятия всей группы и своих подгрупп с обозначением состава; преподаватель — личные занятия и доступную ему недоступность; аудитория — занятые интервалы и ограничения без закрытых причин для неуполномоченных. Доступен также фильтр диапазона дат. Онлайн-проведения без комнаты видны у группы и преподавателя, но не создают фиктивной занятости аудитории. Переход между режимами сохраняет фильтры; выбранное число определяет отображаемую неделю.

Приемка: групповое представление включает общий поток, даже если у исходной записи нет прямого GroupNo. Занятие с двумя подгруппами этой группы не появляется дважды как отдельное проведение.

FR-048. Поиск свободной аудитории — B, ИЭ + НП§

Поиск принимает конкретную дату или набор дат, интервал/слот, вместимость, назначение, корпус и при необходимости кафедру. На полный интервал отдельно проверяются занятость в своей рабочей редакции, жесткая недоступность и пересечения с активными публикациями других учебных периодов; другие независимые черновики не считаются занятостью этой редакции. Выдача явно различает «свободна в рабочей редакции», «пересекается с действующей публикацией другого периода», «подходит требованиям» и предупреждения. Пересечение с чужой действующей публикацией допускает предварительное назначение в черновике с блокирующим публикацию замечанием по FR-032. Показ результата не резервирует помещение.

Приемка: подходящая по размеру, но занятая в своей редакции аудитория не входит в свободные для этой редакции. Аудитория с пересечением только в активной публикации другого периода имеет отдельную блокирующую публикацию пометку и не обозначается безусловно свободной. Если между поиском и назначением помещение занял коллега в этой же редакции, назначение отклоняется; перед активацией выпуска глобальная проверка активных публикаций повторяется атомарно.

FR-049. Очередь неназначенных — B, ИЭ + НП§

Вывести отдельный список unplaced с фильтрами по подразделению, группе, дисциплине, виду, ответственному и причине отсутствия назначения. Показывать недостающие реквизиты, желательные параметры и общий объем. Исключенные при импорте неоднозначные строки имеют отдельную очередь диагностики; они не смешиваются с корректной учебной потребностью без метки.

Приемка: снятое назначение сразу появляется в очереди, отмененное проведение не появляется. Счетчик списка совпадает с числом экземпляров по фильтру; ошибка импорта не превращается в автоматически готовое к размещению занятие.

FR-050. Защищенный просмотр данных — B, НП§

Предоставить технический раздел чтения: каталог разрешенных сущностей/импортных таблиц, описание полей, количество строк, поиск, фильтры, сортировку, страницы и карточку строки со ссылками на связанные объекты. Показывать все предметные исходные поля пользователю с соответствующим правом, различая NULL, пустую строку, ноль, ложь и старый -1. Секреты аутентификации и технические служебные таблицы не входят в этот каталог.

Приемка: можно открыть пустую таблицу, найти текст кириллицей и увидеть исходные DayNo/флаги без выдуманных дат. Раздел не содержит SQL-консоли, команд записи или незащищенной ссылки на весь файл базы.

Согласование и публикация§

FR-051. Передача на кафедру — новое правило — B, ИЭ + НП§

Команда создает заявку кафедре по позиции плана или набору экземпляров: причина, требуемое действие, ответственный и срок при необходимости. Состояния заявки: «открыта», «предложение подготовлено», «принята», «возвращена», «закрыта без изменения». Кафедра предлагает преподавателя, условия или исправление потребности; диспетчер принимает изменения с обычными проверками. Передача сама по себе не снимает назначение и не освобождает ресурс.

Приемка: после передачи существующее занятие остается в расписании; ответ кафедры не меняет его до принятия. Сотрудник другой кафедры не отвечает на заявку путем прямого обращения к ее идентификатору.

FR-052. Рабочий вариант и подготовка выпуска — B, НП§

Для семестра в базовой версии используется один действующий рабочий вариант. Перед выпуском формируется кандидат версии с зафиксированным составом и отчетом проверки: конфликты, неназначенный объем, неполные данные, предупреждения и изменения относительно предыдущей публикации. Неназначенные занятия не выдаются за опубликованные; отчет об остатке обязателен для утверждающего.

Кандидат также фиксирует версию и хеш политики, классификацию участников, временные профили, матрицу помещений, решения о вместимости и применимости ограничений, принятые исключения и раздельный отчёт качества FR-063. Наблюдаемый процент компактных дней не служит порогом выпуска без отдельного утверждённого требования. Смена правил или параметров после проверки делает кандидата устаревшим.

Приемка: исправление в рабочем варианте не меняет предыдущую публикацию. Кандидат с жестким конфликтом или отсутствующими обязательными ресурсами размещенного занятия не утверждается. Выпуск с согласованным остатком неназначенного объема допускается с явным решением и комментарием утверждающего; этот остаток не публикуется как полноценное расписание.

FR-053. Утверждение и неизменяемая публикация — B, НП§

Публикатор утверждает конкретного кандидата и выпускает версию с номером, временем, автором, диапазоном дат и примечанием. Читатели получают целиком одну версию; переключение активной версии выполняется атомарно. Последующая правка требует нового выпуска. Предыдущую версию можно повторно сделать активной отдельной операцией с причиной, сохранив историю и предупреждение о возврате.

Для публикации точечного переноса допустим новый снимок всего расписания, но его подготовка не пересоставляет сетку и не меняет остальные проведения. В сравнении выпусков видны только фактические изменения; при FR-069 старая дата сохраняется у оставшихся групп, новая появляется только у перенесённой группы.

Приемка: одновременное чтение во время выпуска не смешивает старые и новые занятия. Измененный после проверки рабочий вариант не публикуется под прежним неподтвержденным кандидатом; требуется новая проверка.

FR-054. Доступ читателей и отмены в выпуске — B, НП§

По умолчанию просмотр требует авторизации; публичное чтение включается отдельно для выбранного семестра/версии. В публикацию входят только безопасные поля расписания. Отмены и переносы после предыдущего выпуска видны как изменения; нерасписанная потребность, заявки кафедр и внутренние причины не выдаются читателям. В заголовке присутствуют версия и время публикации.

Приемка: после новой публикации перенесенное занятие отображается в новой позиции с доступным указанием изменения. Публичный URL рабочего варианта не открывает черновик; отключение публичного режима закрывает и API той же версии.

Обмен, вывод и справка§

FR-055. CSV-выгрузка — B, НП§

Выгружать текущую разрешенную выборку справочника, плана или расписания в CSV с понятными заголовками, UTF-8, указанием версии/семестра и единиц измерения. Экспорт сохраняет фильтры и использует безопасную обработку значений, которые табличные редакторы могут интерпретировать как формулы. В базовую поставку не входит воспроизведение неизвестного старого формата обмена.

Приемка: кириллица читается в согласованном табличном редакторе; количество строк совпадает с отбором. Закрытые столбцы не добавляются в файл пользователя без соответствующего права, даже если скрыты лишь в текущем представлении.

FR-056. Управляемый импорт — B, ИД + НП§

Интерфейс импорта принимает подготовленный пакет миграции и согласованные CSV-шаблоны справочников/планов. До записи показываются сопоставление столбцов, новые/измененные строки, ошибки ссылок, неоднозначные значения и итоговые количества. Пользователь подтверждает конкретный предварительный результат; исходный файл и протокол доступны уполномоченному для сверки. Повторный импорт того же пакета не создает дубликаты.

Приемка: строки с неизвестным видом занятия, неясной единицей часов или нерасшифрованным DayNo остаются в диагностике. Импорт не выбирает дату из имени каталога и не публикует данные автоматически.

FR-057. Печать и сохранение PDF браузером — B, НП§

Предоставить печатное представление дня, списка и недельной сетки группы, преподавателя или аудитории. Включать заголовок, конкретную дату/диапазон с годом, часовой пояс, номер версии, текстовый формат проведения, обозначения отмен и дату формирования. Не включать панели редактирования, закрытые заметки и реквизиты подключения. Базовый механизм — печать браузера, включая пользовательское сохранение в PDF; отдельный серверный генератор сложных форм не обязателен.

Приемка: согласованные недельные примеры печатаются на A4 без обрезанных строк, с повторяемыми заголовками таблицы. Печать черновика содержит заметную пометку, исключающую смешение с утвержденным выпуском.

FR-058. Встроенная справка и объяснение ошибок — B, ИЭ + НП§

Предоставить краткое руководство по пути «справочники → план → неназначенные → назначение → проверка → публикация». Для статусов, закрепления, потоков, единиц нагрузки и областей изменения серии дать контекстные пояснения. Ошибка сообщает, что не выполнено и какие объекты мешают, без технической трассировки. Раздел «О системе» показывает версию приложения и ссылку на руководство.

Приемка: новый диспетчер по руководству размещает тестовую лекцию и передает ее к выпуску. Сообщение о конфликте открывает доступную карточку/интервал, а ошибка сервера не показывает пароль, SQL или закрытые данные.

FR-059. Перетаскивание в сетке — E, НП§

Дополнительный способ переносить или назначать занятия мышью/касанием. Перетаскивание использует те же права, выбор области серии, проверки, историю и подтверждение, что форма FR-035. Визуальный предварительный перенос не становится сохраненным до успешного ответа. Обязательная базовая поставка выполняет эти операции формами без этого механизма.

Приемка расширения: перенос закрепленного или конфликтующего занятия возвращает карточку в исходную позицию с объяснением. Все действия остаются доступны клавиатурой; особого обхода проверок через перетаскивание нет.

FR-060. Помощник автоматического размещения — E, НП§

Возможное расширение формирует предложения размещения неназначенных занятий для выбранного контура с объяснением непримененных ограничений и невозможных случаев. Предложение сохраняется отдельно и принимается диспетчером после просмотра; не меняет опубликованное расписание и не снимает закрепления. Конкретный оптимизатор, целевая функция и гарантии качества определяются отдельным ТЗ после проверки ручного процесса.

Оптимизатор обязан использовать ту же версию политики и службу проверки, что ручные операции FR-064. Все жёсткие условия проверяются до оценки качества; уменьшение окон не компенсирует их нарушение. Веса и порядок мягких критериев задаются и утверждаются явно, проверяются на допустимых альтернативных вариантах. Коэффициенты нельзя объявлять восстановленными из одного готового расписания или его условных перестановок; сравнение показывает изменение каждого показателя и полноту нагрузки отдельно. FR-061–FR-068 обязательны для ручного редактора и не делают FR-060 частью B.

Приемка расширения: задаче без допустимого размещения соответствует отчет о препятствиях, а не расписание с нарушением жестких запретов. Принятие предложения повторяет актуальные проверки; изменения коллег после расчета не перезаписываются.

Реализация политики и оценка качества§

FR-061. Реестр и версии правил — B, АП + НП§

Предоставить раздел «Политика составления расписания» с каталогом правил, поиском по коду и области, карточкой, историей и сравнением версий. Карточка содержит устойчивый код, формулировку, тип проверяемого условия, параметры, область действия, даты, строгость, порядок приоритетов, допустимость исключений и роли. Отдельно хранить вид основания (owner_clarification/snapshot_observation/approved_regulation/product_decision), ссылку/хеш источника, степень поддержки и статус согласования (draft/in_review/approved/retired). Высокая статистическая поддержка не переводит правило в approved.

Диспетчер готовит изменения; уполномоченный публикатор с policy.approve утверждает конкретную версию. Версии неизменяемы после утверждения; изменение создаёт новую. Привязка версии к черновику выполняется с предпросмотром затронутых занятий и повторной проверкой. Наблюдения можно сравнивать в исследовательском режиме; они не блокируют рабочие операции до утверждения. Общие гарантии отсутствия двойного бронирования, прав доступа и целостности из ТЗ не отключаются настройкой политики.

Приёмка: изменение предпочтения на жёсткий запрет требует новой версии и полномочия; старый выпуск сохраняет прежние правила. Кафедральный пользователь не активирует собственное предложение напрямую через API.

FR-062. Временные профили обучения — B, АП + УВ + НП§

Настраивать профили по форме, уровню, курсу при подтверждённом значении, дню недели, периоду и формату проведения. Профиль различает разрешённые, предпочтительные и исключительные интервалы, с привязкой к конкретной версии сетки звонков. Суббота настраивается отдельно от будней. Начальные предложения из политики загружаются как черновики; для заочной сессии без достаточных данных обязательны явные параметры заказчика. Неизвестная классификация не получает произвольно выбранный дневной или вечерний профиль.

Для совместного проведения проверять условия всех участников. Обязательные интервалы пересекаются; несовместимое пересечение объясняется по каждой группе. Явный приоритет разрешает выбор между перекрывающимися альтернативными профилями одной категории; при равном приоритете и несовместимых параметрах требуется решение. Жёсткие ограничения ресурсов и других участников приоритетом профиля не отменяются. Мягкие предпочтения сохраняются отдельными слагаемыми отчёта.

Приёмка: в утверждённом тестовом вечернем профиле 7–8 предпочтительны, 6 допустима с согласованным исключением, раньше 6 запрещено. Шестая пара требует разрешённого исключения, пятая отклоняется; суббота проверяется по своему профилю. Такой результат является тестом заданной конфигурации, а не утверждением найденного исторического запрета.

FR-063. Отчёт качества и полноты — B, АП + НП§

Показывать раздельные показатели из раздела «Показатели качества»: окна групп, подтверждённых подгрупп и преподавателей; предпочтительные интервалы; соседство одного предмета; порядок видов; смены помещений/корпусов; полноту назначения и качество исходных данных. Фильтры: период/диапазон, форма, уровень, онлайн-признак, билингвальность, группа, преподаватель, кафедра. Для каждого числа доступны единица наблюдения, числитель, знаменатель, исключённые/неизвестные значения и переход к разрешённым исходным объектам. Малый охват выделяется числом наблюдений; оценка сотрудника по фамилии или должности не строится.

Вычисление привязано к снимку редакции, версии правил, классификации и алгоритма метрик. Большой расчёт выполняется фоновой задачей с состоянием и отметкой актуальности. Именные профили, причины ограничений и исходные свободные поля доступны только по предметным правам; публичная выдача отчётов не включается автоматически.

Приёмка: три строки одного подтверждённого совместного проведения дают одну занятую клетку преподавателя и отдельное участие каждой группы; 0 подходящих дней выводится как «нет данных», а не 100% компактности. Отменённые и неназначенные события не улучшают показатель занятости за счёт фиктивных часов.

FR-064. Объяснение последствий ручного изменения — B, АП + НП§

Назначение, перенос, обмен, замена помещения и изменение участников используют общую серверную проверку. Предпросмотр показывает жёсткие препятствия, препятствия публикации, предупреждения, непроверенные условия и изменение каждого затронутого показателя качества «до → после». Пользователь может сравнить два вручную выбранных варианта без сохранения второго рабочего черновика. Сервер возвращает код правила, версию, объекты, параметры расчёта и допустимое действие; причины вне прав скрываются. Предпросмотр сам по себе не бронирует ресурсы.

Приёмка: вариант без окон с конфликтом преподавателя не объявляется лучшим допустимым. При переносе, убирающем окно группы и создающем окно преподавателя, видны оба изменения без скрытого приоритета одного над другим. Устаревшие данные или версия правил требуют пересчёта при подтверждении.

FR-065. Совместное проведение нескольких потребностей — B, АП + НП§

Для новых данных предусмотреть создание одного проведения со связями с несколькими компонентами планов. Для импорта — отдельную очередь кандидатов совместности: исходные ClassNo, PlanNo, SubjectNo, полный предмет, вид, блок/слой или подтверждённые даты, преподаватель, помещение и все участники рядом. Кандидат не является готовым объединением. Диспетчер подтверждает или отклоняет его с причиной; неизвестный ресурс не доказывает равенство ресурсов. Разные ID предмета допускают совместность только после явного подтверждения содержательного соответствия; справочные предметы при этом не сливаются.

Подтверждённое проведение имеет один согласованный интервал, вид, формат и основной набор ресурсов. Связи с потребностями задают фактических участников и учётный объём; система проверяет непротиворечивость и отсутствие повторного зачёта одной потребности. Бронирование преподавателя/комнаты создаётся один раз. Все исходные строки сохраняются, доступны их связи с новым объектом; объединение и разъединение выполняются с предпросмотром, аудитом и повторной проверкой. Разъединение не может оставить два самостоятельных конфликтующих проведения как нормальное размещение.

Приёмка: две исходные строки разных планов подтверждаются как одно событие без потери обоих источников и связей нагрузки. Другой предмет, интервал или известная комната создаёт несовместимость для объединения; простое совпадение координат не снимает конфликт автоматически.

FR-066. Помещения, вместимость и переходы — B, АП + НП§

Вести утверждаемую матрицу «вид/условия занятия → допустимый тип помещения и оборудование», с предпочтительными альтернативами и явными запретами. Неопределённое соответствие выводится как требующее проверки. Физический формат требует подходящей комнаты; онлайн-формат не требует физической комнаты, но сохраняет занятость преподавателя и участников. Билингвальность сама по себе не означает обязательный лингафонный кабинет: такое требование задаётся компоненту явно.

Численность рассчитывать по объединению уникальных участников проведения, без повторного суммирования группы и её подгрупп. При неизвестном составе показывать неизвестность либо явно подтверждённую верхнюю оценку. Для численности и вместимости хранить дату, источник и статус проверки. Рабочий порядок FR-033 требует отдельного решения о строгости, устаревании данных и допустимых исключениях до выпуска физического расписания. Превышения из старого снимка не переносят разрешение в новый продукт.

Корпус хранится явной ссылкой, префикс старого номера — только гипотеза для сопоставления. Смена комнаты/корпуса является мягким критерием. Проверку достаточности времени перехода активировать только при утверждённой матрице направленных переходов в минутах и известных окончаниях занятий; без них показывать «переход не проверен», не ноль минут и не вымышленный конфликт. В B входят ручной ввод матрицы и проверка, географический маршрутизатор не требуется.

Приёмка: общий урок не удваивает численность из-за повторной связи одной группы. Онлайн-группа очной формы может заниматься без комнаты; физическое занятие заочной группы требует её. При подтверждённом переходе 20 минут и перерыве 10 срабатывает заданная строгость; при неизвестном корпусе время не угадывается.

FR-067. Проверяемая миграция аналитических правил — B, АП + НП§

Пакет импорта должен включать версию расшифровки групп, исходные координаты, статус разрешения календаря, кандидатов совместности, сопоставление ограничений и контроль полноты. Показывать отдельно строки источника, уникальные участия, модельные занятые клетки и подтверждённые реальные проведения. Аналитическая координата (q, слой, день, слот) не превращается в дату. Смена правил преобразования создаёт новый предварительный результат, сравнимый с прежним, без потери ручных решений.

Приёмка: на контрольном снимке воспроизводятся счётчики AP-01–AP-04; 288 неназначенных строк с координатами не бронируют ресурсы. Неразрешённые исходные данные сохраняются и доступны, но не получают фиктивного календаря или автоматической совместности.

FR-068. Готовность политики к выпуску — B, АП + НП§

До выпуска система проверяет утверждённость применимой политики, календаря, длительностей, классификации участников, требований ресурсов и необходимых решений DEC. Для каждого неподтверждённого условия видны затронутые объекты и ответственная роль. Уполномоченный может утвердить конкретное правило, подтвердить его неприменимость с основанием либо исключить непроверенные записи из области выпуска с явным остатком; кнопка «игнорировать всё» отсутствует. Новое расписание на подтверждённых датах может выпускаться независимо от неразрешённого архивного импорта, если тот явно не относится к выпускаемой области.

Приёмка: неподтверждённая применимая вместимость или календарная расшифровка не исчезает после общего комментария к выпуску. Смена политики между проверкой и активацией отклоняет устаревший кандидат. Утверждённый выпуск хранит неизменяемый протокол правил, исключений и качества вместе со снимком.

FR-069. Перенос выбранной группы из общего проведения — B, УВ + НП§

Диспетчер выбирает конкретное календарное проведение, одну или несколько участвующих групп и новую дату/время. Выбор группы включает все её части, участвующие именно в этом проведении; он не добавляет отсутствующих участников. По умолчанию из карточки группы выбрана только она; перед подтверждением состав показан явно. Операция действует только на выбранное проведение, не на будущие повторения серии. Для неизвестного или противоречивого состава требуется сначала его уточнить; пустой набор и посторонние группы отклоняются.

Если выбрана часть участников, исходное проведение сохраняет свой ID, дату и оставшиеся группы. Для выбранных участников создаётся отдельное разовое проведение с новым ID и связью с исходным. По умолчанию сохраняются преподаватель, длительность, дисциплина, вид, формат и аудитория; ресурсы на новой дате проходят обычную проверку, их явная замена показывается в том же предпросмотре. Если выбраны все участники, выполняется обычный перенос FR-037 с прежним ID, без пустого исходного проведения. При выборе прежнего интервала и неизменных ресурсов возвращается результат «изменений нет» без искусственного разъединения.

Предпросмотр показывает старую и новую даты, оба состава, связанные потребности и изменение преподавательской нагрузки. Учебный объём выбранной группы переносится между проведениями и не начисляется повторно; у оставшихся групп он сохраняется. Если один преподаватель вместо общей двухчасовой лекции проводит две раздельные, его объём составляет четыре часа вместо двух — это явно видно до сохранения и проверяется по действующей политике нагрузки.

Применение выполняется одной транзакцией: составы, связи зачёта нагрузки, исключение исходной серии, новое проведение, бронирования и аудит. Конфликт ресурса, закрепление без снятия, недостаточные права или устаревшая версия откатывают всё действие; другие занятия не сдвигаются автоматически. Повторная генерация сохраняет оставшийся состав на исходной дате и не возвращает туда перенесённую группу. Опубликованный снимок меняется только новым выпуском по FR-053.

Приёмка: общая лекция групп А и Б 15 марта 2027 года после переноса А на 17 марта остаётся 15 марта только у Б. Повторения 8 и 22 марта не меняются. У каждой группы один зачёт соответствующего объёма, преподаватель занят на обеих датах; повтор команды не создаёт третьего проведения. При конфликте на 17 марта обе группы остаются вместе 15 марта.

Сквозные сценарии обязательной приемки§

  1. Общая лекция. Диспетчер создает позицию плана для двух групп, задает 18 академических часов, получает девять неназначенных двухчасовых экземпляров, формирует календарную серию, выбирает преподавателя и аудиторию. Каждая группа видит девять занятий; нагрузка преподавателя равна 18 часам, не 36. Попытка одновременно поставить другой предмет всей первой группе блокируется.
  2. Деление на подгруппы. Для одной группы создаются две практики по подгруппам в одно время с разными преподавателями/помещениями. Они разрешаются; размещение общей лекции группы в тот же интервал запрещается. Неизвестная численность одной подгруппы вызывает отдельное предупреждение при подборе помещения.
  3. Перенос опубликованного занятия. Диспетчер переносит один экземпляр серии и указывает причину. Активная публикация остается прежней. Публикатор видит различия, утверждает новый кандидат; после выпуска читатель получает новую версию целиком и видит изменение.
  4. Отмена и восстановление. Отмена освобождает ресурсы, сохраняет причину и показывает дефицит плана. Другой диспетчер занимает интервал. Восстановление отмененного занятия на прежнее место блокируется, пока не выбрано допустимое новое размещение.
  5. Кафедральная заявка. Диспетчер передает запрос о замене преподавателя. Сотрудник нужной кафедры предлагает кандидата, сотрудник другой кафедры не может изменить заявку. После принятия меняется преподаватель; до принятия расписание и занятость остаются прежними.
  6. Параллельная работа. Два диспетчера открывают один экземпляр. Первый сохраняет перенос, второй пытается сменить аудиторию по старой версии. Система сообщает об изменении коллегой и не теряет перенос; повторное сохранение после перечитывания проходит новые проверки.
  7. Неоднозначный импорт. Загружается набор со старым кодом дня, неполной ссылкой на факультет, отрицательным служебным ключом и закрытыми текстовыми полями. Подтвержденные справочники проходят проверку; неоднозначные строки доступны в защищенной диагностике, на календарь и в публикацию не попадают. Исходные значения сохранены для сверки.
  8. Безопасная публикация. В карточке существуют публичный комментарий и закрытая заметка. Публикатор выпускает расписание; читатель и неавторизованный пользователь при включенном публичном режиме получают только публичный комментарий. Закрытая заметка отсутствует также в API, CSV, печати и старых значениях истории, доступных читателю.

Решения для обсуждения владельцем продукта§

Эти вопросы не отменяют определенные выше исходные правила и предназначены для следующей редакции ТЗ: подтвердить длительность академического часа и единицы старого PlanQty; точное соответствие буквенных видов; календарную расшифровку старых занятий; возможность одновременного участия студента в нескольких схемах подгрупп; потребность в комиссиях/нескольких помещениях; обязательность двух разных людей для редактирования и публикации; отдельные роли преподавателя/студента; кампусы и время перехода между корпусами. По умолчанию применяется описанная базовая модель, а неподтвержденные исторические значения остаются в диагностике.

Модель данных PostgreSQL§

Принципы и границы модели§

DATA-01. Рабочая база нового приложения — PostgreSQL. Файлы Paradox и schedule.sqlite служат источниками миграции и контрольными снимками. Новые действия пользователя не изменяют исходные файлы. SQLite не становится второй рабочей базой: параллельная запись в две системы не входит в базовый объем.

DATA-02. Основной объект планирования — учебный период организации: семестр, экзаменационная сессия либо другой явно заданный диапазон дат. Общие справочники имеют устойчивые идентификаторы; планы, состав участников, серии, экземпляры занятий и правила ограничений принадлежат конкретной редакции расписания периода. Ссылка из занятия на план другой редакции запрещена составным внешним ключом. Проверять это только на уровне формы недостаточно.

DATA-03. Для бизнес-сущностей использовать uuid как PK; исходные числовые ключи хранить отдельно в реестре происхождения. Для записей аудита и технических журналов допустим bigint GENERATED ... AS IDENTITY. Совпадение названия дисциплины, кафедры, группы или ФИО не является основанием для объединения объектов. Все технические даты создания и изменения — timestamptz; текст — UTF-8. Денежные величины не требуются; объем нагрузки хранится точным numeric, а не float.

Общие поля изменяемой сущности: id, organization_id, created_at, updated_at, created_by_id, updated_by_id, row_version bigint NOT NULL DEFAULT 1. У архивируемых справочников дополнительно archived_at; у сущностей редакции — revision_id и logical_id, сохраняющий идентичность объекта при создании следующей редакции. Уникальность (revision_id, logical_id) обязательна. Значения row_version изменяются сервером.

DATA-04. Удаление используемого справочника запрещено через ON DELETE RESTRICT; пользователь архивирует запись. Она исчезает из списков нового выбора, но сохраняется в существующих планах и истории. Физическое каскадное удаление допустимо только для технических дочерних строк непубличного временного набора, например бронирований внутри полностью откатываемой транзакции. Публикации и завершенные журналы импорта не удаляются обычными операциями интерфейса.

Справочники и учебная структура§

Упрощенная карта основных связей; таблицы участников, аудита и бронирований раскрыты ниже. Связь компонента с серией показывает основной источник генерации; дополнительные компоненты совместного проведения связываются через series_component и occurrence_requirement, описанные в разделе «Сущности политики и совместного проведения». Диаграмма не ограничивает проведение одним планом.

Сокращённая модель данных
Сокращённая модель данныхВсе 13 связей исходной ER-схемы. Стрелка идёт от одной родительской записи к нулю или нескольким дочерним; полный исходный код доступен под схемой. containsversionscontainsrequiresincludesparticipatesgeneratesexpandsattendsparticipatesreservesoccupiedfrozen_sourceorganizationОрганизацияacademic_periodУчебный периодschedule_revisionРедакция расписанияcurriculum_planУчебная потребностьplan_componentВид и объём нагрузкиlesson_seriesСерия занятийlesson_occurrenceЭкземпляр занятияresource_bookingЗанятость ресурсаcomponent_participantУчастник вида нагрузкиacademic_groupУчебная группаoccurrence_participantУчастник занятияschedule_publicationПубликация расписанияschedulable_resourceРесурс расписания

Все связи: одна родительская запись → 0…n дочерних. Названия отношений сохранены из исходной схемы. На узком экране схему можно прокручивать по горизонтали.

Исходный код схемы
erDiagram
    organization ||--o{ academic_period : contains
    academic_period ||--o{ schedule_revision : versions
    schedule_revision ||--o{ curriculum_plan : contains
    curriculum_plan ||--o{ plan_component : requires
    plan_component ||--o{ component_participant : includes
    academic_group ||--o{ component_participant : participates
    plan_component ||--o{ lesson_series : generates
    lesson_series ||--o{ lesson_occurrence : expands
    lesson_occurrence ||--o{ occurrence_participant : attends
    academic_group ||--o{ occurrence_participant : participates
    lesson_occurrence ||--o{ resource_booking : reserves
    schedulable_resource ||--o{ resource_booking : occupied
    schedule_revision ||--o{ schedule_publication : frozen_source

Названия таблиц ниже являются целевой логической схемой. Допускается другое физическое именование при сохранении полей, связей и проверок. ? обозначает разрешенный NULL; поля связи без ? обязательны.

Таблица Ключевые поля и типы Обязательные связи и ограничения
organization id uuid, name text, default_timezone text Часовой пояс — идентификатор IANA; для текущей организации первоначально Asia/Novosibirsk
academic_period id, organization_id, name text, starts_on date, ends_on date, timezone text, week_anchor date, first_week_kind text, active_publication_id uuid? starts_on <= ends_on; период и правила отсчета задаются пользователем; имя папки не задает календарь
faculty id, organization_id, name text, short_name text? Организация 1:N факультетов; название не уникальный ключ
chair id, faculty_id uuid?, name text, short_name text? Факультет 1:N кафедр; отсутствие факультета допустимо и явно отображается
teacher id, chair_id uuid?, full_name text, degree text?, position text?, title text?, private_note text? Кафедра 1:N преподавателей; ФИО не уникально; заметка доступна по отдельному праву
subject id, name text, short_name text?, legacy_character text? Сохранять полное и сокращенное названия раздельно; неизвестный смысл исходного SubjectChar не заменять новым правилом
course_category id, name text, sort_order integer, study_year smallint?, education_level text? study_year > 0 при заполнении; числовой исходный ключ и CourseCount не переносить в год обучения без подтверждения
academic_group id, faculty_id, course_category_id, name text, student_count integer? Численность >= 0, неизвестная численность — NULL; одинаковые отображаемые названия разных сущностей допустимы
group_study_profile id, revision_id, group_id, study_form, education_level, is_online boolean?, is_bilingual boolean?, classification_status, source_rule_id, verified_by_id? Один эффективный профиль группы в редакции; неизвестность не заменяется false; классификация независима от времени назначений и фиксируется в публикации
group_partition id, revision_id, group_id, name text, verification_status text В базовой версии одна действующая схема непересекающихся подгрупп группы в редакции; статусы unverified/confirmed
subgroup id, partition_id, ordinal smallint, name text?, student_count integer? Уникальность (partition_id, ordinal), положительный номер; подгруппа принадлежит ровно одной группе через схему
named_cohort id, name text, private_note text? Именованное административное объединение; само по себе не задает участников занятия
cohort_group revision_id, cohort_id, group_id M:N; уникальная тройка; создается только при существующей или явно введенной связи
building id, name text, address text?, timezone text? Новый нормализованный справочник для кабинетов; неизвестный корпус не угадывать из номера аудитории
room_type id, code text, name text, description text? Отдельный классификатор, не объединяемый с видами занятий
room id, building_id uuid?, chair_id uuid?, name text, capacity integer?, room_type_id uuid?, private_note text? Вместимость >= 0; неизвестная вместимость — NULL; полный идентификатор комнаты не зависит от имени
equipment_feature, room_feature Признак id/code/name; связь room_id/feature_id M:N, уникальная пара; исходный RoomSpec остается сырым значением до расшифровки
lesson_type id, code text, name text, description text? Кириллический исходный код хранится отдельно; подтверждение названий обязательно перед бизнес-расчетами
bell_schedule, bell_slot Сетка: id/name; слот: id/schedule_id/ordinal/start_time time/end_time time Уникальная позиция внутри сетки; начало меньше окончания; конец задается явно, не вычисляется разностью соседних начал
period_calendar_day period_id, date, kind text, teaching_week_number integer?, week_kind text?, comment text? Уникальность (period_id,date); учебный, выходной, праздничный или исключенный день; правила переноса задаются явно

Составы подгрупп и административных объединений фиксируются для редакции. Изменение общей численности либо переименование справочника не должно менять уже опубликованное представление: при публикации сохраняется снимок используемых названий, численности и параметров. Ссылки UUID остаются доступны для перехода к текущей карточке, а экран опубликованной версии использует ее исторические значения.

План, занятия, редакции и публикации§

Таблица Ключевые поля и типы Обязательные связи и ограничения
schedule_revision id, period_id, number integer, state text, based_on_id uuid?, catalog_snapshot jsonb? Состояния draft/frozen; один изменяемый draft на период, обеспеченный частичным уникальным индексом; замороженная редакция неизменяема
curriculum_plan id, revision_id, logical_id, subject_id, chair_id, comment text? Редакция 1:N планов; исходный Stable не трактуется как блокировка; проверенное новое закрепление хранить отдельно
plan_component id, revision_id, plan_id, lesson_type_id, planned_quantity numeric(10,2)?, quantity_unit text?, split_policy text, participant_mode text Уникальность (revision_id,plan_id,lesson_type_id); объем >= 0; единица — явный код academic_hour/clock_minute/session/unknown
plan_participant id, revision_id, plan_id, group_id, subgroup_id uuid? M:N между планами и группами/подгруппами; не более одной одинаковой связи с учетом NULL; подгруппа обязана принадлежать выбранной группе
component_participant id, revision_id, component_id, group_id, subgroup_id uuid? Состав по конкретному виду работы; participant_mode=inherit использует состав плана, override использует полный явно заданный набор компонента; те же проверки группы/подгруппы и уникальности
plan_room_preference revision_id, component_id, room_id, preference text M:N; уникальная пара компонента и комнаты; предпочтение не означает фактическое бронирование
lesson_series id, revision_id, component_id, logical_id, recurrence_kind text, recurrence_rule jsonb?, default_duration_minutes integer?, default_teacher_id uuid?, default_room_id uuid?, delivery_mode text Серия описывает повторение одного учебного события; допустимо одиночное занятие; recurrence_rule проверяется по схеме и не исполняется как код
series_participant revision_id, series_id, group_id, subgroup_id uuid? Фактический состав участников серии; копируется из эффективного состава компонента с учетом деления, затем изменяется явной операцией
lesson_occurrence id, revision_id, series_id, logical_id, origin_date date?, starts_at timestamptz?, ends_at timestamptz?, status text, teacher_id uuid?, room_id uuid?, delivery_mode text, public_comment text?, private_comment text?, is_fixed boolean Конкретное занятие или неразмещенная потребность; статусы unplaced/scheduled/cancelled; одно основное назначение преподавателя и аудитории в базовой версии; публичный и внутренний комментарии раздельны
occurrence_participant revision_id, occurrence_id, group_id, subgroup_id uuid? Материализованный фактический состав занятия; изменение участников серии пересчитывает будущие экземпляры только после предпросмотра
recurrence_exception revision_id, series_id, origin_date, action text, occurrence_id uuid?, reason text Уникальная исходная дата серии; действия cancel/replace/add; исключения не теряются при повторной генерации
occurrence_group_transfer id, revision_id, source_occurrence_id, target_occurrence_id, source_series_id, origin_date, selected_participants_snapshot jsonb, operation_id Связь разъединённых проведений FR-069 одной редакции; исходная дата и точный состав сохранены, источник и результат различны. Создаётся только при переносе части участников, вместе с исключением серии и аудитом
workflow_task id, revision_id, occurrence_id uuid?, plan_id uuid?, assigned_chair_id uuid?, state text, reason text Передача работы кафедре — отдельный процесс; не изменяет смысл даты, отмены и публикации занятия
schedule_publication id, period_id, revision_id, number integer, published_at, published_by_id, content_sha256 char(64), comment text? Уникальная пара периода и номера; публикация ссылается на неизменяемую редакцию, включает сохраненные справочные подписи

Эффективный состав компонента определяется режимом inherit/override: отсутствие переопределения не стирает участников плана, а переопределение задает полный набор конкретного вида работы. Переключение режима и генерация серий показывают сравнение участников. Исходный GRPPLAN заполняет plan_participant; наличие в старом снимке только этой связи не запрещает новому приложению отдельный состав лекций, практик и экзаменов. Генератор берет эффективный состав компонента, а не безусловно все группы плана.

lesson_series.component_id указывает основной источник генерации и включается в полный набор series_component. Для совместного проведения этот набор включает несколько компонентов. Состав серии и экземпляра формируется из подтверждённых связей потребностей, а не только из основного компонента. occurrence_requirement обязателен и для обычного проведения с одним компонентом: это единственный источник зачёта нагрузки, основной FK второй раз часы не начисляет. Отмена, перенос, замена и закрепление относятся ко всему проведению; изменение только одной связанной потребности требует предпросмотра и при необходимости разъединения.

Для FR-069 исходная серия и её обычный состав не меняются. На origin_date сохраняется исключение replace, указывающее на исходный экземпляр с оставшимися участниками; его переопределённый состав авторитетен для повторной генерации. Выделенное проведение принадлежит собственной одиночной серии и связано через occurrence_group_transfer. Если на этой исходной дате уже было исключение, оно обновляется с сохранением истории, а не дублируется. Переносы нескольких групп по очереди поддерживают несколько связанных результатов и одно эффективное исключение даты. Выбор всех оставшихся участников переносит существующий экземпляр, не стирая прежние связи выделения.

Зачёты occurrence_requirement перераспределяются по фактическим участникам: источник сохраняет только оставшийся состав, результат — перенесённый. Идентичность потребности и происхождение из старых данных не теряются; повторного зачёта одной группе нет. Совокупность уникальных проведений для преподавателя пересчитывается отдельно. Сброс исключения к шаблону требует предпросмотра всех связанных выделений; вернуть группу к источнику можно только одновременно разрешив её новое проведение и проверив занятость/нагрузку. Обычная генерация такого сброса не выполняет.

Одинаковая группа вправе входить в два разных плана по одной дисциплине: связи различаются по plan_id. Нельзя делать upsert участников по одному group_id, заменяя ранее существовавшие связи. Если несколько строк состава указывают на одну группу, список групп в карточке дедуплицируется по идентификатору, но состав подгрупп сохраняется. Для соединений с разрешенным NULL использовать корректную уникальность с учетом NULL, например UNIQUE NULLS NOT DISTINCT, либо эквивалентные частичные индексы.

Все изменяемые поля редакции защищаются серверной проверкой state=draft. Любая транзакция изменения самой редакции или ее дочерних сущностей сначала блокирует строку schedule_revision через SELECT ... FOR UPDATE, проверяет состояние и увеличивает агрегатный row_version редакции в той же транзакции. Публикация и заморозка получают ту же блокировку и сверяют ожидаемую агрегатную версию, поэтому новая дочерняя запись не может появиться между последней проверкой и заморозкой. Фоновая подготовка работает с зафиксированным снимком и перед активацией сверяет захваченный row_version; устаревший результат пересчитывается, а не публикуется. После публикации эта же редакция замораживается, а следующий рабочий черновик создается отдельной операцией копирования. Редактирование старой публикации через идентификатор объекта, API, административную форму или фоновую задачу должно отклоняться. Исправление выполняется в новом черновике и выпускается новым номером публикации. Предыдущая версия остается доступна уполномоченным пользователям.

Дополнительные поля и технические сущности§

Схема выше задает основные связи, но не исключает явно требуемые функциональностью поля. Для academic_group предусмотреть диапазон действительности, для справочников — архивирование, для lesson_type — явную политику обязательности преподавателя и допустимых форматов. У lesson_occurrence отдельно хранятся пожелания/прежнее размещение, не создающие занятости, причина отмены и причина закрепления; отсутствие этих сведений в колонках старой БД не отменяет новых требований. Учебные периоды, календарь, звонки, доступность и используемые параметры ресурсов включаются в проверяемый снимок публикации; последующее редактирование общих настроек не меняет исторический вид и смысл уже опубликованной версии.

Для учета объема в academic_period обязательно определить academic_hour_minutes; в plan_component — необязательную weekly_target_quantity с единицей и основанием расчета, отдельную от общего объема. У серии и экземпляра хранить contact_minutes — учебные минуты без перерыва, отличные от полного временного интервала занятости. При известном интервале учебные минуты не превышают его длительность; значение не вычисляется как вся разница между началом и концом, если внутри есть перерыв. Настройки расчета входят в снимок публикации.

Общий объем компонента имеет явную область quantity_scope: рабочее правило для новых планов — потребность каждого выбранного учебного состава. Совместная лекция двух групп засчитывает ее учебное время каждой группе, но преподавателю — один раз; раздельное проведение для двух подгрупп создает отдельную потребность каждой и может увеличить суммарную нагрузку преподавателя. Показывать отдельно выполнение плана по участникам и суммарное время уникальных проведений. Для импортированного объема область остается unknown до подтверждения; генерация с ней запрещена. Недельный ориентир, общий объем и число учебных недель не должны взаимно перезаписывать друг друга без показанного расчета.

Сущность Обязательное содержание
user, серверная сессия Поддерживаемая модель аутентификации Django; индивидуальная учетная запись, состояние, безопасный хеш пароля и отзыв сеансов
role_assignment, permission_scope Пользователь, роль, организация/подразделения, действительность назначения; права внутренней заметки и исходников импорта отдельно
audit_event Автор, время UTC, действие, тип и ID/logical_id объекта, редакция, причина, безопасная разница до/после, общий ID команды; неизменяемая запись
background_job, job_attempt, outbox_message Статус, владелец, параметры без секретов, прогресс, попытки, lease/heartbeat, результат и гарантированная повторная доставка
idempotency_record Ключ, владелец/область, вид команды, хеш входа, статус и ссылка на сохраненный результат
private_file, export_artifact Владелец, права, назначение, размер, SHA-256, безопасный путь хранения вне webroot, срок удаления

Публичное API-представление может использовать другую терминологию: /departments соответствует логической chair, /plan-entries — curriculum_plan, /events — lesson_occurrence, а /event-series — lesson_series. Это не дополнительные дублирующие сущности. Соответствия должны быть включены в словарь новой системы.

Календарь и правила размещения§

Серия и конкретное занятие§

CAL-01. Пользователь должен различать объем учебного плана, правило повторения и конкретное занятие. plan_component задает потребность; lesson_series — правило; lesson_occurrence — фактический экземпляр. Число строк плана и число календарных занятий не обязаны совпадать. Генерация по объему допускается только после задания единицы нагрузки, продолжительности и правил деления группы. Система выводит расчет до сохранения: исходный объем, полученное число занятий, общий объем минут и остаток.

CAL-02. Базовая версия поддерживает одиночное занятие, каждую учебную неделю и через одну учебную неделю. Правило включает начальную и конечную даты, дни недели, локальное время, продолжительность и опорную неделю периода. Понятия «четная/нечетная» определяются календарем учебного периода, а не автоматически номером ISO-недели года. Пользователь видит конкретные получившиеся даты. Правила с неизвестной точкой отсчета не создают экземпляров.

CAL-03. Конкретные интервалы хранятся в timestamptz и передаются API как ISO 8601 со смещением. Часовой пояс периода хранится отдельно: он необходим для повторений в локальном времени и не восстанавливается из UTC-смещения. Для неожиданно неоднозначного или несуществующего локального времени операция требует явного выбора либо отклоняется с объяснением. Время сервера и часовой пояс браузера не переопределяют учебный календарь.

CAL-04. Интервал занятия — полуоткрытый [starts_at, ends_at), с конечными границами и starts_at < ends_at. Занятие 08:00–09:30 не пересекается с занятием 09:30–11:00. Интервалы сравниваются по реальному времени, независимо от номера пары; занятие может занимать несколько слотов либо иметь индивидуальную продолжительность. Отображение номера пары — дополнительное представление. Нельзя считать, что разность двух начал звонков является длительностью пары.

CAL-05. Для изменения повторяющегося занятия интерфейс предлагает область: один экземпляр, этот и следующие либо вся серия. Предпросмотр показывает добавляемые, переносимые, отменяемые экземпляры, затрагиваемые исключения и конфликты. Изменение одного экземпляра сохраняет его origin_date и создает исключение, а не лишний дубль. Повторная генерация с тем же правилом и ключом запроса идемпотентна. Откат не должен восстанавливать уже исключенное занятие незаметно для пользователя.

При FR-069 исключение на исходную дату также сохраняет изменённый состав: перенесённая группа исключена только из этого проведения, но остаётся в обычном составе других дат серии. Ни повторная генерация, ни смена режима просмотра не заменяет календарные исключения первоначальным шаблоном. Примеры дат марта 2027 года в приёмке являются синтетическим новым расписанием и не утверждают расшифровку старой БД.

Праздники, неучебные дни и переносы являются записями календаря периода. Генерация по умолчанию пропускает исключенные дни; ручное размещение на такой день показывает причину и допускается только согласно явно установленному правилу периода. Перенос учебного дня с одной даты на другую сначала показывает все затрагиваемые серии. Система не заимствует автоматически календарь другого года.

Статусы и полнота назначения§

Статус экземпляра Интервал Бронирование ресурсов Смысл
unplaced Оба поля времени NULL Отсутствует Занятие существует как потребность, место в календаре не выбрано
scheduled Начало и окончание обязательны Создается для известных участников, преподавателя и аудитории Занятие размещено в календаре черновика; полнота обязательных ресурсов проверяется отдельно
cancelled Допускается сохраненный прежний интервал либо NULL; пара полей согласована Отсутствует Отмененный экземпляр остается в истории; причина отмены обязательна

CAL-06. В черновике размещенное занятие может временно не иметь преподавателя или аудитории. Известные ресурсы при этом бронируются, неизвестные — нет; карточка явно показывает недостающие назначения. Участники размещенного занятия обязательны; пустой набор не считается свободной группой. Для публикации физический формат onsite требует аудиторию, подтверждённый online может обходиться без неё независимо от формы обучения. Преподаватель обязателен, если соответствующий вид работы предполагает преподавание. Эти правила задаются явно и не выводятся из наличия поля. Для участника очной формы допустим онлайн-формат, для заочной — физическое проведение.

CAL-07. Публикация — состояние версии всего расписания, а не четвертый статус экземпляра. Передача занятия «на кафедру», согласование и возврат — состояния задания workflow_task. Новый признак фиксации is_fixed запрещает перемещение без отдельного права и указанной причины; он не выводится автоматически из старого Stable. Старый Assigned сохраняется в данных происхождения, но не отождествляется с scheduled: в снимке 288 неназначенных строк имеют координаты, а 2 339 назначенных не имеют аудитории.

Участники, занятость и защита от конфликтов§

Атомарные ресурсы групп§

CON-01. Проверка занятости опирается на единый справочник schedulable_resource: преподаватель, аудитория либо атомарная часть группы. Преподаватель, аудитория и группа имеют глобальный устойчивый UUID в организации, одинаковый во всех периодах и редакциях. Атомы также имеют глобальные устойчивые UUID; версии состава хранятся отдельными снимками и не подменяют идентичность ресурса. UUID атома нельзя повторно использовать для другого состава участников. Ресурс идентифицируется UUID, не отображаемым названием. Таблицы resource_group_atom и participant_atom связывают группу/подгруппу с набором атомарных ресурсов в редакции. Занятие всей группы занимает все ее атомы; занятие конкретной подгруппы — атомы этой подгруппы. Благодаря этому «вся группа» конфликтует с любой своей подгруппой, а две подтвержденно непересекающиеся подгруппы могут заниматься одновременно.

Наличие двух разных номеров подгрупп само по себе не доказывает независимость, если используются разные схемы деления либо состав неизвестен. В базовой версии допускается одна подтвержденная непересекающаяся схема группы. До подтверждения все участники этой группы используют общий атом: параллельное размещение блокируется консервативно с сообщением «Состав подгрупп не подтвержден». Если схема подтверждена, но для отдельной записи не удалось сопоставить подгруппу, запись занимает все атомы группы. Учет студентов поименно не требуется; подтверждение схемы является отдельным действием уполномоченного пользователя.

Для объединенного занятия нескольких групп набор ресурсов строится как объединение атомов без повторов. Одна и та же группа не удваивает занятость и численность из-за нескольких строк связи. Если численность подгрупп неизвестна, интерфейс показывает неизвестное значение либо явно обозначенную верхнюю оценку; делить NStudents поровну без согласованного правила нельзя.

Изменение схемы деления выполняется с блокировкой затронутой группы и единым пересчетом участников, численности, бронирований и конфликтов всей редакции. Если новая схема создает пересечения, изменение не применяется частично. Опубликованная версия продолжает использовать прежний снимок состава.

Проверки и транзакционная гарантия§

CON-02. Жесткие конфликты: пересекающиеся интервалы разных самостоятельных проведений одного преподавателя, аудитории или атома группы; попадание в подтверждённый жёсткий запрет ресурса. Они запрещают фиксацию операции независимо от полномочий диспетчера. Подтверждённое совместное проведение имеет одно бронирование каждого уникального ресурса, даже если обеспечивает несколько планов. Неподтверждённый кандидат совместности не является обходом проверки. Дополнительные условия проверяются по утверждённой политике; вместимость — по FR-033/FR-066, рекомендованный допустимый тип и мягкое предпочтение — как предупреждения. Исключение действует только в разрешённых политикой пределах и не отменяет жёсткую занятость.

Целевые технические таблицы:

Таблица Назначение и существенные поля
schedulable_resource id uuid, organization_id, kind, ссылка на преподавателя, комнату либо атом; ограничение ровно одного подходящего владельца
availability_rule id, revision_id, resource_id, severity=hard/soft, календарное правило либо конкретный интервал, reason, created_by_id
resource_booking id, revision_id, resource_id, during tstzrange, occurrence_id?, block_id?; ровно один источник: занятие или материализованный жесткий запрет
booking_block_source Связь объединенного интервала запрета с исходными правилами и причинами; позволяет корректно удалить одно из перекрывающихся правил
active_publication_booking resource_id, during tstzrange, publication_id, occurrence_id; действующая занятость опубликованных расписаний всех периодов, с глобальными UUID ресурсов
active_publication_participant group_id, partition_snapshot_id, subgroup_id?, during, publication_id, occurrence_id; снимок участников для межпериодной проверки разных схем деления
partition_intersection Два снимка схем одной глобальной группы, две подгруппы, результат overlap/disjoint/unknown, автор и основание подтверждения; матрица не переносится на измененный состав автоматически
conflict_decision revision_id, occurrence_id, тип предупреждения, данные проверки, accepted_by_id, reason, created_at; только для разрешенных предупреждений

Правила доступности дополнительно имеют происхождение, статус проверки и период действия; только подтверждённые жёсткие правила создают block_id. conflict_decision ссылается на конкретную версию правила и снимок проверяемых параметров, содержит срок действия и область исключения. После изменения участников, времени, вместимости или правила прежнее исключение перепроверяется и не считается автоматически действительным.

Перед записью API выполняет предварительную проверку для объяснимого сообщения, но окончательную защиту реализует PostgreSQL. Использовать GiST exclusion constraint для пересечения диапазонов и расширение btree_gist для равенства UUID. Это поддерживаемый механизм PostgreSQL для запрета пересекающихся резервирований. Типы диапазонов PostgreSQL, btree_gist.

Принцип ограничения в миграции БД:

CREATE EXTENSION IF NOT EXISTS btree_gist;

ALTER TABLE resource_booking
  ADD CONSTRAINT resource_booking_no_overlap
  EXCLUDE USING gist (
    revision_id WITH =,
    resource_id WITH =,
    during WITH &&
  ) DEFERRABLE INITIALLY IMMEDIATE;

Дополнительно обязательны CHECK: диапазон непустой, обе границы конечные, нижняя включена, верхняя исключена. В этой таблице отсутствуют бронирования отмененных и неразмещенных занятий. Жесткие запреты предварительно объединяются по ресурсу в непересекающиеся интервалы с сохранением всех причин: два перекрывающихся запрета не должны мешать друг другу, но оба препятствуют занятию. Новый запрет, затрагивающий уже назначенные занятия, не применяется молча — система показывает перечень и требует сначала разрешить ситуацию согласованными операциями.

CON-03. Любое размещение, перемещение, замена ресурса, изменение участников и массовая операция выполняются одной транзакцией: заблокировать редакцию и проверить ее состояние; проверить версию объекта и права; заблокировать затронутые записи в устойчивом порядке; пересчитать интервалы и атомы; заменить бронирования; записать новое состояние и аудит; подтвердить ограничения перед commit. Обмен двух занятий может временно отложить exclusion constraint внутри транзакции, но к commit итог обязан быть корректным. Ошибка ограничения отменяет все изменения операции; API возвращает 409 Conflict с актуальным конфликтующим ресурсом и интервалом, если пользователь имеет право их видеть.

Общий порядок блокировок: организация, если операция требует координации публикаций/общих правил; затем редакции по UUID; затем глобальные группы/ресурсы по UUID; затем конкретные изменяемые строки по UUID. Отсутствующие уровни пропускаются, обратный порядок в другой команде не допускается. Публикатор также получает блокировку редакции до блокировок ее групп. Deadlock/serialization failure допускает ограниченный безопасный повтор только всей идемпотентной транзакции; частичный повтор ее SQL-шагов запрещен.

Оптимистическая блокировка по row_version предотвращает потерю изменения одного объекта. Ограничение занятости предотвращает другой случай: два пользователя изменяют разные занятия и одновременно выбирают свободную аудиторию. Проверка вида «SELECT свободно → INSERT» без ограничения БД не считается реализацией требования. Идемпотентный ключ клиентской команды предотвращает повторное выполнение после сетевого повтора.

CON-04. Жесткая защита записи действует внутри одной редакции. Изолированные черновики не конфликтуют между собой: это варианты расписания. Пересечение с действующей публикацией другого периода может сохраняться в черновике как препятствие публикации, но не обходить собственные жесткие ограничения редакции. При публикации проверяется также совместимость с действующими публикациями других периодов организации, если их даты пересекаются. Для active_publication_booking применяется аналогичный exclusion constraint по resource_id и during, без revision_id. Публикация атомарно заменяет бронирования предыдущей действующей версии своего периода; при конфликте с другим периодом прежняя публикация остается действующей. Операции публикации сериализуются блокировкой строки организации и захватывают блокировки всех затронутых глобальных групп в устойчивом порядке UUID. Публикация проверяет ожидаемую версию редакции под ее блокировкой. Активация бронирований, участников и указателя действующей публикации выполняется одной транзакцией. Предварительная проверка черновика может предупреждать о таких межпериодных пересечениях заранее.

Одного exclusion constraint по атомам недостаточно, если разные периоды используют разные схемы деления одной группы. Перед активацией дополнительно сравниваются пересекающиеся интервалы active_publication_participant по глобальному group_id: вся группа пересекается с любой своей подгруппой; одинаковая подтвержденная схема использует атомы; разные схемы используют подтвержденную матрицу partition_intersection. Результат unknown трактуется как возможное пересечение и блокирует публикацию. Проверка и запись удерживают блокировки глобальных групп до commit, поэтому две параллельные публикации не могут одновременно подтвердить отсутствие друг друга. Эту гарантию реализовать общей транзакционной службой и обязательным проверочным триггером активации либо эквивалентным механизмом БД, исключающим запись в обход проверки.

Опубликованный состав и его матрица пересечений неизменяемы. Изменение схемы в черновике создает новый снимок; переименование ресурса не меняет UUID. Изменения глобальных правил, влияющие на совместимость действующих публикаций, используют те же блокировки организации и групп, повторную проверку и явный результат; они не пересчитывают действующую занятость молча.

Политика как проверяемая конфигурация продукта§

POLICY-01. Раздел является обязательной частью B и уточняет FR-011–FR-068. Основание — SRC-08/SRC-09. Статистика снимка фиксирует наблюдение, утверждённая конфигурация задаёт поведение новой системы. Между ними обязательны явные решения об области, строгости и исключениях. В поставке должны различаться: исходные аналитические правила POL, черновые предложения настроек и утверждённая действующая версия. Переименование наблюдения в «правило» не делает его обязательным.

Проверка выполняется в порядке зависимостей: определить участников и реальные интервалы; построить уникальную занятость; проверить жёсткие условия и готовность данных; вычислить мягкие критерии; подготовить протокол публикации. Это проектный порядок, а не восстановленная последовательность работы старой программы. Проверка вместимости и обязательного оборудования не откладывается до выбора красивого варианта. Для всех ручных и фоновых операций действуют одинаковые условия.

Классификация групп и начальные временные профили§

POLICY-02. Подтверждённая расшифровка. Классификатор работает с исходным обозначением и его рабочей копией. Исходная строка сохраняется без изменений; пояснение в скобках отделяется перед анализом кода. Регистр значим для маркеров. Выделение суффиксов онлайн/билингвальности предшествует разбору числового окончания; признаки не стирают друг друга. Конфликтующие, неполные или новые обозначения требуют проверки, а не догадки по времени занятий.

Признак Правило для данного источника Пример / граница применения
Очно-заочная, вечерняя форма Строчная в в коде; имеет приоритет перед числовым окончанием Хранится как part_time, вечерний профиль задаётся отдельно
Очная форма Окончание группы 01, 02, 03 и далее с разделяющим нулём по принятой схеме кода; конечная Б подтверждает очную билингвальную группу Ю601Б; это не правило «любой ноль в названии»
Заочная форма Окончание 1, 2 и далее без этого нуля в схеме кода 3ФЭ51о; разбор целого кода, не произвольной последней цифры
Онлайн Строчная о — независимый признак формата мТП601о — очная онлайн-группа; мБУА51о — заочная онлайн-группа
Билингвальность Конечная прописная Б Углублённый иностранный язык; не отдельная форма и не автоматическое требование кабинета
СПО Начало 9- или 11-; подтверждённые исключения 11РВП601, 11РВП602 Хранить явные исключения классификатора; не расширять на любой префикс 11 без проверки
Магистратура / аспирантура Строчные префиксы м / а Прописная буква другого кода не равнозначна префиксу уровня
Бакалавриат / специалитет Остальные распознанные коды данного справочника Разделить эти два уровня точнее можно по отдельным подтверждённым данным
Курс Подтверждённое название Courses и отдельное сопоставление года CourseNo=6 не шестой год: в источнике это первый курс магистратуры

Регрессионный результат на 554 группах: 394 очные, 123 заочные, 37 вечерних; уровни — 297 бакалавриат/специалитет, 172 СПО, 37 магистратура, 48 аспирантура. Онлайн — 23 группы, включая 2 очные и 21 заочную; билингвальных — 6. Для восьми обозначений с пояснением в скобках исходный текст сохраняется. Это проверка классификатора конкретного снимка, не требуемые количества будущего справочника. Ручное решение по новой группе имеет автора, основание и не переписывает старую публикацию.

POLICY-03. Предложения временных профилей. Числа ниже измерены в уникальных назначенных участиях ClassNo–GroupNo, без умножения на студентов и календарные повторения. До согласования это доступные для просмотра шаблоны, не активные запреты.

Категория Основание из политики Начальная конфигурация для согласования
Очный бакалавриат/специалитет 6 098 участий, 95,33% на парах 1–6 Предпочитать 1–6; поздние занятия не запрещать только по частоте
Очное СПО 5 613 участий, 95,96% на 1–6 Собственный дневной профиль; предельную дневную нагрузку утверждать отдельно
Очная магистратура 235 участий; 96,19% будних участий на 7–8 Отдельный будний вечерний профиль; суббота отдельно
Очная аспирантура Все 456 будних участий на 7–8; все 84 субботних на 2–3 Раздельные шаблоны будней и субботы; не переносить поздний будний диапазон на субботу
Вечерняя форма 470 из 478 будних участий на 7–8, оставшиеся 8 — на 6 7–8 предпочтительны; шестая — кандидат разрешённого исключения; строгость остальных границ согласовать
Заочная форма Размещено 745 из 3 817 участий; активны 27 из 123 групп Календарь сессий, интенсивность и допустимое время ввести явно; профиль не экстраполировать на отсутствующие назначения
Онлайн 547 назначенных участий без комнаты; 20 активных групп из 23 Самостоятельный формат проведения; не считать все онлайн-группы вечерними и все записи без комнаты онлайн
Билингвальные группы Форма подтверждена как очная Использовать форму и уровень; дополнительные языковые требования задаются планом явно

Исходные начала восьми слотов: 08:00, 09:40, 11:25, 13:20, 15:05, 16:50, 18:30, 20:05. Окончания и учебные минуты в этих данных не восстановлены. В новом периоде шаблоны связываются с утверждёнными интервалами; номер «7» сам по себе не гарантирует начало в 18:30 при другой сетке звонков.

Показатели качества и сравнение вариантов§

POLICY-04. Единицы и охват. Рабочая система считает реальные даты. В режиме исследования старого снимка день — ключ (сущность, q=DayNo//14, слой, DayNo%14), где q не объявляется неделей или датой. Назначенные строки представлены в 11 блоках 0,1,2,3,4,5,13,15,19,20,21; их нельзя соединять в одну условную неделю. Для 23 назначенных EachWeek в аналитике раскрываются оба слоя: 11 530 строк дают 11 553 наблюдения «строка × слой». Привязка слоёв к чётности и календарным датам остаётся отдельным DEC-01. Модельные показатели и показатели реального календаря отображаются раздельно.

Показатель Определение и обязательная граница
Занятые позиции Множество уникальных слотов одного ресурса за день; совместное проведение не размножает занятость по числу планов
Внутренние окна Пустые позиции строго между первой и последней занятой позицией одной сетки. Для {1,3,4} — один пропущенный слот и одно окно; для {1,4} — два пропущенных слота и одно окно. Отдельно число участков и сумма пропусков
Доля дней без окон Число дней без внутренних пропусков / дни минимум с двумя занятыми позициями. Однопозиционные дни показываются отдельно; нулевой знаменатель — «нет данных»
Минуты ожидания Отдельный показатель по известным фактическим интервалам с явно заданным учётом плановых перерывов. Перерыв между соседними слотами не становится автоматически «окном»; для старых неизвестных окончаний минуты не вычислять
Группа и подгруппа Показывать объединённый контур группы и отдельные подтверждённые части. Групповой максимум не приписывать отдельному студенту; неподтверждённую схему не выдавать за индивидуальную занятость
Преподаватель Уникальные занятые клетки/интервалы преподавателя, число активных дней, окон, диапазон дня. Считать по ID, не по ФИО; неизвестный преподаватель — отдельный неполный случай
Временной профиль Число участий в предпочтительном/допустимом/исключительном/запрещённом диапазоне и число непроверенных участий; вместе с версией профиля и полным знаменателем
Соседство предмета Доля пар соседних занятых слотов одного дня и подтверждённого состава с одним предметом. При нескольких разных параллельных предметах без подтверждённого состава — неоднозначность, не произвольный выбор. Точное правило нормализации предмета версионируется; оно не сливает справочники
Порядок видов Отдельные счётчики направленных соседств одного предмета лекция → практика/семинар и обратных. Исторические л/с/п интерпретировать только после сопоставления; обратный порядок не является ошибкой без особого утверждённого требования
Перемещения Число смен комнаты и корпуса между последовательными проведениями ресурса за день; знаменатель — переходы с обоими известными значениями. Неизвестные значения показываются отдельно; онлайн-переход не трактуется как посещение неизвестного корпуса
Полнота Отдельно исходные строки, участия, реальные проведения, созданный/размещённый/неназначенный/отменённый объём. Процент размещения не равен соблюдению правил. Неизвестные единицы часов не суммируются с подтверждёнными
Вместимость Число проверенных, недостаточных, неизвестных и устаревших сопоставлений; основание численности и вместимости. Сумма участников совместного проведения не дублирует пересечения

Для нового расписания с нестандартными интервалами вне утверждённой сетки слотов позиционные метрики показывают «не применимо» и число исключённых случаев; интервальные метрики остаются отдельными. Нельзя переводить 90 минут в одну пару без выбранной сетки и правил учебного времени.

Контрольные ориентиры SRC-08: у групп 3 571 из 3 975 многопозиционных модельных дней без окон (89,84%), 404 дня с окнами, 564 пропущенные позиции; 2 674 однопозиционных дня учтены отдельно. У преподавателей 2 859 из 3 210 без окон (89,07%), 351 день с окнами, 515 пропусков. В условной модели подгрупп — 8 392 из 9 278 многопозиционных дней без окон. Это регрессионные результаты исследовательского расчёта до любых подтверждённых объединений; они не обязательные пороги качества новых периодов. Порядок л → с встречается 1 186 раз, обратный — 381; это не универсальная жёсткая зависимость.

POLICY-05. Сравнение. В B отчёт содержит вектор показателей и изменение каждого компонента; общего скрытого балла нет. Если позднее вводится взвешенная оценка для FR-060, требуются единицы, нормализация, веса, версия, разбор конфликтующих интересов и приёмочные пары допустимых вариантов. Нельзя компенсировать сокращением окон неполноту нагрузки, нераспознанные данные или жёсткое нарушение. Условные перестановки из исследования не доказаны как допустимые расписания и не служат эталоном оптимизатора.

Ограничения «не более четырёх пар», «свободный день каждую неделю», «одинаковое начало», «постоянная аудитория», «одинаковые недели» и приоритет преподавателя перед группой в источнике не восстановлены. Их нет среди активных настроек по умолчанию. Введение требует нового явного правила с основанием и проверкой влияния, а не копирования наблюдаемого максимума.

Сущности политики и совместного проведения§

DATA-05. Следующие сущности дополняют основную модель. Все ссылки компонентов, участников, серий и событий согласованы по организации и редакции; это обеспечивается составными FK и транзакционными проверками. Версионированные правила нельзя редактировать через произвольный JSON в обход доменных команд.

Сущность Минимальное содержание и инварианты
policy_version UUID, организация, номер, состояние, хеш содержимого, предшествующая версия, автор, утвердивший, время. Утверждённое содержимое неизменяемо; черновик расписания ссылается на конкретный ID
policy_rule Версия, устойчивый код, тип условия, параметры по проверяемой схеме, область, срок, строгость, приоритет, основание и его хеш, степень поддержки, статус согласования. Произвольный Python/SQL из интерфейса не исполняется
time_profile Версия правила, форма/уровень/модальность/день, версия сетки, допустимые и предпочтительные интервалы, исключения. Неоднозначные пересечения профилей требуют решения
rule_exception Правило и версия, конкретная область/занятия, причина, утверждение, срок, снимок параметров проверки. Не допускается для неотменяемых гарантий занятости и прав
room_compatibility, component_feature_requirement Версия политики, вид занятия, тип комнаты, разрешённость/предпочтение; у компонента — обязательное/желательное оборудование. Незаданный элемент матрицы не означает автоматически разрешение
capacity_verification Ресурс/состав, значение, дата и источник проверки, статус, проверивший; снимок принятой численности и вместимости сохраняется в выпуске
building_transfer Версия, корпус откуда/куда, минуты, область/период действия, источник и статус; направленная пара, неотрицательное подтверждённое время
series_component revision_id, series_id, component_id; уникальная тройка, M:N. Основной lesson_series.component_id обязательно входит в набор
occurrence_requirement revision_id, occurrence_id, component_id, идентификатор подтверждённого учебного состава, зачтённые contact_minutes/единица. Уникальная связь проведения, компонента и состава; не больше учебной длительности проведения на одну потребность
joint_delivery_decision Исходные строки/потребности, снимок сравниваемых признаков, статус candidate/confirmed/rejected, автор, причина, целевое проведение. История решений неизменяема; разъединение — новая операция
source_occurrence_link Исходная строка и целевой экземпляр, правило развёртки/совместности, версия решения. M:N учитывает как повторение одной исходной строки, так и несколько строк одного проведения без потери исходных ID
quality_run Редакция и её агрегатная версия/хеш, политика, версия метрик и классификации, фильтры, единицы, охват, числители/знаменатели, исключённые случаи, статус задания. Результат неизменяем и помечается устаревшим при смене входа
policy_validation Проверяемый снимок, результаты по кодам правил, исключения и нерешённые условия; привязан к кандидату публикации, не заменяется отчётом другого запуска

Сумма зачётов одной потребности по разным событиям сравнивается с её планом; превышение не скрывается. Одно совместное двухчасовое проведение может обеспечить двухчасовую потребность каждой из двух групп/планов: преподавателю — два часа, каждой потребности — два. Сумма четырёх часов участия не является четырьмя часами работы преподавателя. Неоднозначный импортированный зачёт не выполняется до решения единиц и области quantity_scope.

Изменение привязки политики и её зависимостей увеличивает агрегатную версию редакции. Предпросмотр и публикация фиксируют также версии общих ресурсов/ограничений, на которых построена проверка. Их изменение обнаруживается при подтверждении; активация удерживает согласованные блокировки организации и редакции и перепроверяет актуальный набор. Проверка не должна использовать устаревший отчёт качества как доказательство отсутствия конфликта.

Соответствие POL, требований и приёмки§

TRACE-01. Все 20 пунктов каталога SRC-08 имеют явную реализацию. Столбец «Поведение» описывает новую систему, а не подтверждает работу старого алгоритма. AP — сценарии следующего подраздела; вместе с ними обязательны критерии указанных FR.

Правило политики Поведение новой версии Требования Приёмка
POL-01. Все участники Раскрывать состав, объединять участников без повторов FR-012, FR-021, FR-065; CON-01 AP-04, AP-05
POL-02. Совместность и конфликт Подтверждать одно проведение по нескольким потребностям; независимые события конфликтуют FR-032, FR-065; DATA-05 AP-04, AP-05
POL-03. Подгруппы Целая группа занимает все части; параллельность только после подтверждения FR-012; CON-01, CON-04 AP-05
POL-04. Слои и повторения Раскрывать модель до аналитики; даты только по подтверждённой расшифровке FR-028–FR-030, FR-067; MIG-02 AP-01, AP-03
POL-05. Ограничения ресурсов Различать подтверждённый запрет, пожелание и неизвестное исходное правило FR-034, FR-061, FR-068 AP-06
POL-06. Форма и уровень Явная классификация и раздельные временные профили FR-011, FR-062 AP-02, AP-07
POL-07. Вечерний диапазон Настраиваемые 7–8 и отдельное исключение для 6 в утверждённом профиле FR-062; POLICY-03 AP-07
POL-08. Суббота Отдельный профиль по категории FR-062; POLICY-03 AP-07
POL-09. Онлайн Форма и формат независимы; отсутствие комнаты не определяет формат FR-011, FR-031, FR-066 AP-02, AP-08
POL-10. Окна групп Раздельная метрика группы и подтверждённых частей, мягкое предпочтение FR-063, FR-064; POLICY-04 AP-09, AP-10
POL-11. Окна преподавателей Уникальная занятость, отдельная метрика и изменение FR-013, FR-063, FR-064 AP-09, AP-10
POL-12. Соседство предмета Метрика и предпочтение без принудительного объединения длительности FR-063, FR-064 AP-11
POL-13. Порядок видов Направленное мягкое предпочтение после расшифровки кодов FR-017, FR-061, FR-063 AP-11
POL-14. Помещения Матрица совместимости и оборудование, не равенство букв FR-015, FR-026, FR-066 AP-12
POL-15. Перемещения Отдельные показатели комнат/корпусов; минуты только после подтверждения FR-063, FR-066 AP-12
POL-16. Идентичность ID для расчётов, ФИО для поиска; никаких выведенных личных привилегий FR-007, FR-013, FR-034 AP-13
POL-17. Полнота Неназначенные и неизвестные записи отдельно; нет догадки о заочной сессии FR-027, FR-049, FR-063, FR-067 AP-01, AP-14
POL-18. Вместимость Проверенные значения и отдельное утверждение режима FR-033, FR-066, FR-068 AP-12, AP-15
POL-19. Неподтверждённые пределы Нет жёстких максимумов/свободных дней, выведенных из частот FR-061, FR-062; POLICY-05 AP-16
POL-20. Происхождение Основание, согласование, версия, журнал и снимок выпуска FR-061, FR-067, FR-068 AP-17, AP-18

Приёмочные сценарии политики§

AP-00. Сценарии обязательны для B. Аналитические контрольные числа проверяются на неизменённом исходном SQLite и закреплённой версии алгоритма SRC-08; после нормализации совместных проведений счётчики могут измениться, но различия должны объясняться реестром соответствий. Синтетические сценарии используют подтверждённые даты и явно утверждённую тестовую политику. Нельзя объявлять существующий просмотрщик прошедшим эти сценарии: они предназначены для будущей реализации.

ID Вход / действие Ожидаемый результат
AP-01 Полный контрольный снимок 15 111 строк; 11 530 назначенных и 3 581 неназначенных, из последних 288 с координатами. 17 727 уникальных участий всего, 13 795 назначенных; исходные строки не подменяются событиями
AP-02 Все 554 группы и коды Ю601Б, мТП601о, мБУА51о, 11РВП601, новый неизвестный код Контрольные количества POLICY-02; форма/уровень/модальность раздельны, СПО-исключение распознано, неизвестный код не получает выдуманного профиля; исходные строки сохранены
AP-03 23 назначенных EachWeek, разные q при одинаковом слоте и неподтверждённый календарь 11 553 наблюдения строк × слоёв, 11 отдельных блоков; q не календарная неделя. В защищённой аналитике результат доступен, реальные даты/бронирования не создаются
AP-04 Кандидаты 638 преподавательских и 572 аудиторных многозаписных клеток Подтверждаются аналитические совпадения признаков; 236 из 572 имеют один PlanNo. До решения нет автоматического объединения, сохраняются все ClassNo/PlanNo/SubjectNo
AP-05 Две потребности разных планов, одно согласованное проведение и затем независимое занятие той же подгруппы Два зачёта потребностей, одно бронирование учителя/комнаты; независимое пересечение отклонено. Разные подтверждённые подгруппы допускают параллельность; целая группа конфликтует с каждой
AP-06 Неподтверждённый Week/Reason, затем утверждённое пожелание и запрет Исходный текст не становится кодом; неясное применимое правило препятствует выпуску. Пожелание предупреждает, подтверждённый запрет блокирует; исходные 4/3 аналитических совпадения остаются предметом решения
AP-07 Утверждённые тестовые профили вечерних будней 7–8 с исключением 6; аспирантской субботы 2–3; совместное занятие несовместимых профилей Работают отдельные области и исключения, суббота не наследует 7–8. Пустое пересечение обязательных интервалов участников объяснено по группам и блокирует назначение
AP-08 Очная онлайн-группа без комнаты; заочная физическая без комнаты; неизвестный формат Первое допустимо при остальных полных данных; второе не публикуется; третье не переименовывается автоматически в онлайн
AP-09 Контрольная аналитика и синтетические дни {1}, {1,2}, {1,3,4}, {1,4} Регрессионные 3 571/3 975 и 2 859/3 210 воспроизводятся. Для примера три многопозиционных дня, один без окон, три пропущенных слота, два участка окон; однопозиционный день вне знаменателя
AP-10 Перенос уменьшает окна группы и увеличивает окна преподавателя; число участников совместного проведения изменено Показаны обе дельты, нет скрытого общего балла; занятость учителя не умножена на группы. Конфликтующий вариант не помечен допустимым
AP-11 Два последовательных занятия предмета; практика перед лекцией при мягком предпочтении обратного Соседство учитывается, две пары не превращаются в одну длительность. Обратный порядок даёт отклонение предпочтения, а не жёсткий запрет
AP-12 Разные буквенные коды при разрешённой матрице; отсутствующее обязательное оборудование; неизвестный и подтверждённый переход Разрешённая альтернатива допустима, отсутствие обязательного оборудования блокирует, неизвестное время не равно нулю. Подтверждённые 20 минут при перерыве 10 дают нарушение настроенного правила
AP-13 Два разных ID с одинаковым ФИО; изменение должности Записи не слиты, расписания и ограничения независимы. Изменение должности не создаёт приоритет или недоступность
AP-14 Заочные группы контрольного снимка и 24 заочные группы СПО без назначений Отчёт показывает 745/3 817, 27/123 активных групп, 778 неназначенных участий заочного СПО. Не заявляет отсутствие сессии или нулевую потребность
AP-15 30 участников и 24 места; неизвестная численность; повтор той же группы в совместных связях Обычная причина не разрешает выпуск; действует FR-033/FR-066. Неизвестное не считается нулём, повтор группы не удваивает вместимость. Исторические 1 121/4 396 не являются разрешением
AP-16 Пять пар, субботнее занятие и смена комнаты без утверждённых ограничений на них Нет выведенного из статистики жёсткого запрета; применяются только реальные конфликты и явно заданные правила. Stable=True не включает is_fixed и не требует одной комнаты
AP-17 Подготовка новой политики, попытка активации кафедрой, смена версии после предпросмотра Запрет по правам, неизменяемая утверждённая версия, устаревший предпросмотр пересчитан; выпуск хранит хеш конкретной политики и принятые исключения
AP-18 Доступ к именному профилю/основанию правила и публичному выпуску Закрытые причины и свободные исходные поля не раскрыты в UI/API/экспорте; уполномоченный видит источник и версию. Смена общих настроек не меняет старый выпуск
AP-19 Создать разовое занятие 15 марта 2027 года непосредственно из режима «День»; открыть неделю и список Не требуется настройка периодической сетки; во всех режимах одинаковые ID, дата, время и участники. Выбор 8 февраля 2027 года открывает именно этот день; пустой день явно пуст, границы периода проверяются
AP-20 Серия на 8, 15 и 22 марта 2027 года; перенести только 15 марта на 17 марта Сохранён ID перенесённого экземпляра, 8 и 22 марта неизменны. После выпуска изменена только выбранная дата; исходная публикация сохранена, пересоставление остальных занятий не запускается
AP-21 Общая двухчасовая лекция А и Б 15 марта; перенести только А на 17 марта с тем же преподавателем У Б остаётся исходное проведение; у А новое разовое. Каждой группе зачтены два часа, преподавателю четыре вместо двух; дельта видна до подтверждения. Выбор всех участников выполняет обычный перенос без пустого источника
AP-22 Повторить генерацию после AP-20/AP-21; повторить команду, проверить занятый ресурс и конкурентное изменение Переносы и составы сохранены, А не возвращается в общий урок 15 марта, дублей нет. Конфликт на новой дате или устаревшая версия не оставляет частичного изменения участников, зачётов, исключений или бронирований; прежние проведения сохранены
AP-23 Назначить явное онлайн-занятие без комнаты, изменить формат только одного повторения, открыть день/неделю/список, карточку, API и печать Онлайн-метка везде текстовая, преподаватель/группы заняты, фиктивная комната не создана. Остальные повторения сохраняют формат. Закрытые реквизиты подключения не выданы в публичные ответы и печать; пустая комната физического занятия не делает его онлайн

Перенос существующих данных§

Полный охват источников§

MIG-01. Импортер принимает подготовленный exports/schedule.sqlite вместе со схемой и манифестом. Прямое чтение Paradox допускается отдельной утилитой подготовки, воспроизводящей проверенный экспорт. Исходники сохраняются неизменяемыми с SHA-256, а пользователь видит источник каждого импортированного объекта. Не требуется переносить Paradox-индексы в бизнес-таблицы PostgreSQL.

Источник Активных строк Целевая обработка
FACULTY 6 faculty, исходный ключ в реестре соответствий
CHAIRS 47 chair; FacultyNo=46/48 направляются на сверку отсутствующей связи
TEACHERS 866 teacher, отдельные квалификационные поля и закрытая заметка
SUBJECTS 5 068 subject; полное/короткое названия и исходный SubjectChar сохраняются
Courses 12 course_category; CourseCount — исходный атрибут, не год обучения
GROUPS 554 academic_group, неподтвержденная схема подгрупп по NSubgroups; факультет и классификатор курса по ID
STREAMS 140 named_cohort; никаких связей с группами по сходству названий
Rooms 184 room и отдельный room_type; исходный RoomSpec сохраняется без догадки о назначении
DAYS 6 Таблица соответствия исходных дней 0–5; для новой модели — ISO-день 1–7 и реальные даты
TIMES 8 Начала bell_slot; окончания требуют ввода/подтверждения до генерации календаря
Plan 4 748 curriculum_plan; Stable сохраняется как исходный признак без присвоения is_fixed
PLANITEM 7 098 plan_component; PlanQty и GrpSplit сохраняются, объем имеет единицу unknown до подтверждения
GRPPLAN 21 419 plan_participant; полная комбинация плана, группы и подгруппы, без потери повторных членств
PLANROOM 0 Поддержать схему связи с plan_room_preference; пустота не доказывает работавший механизм предпочтений
Classes 15 111 Основной источник занятий; импортируемая потребность и исходные координаты, календарные экземпляры только после подтверждения декодирования
CLASSINF 0 Самостоятельный источник дополнительных ресурсов; схема и пустой набор сохраняются, функция нескольких ресурсов — расширение
ClassesInf 15 111 Служебный снимок для сверки; не создает дополнительные занятия и не перезаписывает Classes автоматически
TCHRRSTR 4 541 Исходные ограничения преподавателей; нормализованные availability_rule после подтверждения смысла Week, привязки и длительности
ROOMRSTR 990 Аналогично ограничениям преподавателей, с ресурсом комнаты
class_details Представление Воспроизвести как чтение/DTO с обогащенными названиями; не импортировать как новые строки занятий
plan_group_membership Представление Воспроизвести запросом связей участников плана; не считать отдельным источником данных
_source_manifest Служебная таблица Перенести метаданные происхождения файлов; не включать в количество бизнес-строк

Итого в 19 исходных таблицах 75 909 активных строк, включая связи и вспомогательную копию; фактических строк Classes — 15 111. Количество объектов в нормализованной модели может отличаться из-за разложения связей, но отчет объясняет каждое отличие. Названия источников регистрозависимы: CLASSINF и ClassesInf — две разные таблицы. Импортер не нормализует их к одному имени.

Происхождение, промежуточное хранение и разрешение неопределенностей§

Таблица Обязательные данные
import_batch UUID; SHA-256 пакета и SQLite; дата; пользователь; версия импортера; версия и hash правил; целевой период/редакция; статусы uploaded/validated/needs_resolution/ready/committed/failed/rolled_back; агрегированные счетчики
import_source_file Пакет, точное имя и регистр файла, размер, SHA-256, исходная кодировка, схема, счетчик заголовка и активных строк
import_raw_row Файл/таблица, исходный составной ключ JSON, порядковый номер, hash содержимого, raw_payload jsonb, статус разбора
import_issue Пакет, исходная строка/поле, код проблемы, уровень, текст объяснения, возможные решения, принятое решение, автор и время
legacy_identity Пространство имен источника, точное имя таблицы, канонический исходный ключ, UUID целевой сущности, тип сущности; уникальность исходной идентичности
import_entity_change Пакет, целевая сущность, действие создания/изменения, версии до/после, исходная строка; база для проверки и безопасного отката

В legacy_identity для справочника целевая идентичность соответствует устойчивому UUID, а для сущности редакции — ее logical_id; конкретный UUID строки и редакция фиксируются в import_entity_change. Копирование черновика не меняет исходное соответствие и не создает нового исходного ключа. Реестр идентичности либо отдельные типизированные связи обеспечивают FK до целевых сущностей; полиморфный идентификатор без проверки существования не считается достаточным.

Для ClassesInf, не имеющей PK, сохранять порядковый номер в конкретном исходном файле и hash строки; проверять мультимножество, не превращая порядок строк в бизнес-идентификатор. Повторяющиеся одинаковые строки этой вспомогательной таблицы не теряются. raw_payload сохраняет NULL, 0, -1, логические значения, пробелы и полный текст; значения не публикуются в технических логах. Все 88 исходных полей доступны пользователю с правом просмотра исходных данных, в том числе если их нормализация заблокирована.

MIG-02. Импорт обязан иметь отдельную страницу «Требует сопоставления». Нерасшифрованная строка не исчезает и не объявляется отсутствующей: доступны исходные поля, связанные записи, проблема и ввод решения. Загрузка исходного архива может быть успешно завершена, даже если календарная нормализация части записей не готова. Это не дает права объявлять завершенной миграцию редактируемого расписания. Пользователь видит раздельные счетчики «сохранено исходных», «нормализовано», «ожидает решения», «отклонено».

Обязательные правила для данного снимка:

  1. Classes.GroupNo=-1 раскрывается через GRPPLAN того же PlanNo; это 3 458 записей, в том числе с единственной группой. Прямая группа раскрывается только как указанная группа/подгруппа, а не как все участники плана. Исходная форма связи сохраняется.
  2. TeacherNo=-1 и RoomNo=-1 в Classes преобразуются в отсутствие назначения только по явному правилу соответствующего поля. Для Rooms.ChairNo=0 и -1 сохраняются разные исходные значения до объяснения их различия. Глобальная замена нуля на NULL запрещена: исходный день 0 — понедельник, а Week=0 — наблюдаемое значение ограничения.
  3. Положительные CHAIRS.FacultyNo=46/48, отсутствующие в FACULTY, создают две проблемы связи. Допускается сопоставить существующий факультет, создать подтвержденный недостающий либо явно оставить кафедру без факультета с причиной. Создавать фиктивный факультет только ради FK нельзя.
  4. Все 554 значения GROUPS.StreamNo=-1 не создают членства в 140 строках STREAMS. Участники объединенных занятий определяются планом; название старого потока не заменяет эти связи.
  5. CourseNo и равный ему в этом снимке CourseCount являются исходными числовыми атрибутами классификатора. Например, код 6 соответствует первому курсу магистратуры. Реальный год обучения оставляется пустым до подтверждения.
  6. Classes.DayNo сохраняется целиком. Проверенное арифметическое свойство DayNo % 14 ∈ 0..5 не является утвержденным календарным алгоритмом. До подтверждения точки отсчета, периодов, EachWeek/OddWeek, статуса Assigned и окончания пар даты не рассчитываются, бронирования не создаются. Неразмещенная новая потребность и исходная строка с неизвестной интерпретацией различаются в интерфейсе.
  7. Для ClassesInf журнал фиксирует 15 124 строки в заголовке против 15 111 активных. Не добавлять 13 пустых строк и не считать их восстановленными. Зафиксировать также одно расхождение комнаты с основной Classes; выбор значения допускается только явным решением. По умолчанию основной источник занятий — Classes.
  8. PlanQty, Stable, коды видов занятий, RoomSpec, SubjectChar и смысл Week в ограничениях не получают новой бизнес-семантики по созвучию. Исходные значения сохраняются; согласованные трактовки оформляются версионированным набором правил. Заполнение правил выполняется через интерфейс, а не скрытой правкой SQL.
  9. Классификация всех групп воспроизводит POLICY-02 по уточнениям владельца с сохранением исходного обозначения и версии правил. Онлайн-признак и форма независимы; неизвестные будущие коды требуют сопоставления. Временной профиль не участвует в определении формы.
  10. Исторические многозаписные клетки направляются в проверку FR-065; импорт сохраняет все строки и M:N-связи происхождения. Справочники с одинаковыми названиями не сливаются. Принятие совместности, календарной развёртки и правил зачёта нагрузки — отдельные решения; один legacy_identity не заменяет source_occurrence_link.
  11. Полнота исходника, реконструкция модельных координат и готовность реального календаря имеют разные статусы. Сравнение ограничений по наиболее согласованным слоям не подтверждает их строгую обязательность; расхождения вместимости не создают разрешения превышения. Применимость неизвестных ограничений и требования публикации закрываются по FR-068.

Порядок и повторяемость импорта§

MIG-03. Импорт состоит из отдельных шагов: загрузка и проверка пакета; сохранение исходных строк; проверка схемы, PK и связей; предварительное сопоставление; решение неопределенностей; предпросмотр изменений; подтверждение переноса; сверка результата. После загрузки все исходные таблицы доступны в защищенном браузере данных. Предпросмотр показывает новые и измененные сущности, неразрешенные вопросы, конфликты, отличия от действующего черновика и ожидаемые счетчики.

MIG-04. Повтор того же пакета с теми же правилами и целевой областью возвращает уже полученный результат без дублей. Ключ идентичности импорта включает hash пакета, hash правил, версию импортера и целевую область. Новый снимок того же источника сопоставляется по исходным ключам, но автоматически не затирает пользовательские изменения: конфликт версии требует выбора или импорта в новый подготовительный набор. Исчезновение строки из нового снимка не означает команду удаления.

MIG-05. Подтверждение переноса выполняется транзакционно в разрешенный черновик. Для больших наборов разрешено заранее формировать изолированный подготовительный набор и транзакционно переносить его в рабочий черновик после полной проверки. Публикация остается отдельной явной командой. Нельзя «успешно импортировать» первую часть, оставив половину ссылок незаписанной, или очищать рабочие таблицы перед проверкой пакета.

MIG-06. До подтверждения отмена импорта не меняет рабочий черновик. После подтверждения откат восстанавливает предыдущую редакцию или создает компенсирующую редакцию по журналу, сохраняя пакет и аудит. Если появились последующие ручные изменения, система показывает различия и блокирует разрушительный автоматический откат. Опубликованный импорт исправляется новой публикацией; удаление истории не является допустимым способом отката.

Приемка модели, конфликтов и миграции§

Проверка Ожидаемый результат
AC-D01. Полнота исходников Для контрольного SQLite сохранены 19 таблиц, все 88 полей и 75 909 активных строк; две views и манифест учтены отдельно; исходный SHA-256 не изменился
AC-D02. Повторный импорт Два запуска одного пакета с теми же правилами дают одинаковые счетчики и UUID соответствий, без новых копий справочников и занятий
AC-D03. Вспомогательные таблицы CLASSINF остается отдельным пустым источником; 15 111 строк ClassesInf не увеличивают число исходных занятий; расхождение счетчика 13 и одна аудитория видны в отчете
AC-D04. Нерасшифрованный календарь При неподтвержденном DayNo все исходные записи доступны для просмотра, но ни одна дата не придумана и занятость не создана на основании имени папки
AC-D05. Полнота расписания группы Для группы с GroupNo=434109 исходный просмотр возвращает 79 уникальных занятий: 39 прямых и 40 через план. Для всех 554 групп результат совпадает с проверенным раскрытием связей; суммарно 17 727 пар «занятие–группа» при 15 111 исходных занятиях
AC-D06. Состав участников Одна группа в двух планах сохраняет оба членства; несколько ее подгрупп в одном плане не дублируют само занятие в выдаче группы и не удваивают полную численность
AC-D07. Служебные значения Преподаватель/комната -1 отображаются как неназначенные с сохранением исходного числа; день 0 остается понедельником; кафедры с FacultyNo 46/48 требуют отдельного решения
AC-D08. Ресурсы в черновике Размещенное по известной дате занятие без комнаты сохраняется в черновике с отметкой неполноты; режим, требующий аудиторию, блокирует публикацию, а дистанционный режим по утвержденным правилам — нет
AC-D09. Граница интервалов [08:00,09:30) и [09:30,11:00) одного ресурса допустимы; [08:00,09:31) и [09:30,11:00) отклоняются
AC-D10. Группа и подгруппы Занятие всей группы конфликтует с каждой ее подгруппой; подтвержденные разные атомы допускают параллельность; неподтвержденная схема блокирует ее с понятной причиной
AC-D11. Гонка двух пользователей Два независимых соединения одновременно бронируют один ресурс на пересекающееся время: ровно одна операция завершается, другая получает 409; в БД нет двойной занятости
AC-D12. Обмен и откат Обмен двух слотов фиксируется целиком; ошибка третьего ресурса откатывает оба переноса и связанные бронирования, оставляя прежнее расписание
AC-D13. Запреты ресурсов Перекрывающиеся жесткие запреты объединяются без потери причин; занятие внутри них отклоняется; снятие одного правила не снимает другое
AC-D14. Повторение и исключение Отмена одного экземпляра сохраняется после повторной генерации; перенос одного экземпляра не создает дубль на исходную дату; область «следующие» не меняет прошедшие экземпляры
AC-D15. Версии и публикация Старый номер публикации сохраняет занятия, подписи и состав участников после правки справочника и выпуска новой версии; прямое изменение frozen-редакции отклоняется
AC-D16. Несколько периодов Конкурирующие публикации разных периодов с одним преподавателем либо пересекающимися участниками одной группы не могут обе стать действующими, включая разные UUID атомов двух схем; неизвестное пересечение схем блокирует активацию; предыдущая публикация сохраняется при неуспехе
AC-D17. Безопасный откат импорта Откат не удаляет последующие ручные изменения и исходный пакет; при их наличии требуется разрешение конкретных различий либо новая компенсирующая редакция

Численные проверки исходного снимка являются обязательными регрессионными фикстурами миграции. Проверки гонок должны выполняться на PostgreSQL с отдельными соединениями и реальными транзакциями; тест на SQLite или последовательный вызов одной функции не подтверждает защиту от одновременного редактирования.

Архитектура и технологический стек§

Общая схема§

SYS-002. Реализовать модульное серверное приложение с единой предметной моделью и одной основной PostgreSQL. Отдельные процессы API и фонового обработчика используют один и тот же прикладной код и правила. Бизнес-операции не дублируются в React, SQL-скриптах импорта и служебной административной панели.

Архитектура веб-приложения
Архитектура веб-приложенияБраузер обращается к Nginx по HTTPS, Nginx — к Django API. API связан с PostgreSQL и приватными файлами. PostgreSQL содержит фоновые задания. Celery worker обменивается сообщениями с Redis и работает с PostgreSQL и файлами. Для PostgreSQL и файлов предусмотрены резервные копии. HTTPSБраузер пользователяNginx: статика и проксиDjango REST APIPostgreSQLПриватные файлы импортаи экспортаСохранённые фоновыезаданияCelery worker идиспетчер заданийRedis: доставка задачРезервные копии

На узком экране схему можно прокручивать по горизонтали.

Исходный код схемы
flowchart LR
    U[Браузер пользователя] -->|HTTPS| N[Nginx: статика и прокси]
    N --> A[Django REST API]
    A --> P[(PostgreSQL)]
    A --> F[Приватные файлы импорта и экспорта]
    P --> O[Сохранённые фоновые задания]
    O --> W[Celery worker и диспетчер заданий]
    W <--> R[Redis: доставка задач]
    W --> P
    W --> F
    P --> B[Резервные копии]
    F --> B

В схеме PostgreSQL хранит предметные данные, версии, журнал и состояния заданий. Redis используется для доставки небольших сообщений с идентификатором задания. Файлы базы и полные наборы строк не отправляются через очередь. Копия утверждённой выдачи не получает прав редактирования черновика.

Приёмка SYS-002: одинаковый перенос через интерфейс, API и пакетную операцию вызывает один механизм правил и даёт одинаковые конфликты; администратор Django не может обойти эти правила редактированием бронирований.

Рекомендуемый базовый стек§

Выбор стека ниже — проектная рекомендация для автономной серверной работы. Совместимость веток проверена по официальной документации на дату ТЗ; конкретные исправленные версии и образы фиксируются исполнителем при старте разработки и обновляются контролируемо.

Слой Базовый выбор Назначение и ограничение
Клиент React 19, TypeScript в строгом режиме Сетка расписания, формы, таблицы, клиентское состояние; сервер остаётся источником правил
Сборка клиента Vite 8, Node.js 24 LTS Сборка статических файлов в CI/установочном комплекте; Node не требуется как отдельный production-сервер для этой SPA
Сервер Python 3.13, Django 5.2 LTS ORM, миграции, пользователи, сессии, транзакции, административные операции
API Django REST Framework 3.16 или совместимая поддерживаемая версия Сериализация, объектные права, единый REST-контракт, JSON и OpenAPI
СУБД PostgreSQL 18 с актуальным исправляющим выпуском FK, транзакции, история, поиск, диапазоны времени и защита бронирований
Драйвер БД Psycopg 3, совместимая версия Доступ Django к PostgreSQL; управляемые параметры соединений
Фоновые задачи Celery 5.6, Redis 8 как брокер Импорт, формирование больших экспортов, подготовка снимков; надёжность обеспечивается также записью задания в PostgreSQL
HTTP-процесс Python Gunicorn, поддерживаемая совместимая версия Запуск Django за Nginx; число процессов/потоков выбирается по измерениям
Входящий HTTP Nginx и TLS Статические файлы, проксирование, ограничения запросов, защищённая выдача экспортов
Поставка Docker Engine и Docker Compose Воспроизводимый запуск API, worker, PostgreSQL, Redis и Nginx на одной машине
Проверки pytest/pytest-django, Playwright, средства проверки TypeScript и кода Тестирование на настоящем PostgreSQL, пользовательские сценарии и проверки сборки

React 19.2 указан в актуальной линейке документации; Vite 8 предъявляет требования к Node, которым выбранная LTS-ветка 24 соответствует. Эти сведения не являются требованием использовать устаревший исправляющий выпуск. React: версии, Vite 8, Node.js: график поддержки.

Django 5.2 — LTS-ветка с расширенной поддержкой до апреля 2028 года; DRF 3.16 документирует совместимость с Django 5.2 и Python 3.13. До окончания поддержки должен быть выполнен плановый переход на поддерживаемую ветку. Django: поддерживаемые версии, DRF 3.16.

Для PostgreSQL 18 предусмотрена поддержка до ноября 2030 года; эксплуатация должна использовать актуальные исправления выбранной основной версии. PostgreSQL: политика версий. Redis входит в документированные стабильные брокеры Celery; состояние выполнения важных операций следует сохранять в PostgreSQL независимо от брокера. Celery: брокеры и хранилища результатов.

Правила выбора зависимостей§

SYS-003. Поставить pyproject.toml и lock-файл Python, package.json и lock-файл JavaScript, Dockerfile и Compose-файлы. Образы выпуска закрепляются тегом версии и digest; тег latest не считается воспроизводимой поставкой. В документации выпуска перечислить фактически проверенные версии.

SYS-004. В B не требуются Kubernetes, микросервисы, отдельный поисковый кластер, обязательная коммерческая облачная БД или платная библиотека календаря. Визуальную сетку разрешено строить на проверенной библиотеке с подходящей лицензией или собственных компонентах; предметные ограничения расписания должны оставаться в серверном домене.

SYS-005. Клиентские шрифты, скрипты и стили поставляются локально. После установки система должна выполнять основные функции при недоступности внешнего Интернета, если пользователь имеет сетевой доступ к серверу. Для установки пакетов, обновлений, внешнего резервного хранения и продления публичного TLS-сертификата могут потребоваться отдельные сетевые соединения. Внутрисетевая установка должна поддерживать сертификат заказчика.

Приёмка SYS-003–005: зафиксированный выпуск собирается на чистой машине; после сборки запросы браузера не требуют CDN, API лицензирования или стороннего аккаунта; отключение брокера не повреждает сохранённые занятия и не блокирует обычное чтение и ручное редактирование.

Прикладные модули§

Модуль Ответственность
identity Пользователи, сессии, роли, области доступа
catalogs Подразделения, группы, подгруппы, преподаватели, дисциплины, аудитории
academic_calendar Учебные периоды, даты, календарные исключения, сетки звонков
curriculum Позиции плана, виды и объёмы потребности, состав участников
scheduling Серии и экземпляры, назначения, перестановки, замены, блокировки
constraints Пересечения, запреты, вместимость, качество и полнота
policy Версии и согласование правил, временные профили, совместимость помещений, исключения, единая проверка ручных и фоновых команд
quality Версионированные метрики, полнота, сравнение последствий и защищённые профили; расчёт по снимкам, без изменения расписания
publication Согласование, неизменяемые снимки и текущая опубликованная выдача
migration Приём SQLite, исходные записи, сопоставления, протоколы импорта
audit Автор, причина, до/после, связь действий в одну операцию
jobs / exports Фоновые задания, печать/экспорты, временные файлы

Границы модулей — границы ответственности внутри одного репозитория. Общие модели и транзакции не заменяются сетевыми запросами между «микросервисами». Служебная панель Django предназначена прежде всего для технических справочников и пользователей; пользовательский редактор должен быть полноценной частью веб-интерфейса.

Рекомендуемая структура поставки:

backend/                 Django-приложения, доменные операции, миграции
frontend/                React/TypeScript, формы, сетка, клиент API
tests/                   интеграционные, конкурентные, нагрузочные сценарии
fixtures/                обезличенные и синтетические тестовые данные
deploy/                  Dockerfile, Compose, Nginx, резервное копирование
docs/                    OpenAPI, ER-схема, инструкции, решения по архитектуре
scripts/                 импорт, диагностика и контролируемое обслуживание

Фоновые задания и отказоустойчивость операций§

SYS-006. Импорт, большой экспорт и формирование объёмного снимка выполняются асинхронно. HTTP-запрос регистрирует задание и возвращает его ID. Пользователь видит статус queued/running/succeeded/failed/cancelled, фазу, счётчики обработанных строк, ошибки и ссылку на разрешённый результат. Процент показывается только при известном знаменателе.

Запись задания и сообщение outbox создаются в одной транзакции PostgreSQL. Диспетчер отправляет ожидающие сообщения в Celery и умеет повторять отправку. Повторная доставка не должна повторно применять импорт или создавать две публикации. Worker фиксирует попытку, lease/heartbeat и результат в PostgreSQL; задача с истёкшей арендой может быть безопасно повторена.

Служебный диспетчер разрешается запускать отдельным лёгким процессом или системным расписанием. В одной установке должен быть один активный диспетчер либо БД-блокировка, исключающая конфликтующее управление. Простого on_commit(send_task) без восстанавливаемой записи задания недостаточно: необходимо обработать отказ между фиксацией данных и доставкой сообщения.

Приёмка SYS-006: остановка worker во время подготовки импорта не оставляет частично активированный семестр; повторный запуск доводит задание до однозначного состояния. Очистка брокера не удаляет предметные данные и не теряет задания, зарегистрированные в PostgreSQL. Повторная доставка одной команды не изменяет итог второй раз.

Требования к HTTP API§

Общие правила контракта§

API-001. Предоставить версионированный API /api/v1/ и спецификацию OpenAPI. Для публичного представления при его включении использовать отдельный набор маршрутов и сериализаторов, например /api/public/v1/. Авторизация обязательна для каждого внутреннего маршрута, а не только для страницы клиента.

API-002. Использовать JSON UTF-8. Идентификаторы сущностей — UUID в строковом виде; старые числовые ID доступны только как сведения происхождения. Время события передавать ISO 8601 с явным смещением, дополнительно возвращать часовой пояс периода. Числовые объёмы с дробной частью передавать десятичной строкой, если требуется точность; NULL, пустая строка и ноль имеют разные значения.

API-003. Списки поддерживают ограниченную пагинацию, поиск и белый список сортировок. По умолчанию 50, максимум 200 записей на страницу. Календарная выдача ограничивается периодом запроса и числом событий; при превышении лимита возвращается требование сузить фильтр, а не непомеченная усечённая сетка. Для всех выборок задаётся стабильный дополнительный порядок по ID.

API-004. Проверка прав и фильтра области ответственности выполняются на сервере до выдачи объектов. Подмена department_id, period_id, UUID или параметров экспорта не должна расширять доступ. Общий просмотрщик данных использует такой же контроль; произвольного SQL, загрузки серверного файла по пути и прямого доступа к таблицам пользователей через него нет.

Основные группы маршрутов§

Названия маршрутов ниже задают рабочий контракт для согласования; окончательный OpenAPI должен содержать поля, примеры, права, ошибки и ссылки на требования. Префикс /api/v1 в таблице опущен.

Метод и маршрут Назначение
POST /auth/login, POST /auth/logout, GET /auth/me Вход, завершение сессии и собственные права
GET/POST /users, PATCH /users/{id} Управление пользователями в пределах административных полномочий
GET/POST /faculties, /departments, /course-labels Организационные справочники и классификатор обучения
GET/POST /groups, GET/PATCH /groups/{id}, GET /groups/{id}/subgroups Группы и подгруппы
GET/POST /teachers, /subjects, /rooms Справочники преподавателей, дисциплин и аудиторий
POST /{catalog}/{id}/archive Контролируемое архивирование справочной записи
GET/POST /academic-periods, GET/PATCH /academic-periods/{id} Учебный период и его рабочие параметры
GET/POST /academic-periods/{id}/calendar-rules Календарь, рабочие даты и исключения
GET/POST /bell-schedules, PATCH /bell-schedules/{id} Начала и окончания временных слотов
GET/POST /plan-entries, GET/PATCH /plan-entries/{id} Учебные потребности, виды нагрузки и участники
POST /plan-entries/{id}/generation-preview Предварительный расчёт экземпляров по подтверждённым правилам
POST /plan-entries/{id}/generate Идемпотентное создание подтверждённого набора экземпляров
GET /schedule-revisions/{id}/events Датированные занятия черновика или разрешённой версии
GET /schedule-revisions/{id}/events?date=YYYY-MM-DD Режим «День»: фильтр по локальной дате периода; те же ID событий, что у недельной и списочной выдачи, включая разовые проведения и исключения
GET /schedule-revisions/{id}/unplaced Неразмещённые занятия
GET/PATCH /events/{id} Карточка и изменение разрешённых простых полей
POST /events, POST /event-series Отдельное занятие и серия повторений
POST /events/{id}/move-preview, POST /events/{id}/move Проверка и применение переноса
POST /events/{id}/move-groups-preview, POST /events/{id}/move-groups Предпросмотр и атомарный перенос выбранных групп одного календарного проведения по FR-069; по умолчанию остальные участники и даты не меняются
POST /events/swap Атомарный обмен местами двух занятий
POST /events/{id}/replace-teacher, /replace-room Замена ресурса с повторной проверкой
POST /events/{id}/unplace, /cancel, /restore Размещение снять, занятие отменить либо восстановить по правилам
POST /event-series/{id}/change-preview, /apply-change Изменение одного, будущих либо всех экземпляров серии
POST /events/{id}/lock, /unlock Управление явно определённым закреплением
GET/POST /resource-restrictions, PATCH /resource-restrictions/{id} Ограничения доступности
GET /rooms/availability Поиск помещений на дату и интервал с выбранными требованиями
POST /schedule-revisions/{id}/validate Проверка полноты, предупреждений и готовности к публикации
POST /department-requests, POST /department-requests/{id}/submit Передача потребности и отправка предложения кафедры
POST /department-requests/{id}/accept, /reject Принятие или возврат предложения уполномоченным сотрудником
POST /schedule-revisions/{id}/publish Публикация проверенной версии с защитой от гонок
GET /publications, GET /publications/{id}, POST /publications/{id}/activate История, чтение и контролируемое повторное назначение активной версии
POST /imports, GET /imports/{id}, GET /imports/{id}/issues Загрузка снимка, анализ и ошибки
POST /imports/{id}/mapping, /preview, /commit Сопоставления, предварительная проверка и подтверждённое применение
GET /data/catalog, GET /data/{entity}/rows Просмотр разрешённых нормализованных данных и исходных записей импорта
POST /exports, GET /jobs/{id}, GET /exports/{id}/download Фоновая выгрузка и защищённое получение результата
GET /audit-events Журнал в пределах прав пользователя
GET /health/live, GET /health/ready Минимальная проверка процесса и готовности, без секретов и структуры БД
GET/POST /policy-versions, GET /policy-versions/{id}, PATCH /policy-versions/{id}/rules/{ruleId} Создание и изменение только черновой политики; просмотр версии и оснований по правам
POST /policy-versions/{id}/submit, /approve, GET /policy-versions/{id}/diff Согласование, утверждение неизменяемой версии, сравнение правил
POST /schedule-revisions/{id}/policy-preview, /apply-policy Последствия и атомарная привязка утверждённой политики с проверкой версии редакции
GET/POST /policy-versions/{id}/time-profiles, /room-compatibility, /building-transfers Конфигурация профилей и ресурсов по FR-062/FR-066; запись только в черновую политику
GET/PATCH /groups/{id}/study-profile, POST /groups/{id}/study-profile/confirm Профиль группы в явно переданной редакции; классификация и подтверждение по правам
POST /schedule-revisions/{id}/placement-preview Последствия заданного варианта: правила, непроверенные условия, раздельные изменения качества; без бронирования
POST /schedule-revisions/{id}/quality-runs, GET /quality-runs/{id} Фоновый расчёт, фильтры, единицы и неизменяемый отчёт с актуальностью
GET /imports/{id}/joint-candidates, POST /joint-deliveries/preview, /confirm, /split-preview, /split Сравнение, подтверждение и разъединение совместных проведений с сохранением происхождения и обычными проверками
POST /rule-exceptions, POST /rule-exceptions/{id}/approve Исключение только в разрешённых политикой пределах, со сроком, объектами и полномочиями

API-010. Контракт политики. Предпросмотр возвращает revision_id, expected_revision_version, policy_version_id, policy_sha256, версии использованных ресурсов и классификации, blocking_errors, publication_blockers, warnings, unverified_conditions, quality_before, quality_after, quality_delta. Каждый результат содержит rule_code, область и разрешённые пользователю ссылки на объекты; показатели включают единицу, числитель, знаменатель и охват. Подтверждение передаёт ID предпросмотра и ожидаемые версии; сервер заново проверяет их и актуальную допустимость внутри транзакции. Недоступный по правам источник не раскрывается через объяснение ошибки.

Доменные коды: POLICY_NOT_APPROVED, POLICY_SCOPE_UNRESOLVED, TIME_PROFILE_CONFLICT, CAPACITY_UNVERIFIED, CAPACITY_EXCEEDED, JOINT_DELIVERY_UNCONFIRMED, RESOURCE_COMPATIBILITY_UNKNOWN, CLASSIFICATION_UNRESOLVED. Они используют общую оболочку API-008: нарушение правила — 422, конфликт занятости — 409, устаревшая ожидаемая версия — 412. Возврат can_publish=false в успешном отчёте проверки отличается от успешной публикации. PATCH простых полей не обходит команды утверждения, совместности или проверки размещения.

API-011. Даты и перенос группы. date задаёт полный локальный календарный день в часовом поясе периода; отсутствие событий возвращает пустой набор. Одновременное указание одиночной даты и альтернативного диапазона отклоняется как неоднозначный фильтр. DTO события во всех представлениях содержит delivery_mode=onsite/online и реальные начало/окончание; он не раскрывает реквизиты подключения публичному читателю.

Команды move-groups-preview/move-groups принимают group_ids — непустой набор ID участвующих групп, start_at/end_at со смещением, scope=occurrence, причину и ожидаемые версии по API-005/010. Длительность по умолчанию сохранена; её изменение выполняется обычной отдельной командой. Необязательные teacher_id/room_id означают явно выбранную замену; отсутствие поля сохраняет прежний ресурс, room_id=null явно снимает комнату с учётом формата и правил полноты. Пустые/посторонние группы, неподдерживаемая область серии и невалидная дата отклоняются. Предпросмотр возвращает оба состава, связи потребностей, конфликты, изменение нагрузки, ID предпросмотра и режим результата split/move/no_change.

Применение требует ID предпросмотра, совпадения его параметров и ожидаемых версий, а также If-Match исходного экземпляра и Idempotency-Key. Проверяются права на исходное и получаемое проведения, вся редакция и актуальные ресурсы. split атомарно возвращает исходное и выделенное проведения плюс ID общей операции; move возвращает перенесённый исходный экземпляр; no_change не создаёт событий или исключений. Ошибка занятости — 409, устаревшая версия — 412, недопустимый состав/интервал — 422. Самостоятельное создание копии события клиентом вместо доменной операции запрещено.

Изменения, повторные запросы и ошибки§

API-005. Карточка изменяемой сущности содержит version: bigint и ETag. Изменение существующей сущности требует If-Match её версии; отсутствие обязательного условия — 428 Precondition Required, устаревшая версия — 412 Precondition Failed. Создание нового объекта не требует несуществующего ETag: для дочернего объекта передаётся expected_revision_version родительской редакции, для нового независимого справочника действуют проверки уникальности и Idempotency-Key. Обмен и массовая операция передают expected_revision_version и версии всех изменяемых объектов; сервер проверяет их совместно в одной транзакции. Ответ включает доступную пользователю текущую версию и позволяет обновить карточку. Автоматическая перезапись последнего изменения другого диспетчера запрещена.

API-006. Команды создания, переноса, обмена, массового изменения, импорта и публикации принимают Idempotency-Key. Ключ связан с пользователем, видом операции, областью и хешем нормализованного тела. Повтор одного ключа с тем же запросом возвращает исходный результат; с другим телом — 409. Для обычных команд результат хранится не менее 24 часов; для импорта и публикации сохраняется постоянный идентификатор операции и её происхождения.

API-007. Предварительная проверка возвращает проект результата, список затронутых записей, ошибки/предупреждения и версии входных данных. Предпросмотр не резервирует аудиторию навсегда. При применении сервер повторяет проверку и фиксирует изменения в транзакции. Если ресурсы или правила изменились, прежний результат не считается разрешением обойти конфликт.

Пример команды переноса; UUID условные, дата относится к новому тестовому расписанию, а не к восстановленной дате старого DayNo:

POST /api/v1/events/11111111-1111-4111-8111-111111111111/move
If-Match: "17"
Idempotency-Key: 7f2f9d79-d7b8-492d-b99f-1a839d6d1111
Content-Type: application/json
X-CSRFToken: <токен сессии>

{
  "start_at": "2026-09-14T09:40:00+07:00",
  "end_at": "2026-09-14T11:10:00+07:00",
  "room_id": "22222222-2222-4222-8222-222222222222",
  "scope": "occurrence",
  "reason": "Изменение доступности помещения"
}

Пример структурированной ошибки:

{
  "code": "RESOURCE_CONFLICT",
  "message": "Аудитория занята в выбранное время",
  "request_id": "46d75d83-923f-48f6-a082-95c0cd7d1111",
  "conflicts": [{"resource_type": "room", "start_at": "2026-09-14T09:00:00+07:00", "end_at": "2026-09-14T10:30:00+07:00"}],
  "field_errors": {}
}

API-008. Установить общую семантику кодов: 200/201 — выполнено, 202 — задание зарегистрировано, 400 — неверный формат, 401 — нет действующей сессии, 403 — нет права, 404 — объект отсутствует или скрыт областью доступа, 409 — предметный конфликт/повтор ключа с иным телом, 412/428 — версия, 422 — невозможное значение или бизнес-правило, 429 — ограничение частоты, 503 — временная неготовность зависимости. Обёртка ошибки одна для всех маршрутов. Сведения о конфликтующих занятиях за пределами прав пользователя заменяются нейтральным сообщением о занятости.

API-009. Зафиксировать лимиты входных списков и максимальное число изменяемых событий. Рабочий предел одной синхронной команды — 200 экземпляров; больший набор обрабатывается заданием с предпросмотром. Публикация большого снимка подготавливается в фоне и активируется атомарно. Ни один лимит не допускает частичного молчаливого применения.

Приёмка API-001–011: спецификация проверяется в CI; клиент строится против этого контракта; неизвестные поля, недопустимые ID, повторы команд, устаревшие версии и попытки доступа к чужому подразделению проверяются автоматическими сценариями. Контракт политики дополнительно проверяется сценариями AP-07, AP-10, AP-17 и AP-18; календарные операции и онлайн-формат — AP-19–AP-23.

Безопасность, доступ и защита данных§

Учётные записи и сессии§

SEC-001. Каждый сотрудник работает под индивидуальной учётной записью. Общий пароль текущего исследовательского просмотрщика не переносится в новый продукт. При установке создаётся первый администратор безопасной командой; в поставке отсутствуют заранее заданные рабочие пароли.

SEC-002. В B использовать серверные сессии Django, защищённые cookies HttpOnly, Secure, SameSite=Lax и CSRF-защиту изменяющих запросов. Серверные сессии хранятся в PostgreSQL; отказ Redis не должен разлогинивать всех пользователей. Долгоживущие токены в localStorage не используются. Авторизация для API проверяется явно и тестируется отдельно от middleware HTML-страниц. Публичный и внутренний API разделены.

SEC-003. Пароли сохраняются стандартным поддерживаемым адаптивным хешированием Django. Базовая политика: не менее 12 символов, проверка очевидных/распространённых паролей, ограничение частоты неудачных входов с нарастающей задержкой. Политика не должна позволять злоумышленнику навсегда заблокировать другого пользователя несколькими запросами. Выход и административное отключение аккаунта прекращают его сессии. По умолчанию: 8 часов абсолютной длительности и 60 минут неактивности; при приближении тайм-аута показать предупреждение без потери текста формы.

SEC-004. Сброс пароля в автономном профиле выполняет уполномоченный администратор через одноразовый временный секрет с принудительной сменой. Почтовое восстановление и единый вход подключаются отдельной настройкой/расширением. Отсутствие SMTP не должно блокировать эксплуатацию.

Поля, объекты и внешняя выдача§

SEC-005. Применять разрешения к спискам, карточкам, поиску, счётчикам, журналу, заданиям, экспорту и файловым ссылкам. По одному UUID нельзя получить чужое задание импорта или приватные поля недоступного подразделения. Возможность посмотреть занятия преподавателя не тождественна праву читать его внутреннюю заметку.

SEC-006. Зафиксировать классификацию полей: публичные поля опубликованного расписания; внутренние рабочие поля; ограниченные заметки и исходные данные импорта; технические секреты. Внешний сериализатор выдаёт только разрешённые поля: дата/интервал, дисциплина, вид занятия, группы/подгруппы, разрешённое отображаемое имя преподавателя, формат проведения, аудитория и публичный комментарий. Внутренний комментарий, причина ограничений, служебные метаданные и реквизиты подключения в него не попадают. Публичная метка «Онлайн» не даёт права раскрывать закрытую ссылку, пароль или код подключения.

SEC-007. Разделить публичный комментарий и внутреннюю заметку в модели и форме. Не переносить текст из старого Comment/Reason/Memo в публичный комментарий автоматически. При включении анонимной выдачи выполнить предпросмотр точного состава полей. По умолчанию она выключена. Учётные данные приложения, SSH и СУБД вообще не являются пользовательскими полями расписания.

SEC-008. Все строки из импорта выводить как текст, с экранированием. Буквальное &nbsp; хранить как исходный текст до отдельного подтверждённого исправления. Произвольный HTML, JavaScript и SQL в заметках не выполняются. Для CSV учитывать формульные префиксы ячеек, чтобы выгрузка при открытии в табличном редакторе не выполняла формулы из введённого текста; изменение представления в CSV не меняет значение в БД.

Инфраструктурная защита§

SEC-009. Рабочий доступ — по HTTPS. PostgreSQL и Redis не публикуются в Интернет; API доступен через Nginx. Сервисная роль приложения в PostgreSQL не имеет SUPERUSER, права создавать роли и менять кластер; учётная запись миграций отделена от runtime. Процессы контейнеров выполняются без root, кроме минимальной необходимой подготовки окружения.

SEC-010. SQLite и архивы импорта считаются недоверенными входными файлами. Проверять сигнатуру, разрешённую схему/типы, размер, счётчики и целостность. Рабочий предел загрузки — 100 МБ с контролируемым изменением настройки; неизвестные таблицы сохраняются в диагностике, но не выполняются как схема PostgreSQL. Запрещены загрузка SQLite-расширений и выполнение SQL из входных данных. Импорт выполняется ограниченным worker с тайм-аутом и ограничением памяти. Поддержка архивов Paradox, если будет добавлена, требует защиты от выхода путей из каталога распаковки и архивных бомб.

SEC-011. Приватные файлы располагаются вне статического веб-каталога. Скачивание экспорта происходит после проверки владельца и области прав; неподписанная постоянная ссылка на файл не даёт доступ. Временные экспорты удаляются по расписанию, базовый срок — 24 часа. Удаление временного файла не удаляет запись о выполненном задании.

SEC-012. Пароли, токены, cookies, строки подключения и полные тела приватных запросов исключаются из access/error-логов. Журнал предметных действий сохраняет автора, время, вид операции, объект, причину и разрешённую разницу значений. Для технических секретов сохраняется факт изменения, а не прежний/новый секрет. Подробные приватные изменения доступны только специальному разрешению; общий аудит не является способом прочитать закрытые заметки.

SEC-013. В конфигурации выпуска: DEBUG=False, ограниченные допустимые Host, доверенные reverse proxy, ограниченный CORS или единый origin, защитные HTTP-заголовки. Применить поддерживаемый проверочный режим Django к production-настройкам. Django: проверка конфигурации развёртывания.

Приёмка SEC: негативные тесты доступа по прямым UUID и API, попытки CSRF, XSS и SQL-инъекций, выгрузки с формульными префиксами, просроченная сессия, отключённый аккаунт, приватная заметка в публичном ответе, неподтверждённый импорт и отсутствие открытых портов БД. Необработанная критическая уязвимость авторизации или раскрытие секретов блокирует выпуск.

Нефункциональные требования§

Проверочный профиль нагрузки§

Числа ниже — проектные целевые показатели для приёмки, а не результаты измерения ещё не разработанного приложения. Исполнитель должен воспроизвести профиль на выделенном стенде и приложить отчёт. Профиль изменяется вместе с бюджетом ресурсов при согласовании ТЗ.

Параметр стенда Рабочая величина
Ресурсы стенда без посторонней нагрузки 4 vCPU, 8 ГиБ RAM, SSD
Группы / преподаватели / аудитории 1 000 / 1 500 / 300
Учебные периоды 10 в истории; не менее 2 с пересекающимися рабочими датами
Датированные экземпляры 250 000 в БД, включая историю; не менее 50 000 в проверяемой редакции
Журнал 1 000 000 предметных изменений
Одновременные сессии 50 читателей и 10 редакторов
Длительность прогона 30 минут после отдельного прогрева
Базовый поток 20 запросов чтения/сек. и 2 изменения/сек.; пакетные задания проверяются отдельным сценарием

NFR-001. На указанном стенде p95 API-поиска справочника и выдачи страницы из 50 записей — не более 500 мс; p95 календарной выдачи выбранной недели до 100 групп и до 2 000 событий — не более 1,5 с; p95 одиночного изменения с повторной проверкой конфликтов — не более 1 с. Измерять успешные запросы отдельно от намеренно ошибочных. Доля неожиданных 5xx — менее 0,1%; намеренно полученный 409/412 не считается сбоем сервера.

NFR-002. На контрольном рабочем месте с современным браузером и каналом 20 Мбит/с, RTT до сервера 50 мс, первая полезная отрисовка выбранного расписания — до 3 с в 95% измерений. Сетка должна ограничивать объём DOM виртуализацией/постраничной загрузкой колонок и строк. Нельзя выдавать десятки тысяч событий в браузер для локальной фильтрации.

NFR-003. Предварительный разбор текущей SQLite и построение отчёта импорта укладываются в 60 с на контрольном стенде; счётчики и ошибки доступны независимо от возможности расшифровать даты. Для больших согласованных наборов допустимо фоновое выполнение с видимым состоянием. Полное время конвертации неизвестной календарной семантики в этот норматив не входит: оно зависит от принятия решения, а не от скорости кода.

NFR-004. Публикация 50 000 экземпляров подготавливается заданием; финальная блокирующая транзакция активации должна быть измерена и обоснована. Рабочий предел недоступности изменений выбранной редакции — 5 с; если он не достигается, требуется изменить реализацию подготовки/индексов и повторить измерение, а не скрыть продолжительную блокировку под анимацией. До переключения читатели видят целиком прежнюю версию, после — целиком новую.

NFR-015. Политика и качество. На том же стенде проверять 50 000 экземпляров, до 500 активных правил разных областей и совместные проведения до 27 исходных строк в контрольных примерах. Целевой p95 предпросмотра одного изменения с локальным пересчётом метрик — до 2 с; полный отчёт качества — до 60 с фоновой задачей. Замер включает раскрытие участников, профилей и объяснения. Загрузка результата не требует передачи всех исходных строк в браузер. Сбой/устаревание отчёта не блокирует обычное чтение и не заменяет обязательную проверку допуска к записи/выпуску. Это новые приёмочные цели, а не измеренные характеристики старой программы.

Надёжность и эксплуатационные свойства§

NFR-005. Любая предметная команда атомарна: занятие, участники, занятость ресурсов и запись аудита фиксируются совместно. Ошибка последнего участника массовой операции откатывает всю заявленную единицу изменения. Явно разделённые независимые задания показывают отдельный результат каждого, а не называются атомарной операцией.

NFR-006. Подтверждённые сервером изменения не теряются после перезапуска API/worker. Для PostgreSQL сохраняются настройки надёжной фиксации WAL; отключение fsync ради выполнения нагрузочного теста запрещено. Потеря всей машины восстанавливается в пределах отдельно заданных RPO/RTO, а не обещается как нулевая потеря.

NFR-007. Сбой брокера приостанавливает фоновые задачи, но сохраняет чтение, обычное редактирование и очередь зарегистрированных заданий. При недоступности PostgreSQL интерфейс сообщает о невозможности сохранения и не показывает ложное «Сохранено». Повторный запрос использует прежний ключ операции.

NFR-008. Для production установлен целевой месячный показатель доступности 99,5% на согласованном окне обслуживания. Одна серверная машина не обеспечивает автоматический переход на резервный узел; это ограничение базовой архитектуры. Расчёт доступности, плановых окон и ответственных за инфраструктурный простой фиксируется перед вводом в эксплуатацию. Высокая доступность с репликацией и failover относится к расширению.

Интерфейс и сопровождаемость§

NFR-009. Поддерживать актуальную и предыдущую стабильные версии Chrome, Firefox и Edge на момент приёмки. Просмотр расписания и карточек доступен в Safari и мобильном браузере; таблицы на ширине 390 px имеют контролируемую прокрутку. Основной плотный редактор должен быть удобен от 1280×720; необходимые изменения через форму выполняются и без перетаскивания мышью.

NFR-010. Основные операции доступны с клавиатуры. Диалоги удерживают и возвращают фокус; поля имеют подписи; ошибки связаны с полями; статусы различаются текстом/значком, а не только цветом. Масштаб 200% не скрывает кнопку сохранения и объяснение конфликта. Для screen reader предоставить табличное/списочное представление расписания вместо единственной графической сетки.

NFR-011. Интерфейс показывает отдельные состояния загрузки, пустой таблицы, отсутствия результатов, недоступности сервера и отказа в правах. Во время незавершённого изменения нельзя незаметно сменить семестр или закрыть карточку с потерей ввода. Несохранённый приватный текст не сохраняется бессрочно в общедоступном хранилище браузера.

NFR-012. Числа и даты отображаются в русской локали, внутри API формат однозначен. Поиск не зависит от регистра кириллицы. Политику е/ё, Unicode-нормализации и пробелов закрепить тестами; по умолчанию е и ё различаются, поиск по подстроке регистронезависим. Имена людей и групп не преобразуются автоматически в уникальные идентификаторы.

NFR-013. Исключить SQL N+1 на календарных выдачах, индексировать FK и основные фильтры, профилировать запросы на приёмочном наборе. Настройки индексов и поиск выбираются по EXPLAIN, а не по числу таблиц в старой Paradox. PostgreSQL-поиск и необходимые расширения достаточны для B; отдельный поисковый сервис не требуется.

NFR-014. Поставлять автоматические тесты правил повторений, участников, конкуренции, прав и импорта. Проверки БД выполняются на PostgreSQL той же основной версии, что production; SQLite не подменяет тесты диапазонных ограничений и блокировок. Сборка клиента, типизация, линтеры и миграции проверяются в CI.

Матрица покрытия возможностей исходной системы§

Матрица связывает целевое веб-приложение с полным каталогом из 59 пунктов анализа экранов. Номера LEG-01–LEG-59 соответствуют номерам исходного каталога. Источник S03 означает Screenshot_3.jpg; остальные изображения именуются аналогично и находятся в каталоге экранов. Скриншоты календаря относятся к сентябрю 2024 года; их принадлежность снимку данных 1_sem_2026_2027 не подтверждена.

Доказательность: «Экран», «Поле» и «Команда» подтверждают наличие соответствующего элемента интерфейса, но не успешное выполнение операции; «Гипотеза» означает вывод по неподписанной пиктограмме или предполагаемому переходу. Ни одна строка не должна трактоваться как протокол испытания исходной программы. Колонка «Целевое поведение» задает проектное решение для новой реализации.

Области: REF — справочники; PLAN — учебная потребность и виды нагрузки; STREAM — именованные наборы групп; CAL — календарные представления; EDIT — изменения занятий; AVAIL — доступность ресурсов; ADMIN — данные и настройки; HELP — справка; AUTH — доступ.

Объем: «База» — обязательное покрытие первой рабочей версии; «Уточнить» — возможность учитывается в проекте, но воспроизведение исторической семантики требует решения из реестра ниже. «Уточнить» не означает разрешение убрать возможность без согласования. Проектные расширения, не доказанные для исходной системы, перечислены отдельно после матрицы.

ID Возможность исходного каталога Источник и доказательность Область Целевое поведение Объем
LEG-01 Открыть список групп S01, S03; экран REF Таблица групп с переходом к карточке и связанному расписанию База
LEG-02 Найти/отфильтровать группы S03; поле, алгоритм не показан REF Поиск по названию; отбор по факультету, курсу и активности База
LEG-03 Вести факультет, численность, подгруппы и курс группы S03; поля, сохранение не показано REF Карточка с проверкой ссылок и неотрицательной численности; курс отображается названием База
LEG-04 Добавить/изменить/удалить группу S03; гипотеза по пиктограммам REF Создание и редактирование; связанная с расписанием группа архивируется, удаление не разрушает историю База
LEG-05 Открыть список преподавателей S01, S04; экран REF Таблица преподавателей с карточками База
LEG-06 Найти/отфильтровать преподавателя S04; поле REF Поиск по имени, отбор по кафедре и активности База
LEG-07 Вести кафедру, должность, звание, степень, замечания преподавателя S04; поля REF Сохранение всех перечисленных атрибутов; доступ к заметкам определяется ролью База
LEG-08 Добавить/изменить/удалить преподавателя S04; гипотеза по пиктограммам REF Создание, редактирование, архивирование; запрет потери связей с проведенными и планируемыми занятиями База
LEG-09 Открыть список дисциплин S01, S05; экран REF Таблица дисциплин и переход к использующим их планам База
LEG-10 Найти/отфильтровать дисциплину S05; поле REF Поиск по полному и краткому названию База
LEG-11 Вести полное и краткое название дисциплины S05; поля REF Редактирование обоих названий; краткое используется в плотной сетке, полное доступно в карточке База
LEG-12 Добавить/изменить/удалить дисциплину S05; гипотеза по пиктограммам REF Создание, изменение и архивирование; названия не используются как ключи База
LEG-13 Открыть список аудиторий S01, S06; экран REF Таблица аудиторий с вместимостью, назначением и переходом к занятости База
LEG-14 Найти/отфильтровать аудиторию S06; поле REF Поиск по названию, отбор по типу, кафедре и вместимости База
LEG-15 Вести вместимость, назначение, кафедру, замечания аудитории S06; поля REF Карточка перечисленных атрибутов; тип помещения отделен от типа занятия База
LEG-16 Добавить/изменить/удалить аудиторию S06; гипотеза по пиктограммам REF Создание, изменение, архивирование; действующие назначения сохраняют ссылки База
LEG-17 Открыть список кафедр S01, S07; экран REF Таблица кафедр и их организационных связей База
LEG-18 Найти/отфильтровать кафедру S07; поле REF Поиск по названию, фильтр по факультету База
LEG-19 Связать кафедру с факультетом S07; поле REF Выбор существующего факультета; несогласованные ссылки импорта требуют исправления База
LEG-20 Добавить/изменить кафедру S07; гипотеза по пиктограммам REF Создание и изменение кафедры; поведение удаления в старой программе не заявляется База
LEG-21 Просмотреть факультеты S01, S08; экран REF Таблица факультетов; управление справочником предоставляется администратору как проектное дополнение База
LEG-22 Просмотреть учебный план выбранной группы S01, S09; экран PLAN Список позиций плана по группе и учебному периоду, включая общие занятия нескольких групп База
LEG-23 Указать дисциплину и кафедру в плане S09; поля PLAN Позиция плана с отдельными ссылками на дисциплину и ответственную кафедру База
LEG-24 Указать недельную нагрузку по лекциям, практикам, лабораторным S09; поля PLAN Явное указание вида, объема, единицы измерения и периода действия; исторический PlanQty не пересчитывается без правила Уточнить
LEG-25 Учитывать проведение практик/лабораторных по подгруппам S09; флажки PLAN Участники задаются группой целиком либо конкретными подгруппами; учитываются при генерации и конфликтах База
LEG-26 Учитывать экзамены, консультации, зачеты S09; блоки, поведение ввода не показано PLAN Отдельные виды учебной потребности и занятий; объем и правила порождения согласуются отдельно База
LEG-27 Задать признак «Стабильное» S09; поле, смысл неизвестен PLAN Сохранение исходного Stable как наследуемого атрибута; блокировка изменений вводится отдельным явным действием Уточнить
LEG-28 Просмотреть группы, объединенные для записи плана S09; поле «Поток» PLAN Уникальный состав групп и подгрупп конкретной позиции плана; не подменяется справочником STREAMS База
LEG-29 Добавить/изменить/удалить запись учебного плана S09; гипотеза по пиктограммам PLAN Управление потребностью с предварительным показом влияния на существующие занятия База
LEG-30 Просмотреть классификатор курсов и уровней обучения S01, S10; экран REF Названия курсов/уровней, отдельные от технических идентификаторов; исходный CourseCount не трактуется как год обучения База
LEG-31 Просмотреть потоки и состав групп S01, S11; экран STREAM Именованные наборы групп для отбора и просмотра; членство отделено от состава участников плана База
LEG-32 Создать поток S11; команда STREAM Создание именованного набора групп в учебном периоде База
LEG-33 Удалить поток S11; команда STREAM Удаление либо архивирование набора без удаления групп и занятий База
LEG-34 Включить/исключить группу из потока S11; гипотеза по стрелкам STREAM Явное редактирование членства набора с отображением результата до сохранения База
LEG-35 Выбрать «Полное»/«Нечетная»/«Четная»/«Экзамены» для потока S11; неактивные команды, результат неизвестен STREAM, CAL В новой версии — фильтры состава показываемого расписания; печать/экспорт старых кнопок не предполагаются Уточнить
LEG-36 Просмотреть начала занятий S01, S12; экран REF Сетка звонков с номером, началом и явно заданным окончанием; импорт не вычисляет окончание по следующему началу База
LEG-37 Открыть общее расписание S14, S15; экран; S02 — гипотеза перехода CAL Основной календарь групп, дней и временных интервалов База
LEG-38 Выбрать неделю S14, S15; поле CAL Выбор фактической недели и учебного периода; старые коды переводятся в даты только после подтверждения правил База
LEG-39 Просмотреть занятия по дням, позициям и группам S14, S15; экран CAL Календарная сетка и табличный вид с согласованным составом занятий; легенда цветов и статусов База
LEG-40 Просмотреть детали занятия при наведении S14; экран CAL Краткая подсказка и доступная по нажатию/клавиатуре карточка дисциплины, участников, преподавателя и аудитории База
LEG-41 Просмотреть неназначенные занятия S14, S15; экран CAL Отдельный список занятий, ожидающих размещения; исходный Assigned=False не заменяется проверкой пустых координат База
LEG-42 Обновить представление расписания S14, S15; команда CAL Получение актуальной версии данных с сохранением фильтров и уведомлением об изменениях База
LEG-43 Отменить выбранный элемент S15; команда, семантика неизвестна EDIT Раздельные действия «Снять назначение» и «Отменить проведение»; историческая команда не считается эквивалентной обоим Уточнить
LEG-44 Переставить занятие S15; команда EDIT Перенос выбранного проведения в другую дату/время после проверки участников, ресурсов и ограничений База
LEG-45 Сменить аудиторию занятия S15; команда EDIT Замена аудитории с проверкой доступности и совместимости, журналом прежнего и нового значения База
LEG-46 Заменить преподавателя S15; команда EDIT Замена преподавателя с проверкой занятости, границ полномочий и журналом изменений База
LEG-47 Отдать на кафедру S15; команда, семантика неизвестна EDIT До уточнения — отдельное состояние/задание ответственной кафедре; не очищает преподавателя и помещение неявно Уточнить
LEG-48 Открыть расписание группы S15; команда CAL Календарь всех занятий группы, включая общие занятия через участников плана и ее подгруппы База
LEG-49 Открыть расписание преподавателя S15; команда CAL Календарь назначений преподавателя и доступных пользователю ограничений База
LEG-50 Открыть расписание аудитории S15; неактивная команда CAL Календарь занятости аудитории с переходом к занятиям База
LEG-51 Работать с комментарием занятия S15; команда EDIT Чтение и изменение комментария согласно роли; внутренние сведения исключаются из публичного представления База
LEG-52 Открыть поиск свободных аудиторий S02, S13; команда и экран AVAIL Поиск по фактической дате и временному интервалу с учетом занятий и ограничений База
LEG-53 Выбрать день поиска аудитории S13; команды AVAIL Выбор даты, а также шаблона недели для предварительного планирования База
LEG-54 Отобрать аудитории по назначению S13; варианты фильтра AVAIL Отбор по отдельному справочнику типов помещений; «Любая» является только состоянием фильтра База
LEG-55 Просмотреть свободные аудитории по времени S13; экран, выдача пуста AVAIL Результаты по слотам/интервалам с объяснением недоступности и временем актуальности расчета База
LEG-56 Выполнить действие «База данных» S02; команда, содержание неизвестно ADMIN В новой версии — выбор учебного периода и раздел импорта/диагностики по правам; PostgreSQL не выбирается как локальный файл в браузере Уточнить
LEG-57 Открыть параметры S02, S14, S15; команды, состав неизвестен ADMIN Явные настройки календаря, звонков и отображения, разграниченные по полномочиям; произвольная настройка соединения обычным пользователем не требуется Уточнить
LEG-58 Открыть помощь S01, S02; меню, содержание неизвестно HELP Встроенное руководство по сценариям, обозначениям, ограничениям и версии приложения База
LEG-59 Выйти из приложения S01; команда AUTH Завершить серверную сессию и вернуться на экран входа; браузерное окно закрывать не требуется База

Требования, которые нельзя обосновывать только этими 59 пунктами§

Следующие возможности должны иметь собственные требования и приемочные проверки; их нельзя записывать как доказанные алгоритмы старого приложения:

  • Ограничения преподавателей и аудиторий: хранение подтверждено таблицами TCHRRSTR и ROOMRSTR, но редактор и последовательность применения не показаны на скриншотах.
  • Проверка пересечений групп, подгрупп, преподавателей и аудиторий, вместимости и совместимости помещений: это необходимые проектные правила корректности новой системы, а не проверенное поведение прежней.
  • Порождение неназначенных занятий из нагрузки: связь модели правдоподобна, однако алгоритм, округление и единицы объема не установлены. Порождение перечня занятий и автоматический выбор для них времени/ресурсов — разные функции.
  • Автоматическое составление или оптимизация расписания не продемонстрированы. Такая подсистема должна оформляться отдельным расширением с входными ограничениями, целевой функцией, пределом времени расчета и критериями качества.
  • Совместная работа, роли, серверные сессии, аудит, контроль конкурентных изменений, резервное копирование и восстановление — требования новой серверной реализации. Они не следуют из наличия файлов блокировок Paradox.
  • Публикация утвержденного расписания и отделение внутренних заметок от внешнего представления — проектные возможности веб-продукта; текущий защищенный просмотрщик данных не является полноценным редактором расписания.
  • Печать, выгрузки, интеграции, уведомления, согласование и универсальная отмена/повтор изменений не подтверждены показанными экранами. Каждый включаемый сценарий требует отдельного описания; подписи «Полное» и «Отменить» не заменяют такого описания.
  • Перестановка групп и аудиторий обнаружена в ресурсах утилиты Reorder.EXE, а не в каталоге 59 функций. Если пользовательский порядок необходим в новом календаре, его следует принять отдельным требованием, сохранив числовые идентификаторы исходных объектов.

Реестр предметных решений и неопределенностей§

Рабочие допущения ниже позволяют проектировать новую систему. Они не подтверждают исторические правила и не разрешают без проверки преобразовывать неоднозначные данные в рабочее расписание. «До уточнения» означает сохранение исходного значения в слое импорта и в отчете расхождений; записи не теряются и не получают придуманных дат, участников или статусов. Подтверждение решения оформляется в журнале решений проекта со ссылкой на ID и примером до/после. Указанные роли обозначают представителей заказчика, а не конкретных людей.

ID Требуется определить Рабочее правило новой версии / действие до уточнения Влияние на импорт и ввод в эксплуатацию Кто подтверждает и на каком примере
DEC-01 Кодирование Classes.DayNo, начало отсчета и соотношение OddWeek/EachWeek Для новых данных используются реальные даты и явное повторение; исходные коды сохраняются. Формула DayNo // 14 — гипотеза, автоматическое преобразование по ней запрещено Блокирует достоверный импорт дат, календарную проверку конфликтов и расчет свободных ресурсов по старым занятиям Старший диспетчер и сопровождающий прежнюю программу: минимум по одному занятию каждой четности, еженедельное занятие, переход двухнедельного блока
DEC-02 Учебный период, его даты, каникулы, праздничные исключения, часовой пояс и опорная неделя Период и календарь задаются явно; рекомендуемый часовой пояс развертывания — Asia/Novosibirsk. Название каталога не определяет дату первого учебного дня Блокирует публикацию перенесенного расписания на фактические даты; отдельно фиксируется несоответствие экранов 2024 года и имени снимка 2026–2027 Учебное управление: утвержденный календарный график и параметры рабочей программы
DEC-03 Значение Week=0/1 в ограничениях и применение ограничения к периоду Для новых ограничений указываются даты действия и повторение. Исходный вариант недели сохраняется без переименования в четный/нечетный Неопознанные ограничения требуют проверки до допуска автоматического назначения ресурсов Диспетчер: по одному известному запрету на каждой неделе с сопоставлением экранов
DEC-04 Единица PlanQty, длительность академического часа, понятие пары, периодичность и округление Новая нагрузка имеет явную единицу и область действия. Импорт сохраняет число и код вида без автоматического умножения на недели или деления на два Блокирует эквивалентную генерацию занятий и контроль выполнения нагрузки; чтение исходного значения возможно Учебно-методическое управление и диспетчер: один план с расчетом вручную и фактическим количеством созданных занятий
DEC-05 Время окончания слотов и занятия длительностью больше одного слота Начало и окончание задаются независимо, интервалы учитывают фактическое пересечение. Конец не выводится из начала следующей пары Начала всех восьми слотов импортируются; окончания требуют заполнения до точной проверки занятости Учебное управление: утвержденное расписание звонков, примеры экзамена и удлиненного занятия
DEC-06 Значение Plan.Stable Сохраняется отдельный исторический признак; блокировка переноса, фиксация и факт проведения имеют самостоятельные статусы Не применять импортированный флаг как запрет изменения или признак проведенности Диспетчер: изменение флага на копии и наблюдение за разрешенными операциями
DEC-07 Разница между снятием назначения, отменой проведения, удалением и Assigned=False с заполненной позицией В новой версии это раздельные операции. Снятие освобождает ресурсы и возвращает потребность к размещению; отмена сохраняет историю и причину. Старая позиция сохраняется как исходный атрибут 288 неназначенных записей с координатами не должны занимать ресурсы только из-за наличия координат; требуется подтвердить их отображение Диспетчер: отмена одного занятия на рабочей копии и сравнение до/после
DEC-08 Значение «Отдать на кафедру» и полномочия кафедрального пользователя Предварительное проектное значение — передать ответственность за уточнение преподавателя/условий. Операция не меняет ресурсы и статус размещения неявно Нет надежного признака для автоматического восстановления исторических передач; импорт не создает вымышленные задания Руководитель расписания и представитель кафедры: полный сценарий передачи и возврата
DEC-09 Состав и пересечение подгрупп, нумерация, неизвестная численность, возможность совместного участия Подгруппы представляются явно; занятие целой группы пересекается со всеми ее подгруппами. При неизвестном составе разных схем подгрупп система не объявляет отсутствие конфликта Нельзя делить NStudents на NSubgroups и считать результат подтвержденной численностью; GRPPLAN сохраняется без схлопывания строк подгрупп Диспетчер и учебное управление: план с разными подгруппами и две параллельные записи
DEC-10 Участники занятия при GroupNo=-1, связи с GrpSplit и общими экзаменами Отсутствие прямой группы разбирается в контексте позиции плана и вида занятия; справочник STREAMS не используется как замена участникам 3 458 записей требуют восстановления через GRPPLAN; повторяющаяся группа не увеличивает численность повторно Диспетчер: общий потоковый курс, общий экзамен и план с единственной группой
DEC-11 Значения видов занятий с/л/п/з/э/к, типов помещений и RoomSpec Два отдельных справочника. Неоднозначные коды сохраняются с исходной подписью до утверждения таблицы соответствий Блокирует корректное автоматическое сопоставление типа занятия и аудитории; особенно проверяются с/п, к и отсутствующий код лингафонного кабинета Диспетчер и администратор помещений: карточки каждого типа и по одному сохраненному изменению
DEC-12 Допустимость назначенного занятия без аудитории/преподавателя, дистанционные и внешние площадки Неполное назначение явно помечается; новый формат проведения задается отдельным полем, отсутствие аудитории само по себе не означает онлайн-формат 2 339 строк Assigned=True без аудитории и 23 из них без преподавателя требуют классификации до признания готовыми к публикации Руководитель расписания: примеры допустимых исключений и правила выпуска расписания
DEC-13 Являются ли ограничения запретами, пожеланиями или справочными заметками; нужны ли исключения на конкретную дату Для новых ограничений явно задаются жесткость, ресурс и интервал; исключение имеет причину и полномочие. До классификации исходные строки показываются как неуточненные ограничения Нельзя считать произвольный текст Reason однозначным машинным запретом; требуется согласовать влияние 4 541 ограничения преподавателей и 990 ограничений аудиторий Диспетчер и ответственные за ресурсы: перечень типов ограничений и приоритетов
DEC-14 Подтверждение совместных проведений, в том числе разных планов/ID дисциплин Одно согласованное проведение связывает несколько потребностей и бронирует ресурс один раз по FR-065. Разные независимые проведения не получают исключения из запрета пересечения 638 преподавательских и 572 аудиторных многозаписных клетки — кандидаты проверки; строки и все исходные ID сохраняются Диспетчер: одинаковый и разный PlanNo, совпадающее полное имя при разных SubjectNo, неизвестная комната, разъединение с повторной проверкой
DEC-15 Смысл именованных потоков, их привязка к периоду и кнопки «Полное»/«Нечетная»/«Четная»/«Экзамены» Рабочее назначение — именованный набор групп и режимы просмотра. Объединение участников плана остается отдельным механизмом Все 140 строк STREAMS сохраняются; при StreamNo=-1 у всех 554 групп членство не восстанавливается по похожим названиям Диспетчер: создать поток, включить группу и выполнить каждую из четырех команд на копии
DEC-16 Авторитетный источник при расхождении Classes и ClassesInf; роль CLASSINF/PLANROOM Основным кандидатом считается Classes; вспомогательные данные сохраняются для сверки, не порождают дубликаты занятий. Пустые таблицы не доказывают востребованность нескольких ресурсов Расхождение счетчика 15 124/15 111 и одной аудитории оформляется отдельным результатом сверки; решение фиксируется до утверждения миграции Сопровождающий старую систему и диспетчер: отображение спорного занятия и сохранение на тестовой копии
DEC-17 Исправление отсутствующих факультетов и буквальных HTML-сущностей в справочниках Сохраняется исходный текст и ссылка; исправления делаются по согласованной карте соответствий. Похожие названия не сливаются автоматически Две ссылки кафедр на факультеты 46 и 48 остаются в отчете проблем; импорт не создает фиктивный действующий факультет без решения Владелец организационных справочников: корректные названия и принадлежность кафедр
DEC-18 Допустимый доступ к персональным сведениям и свободному тексту Авторизованные пользователи видят поля по ролям; публичное представление, если оно включено, не содержит внутренних заметок и реквизитов онлайн-занятий. Пароли доступа не включаются в документацию и журналы Все исходные поля сохраняются в защищенном контуре, но не копируются автоматически в публичные API, журналы и экспорт для посетителей Владелец продукта и ответственный за доступ: утвержденная матрица полей/ролей; действующий пароль просмотрщика не является моделью ролей будущего приложения
DEC-19 Точечное редактирование серии и перенос выбранной группы — решение принято по SRC-10 В новой версии по умолчанию меняется только календарное проведение; FR-069 выделяет выбранную группу. Остальные даты/участники сохраняются, публикация выполняется новым снимком без пересоставления сетки Ограничение старой системы подтверждено владельцем; это не расшифровывает DayNo. Импортированный шаблон не меняет несвязанные строки по одному PlanNo Владелец подтвердил поведение новой версии; приёмочные примеры AP-20–AP-22, историческая календарная формула остаётся DEC-01
DEC-20 Генерация занятий из плана и поведение повторной генерации Только после определения единиц, периода и повторения; повторный запуск показывает разницу, не создает дубликаты и не стирает ручные изменения Существующие 15 111 записей не заменяются результатом недоказанной формулы; создается сверка план/занятия Учебное управление и диспетчер: ручной расчет трех типов нагрузки, повторный запуск после переноса занятия
DEC-21 Граница запуска новой системы и дальнейшие изменения старой Рабочая схема — согласованный финальный снимок, сверка, переключение на PostgreSQL как единственный источник записи. Обратная запись в Paradox и двусторонняя синхронизация не предполагаются Требуется дата прекращения изменений старой копии и процедура повторного импорта до переключения; автономные изменения двух систем не сливаются автоматически Владелец продукта и руководитель эксплуатации: план перехода, ответственное лицо и критерии отката
DEC-22 Кто выпускает расписание, допустимы ли черновики и неполные назначения Редактирование выполняется в черновике; выпуск требует отсутствия блокирующих ошибок. Правила согласования кафедрами не добавляются автоматически из команды «Отдать» Исходный Assigned не считается признаком публикации. Импортированный период требует отдельного решения о выпуске Руководитель расписания: полномочия, перечень блокирующих ошибок и порядок уведомления об изменениях

Дополнительные решения редакции 0.2:

ID Требуется определить До решения / влияние Кто и на чём подтверждает
DEC-23 Временные профили формы × уровня × дня, включая субботу и вечернюю шестую пару POLICY-03 — черновые предложения; неизвестный применимый профиль блокирует выпуск до утверждения профиля либо явного решения об отсутствии отдельного временного ограничения Учебное управление и диспетчер: будний/субботний пример каждой категории и конфликт совместного занятия
DEC-24 Календарь заочных сессий и интенсивность по программам 19,52% размещения не позволяют восстановить общий режим; будущие занятия задаются по подтверждённым параметрам, отсутствующие не считаются отменёнными Ответственный за заочную форму: полный сессионный план и календарь
DEC-25 Актуальность численности/вместимости, строгость, устаревание, полномочия исключений FR-033/FR-066: никакого разрешения по одному комментарию; неизвестное или превышенное значение препятствует выпуску, до утверждения жёсткости доступен исследовательский черновик Владелец продукта и ответственный за помещения: проверенный состав, паспорт комнаты, порядок разрешения расхождений
DEC-26 Матрица помещений, оборудование, корпуса и времена переходов Старые буквы и префиксы не задают норму; неподтверждённые обязательные соответствия препятствуют выпуску, неизвестные минуты перехода явно не проверены. Решение о необходимости жёсткой проверки переходов принимается отдельно Ответственный за помещения и диспетчер: допустимая альтернатива, обязательная лаборатория, переход двух корпусов
DEC-27 Применимость и строгость исторических ограничений, объяснение 4/3 совпадений DEC-03/DEC-13 дополняются проверкой сроков и исключений; неразрешённые применимые строки не игнорируются при публикации Диспетчер и владелец ресурса: конкретные исходные запреты, допустимый случай и срок действия
DEC-28 Метрики, приоритеты и веса предпочтений; новые максимумы и свободные дни Раздельные показатели B без скрытого балла; наблюдаемые максимумы не активируют пределы. Веса оптимизатора E согласуются отдельно Владелец продукта и диспетчер: два допустимых варианта с противоположными изменениями окон группы/учителя
DEC-29 Процесс утверждения политики и пределы исключений Право policy.approve назначается явно, версии и основания сохраняются; технический администратор без предметной роли не утверждает правила Руководитель расписания: матрица полномочий, образец версии, исключения и протокола выпуска

Расшифровка обозначений групп из SRC-09 принята как основание классификатора, а не оставлена вопросом к владельцу. Проверка новых неизвестных кодов и спорных исходных записей остаётся обязательной. Значение Stable по-прежнему не восстановлено: одно помещение и блокировка переноса не следуют из этого флага.

Условия закрытия неопределенностей§

  1. Для DEC-01–DEC-05 готовится воспроизводимый пример с исходной строкой, настройками старой программы, ожидаемой датой/длительностью и утвержденным результатом преобразования. Без этого импорт может быть завершен как загрузка исходных данных, но не как проверенная миграция действующего календаря.
  2. Для спорной операции фиксируются исходная запись, действие в тестовой копии прежней программы и результат после сохранения. Сведения из скриншота без выполнения не закрывают вопрос семантики.
  3. Если проверить старое поведение невозможно, заказчик утверждает новое правило как проектное отклонение. Исходные значения остаются доступны для сверки; критерий приемки проверяет утвержденное новое правило, а не заявленное полное совпадение неизвестного алгоритма.
  4. Автоматическое размещение/оптимизация не является условием признания ручного веб-редактора эквивалентным показанным функциям. Включение оптимизатора в первую версию требует самостоятельного решения об объеме и приемке.

Установка и автономная эксплуатация§

Профили окружения§

OPS-001. Предусмотреть три независимых окружения: разработка, приёмочный стенд и production. У них разные базы, пароли, домены/порты, тома и каталоги приватных файлов. Тесты и демонстрационные данные не запускаются на рабочей БД. Данные production для разработки обезличиваются либо используются только в специально защищённом стенде по принятому порядку доступа.

OPS-002. Поставка запускается на поддерживаемом Linux x86_64 с Docker Engine/Compose и постоянными томами. Рекомендуемый начальный профиль для всего приложения — 4 vCPU, 8 ГиБ RAM и 80 ГБ SSD; это плановый ориентир, который подтверждается нагрузочной приёмкой. Объём хранения учитывает БД, историю, WAL, исходники импорта, экспорты и резерв свободного места; он не равен размеру исходной SQLite.

На общем сервере Gintoft ресурсы уже используют другие приложения. Размещение новой системы на нём требует проверки доступной памяти, CPU, диска, портов и совместного нагрузочного испытания. Настоящее ТЗ не предписывает останавливать другие приложения, очищать их данные или менять действующее расписание. Для изоляции допустим отдельный сервер или отдельная согласованная квота ресурсов.

OPS-003. Основные сервисы Compose: web (Nginx и собранный клиент), api, worker, postgres, redis. Диспетчер сохранённых заданий имеет отдельный однозначный способ запуска. API и worker используют один образ приложения; разработческие серверы React/Django в production не запускаются. Для каждого процесса задать restart policy, healthcheck, ограничения памяти, разумный предел CPU и размер логов. Нехватка памяти одного процесса не должна вытеснять все соседние сервисы.

Предусмотреть два сетевых профиля: отдельная машина, где Nginx приложения принимает 80/443, и размещение за уже существующим Nginx заказчика, где сервис приложения слушает только свободный loopback-порт. Внешними остаются только нужные HTTP(S)-порты. Предметная PostgreSQL не должна использовать ту же роль/БД, что другие приложения на сервере.

Docker Compose поддерживает установку на одной машине и отдельные production-настройки; параметры эксплуатации необходимо поставлять явно. Docker: использование Compose в production.

Первичная установка и конфигурация§

OPS-004. Инструкция установки описывает: подготовку каталогов и секретов; создание томов; запуск PostgreSQL; применение миграций; создание администратора; настройку организации, часового пояса и домена; запуск сервисов; настройку HTTPS; проверку health; пробный вход; загрузку контрольного снимка и проверку восстановления. Чистая установка должна воспроизводиться человеком, который не разрабатывал систему, по этой инструкции.

OPS-005. Поставить .env.example с названиями параметров и безопасными примерами без реальных секретов. Рабочие секреты хранятся в закрытых файлах/секретах окружения вне репозитория. В обязательных параметрах: URL/реквизиты PostgreSQL, Django secret key, allowed hosts, trusted origins, режим TLS/proxy, часовой пояс, каталог приватных файлов, предел импорта, параметры брокера, лимиты заданий и срок экспорта.

OPS-006. Локальные Docker-тома PostgreSQL и приватных файлов переживают пересоздание контейнеров. Обычная команда обновления не содержит удаления томов. Для установки в закрытой сети предоставить архив образов/артефактов и необходимые зависимости; после запуска основная работа не требует входа в облачный сервис разработчика.

Резервное копирование и восстановление§

OPS-007. В B задать RPO не более 24 часов и RTO не более 4 часов для контрольного объёма. RPO означает допустимую потерю изменений при утрате всей установки; RTO — время восстановления доступности из подготовленной копии. Эти значения подтверждаются испытанием и согласуются с ответственным за инфраструктуру.

OPS-008. Не реже одного раза в сутки автоматически формировать согласованный комплект: PostgreSQL-дамп, необходимые роли/параметры восстановления, приватные исходники импорта, файлы, на которые ссылается БД, версии образов и схемы. Секреты восстанавливаются из отдельного защищённого источника. Проверять код завершения, размер, контрольную сумму и возможность чтения копии; один факт наличия файла не считается успешным backup.

OPS-009. Сохранять не менее 7 ежедневных и 4 еженедельных копий, как минимум одну вне основного сервера. Копии и передача защищаются шифрованием и отдельными правами. Раз в месяц выполнять восстановление в изолированном окружении с проверкой контрольных счетчиков и входа в систему. Перед изменением схемы — дополнительная копия и подтверждение возможности её восстановления. Не удалять последнюю исправную копию из-за ошибки очередной.

Для B предусмотрен логический backup PostgreSQL подходящими штатными средствами. Непрерывное архивирование WAL/PITR и меньший RPO могут быть расширением; если они понадобятся, задаётся отдельный профиль хранения и регулярно проверяется восстановление на выбранный момент. PostgreSQL: способы резервного копирования.

Обновления и откат§

OPS-010. Каждый выпуск имеет номер, хеш исходников/образов, список миграций, изменения конфигурации и инструкцию обновления. Обновление сначала проходит на стенде с копией структуры production. Миграции выполняет один процесс под отдельной ролью; одновременно запущенные API не пытаются мигрировать БД независимо друг от друга.

OPS-011. При изменении схемы предпочитать последовательность расширить → перенести → переключить → удалить устаревшее в последующем выпуске. План отката должен различать возврат образа и восстановление данных. Откат только приложения допустим, если предыдущий код совместим с новой схемой; иначе требуется заранее предусмотренная обратная миграция либо восстановление копии с явным учётом возможной потери новых изменений. Обещание «просто вернуть предыдущий контейнер» недостаточно.

OPS-012. Во время обслуживания показать понятное состояние, корректно завершить активные операции и не оборвать транзакцию с ложным успешным ответом. После обновления проверить вход, чтение расписания, тестовую команду в отдельной проверочной области, очередь, права и резервное копирование. Действующая публикация сохраняется до атомарного переключения.

Наблюдаемость§

OPS-013. Собирать структурированные логи с временем UTC, уровнем, request_id/job_id, идентификатором операции и безопасным кодом ошибки. Предметный аудит хранить отдельно от технического лога. Для каждой ошибки из интерфейса должен существовать диагностический идентификатор без раскрытия SQL, внутреннего пути и секрета.

OPS-014. Контролировать доступность API и PostgreSQL, CPU/RAM/свободный диск, длительность SQL и блокировок, очередь и время последнего heartbeat worker, ошибки публикации/импорта, возраст последнего исправного backup и срок TLS-сертификата. Выбранный канал уведомлений настраивается заказчиком; базовая диагностика и журнал доступны без внешнего мессенджера.

OPS-015. По умолчанию технические логи сохраняются 30 дней с ротацией; предметный аудит — 365 дней. Учебные периоды, опубликованные версии и исходники принятых импортов автоматически не удаляются: срок их хранения устанавливает заказчик, а удаление выполняется отдельной контролируемой процедурой с проверкой ссылок и резервных копий. Изменение политики хранения само фиксируется в аудите.

Порядок разработки и комплект поставки§

Этапы с проверяемым результатом§

Этап Работы Условие завершения
0. Уточнение предметных правил Выбрать календарь, единицы нагрузки, подгруппы, совместность, временные профили, вместимость и публикацию; оформить Q/DEC и проект версии политики Реестр решений с примерами входа/выхода; классификатор по SRC-09, оставшиеся неизвестные отделены в импортном карантине
1. Основа и перенос Окружение, пользователи, PostgreSQL, справочники, raw/staging-импорт и контрольный просмотр Все 19 источников сохранены; нет потерь полей; права и повторный импорт проверены
2. План и календарь Учебные периоды, звонки, состав групп по видам нагрузки, разовые даты, серии и генерация Синтетическое новое расписание имеет явные даты, корректную нагрузку и исключения; день, неделя и список показывают одинаковые проведения
3. Редактор и ограничения Назначение, точечный перенос, перенос выбранной группы, обмен, отмена, онлайн-формат, ресурсы, совместные проведения, версии политики, профили, качество и конкуренция Сквозные операции и конкурентные тесты не создают двойную занятость; FR-061–FR-069 и AP-01–AP-23 проверены, последствия ручных изменений объяснимы
4. Согласование и выдача Кафедральные предложения, версии, публикация, печать и экспорт Опубликованный снимок неизменяем и соответствует проверенному состоянию
5. Производственная готовность Нагрузка, резервное копирование, восстановление, обновление, документация Воспроизведены NFR и RPO/RTO, выполнена установка на чистом стенде
6. Пилот и ввод Работа реального диспетчера на ограниченном периоде, устранение дефектов, подтверждение переноса Заказчик выполнил согласованные сценарии и утвердил рабочую редакцию данных

Этапы 1–5 можно частично выполнять параллельно. Неизвестная формула старого DayNo не блокирует создание нового расписания на явных датах, но блокирует утверждение, что импортированные записи уже имеют достоверное положение в календаре. Этап просмотра данных не считается завершением всего редактора.

Обязательные результаты передачи§

DEL-001. Передать заказчику:

  1. Репозиторий исходного кода клиента, сервера, миграций и инфраструктуры; инструкции сборки и запуска, перечень зависимостей и лицензий.
  2. OpenAPI, ER-схему PostgreSQL, словарь полей новой системы, правила состояний, повторений, конфликтов и публикаций.
  3. Зафиксированное соответствие всех 88 исходных полей и всех 59 пунктов каталога; список принятых преобразований и оставшихся ошибок импорта.
  4. Контрольный импорт с манифестом, хешами, исходными счётчиками, нормализованными результатами и причинами отклонений.
  5. Автоматические тесты и протоколы функциональных, конкурентных, нагрузочных и негативных проверок.
  6. Инструкции диспетчера, сотрудника кафедры, публикатора и администратора с конкретными сценариями и снимками новой версии интерфейса.
  7. Compose-конфигурации, шаблоны секретов без значений, проверенный сценарий обновления, резервного копирования и восстановления.
  8. Паспорта production и приёмочного окружений без секретов; список известных ограничений, миграционные решения и журнал изменений.
  9. Рабочие административные реквизиты через согласованный защищённый канал; никаких универсальных паролей разработчика в коде или документации.
  10. Версионированный каталог POL-01–POL-20, матрицу TRACE-01, согласованную конфигурацию политики, классификатор групп с фикстурами, образцы отчётов качества и исключений; отдельно реестр неподтверждённых правил и протокол AP-01–AP-23, включая подневное расписание, точечные переносы и онлайн-формат. Шаблоны из наблюдений не передаются как автоматически утверждённые нормы.

Что считается готовым требованием§

DEL-002. Для каждого базового требования выполнены: реализация; проверка положительного и существенного отрицательного сценария; объектные права; нужные миграции; доступное сообщение об ошибке; документация; связь с тестом или ручным протоколом. Для операции записи также обязательны аудит, транзакционность и защита от повторного/конкурентного запроса. Запись «экран нарисован» не закрывает требование сохранения данных.

Общая программа приёмки§

Сценарии ниже дополняют критерии у функциональных требований и проверок данных. Используются исходный исследованный снимок и отдельный синтетический набор с достоверными датами, ресурсами и составом подгрупп. Названия тестовых людей и внутренние реквизиты не должны попадать в публичную демонстрацию.

ID Проверка Ожидаемый результат
ACC-01 Чистая автономная установка из поставки Вход, создание справочника и занятия без инструментов разработчика и внешнего SaaS
ACC-02 Импорт контрольного SQLite 75 909 исходных строк сохранены в raw-слое; 19 таблиц различимы; доступна сверка 88 полей
ACC-03 Неизвестные даты и единицы нагрузки Никаких вымышленных дат или автоматически созданных «пар»; строки видны в импорте и имеют причину ожидания
ACC-04 Повтор того же снимка и повтор команды commit Ни дублей предметных сущностей, ни второй активации; результат операции однозначен
ACC-05 Полный путь диспетчера Созданы период, группы, план, серия; занятие назначено, перенесено, ресурсы изменены; история доступна
ACC-06 Подгруппы и объединённое занятие Подтверждённые непересекающиеся части могут идти параллельно; целая группа конфликтует с любой своей частью; общий урок не дублируется по числу групп
ACC-07 Часы и фактические минуты Изменение длительности/повторений даёт объяснимый пересчёт по выбранной единице; 1 час не приравнивается к 1 паре неявно
ACC-08 Пустые ресурсы в черновике Сохранено датированное предварительное занятие с замечанием; публикация отклонена при невыполненных обязательных требованиях
ACC-09 Одновременное занятие одной аудитории Два независимых соединения пытаются занять пересекающиеся интервалы: не более одного commit в одном черновике
ACC-10 Одновременное изменение одной карточки Второй запрос получает конфликт версии; первое изменение не теряется
ACC-11 Атомарный обмен местами При успехе изменены оба события; при внешнем конфликте сохранены прежние значения обоих
ACC-12 Конфликт при изменении серии Указан конкретный конфликтующий экземпляр; заявленная атомарная операция не применена частично
ACC-13 Публикация одновременно с редактированием Активируется точно проверенная версия либо запрос отклоняется/пересчитывается; изменившийся кандидат не выдаётся как ранее проверенный
ACC-14 Общие ресурсы разных периодов Конфликтующие активные публикации не появляются даже при одновременной активации; смена схемы подгрупп не обходит проверку
ACC-15 Изменение справочника после публикации Исторический опубликованный вид сохраняет зафиксированные названия и состав; новый черновик получает изменения контролируемо
ACC-16 Права по API и экспортам Кафедра не меняет чужую область, читатель не редактирует, закрытые заметки не выдаются в публичный API или экспорт
ACC-17 Снятие и отмена Снятие возвращает в список размещения, отмена не считается проведённым занятием; занятость освобождена, причина и история сохранены
ACC-18 Недоступность worker/Redis/API Нет ложного успеха или двойной операции; после восстановления задача имеет корректное состояние
ACC-19 Отказ загрузки/транзакции импорта Рабочий черновик и действующая публикация не становятся наполовину импортированными
ACC-20 Резервная копия и утрата установки Изолированное восстановление укладывается в RPO/RTO; восстановлены данные, происхождение, права и история
ACC-21 Обновление и откат Следование инструкции сохраняет совместимую схему и данные либо явно восстанавливает согласованную копию
ACC-22 Нагрузка и удобство Приложены измерения NFR; формы, ошибки, таблицы и печать работают в заявленных браузерах и с клавиатуры
ACC-23 Публичный режим выключен/включен Без включения доступ закрыт; после включения выдаётся только текущий утверждённый разрешённый набор полей
ACC-24 Матрица старого и нового Все LEG-01…LEG-59 имеют реализацию, явно согласованное уточнение или статус расширения, без молчаливого пропуска

ACC-25. Условия выпуска. Закрыты все обязательные требования B либо оформлено явное изменение состава версии. Нет дефектов потери данных, обхода прав, незаметного перезаписывания и двойного бронирования. Согласованы решения, необходимые для рабочего календаря. Наличие нерешённых исторических записей допустимо лишь при их полном сохранении, объяснимом статусе и согласованном плане обработки; их нельзя выдавать за успешно восстановленное опубликованное расписание.

ACC-26. Политика и качество. Выполнены AP-01–AP-18, все 20 POL связаны с реализацией и проверкой. В выпускаемой области закрыты применимые DEC-23–DEC-29 наряду с прежними календарными и миграционными решениями. Кандидат содержит конкретную утверждённую политику и проверенные зависимости. Совместность не скрывает независимых конфликтов; компактность не подменяет полноту; превышение вместимости не разрешается произвольным комментарием. Автоматический оптимизатор не требуется для приёмки B.

ACC-27. Календарные изменения и онлайн. Выполнены AP-19–AP-23. В B обязательны непосредственное создание занятия на дату, режим «День», перенос одного проведения и выделение выбранной группы по FR-069 без изменения остальных повторений. Исключения сохраняются при генерации, онлайн-формат явно назначается и отображается. Новая публикация точечного изменения не запускает пересоставление остальной сетки. Интеграции с видеоплатформами и автоматический оптимизатор не входят в эту приёмку.

Сроки пилотной эксплуатации, поддержки и исправления дефектов определяются отдельным соглашением после оценки объёма; в этом документе они не подменяются произвольными обещаниями исполнителя.

Развитие продукта после базовой версии§

Эти возможности представлены как кандидаты. Они не являются установленными функциями старой программы и не включаются в B только из-за упоминания в списке.

ID Расширение Что требуется определить до разработки
EXT-01 Перетаскивание занятий по сетке Жесты, доступная альтернатива, выбор области серии, ошибка конфликта, подтверждение переноса
EXT-02 Автоматический подбор/оптимизация расписания Целевая функция, жёсткие и мягкие ограничения, веса, время поиска, фиксация неизменяемых элементов и объяснение невозможности
EXT-03 Несколько преподавателей/аудиторий на занятие Роли ресурсов, одновременность, распределение участников, правила занятости и оплаты/нагрузки
EXT-04 Разные схемы подгрупп по дисциплинам Сведения о пересечении составов, источник членства, проверка конфликтов и версионирование схем
EXT-05 Личные кабинеты студентов и преподавателей Способ идентификации, связь с персоной, источники данных, доступ к изменениям и личные предпочтения
EXT-06 SSO и многофакторный вход Провайдер, OIDC/SAML-контракт, правила связывания и отключения локальных аккаунтов
EXT-07 Интеграция с учебной системой/1С/кадрами Владельцы полей, направления обмена, внешние ключи, ошибки, повторные доставки и разрешение конфликтов
EXT-08 iCalendar, подписки и уведомления Состав событий, отмены/переносы, UID, приватность ссылок, частота и гарантии доставки
EXT-09 Несколько площадок и переходы между корпусами Справочник зданий, матрица времени перехода, дистанционный формат и временные буферы
EXT-10 Ограничения преподавателя и пожелания нагрузки Приоритеты, владельцы согласования, пределы занятий/окон и способ разрешения предупреждений
EXT-11 Фактическое проведение и замены по дням Разделение планового и фактического расписания, подтверждение проведения и учёт нагрузки
EXT-12 Несколько организаций/SaaS Изоляция арендаторов, квоты, администрирование, хранение и миграции каждого арендатора
EXT-13 Высокая доступность и RPO меньше суток Репликация PostgreSQL, резервный узел, WAL/PITR, мониторинг и испытание переключения
EXT-14 Обратный экспорт в старую программу Точные форматы и правила BDE/Paradox, проверка основной программы, тестовые копии и риск повреждения индексов
EXT-15 Сравнение нескольких альтернативных черновиков Ветки, общий план, независимые бронирования, сравнение, слияние и выбор публикации

Для оптимизатора базовый критерий будущего ТЗ должен включать воспроизводимый набор данных, запрет нарушения жёстких правил, статус «решение не найдено за отведённое время», возможность остановки и предпросмотр до применения. Нельзя обещать оптимальное расписание для любого набора ограничений без определения критерия и допустимого времени.

Шаблон карточки нового требования§

### NEW-001. Название функции

- Статус: предложение / согласовано / отложено / снято.
- Приоритет и целевая версия:
- Проблема пользователя и ожидаемый результат:
- Роли и область доступа:
- Основание: новая потребность / источник / действующее требование:
- Входные данные и предварительные условия:
- Основной сценарий:
- Ошибки и альтернативные сценарии:
- Изменяемые сущности, публикации и история:
- Влияние на календарь, занятость и ограничения:
- Новые поля, миграция данных и совместимость API:
- События аудита и приватные данные:
- Массовые операции, повторный запрос и конкуренция:
- Ограничения ресурсов и времени выполнения:
- Критерии приёмки (дано / действие / ожидаемый результат):
- Какие существующие требования меняются:
- Открытые вопросы и кто принимает решение:

Журнал редакций ТЗ§

Версия Дата Изменение Статус
0.1 2026-09-09 Исходное ТЗ на веб-версию, PostgreSQL, миграцию и автономную эксплуатацию по исследованной системе Подготовлено для правок заказчика
0.2 2026-09-09 Переработано по SRC-08/SRC-09: FR-061–FR-068; формы/уровни/онлайн; совместные проведения разных планов; профили времени; метрики качества; вместимость и ресурсы; версии политики, API, миграция, DEC-23–DEC-29; полное соответствие 20 POL и 18 сценариев AP Рабочий проект: наблюдения отделены от утверждаемых настроек; ручная версия B сохранена, оптимизатор E
0.3 2026-09-09 По SRC-10 уточнены FR-028–FR-031, FR-035, FR-037, FR-046–FR-047, FR-053 и FR-057; добавлены FR-069, связь выделенных проведений, API-011 и AP-19–AP-23: конкретные даты, подневный просмотр, перенос одной группы, сохранение исключений и явный онлайн-формат Рабочая редакция по согласованному плану владельца; модернизация стека сохраняется, новые функции относятся к B

Приложение: сопоставление всех 88 исходных полей§

Каждое поле дополнительно сохраняется в import_raw_row.raw_payload независимо от выбранной нормализованной цели. «Только исходное» означает доступность в защищенном браузере источника и отсутствие неподтвержденного влияния на расчет расписания. Указанные ниже типы — типы исходного Paradox; типы новой PostgreSQL-модели определены выше. Отсутствующие в старой системе данные, включая дату окончания периода, концы пар, часовой пояс и правила публикации, задаются в интерфейсе настройки.

Исходное поле Исходный тип Перенос и правило
CHAIRS.ChairNo AutoIncrement legacy_identity → chair.id; не рабочий PK PostgreSQL
CHAIRS.ChairName Alpha(50 байт) chair.name
CHAIRS.FacultyNo Long chair.faculty_id; отсутствующие 46/48 — задача сопоставления
CLASSINF.ClassNo Long Только исходная связь дополнительного ресурса до включения расширения; самостоятельный источник
CLASSINF.RoomNo Long Только исходная связь дополнительной аудитории; часть составного ключа
CLASSINF.TeacherNo Long Только исходная связь дополнительного преподавателя
Classes.ClassNo AutoIncrement legacy_identity → импортируемая lesson_series; порожденные экземпляры сохраняют ссылку происхождения
Classes.GroupNo Long series_participant.group_id / occurrence_participant.group_id; для −1 раскрыть GRPPLAN
Classes.Subgroup Short series_participant.subgroup_id / occurrence_participant.subgroup_id; −1 не создает фиктивную подгруппу
Classes.PlanNo Long Найти plan_component через исходную пару (PlanNo,PlanType), установить lesson_series.component_id
Classes.PlanType Alpha(1 байт) Та же исходная пара определяет plan_component.lesson_type_id; название кода подтвердить
Classes.EachWeek Logical Исходное значение; lesson_series.recurrence_rule только после подтверждения календарных правил
Classes.Assigned Logical Исходное значение; не присваивать напрямую lesson_occurrence.status
Classes.OddWeek Logical Исходное значение; правило чередования только после утверждения точки отсчета и приоритета EachWeek
Classes.DayNo Short Исходный составной код; даты lesson_occurrence только по подтвержденному декодеру
Classes.TimeNo Short Сопоставление bell_slot; время экземпляра после утверждения даты и окончания/длительности
Classes.TeacherNo Long lesson_series.default_teacher_id и lesson_occurrence.teacher_id; −1 → NULL с сохранением оригинала
Classes.RoomNo Long lesson_series.default_room_id и lesson_occurrence.room_id; −1 → NULL с сохранением оригинала
Classes.Comment Alpha(64 байт) lesson_occurrence.private_comment после генерации экземпляров; полный текст в исходной строке
ClassesInf.PlanNo Long Только служебная сверка по исходному плану; не создает план или занятие
ClassesInf.RoomNo Long Только служебная сверка; одно расхождение с Classes требует решения
ClassesInf.EachWeek Logical Только служебная сверка исходного флага
ClassesInf.OddWeek Logical Только служебная сверка исходного флага
ClassesInf.Assigned Logical Только служебная сверка исходного флага
ClassesInf.DayNo Short Только служебная сверка исходного кода позиции
ClassesInf.TimeNo Short Только служебная сверка исходного номера времени
ClassesInf.Stable Logical Только сверка с Plan.Stable; не задает фиксацию занятия
Courses.CourseNo AutoIncrement legacy_identity → course_category.id; не study_year
Courses.CourseCount Short Только исходное число до расшифровки; не study_year
Courses.CourseName Alpha(255 байт) course_category.name
DAYS.DayNo Short Таблица соответствия день 0–5 → ISO-день 1–6; не FK для всех Classes.DayNo
DAYS.DayName Alpha(11 байт) Исходная подпись дня для просмотра/проверки локализации
DAYS.ShortDayName Alpha(2 байт) Исходная короткая подпись дня для просмотра/проверки локализации
FACULTY.FacultyNo AutoIncrement legacy_identity → faculty.id
FACULTY.FacultyName Alpha(32 байт) faculty.name
GROUPS.GroupNo AutoIncrement legacy_identity → academic_group.id
GROUPS.GroupName Alpha(8 байт) academic_group.name; классификация формы/уровня/онлайн/билингвальности в group_study_profile по версионированному POLICY-02 с сохранением исходного обозначения
GROUPS.FacultyNo Long academic_group.faculty_id по исходному ключу
GROUPS.NSubgroups Short Число исходных подгрупп; подготовить group_partition и subgroup, требующие подтверждения независимости
GROUPS.NStudents Short academic_group.student_count; число подгруппы не вычислять равным делением
GROUPS.StreamNo Long cohort_group только при подтвержденной положительной ссылке; в этом снимке −1 у всех групп
GROUPS.CourseNo Long academic_group.course_category_id по ключу классификатора
GRPPLAN.GroupNo Long plan_participant.group_id; часть исходного составного ключа
GRPPLAN.Subgroup Short plan_participant.subgroup_id; исходную −1 трактовать в контексте состава
GRPPLAN.PlanNo Long plan_participant.plan_id; часть исходного составного ключа
PLANITEM.PlanNo Long plan_component.plan_id; часть исходного составного ключа
PLANITEM.PlanType Alpha(1 байт) plan_component.lesson_type_id через подтвержденный справочник кодов
PLANITEM.PlanQty Short plan_component.planned_quantity, первоначально quantity_unit=unknown; не счетчик занятий
PLANITEM.GrpSplit Logical Исходный флаг и предлагаемый split_policy; способ генерации подтверждается до применения
PLANROOM.PlanNo Long plan_room_preference.component_id через пару (PlanNo,PlanType), если появятся строки
PLANROOM.PlanType Alpha(1 байт) Та же пара определяет компонент; смысл предпочтения требует подтверждения
PLANROOM.RoomNo Long plan_room_preference.room_id по исходному ключу; не фактическое бронирование
Plan.PlanNo AutoIncrement legacy_identity → curriculum_plan.id
Plan.SubjectNo Long curriculum_plan.subject_id
Plan.ChairNo Long curriculum_plan.chair_id
Plan.Stable Logical Только исходный флаг до проверки действия; не lesson_occurrence.is_fixed
ROOMRSTR.RoomNo Long availability_rule.resource_id ресурса комнаты после нормализации ограничения
ROOMRSTR.DayNo Short Исходный день 0–5; календарное правило доступности после привязки периода
ROOMRSTR.TimeNo Short Ссылка на исходный слот; конкретный интервал требует времени окончания
ROOMRSTR.Week Short Исходное значение 0/1; смысл и приоритет чередования должны быть утверждены
ROOMRSTR.Reason Alpha(64 байт) availability_rule.reason; закрытое текстовое поле, полный текст сохраняется
Rooms.RoomNo AutoIncrement legacy_identity → room.id
Rooms.RoomName Alpha(8 байт) room.name; не разбирать автоматически на корпус/кабинет
Rooms.RoomCap Short room.capacity
Rooms.RoomSpec Logical Только исходный флаг; не создавать оборудование по догадке
Rooms.RoomType Alpha(1 байт) room.room_type_id через отдельный подтвержденный классификатор
Rooms.RoomMemo Alpha(64 байт) room.private_note
Rooms.ChairNo Long room.chair_id; 0 и −1 сохраняются раздельно до решения
STREAMS.StreamNo AutoIncrement legacy_identity → named_cohort.id
STREAMS.StreamName Alpha(255 байт) named_cohort.name; имя не определяет участников занятия
SUBJECTS.SubjectNo AutoIncrement legacy_identity → subject.id
SUBJECTS.SubjectName Alpha(35 байт) subject.name
SUBJECTS.SubjectChar Alpha(1 байт) subject.legacy_character; без новой бизнес-логики до расшифровки
SUBJECTS.SubjectShortName Alpha(10 байт) subject.short_name
TCHRRSTR.TeacherNo Long availability_rule.resource_id ресурса преподавателя после нормализации ограничения
TCHRRSTR.DayNo Short Исходный день 0–5; календарное правило доступности после привязки периода
TCHRRSTR.TimeNo Short Ссылка на исходный слот; конкретный интервал требует времени окончания
TCHRRSTR.Week Short Исходное значение 0/1; трактовка требует подтверждения
TCHRRSTR.Reason Alpha(64 байт) availability_rule.reason; закрытое текстовое поле, полный текст сохраняется
TEACHERS.TeacherNo AutoIncrement legacy_identity → teacher.id
TEACHERS.TeacherName Alpha(30 байт) teacher.full_name; не уникальный ключ
TEACHERS.ChairNo Long teacher.chair_id; −1 → NULL только по правилу этого поля
TEACHERS.TeacherDegree Alpha(16 байт) teacher.degree
TEACHERS.TeacherPosition Alpha(16 байт) teacher.position
TEACHERS.TeacherTitle Alpha(16 байт) teacher.title
TEACHERS.TeacherMemo Alpha(40 байт) teacher.private_note
TIMES.TimeNo Short legacy_identity → bell_slot.id; исходный номер → bell_slot.ordinal
TIMES.TimeName Alpha(10 байт) Разбор в bell_slot.start_time; оригинальная строка сохраняется, окончания нет в источнике