# План разработки приложения «Расписание НГУЭУ»

**Версия плана:** 1.0 · **Дата:** 9 сентября 2026 года · **Основание:** ТЗ 0.3.  
**Статус:** комплект для начала реализации; приложение по этому плану ещё не разработано.  
**Исполнитель:** GPT-6 Astra под контролем владельца продукта и ответственного за эксплуатацию.

## 1. Назначение и состав комплекта

План превращает [ТЗ версии 0.3](web-system-specification.html) и [политику составления расписания](schedule-policy.html) в 64 проверяемые задачи на 10 этапах. Он сохраняет весь базовый объём: 67 обязательных FR, календарные даты, точечные переносы, выделение группы, онлайн-формат, политику, миграцию, публикации и эксплуатацию. FR-059 и FR-060 остаются расширениями.

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

Комплект включает этот редактируемый Markdown, [инструкцию и готовые запросы для Astra](astra-implementation-runbook.html), производный список задач `planning/backlog.json`, [матрицу покрытия](implementation-coverage.html), реестр состояния `planning/progress.json` и утилиту `tools/implementation_plan.py`. JSON формируется из Markdown; задачи редактируются здесь. Состояние выполнения и доказательства хранятся отдельно и не сбрасываются при пересборке документов.

| Источник | Зафиксированное основание |
|---|---|
| ТЗ | `docs/web-system-specification.md`, версия 0.3 |
| SHA-256 ТЗ | `97da2966972f68081b459107cd2fa4c868950331013452e4e6b5df3cbec98631` |
| Политика | `docs/schedule-policy.md`, аналитическая версия 0.1 |
| SHA-256 политики | `ed4ca4c44b69a4e2b2f9510cc4912fe90593797b8f5a90f2b30b91af019cf29d` |
| Исходная SQLite | `exports/schedule.sqlite`, только чтение, закрытый контур |
| SHA-256 SQLite | `c9754cd457d4902429ccfcbf85cdf54c7307b0cfdf74f3ed6b6ead0f8ca207b0` |

## 2. Результаты анализа текущего ТЗ

ТЗ уже подробно определяет поведение нового продукта, но текущий проект содержит исследование, извлечение данных, статические документы и исследовательский просмотрщик. Этот просмотрщик не является каркасом полноценного редактора: в нём нельзя считать реализованными Django-модель, объектные права, транзакционные команды, календарные исключения или публикации. Аналитические скрипты полезны как контрольные источники и примеры; их предположения нельзя автоматически переносить в рабочие правила.

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

| Наблюдение по ТЗ | Следствие для реализации |
|---|---|
| Реальная дата принадлежит каждому проведению | Отдельные модели серии, экземпляра и исключения; режим «День» не вычисляется из старого DayNo |
| Одно проведение обслуживает несколько планов | M:N связи и отдельные зачёты потребностей; нельзя строить модель «одна серия — один план» |
| Перенос группы меняет состав исходного события | Одна доменная транзакция для двух событий, зачётов, исключения и бронирований |
| Черновики изолированы, публикации делят реальные ресурсы | Отдельные ограничения для редакции и активных публикаций всей организации |
| Много свойств старых данных не расшифровано | Raw/staging, очередь решений и проверяемые преобразования; чтение доступно до нормализации |
| Статистическая политика не равна утверждённой норме | Черновые шаблоны, область, доказательность, явное утверждение и версии |
| Индивидуальные переносы допускают новый снимок | Выпуск версии не должен вызывать пересоставление остальных занятий |
| Онлайн не определяется отсутствием комнаты | Явный формат, отдельные права на реквизиты, единая метка в выдаче и печати |
| Автономность включает эксплуатацию | Локальные ассеты, устойчивые задания, backup/restore, инструкции без облака разработчика |

До разработки зависимых миграций TASK-003 фиксирует ADR: единую терминологию DTO/БД, границу версии справочников и редакции, идентичность участников между периодами, порядок блокировок, происхождение выделенного события и повторяемость заданий. Это техническая детализация уже выбранной архитектуры. Часы, календарь и строгость норм остаются решениями соответствующих владельцев.

## 3. Архитектура и организация исходников

Сохраняется модульный монолит: **React/TypeScript → Django/DRF → PostgreSQL**, фоновые задания Celery/Redis, Nginx и Docker Compose. PostgreSQL является серверной СУБД, SQLite — неизменяемым источником переноса. Delphi, BDE и Paradox не нужны для работы новой системы. GPT-6 Astra используется как исполнитель разработки; работа приложения не зависит от модели и OpenAI API.

Версии стека из ТЗ: React 19, Vite 8 / Node.js 24 LTS для сборки, Python 3.13, Django 5.2 LTS, DRF 3.16, PostgreSQL 18, psycopg 3, Celery 5.6, Redis 8. Это зафиксированная база планирования, а не новая проверка совместимости всех пакетов. В TASK-003 исполнитель сверяет официальные требования, поддержку и лицензии, в TASK-005 фиксирует точные версии в lock-файлах и образах. Несовместимость оформляется ADR и предложением изменения, а не скрытой заменой технологии.

Рабочее решение для размещения исходников — изолированный каталог `product/` в текущем проекте с собственным контролем версий. Его можно перенести в отдельный репозиторий без изменения предметной модели. До начала работ TASK-001 проверяет фактическое состояние Git и не добавляет исследовательские БД в историю.

```text
product/
  backend/        accounts, access, catalogs, participants, planning,
                  calendar, scheduling, policy, quality, imports,
                  workflow, publications, jobs, audit
  frontend/       app, shared/ui, shared/api, features
  tests/          unit, db, api, e2e, security, migration, load
  fixtures/       синтетические данные; приватный источник снаружи
  deploy/         Compose, Nginx, диагностика
  scripts/        импорт, backup, restore, release
  docs/           ADR, OpenAPI, ER, инструкции, решения, evidence
  Makefile        единый набор воспроизводимых команд
```

Корневая папка `deploy/` продолжает обслуживать сайт исследования. Будущая `product/deploy/` относится к приложению. Существующая парольная защита всего `/data/`, включая `/data/policy/`, сохраняется. Тестовые, приёмочные и рабочие базы, тома, домены/порты и секреты должны различаться.

## 4. Этапы и демонстрируемые результаты

Этапы — контрольные рубежи. Исполняемый порядок определяют зависимости задач: TASK-040 относится к основе и выполняется до зависимых задач календаря/импорта, несмотря на его номер. Номер задачи — стабильный идентификатор, не жёсткий календарный порядок.

| Этап | Задачи | Проверяемый результат |
|---|---|---|
| 00. Исходная точка и решения | 001–004 | Зафиксированы источники, ADR, ограничения и тестовые примеры |
| 01. Основа приложения | 005–010, 040 | Чистый запуск, CI, сессии, области доступа, оболочка и устойчивая очередь |
| 02. Учебная модель | 011–017 | Справочники, периоды, потребность и проверенные участники |
| 03. Календарное ядро | 018–024 | Разовая дата, серии, исключения, генерация и защита занятости |
| 04. Ручной редактор | 025–032 | День/неделя/список, перенос одного занятия и выбранной группы |
| 05. Политика и качество | 033–039 | Утверждаемые правила, объяснения конфликтов и раздельные дельты |
| 06. Управляемый перенос | 041–046 | Все источники сохранены, неоднозначности видны, перенос и откат проверены |
| 07. Согласование и выпуск | 047–052 | Неизменяемые публикации, читатели, печать, выгрузки и справка |
| 08. Производственная готовность | 053–058 | Безопасность, нагрузка, автономная установка, восстановление и обновление |
| 09. Приёмка и запуск | 059–064 | Доказательства покрытия, пилот, согласованный переход и передача |

Первый содержательный показ пользователю: после TASK-021 и TASK-026 создать занятие 15 марта и открыть его в трёх режимах. Этот показ не требует завершённой исторической миграции. Следующий рубеж — TASK-032 с переносом группы и исключениями. Базовая поставка завершена только после всех обязательных задач, владельческого согласования применимых решений и производственной приёмки.

Критические цепочки: участники → бронирования → единые команды → исключения → совместность → перенос группы; политика → readiness → frozen snapshot → глобальная активация; staging → подтверждение семантики → commit → сверка миграции; стенд → backup/restore → обновление → пилот → ввод. Зависимости, включая боковые входы каждой цепочки, перечислены в карточках и проверяются программно.

Не назначаются вымышленные сроки по размеру контекста или названию модели. S — одна ограниченная задача; M — несколько связанных изменений с одной демонстрацией результата. Если M не помещается в один безопасный цикл реализации и проверки, Astra сначала делит её на подзадачи `TASK-NNN/a`, `/b` с собственными критериями, сохраняя родительскую приёмку. После TASK-009 и TASK-021 можно оценить темп по фактическим изменениям, дефектам и длительности проверок. Внешние согласования и серверные испытания оцениваются отдельно.

## 5. Решения владельца и блокировки

Все 29 DEC передаются в машинный реестр. DEC-19 уже подтверждает точечные изменения новой версии. Остальные записи сохраняют нерешённые предметные вопросы до конкретного ответа или доказательства; некоторые вопросы допускают решение «не применяется к пилоту» с областью и обоснованием. Это не разрешение пропустить требование в окончательной поставке.

| Условие допуска | Решения | Что нельзя объявить готовым до решения | Что можно делать сразу |
|---|---|---|---|
| Достоверные исторические даты | DEC-01, 02, 05 | Календарную миграцию и публикацию восстановленных дат | Новые периоды и события на явно заданных тестовых датах |
| Часы и повторения | DEC-04, 20 | Эквивалентную генерацию из старого PlanQty | Новую потребность с явной единицей и областью |
| Состав и совместность | DEC-09, 10, 14 | Подтверждение соответствующих исторических объединений | Модель атомов, консервативные конфликты и synthetic joint |
| Старые признаки/справочники | DEC-06, 07, 11, 15, 16, 17 | Семантическую сверку затронутых строк | Сохранение raw и диагностический просмотр |
| Доступ и согласование | DEC-08, 18, 22, 29 | Назначение реальных полномочий и выпуск пилота | Реализацию проверяемой матрицы на тестовых ролях |
| Ограничения ресурсов | DEC-03, 12, 13, 27 | Публикацию с неразрешёнными применимыми ограничениями/ресурсами | Механизм версий, сроков, предупреждений и блокировок |
| Временные режимы и заочная сессия | DEC-23, 24 | Превращение наблюдений в обязательные реальные профили | Черновые шаблоны и сценарии с явными тестовыми профилями |
| Помещения и переходы | DEC-25, 26 | Реальный выпуск при непроверенной обязательной вместимости/совместимости | Формы и механизм применения утверждённых правил |
| Качество | DEC-28 | Скрытую целевую функцию или новые жёсткие пределы | Раздельные метрики B; оптимизатор остаётся E |
| Переключение записи | DEC-21 | Финальный переход на новую систему | Репетицию, сверку и подготовку конкретного плана |

Поле «Решения» в карточке задаёт обязательный контекст. Оно не блокирует написание механизма на синтетических данных. Поле «Допуск» задаёт решения, необходимые для закрытия всей задачи, включая работу с реальными данными. Если закрыта только техническая часть, задача остаётся `blocked` или `in_progress` с точным остатком, а независимые готовые задачи продолжаются.

TASK-043 и TASK-046 содержат явные допуски реальной миграции. Перед TASK-061 владелец проверяет применимость всех DEC; для ограниченного пилота исключение имеет область, причину и подтверждение. TASK-062/063 требуют подтверждённого окна и порядка перехода. Модель не принимает эти решения за владельца и не выдаёт отсутствие ответа за согласие.

## 6. Проверки, которые нельзя отложить до финала

| Риск | Минимальное доказательство | Основные задачи |
|---|---|---|
| Двойная занятость | Реальные конкурентные транзакции PostgreSQL, два соединения и барьер; успешна не более одной записи | 017, 019, 020, 049 |
| Потеря исключений | Повторить материализацию после переноса/отмены/выделения группы и сверить ID, составы, зачёты | 023, 027, 031, 032 |
| Удвоение учебного объёма | Два плана, общее событие и разделение А/Б: группе по 2 часа, учителю 4 после разделения | 016, 030, 031 |
| Неверная публикация | Гонки freeze/редактирования и двух периодов; старый снимок целиком сохраняется при отказе | 048, 049 |
| Утечка данных | Прямые UUID, чужие поля, ошибки, аудит, экспорт, print и файлы по ролям | 008, 050, 051, 053 |
| Потеря исходников | 19 таблиц, 88 полей, 75 909 строк, происхождение и идемпотентный повтор | 041–046 |
| Неработающее восстановление | Удаление только изолированного тестового окружения и восстановление с замерами | 056, 057 |
| Формальная «готовность» | Ссылка на код, конкретный тест/протокол и проверенную версию по каждому B | 059, 060 |

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

Стандартные точки запуска после TASK-006: `make lint`, `make typecheck`, `make test-unit`, `make test-db`, `make test-api`, `make test-e2e`, `make build`, `make check-migrations`. Это контракт будущего каркаса: сейчас в исследовательском проекте таких целей ещё нет. Специализированные `make test-migration`, `make test-security`, `make test-load` добавляются соответствующими задачами. В отчёте всегда указываются реально выполненная команда и её результат.

## 7. Порядок работы GPT-6 Astra

Рабочая единица — одна доступная по зависимостям задача с законченным результатом. Модель читает общие инструкции, карточку, непосредственно связанные разделы ТЗ и фактический код, реализует задачу, выполняет проверку и сохраняет короткий handoff. Повторное чтение всего исследования при каждом запуске не требуется. Для сложной миграции, переноса группы и публикации нужен пересмотр решения с позиции конфликтов и частичного отказа перед завершением.

В официальном руководстве Astra отмечены чувствительность к инструкциям, склонность уточнять важные неопределённости и необходимость соразмерных проверок. Поэтому здесь явно заданы границы автономности, условия предметных решений и формат доказательств. Идентификатор модели — `gpt-6-astra`. [Официальное руководство OpenAI по GPT-6 Astra](https://developers.openai.com/api/docs/guides/latest-model).

Предлагаемые усилия в карточках — настройка процесса этого проекта: `high` для обычной реализации, `xhigh` для схемы, конкурентных операций, миграции и публикации. Это не гарантия качества и не лимит токенов. Конкретные доступные настройки проверяются в среде запуска; они не добавляются в код приложения. Последовательная работа — исходный режим. Дополнительные агенты возможны только при отдельном разрешении пользователя и независимых областях файлов; одновременные изменения общей схемы и API требуют единого согласованного контракта.

Полные готовые запросы, правила возобновления и формат отчёта находятся в [инструкции Astra](astra-implementation-runbook.html).

## 8. Карточки задач

Ссылки требований используют идентификаторы действующего ТЗ. Диапазон `AP-01..AP-23` включает обе границы. Размер и усилие помогают подготовить сеанс; они не заменяют критерии приёмки. Все задачи ниже относятся к базовой реализации B; каждая первоначально имеет статус `todo`.

<a id="task-001"></a>

### TASK-001. Зафиксировать исходную точку проекта

| Поле | Значение |
|---|---|
| Этап | 00 |
| Зависимости | — |
| Требования | SYS-001 DATA-01 DEL-001 |
| Проверки ТЗ | — |
| Решения | — |
| Допуск | — |
| Размер | S |
| Усилие | high |
| Область | `product/docs/baseline.md`; `product/README.md` |

**Работы.** Создать изолированную область product/ и паспорт исходной точки. Проверить отсутствие чужих изменений, описать существующий исследовательский просмотрщик и границы нового продукта. Зафиксировать хеши ТЗ 0.3, политики и SQLite, структуру будущего репозитория; настроить исключение секретов, исходных БД и локальных томов из Git.

**Приёмка.** Изменения старого viewer/, DB/, exports/ и действующего deploy/ не требуются. Новый продукт не выдаётся за уже реализованный. Команды запуска пока помечены как будущие.

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

<a id="task-002"></a>

### TASK-002. Вести предметные решения и условия допуска

| Поле | Значение |
|---|---|
| Этап | 00 |
| Зависимости | TASK-001 |
| Требования | POLICY-01 TRACE-01 FR-068 |
| Проверки ТЗ | ACC-03 |
| Решения | DEC-01..DEC-29 |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/docs/decisions/`; `product/docs/readiness.md` |

**Работы.** Перенести DEC-01–DEC-29 в рабочий реестр: владелец, вопрос, пример, доказательство, статус, блокируемая операция. DEC-19 пометить подтверждённым; остальные сверить с новыми ответами владельца. Для нерешённых дат, часов и ограничений подготовить короткие воспроизводимые примеры.

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

**Проверка.** Сверить все 29 DEC с ТЗ и таблицей условий допуска этого плана; составить один сгруппированный запрос владельцу только по действительно отсутствующим сведениям.

<a id="task-003"></a>

### TASK-003. Согласовать технические контракты и ADR

| Поле | Значение |
|---|---|
| Этап | 00 |
| Зависимости | TASK-001 |
| Требования | SYS-002 SYS-003 SYS-004 DATA-02 DATA-03 DATA-05 |
| Проверки ТЗ | — |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/docs/adr/`; `product/docs/domain/`; `product/docs/dependencies.md` |

**Работы.** Подготовить ADR по модульному монолиту, границам периодов/редакций, глобальным ресурсам, версиям справочников, M:N серия–компонент, атомам участников, публикации и очереди. Согласовать имена start_at в API и starts_at в БД. Проверить официальную совместимость и лицензии зависимостей ТЗ перед фиксацией точных версий.

**Приёмка.** Архитектура сохраняет React/TypeScript, Django/DRF, PostgreSQL. Каждое ADR содержит инвариант, выбранный вариант, отклонённые варианты и проверку. Неподтверждённые нормы расписания не становятся техническими константами.

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

<a id="task-004"></a>

### TASK-004. Подготовить контрольные данные и каталог проверок

| Поле | Значение |
|---|---|
| Этап | 00 |
| Зависимости | TASK-001 TASK-002 TASK-003 |
| Требования | NFR-014 AP-00 |
| Проверки ТЗ | AP-01 AP-03 AP-04 AP-09 AP-14 AC-D01 AC-D05 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/fixtures/`; `product/tests/cases/`; `product/docs/test-catalog.md` |

**Работы.** Создать синтетические группы А/Б, подгруппы, два периода, преподавателей, комнаты, планы и даты 8/15/17/22 марта 2027 года. Составить обезличенные пограничные наборы. Реальный SQLite подключать только read-only в закрытом локальном профиле, с отдельным манифестом ожидаемых счётчиков.

**Приёмка.** Обычный CI не требует приватной БД; отдельный локальный прогон проверяет подлинные контрольные числа. Синтетические даты и нормы подписаны как тестовые.

**Проверка.** Проверить отсутствие персональных заметок и реквизитов подключения в публичных фикстурах; установить соответствие сценариев AP/AC-D/ACC тестовым идентификаторам.

<a id="task-005"></a>

### TASK-005. Создать воспроизводимый каркас приложения

| Поле | Значение |
|---|---|
| Этап | 01 |
| Зависимости | TASK-003 |
| Требования | SYS-003 SYS-004 SYS-005 OPS-001 OPS-002 OPS-003 OPS-005 OPS-006 |
| Проверки ТЗ | — |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/`; `product/frontend/`; `product/deploy/`; `product/Makefile` |

**Работы.** Создать Django/DRF и React/TypeScript strict, локальные PostgreSQL и Redis, Dockerfile и Compose, lock-файлы и .env.example без секретов. Добавить единый origin через прокси, health/readiness и команды установки, lint, typecheck, test, build, migrate. Все ассеты поставлять локально.

**Приёмка.** Чистый checkout запускается по README. Данные переживают пересоздание контейнеров. Runtime БД не суперпользователь, миграции выполняются отдельной ролью. Приложение не требует OpenAI API для работы.

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

<a id="task-006"></a>

### TASK-006. Настроить CI и обязательные проверки

| Поле | Значение |
|---|---|
| Этап | 01 |
| Зависимости | TASK-004 TASK-005 |
| Требования | SYS-003 NFR-014 DEL-002 |
| Проверки ТЗ | — |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/.github/workflows/`; `product/tests/`; `product/Makefile` |

**Работы.** Зафиксировать команды make lint, typecheck, test-unit, test-db, test-api, test-e2e, build и check-migrations. Поднять в CI PostgreSQL той же основной версии; разделить быстрые проверки PR, интеграционные и отдельный нагрузочный прогон. Выбранная CI-площадка заменяема локальными командами.

**Приёмка.** На каждом изменении видны реальные результаты и код завершения. Range constraints, блокировки и гонки никогда не проверяются заменой PostgreSQL на SQLite.

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

<a id="task-007"></a>

### TASK-007. Реализовать индивидуальные учётные записи

| Поле | Значение |
|---|---|
| Этап | 01 |
| Зависимости | TASK-005 TASK-006 TASK-009 TASK-010 |
| Требования | FR-001 SEC-001 SEC-002 SEC-003 SEC-004 LEG-59 |
| Проверки ТЗ | — |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/accounts/`; `product/frontend/features/auth/` |

**Работы.** Добавить вход/выход, PostgreSQL-сессии, CSRF, защищённые cookies, отключение аккаунта, ограничения попыток и административный одноразовый сброс. Создавать первого администратора командой. Реализовать абсолютный и неактивный тайм-аут с предупреждением формы.

**Приёмка.** Нет встроенного пароля и токенов в localStorage; Redis не является хранилищем сессий. Отключение аккаунта завершает все его сеансы; отсутствие SMTP не мешает сбросу.

**Проверка.** Реальные HTTP-тесты входа, CSRF, просроченной и отозванной сессии, перебора и сброса; повторить чтение при недоступном Redis.

<a id="task-008"></a>

### TASK-008. Ввести роли, области и доступ к полям

| Поле | Значение |
|---|---|
| Этап | 01 |
| Зависимости | TASK-007 TASK-010 |
| Требования | FR-002 FR-003 FR-004 FR-005 SEC-005 SEC-006 SEC-007 SEC-012 API-004 |
| Проверки ТЗ | ACC-16 |
| Решения | DEC-18 DEC-22 DEC-29 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/access/`; `product/frontend/features/access/`; `product/tests/security/` |

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

**Приёмка.** Скрытый UUID не раскрывает существование или поля объекта. Технический администратор не получает предметное утверждение политики неявно. По умолчанию анонимная выдача выключена.

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

<a id="task-009"></a>

### TASK-009. Создать корпоративную оболочку и формы

| Поле | Значение |
|---|---|
| Этап | 01 |
| Зависимости | TASK-005 |
| Требования | FR-006 NFR-009 NFR-010 NFR-011 NFR-012 SYS-005 |
| Проверки ТЗ | — |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/frontend/app/`; `product/frontend/shared/ui/` |

**Работы.** Перенести корпоративные токены, Verdana и выбранный SVG «Сетка расписания» в локальные ассеты. Сделать навигацию, выбор периода, общие таблицы/формы/диалоги и состояния загрузки, пустоты, ошибки, отказа и несохранённого ввода.

**Приёмка.** Отступы компактные; текст на всю ширину колонки, таблицы прокручиваются локально. Фокус удерживается и возвращается; операция доступна без drag-and-drop.

**Проверка.** Проверить 1440×900, 1280×720, 390 px и масштаб 200%, клавиатуру и контраст; компонентные тесты на потерю ввода и смену периода.

<a id="task-010"></a>

### TASK-010. Зафиксировать OpenAPI и инфраструктуру команд

| Поле | Значение |
|---|---|
| Этап | 01 |
| Зависимости | TASK-003 TASK-005 TASK-006 |
| Требования | API-001 API-002 API-003 API-005 API-006 API-008 API-009 |
| Проверки ТЗ | — |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/api/`; `product/docs/openapi.yaml`; `product/frontend/shared/api/` |

**Работы.** Описать версионированные маршруты, фильтрацию, пагинацию, единую ошибку, ETag/If-Match, expected_revision_version и Idempotency-Key. Реализовать общую регистрацию команды и повтор результата; настроить проверяемые типы клиента из OpenAPI. Бизнес-команды появятся в своих задачах.

**Приёмка.** Отсутствующее условие версии даёт 428, устаревшее 412, изменённое тело под тем же ключом 409. Лимит синхронной пачки 200 не допускает частичного успеха. Обычные ключи живут минимум 24 часа.

**Проверка.** Контрактные HTTP-тесты неизвестных полей, неверных ID, повторов и ошибок; временно недоступная БД даёт честную ошибку, не успешную квитанцию.

<a id="task-011"></a>

### TASK-011. Реализовать общие справочники

| Поле | Значение |
|---|---|
| Этап | 02 |
| Зависимости | TASK-008 TASK-009 TASK-010 |
| Требования | FR-007 FR-008 FR-009 FR-010 FR-013 FR-014 FR-017 DATA-03 DATA-04 LEG-05..LEG-12 LEG-17..LEG-21 LEG-30 POL-16 |
| Проверки ТЗ | AP-13 |
| Решения | DEC-11 DEC-17 |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/catalogs/`; `product/frontend/features/catalogs/` |

**Работы.** Создать организацию, факультеты, кафедры, уровни/курсы, преподавателей, дисциплины и виды занятий с UUID, архивированием и ограничением удаления используемых записей. Подключить унифицированные CRUD-формы, поиск кириллицей, пагинацию и версии.

**Приёмка.** Одинаковые ФИО и названия не сливаются. Должность преподавателя не порождает приоритеты. CourseNo не превращается в год обучения; е/ё различаются согласно ТЗ.

**Проверка.** Проверить архивирование связанного справочника, роли кафедры, одинаковые ФИО, поиск и конкурентную правку карточки.

<a id="task-012"></a>

### TASK-012. Описать группы, подгруппы и административные потоки

| Поле | Значение |
|---|---|
| Этап | 02 |
| Зависимости | TASK-011 |
| Требования | FR-011 FR-012 FR-016 DATA-05 LEG-01..LEG-04 LEG-31..LEG-34 |
| Проверки ТЗ | AC-D06 |
| Решения | DEC-09 DEC-15 |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/participants/`; `product/frontend/features/groups/` |

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

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

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

<a id="task-013"></a>

### TASK-013. Реализовать подтверждённый классификатор групп

| Поле | Значение |
|---|---|
| Этап | 02 |
| Зависимости | TASK-012 TASK-004 |
| Требования | POLICY-02 FR-011 POL-06 |
| Проверки ТЗ | AP-02 |
| Решения | — |
| Допуск | — |
| Размер | S |
| Усилие | high |
| Область | `product/backend/participants/classification.py`; `product/tests/fixtures/classification/` |

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

**Приёмка.** 394 очные, 123 заочные, 37 вечерние, 23 онлайн и 6 билингвальных воспроизводятся на исходном снимке. Форма, уровень и модальность независимы.

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

<a id="task-014"></a>

### TASK-014. Создать каталог помещений и оснащения

| Поле | Значение |
|---|---|
| Этап | 02 |
| Зависимости | TASK-011 |
| Требования | FR-015 FR-066 LEG-13..LEG-16 |
| Проверки ТЗ | — |
| Решения | DEC-25 DEC-26 |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/rooms/`; `product/frontend/features/rooms/` |

**Работы.** Описать корпуса, комнаты, типы, вместимость, оснащение, источник и дату проверки. Добавить редактор совместимости и матрицы переходов как явных данных. Не выводить корпус и назначение комнаты только из префикса.

**Приёмка.** Неизвестное значение отличается от нуля. Изменение справочника имеет версию; будущие публикации смогут фиксировать исторические подписи.

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

<a id="task-015"></a>

### TASK-015. Настроить учебные периоды и звонки

| Поле | Значение |
|---|---|
| Этап | 02 |
| Зависимости | TASK-011 |
| Требования | FR-018 FR-019 FR-028 CAL-03 CAL-04 DATA-02 LEG-36 LEG-57 |
| Проверки ТЗ | AC-D09 |
| Решения | DEC-02 DEC-05 |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/calendar/periods/`; `product/frontend/features/periods/` |

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

**Приёмка.** Дата за границей периода отклоняется; конец пары не выводится из следующего старта. Интервалы конечные [start,end), сохраняются timestamptz и ISO со смещением.

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

<a id="task-016"></a>

### TASK-016. Реализовать учебную потребность и расчёт объёма

| Поле | Значение |
|---|---|
| Этап | 02 |
| Зависимости | TASK-012 TASK-015 |
| Требования | FR-020 FR-021 FR-022 FR-023 FR-025 FR-026 FR-027 CAL-01 LEG-22..LEG-26 LEG-28 LEG-29 |
| Проверки ТЗ | ACC-07 |
| Решения | DEC-04 DEC-10 DEC-11 DEC-20 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/planning/`; `product/frontend/features/plans/` |

**Работы.** Создать позиции плана и компоненты по видам нагрузки, составы групп/подгрупп, единицы, quantity_scope и округление. Рассчитывать остаток размещения отдельно от фактических минут, ресурсов и числа студентов. Предпросмотр изменения плана показывает затронутые занятия.

**Приёмка.** Новые явно заданные единицы работают; неизвестный исторический PlanQty не пересчитывается автоматически. Два плана одной группы остаются разными потребностями.

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

<a id="task-017"></a>

### TASK-017. Построить атомарную модель участников

| Поле | Значение |
|---|---|
| Этап | 02 |
| Зависимости | TASK-012 TASK-016 |
| Требования | CON-01 DATA-05 POL-01 POL-03 |
| Проверки ТЗ | AC-D10 AP-05 |
| Решения | DEC-09 DEC-10 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/participants/resources/`; `product/tests/db/participants/` |

**Работы.** Создать глобальные schedulable_resource, атомы подтверждённых непересекающихся составов и сопоставление разных схем. Ввести консервативное пересечение при неизвестном составе; изменение схемы должно выявлять затронутые события и публикации.

**Приёмка.** Целая группа занимает все свои атомы; отдельные подтверждённые части идут параллельно. Разные UUID разных схем не доказывают непересечение.

**Проверка.** На реальном PostgreSQL проверить целую группу, две части, неизвестную и сменённую схему, включая два периода; приложить ER и доказательство покрытия участников.

<a id="task-018"></a>

### TASK-018. Создать редакции, серии и экземпляры

| Поле | Значение |
|---|---|
| Этап | 03 |
| Зависимости | TASK-014 TASK-015 TASK-016 TASK-017 |
| Требования | DATA-02 DATA-05 FR-030 FR-031 CAL-06 CAL-07 |
| Проверки ТЗ | AC-D08 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/scheduling/models/`; `product/backend/scheduling/migrations/` |

**Работы.** Создать draft/frozen-редакции, series_component M:N, календарные экземпляры, назначения потребностей и ресурсы. Разделить unplaced/scheduled/cancelled, fixed и согласование. Ввести версию агрегата и запрет изменения frozen, включая обход через служебные операции.

**Приёмка.** Один редактируемый черновик на период. unplaced с историческими координатами не занимает ресурсы. У scheduled есть явные дата/время/участники/формат; известные ресурсы резервируются даже при неполноте.

**Проверка.** Проверить состояния и ограничения БД, миграции с чистой схемы, невозможность прямой записи в frozen разрешёнными прикладными путями.

<a id="task-019"></a>

### TASK-019. Обеспечить транзакционную занятость ресурсов

| Поле | Значение |
|---|---|
| Этап | 03 |
| Зависимости | TASK-017 TASK-018 |
| Требования | FR-032 CON-02 CON-03 CON-04 NFR-005 |
| Проверки ТЗ | AC-D09 AC-D10 AC-D11 ACC-09 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/scheduling/bookings/`; `product/tests/db/concurrency/` |

**Работы.** Реализовать resource_booking с PostgreSQL btree_gist и exclusion по редакции/ресурсу/[start,end). Задать порядок блокировок организация → редакция → глобальные группы/ресурсы UUID → строки UUID. Согласовать освобождение и повторное резервирование в одной транзакции.

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

**Проверка.** Гонки синхронизировать барьером между реальными соединениями; проверить соседние интервалы, разные атомы, deadlock/retry и откат на последнем ресурсе.

<a id="task-020"></a>

### TASK-020. Связать команды, версии и предметный аудит

| Поле | Значение |
|---|---|
| Этап | 03 |
| Зависимости | TASK-008 TASK-010 TASK-018 TASK-019 |
| Требования | FR-043 FR-044 API-005 API-006 API-007 NFR-005 SEC-012 |
| Проверки ТЗ | ACC-10 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/scheduling/commands/`; `product/backend/audit/` |

**Работы.** Провести запись через единый доменный сервис: права, блокировки, проверка версии редакции и строк, правило, изменение, бронирования, аудит и результат идемпотентности. Установить формат предпросмотра с версиями политики/справочников и повторной проверкой применения.

**Приёмка.** Падение между бронированием и аудитом не оставляет частичный успех. Старый предпросмотр не резервирует ресурсы и не обходит актуальные правила.

**Проверка.** Проверить две правки одной карточки, повтор ключа после сетевого тайм-аута, смену правил между preview/apply и сокрытие закрытых полей аудита.

<a id="task-021"></a>

### TASK-021. Создать разовое календарное занятие и онлайн-формат

| Поле | Значение |
|---|---|
| Этап | 03 |
| Зависимости | TASK-018 TASK-020 TASK-009 |
| Требования | FR-028 FR-031 FR-035 FR-045 CAL-03 LEG-51 POL-09 |
| Проверки ТЗ | AP-08 AP-19 AP-23 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/scheduling/commands/create.py`; `product/frontend/features/events/` |

**Работы.** Реализовать API и форму «Создать на дату» с временем, участниками, компонентами потребности, преподавателем, форматом onsite/online и комнатой. Для разового события внутреннюю серию создавать автоматически; шаблон не является обязательным шагом пользователя.

**Приёмка.** Онлайн без физической комнаты допустим; преподаватель и участники заняты. Пустая комната не означает онлайн. Закрытая ссылка не попадает в публичный комментарий.

**Проверка.** Создать 15 марта 2027, отклонить недопустимую дату/интервал, проверить метку и защищённость реквизитов через API и форму.

<a id="task-022"></a>

### TASK-022. Реализовать повторения и материализацию

| Поле | Значение |
|---|---|
| Этап | 03 |
| Зависимости | TASK-018 TASK-020 |
| Требования | FR-029 CAL-01 CAL-02 |
| Проверки ТЗ | — |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/calendar/recurrence/`; `product/tests/calendar/` |

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

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

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

<a id="task-023"></a>

### TASK-023. Сохранить исключения и области изменения серии

| Поле | Значение |
|---|---|
| Этап | 03 |
| Зависимости | TASK-022 TASK-020 |
| Требования | FR-030 CAL-05 |
| Проверки ТЗ | AC-D14 ACC-12 |
| Решения | DEC-19 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/calendar/exceptions/`; `product/tests/calendar/exceptions/` |

**Работы.** Добавить отмену/замещение конкретного origin_date и области одно/это и следующие/вся серия. При разделении серии сохранять происхождение и прежние исключения; предусмотреть ссылки для будущих group transfer. Повторная генерация показывает diff и сохраняет ручные изменения.

**Приёмка.** По умолчанию выбрано одно проведение. Отмена и индивидуальные дата/ресурсы/формат не теряются при генерации; серия не заменяет стабильный ID перенесённого события.

**Проверка.** Проверить 8/15/22 марта, отмену 15-го, перенос и изменение будущей части, повторную генерацию, конфликт и полный откат.

<a id="task-024"></a>

### TASK-024. Генерировать неназначенные занятия и считать остатки

| Поле | Значение |
|---|---|
| Этап | 03 |
| Зависимости | TASK-016 TASK-022 TASK-023 TASK-040 |
| Требования | FR-024 FR-027 CAL-01 API-009 |
| Проверки ТЗ | ACC-07 |
| Решения | DEC-04 DEC-20 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/planning/generation/`; `product/frontend/features/load-preview/` |

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

**Приёмка.** Повтор запуска не увеличивает учебную потребность и не стирает назначение. Неизвестные единицы удерживают только соответствующий компонент в ожидании.

**Проверка.** Проверить три типа нагрузки, дробные остатки и округление, изменение плана, повтор после переноса/отмены и восстановление прерванного задания.

<a id="task-025"></a>

### TASK-025. Сделать ручное назначение и список неразмещённого

| Поле | Значение |
|---|---|
| Этап | 04 |
| Зависимости | TASK-021 TASK-024 TASK-009 |
| Требования | FR-035 FR-036 FR-048 FR-049 LEG-41 LEG-52..LEG-55 |
| Проверки ТЗ | ACC-05 ACC-08 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/frontend/features/editor/`; `product/backend/scheduling/queries/` |

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

**Приёмка.** Проверка свободной комнаты не гарантирует последующую запись: сервер повторно проверяет занятость. Назначение доступно с клавиатуры без drag-and-drop.

**Проверка.** Сквозной тест реального API: создать потребность, назначить, открыть карточку, получить 409 из-за конкурента и исправить вариант без потери полей.

<a id="task-026"></a>

### TASK-026. Показать день, неделю и список одних событий

| Поле | Значение |
|---|---|
| Этап | 04 |
| Зависимости | TASK-021 TASK-009 TASK-010 |
| Требования | FR-046 FR-047 NFR-002 NFR-009 NFR-010 NFR-012 API-011 LEG-35 LEG-37..LEG-40 LEG-42 LEG-48..LEG-50 |
| Проверки ТЗ | AP-19 AP-23 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/frontend/features/calendar/`; `product/backend/scheduling/read_api/` |

**Работы.** Создать режимы День/Неделя/Список с датой, предыдущим/следующим днём и сегодня, фильтрами ресурсов и безопасной выдачей по диапазону. Сохранять выбранную область в URL. Для административного потока предусмотреть режимы полного расписания, двух слоёв повторения и экзаменов по явному календарю, не угадывая старую чётность; карточка доступна без наведения мыши. Ограничить DOM и размер ответа; показать текстовый формат и неполноту.

**Приёмка.** Все режимы используют одни occurrence ID и актуальную редакцию. 8 февраля открывает именно выбранный день; пустой день не подменяется ближайшей неделей.

**Проверка.** Сравнить набор ID и даты трёх представлений, проверить 390 px, клавиатуру, список для screen reader, часовой пояс и отсутствие выгрузки всего периода в браузер.

<a id="task-027"></a>

### TASK-027. Переносить одно проведение без пересоставления

| Поле | Значение |
|---|---|
| Этап | 04 |
| Зависимости | TASK-023 TASK-025 TASK-026 |
| Требования | FR-037 CAL-05 API-007 API-011 LEG-44 |
| Проверки ТЗ | AP-20 |
| Решения | DEC-19 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/scheduling/commands/move.py`; `product/frontend/features/event-move/` |

**Работы.** Реализовать предпросмотр и применение переноса выбранного occurrence с устойчивым ID, причиной, версиями и исключением на исходную дату. Явно показывать область «одно проведение» и изменения ресурсов.

**Приёмка.** 15 марта переносится на 17-е, 8 и 22 марта неизменны. Конфликт не запускает перестановку других событий и не оставляет частичный перенос.

**Проверка.** Проверить исходные/новые bookings, audit, повтор Idempotency-Key и сохранность после повторной генерации; позже TASK-049 проверит публикацию этого изменения.

<a id="task-028"></a>

### TASK-028. Выполнить атомарный обмен и замену ресурсов

| Поле | Значение |
|---|---|
| Этап | 04 |
| Зависимости | TASK-020 TASK-027 |
| Требования | FR-038 FR-039 FR-040 LEG-45 LEG-46 |
| Проверки ТЗ | AC-D12 ACC-11 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/scheduling/commands/swap.py`; `product/frontend/features/resource-change/` |

**Работы.** Реализовать обмен двух проведений и замену преподавателя/комнаты с общим preview/apply. Проверять версии обеих строк и агрегата, все освобождаемые/новые ресурсы и оба набора участников.

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

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

<a id="task-029"></a>

### TASK-029. Реализовать снятие, отмену, фиксацию и массовую правку

| Поле | Значение |
|---|---|
| Этап | 04 |
| Зависимости | TASK-020 TASK-023 TASK-028 TASK-040 |
| Требования | FR-041 FR-042 FR-043 FR-044 LEG-27 LEG-43 |
| Проверки ТЗ | ACC-17 |
| Решения | DEC-06 DEC-07 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/scheduling/commands/bulk.py`; `product/frontend/features/event-actions/` |

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

**Приёмка.** Снятие возвращает объём к размещению; отмена сохраняет историю. Fixed проверяется во всех командах; старый Stable не устанавливает его автоматически.

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

<a id="task-030"></a>

### TASK-030. Связать совместное проведение с несколькими потребностями

| Поле | Значение |
|---|---|
| Этап | 04 |
| Зависимости | TASK-016 TASK-017 TASK-020 TASK-023 |
| Требования | FR-021 FR-065 DATA-05 POL-02 |
| Проверки ТЗ | AP-05 AC-D06 ACC-06 |
| Решения | DEC-14 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/scheduling/joint/`; `product/frontend/features/joint-events/` |

**Работы.** Поддержать подтверждённое общее событие разных планов через series_component и occurrence_requirement с точными участниками/зачётами. Добавить явное создание, изменение состава и разъединение с проверкой ресурсов и объёма.

**Приёмка.** Преподаватель и комната бронируются один раз на реальное проведение, каждая потребность учитывается корректно. Совпадение имени/времени/PlanNo само не сливает записи.

**Проверка.** Проверить два плана с одинаковым полным предметом и разными ID, повтор группы, параллельные части и последующее разъединение; показать расчёт нагрузки.

<a id="task-031"></a>

### TASK-031. Перенести выбранную группу из общего занятия

| Поле | Значение |
|---|---|
| Этап | 04 |
| Зависимости | TASK-027 TASK-030 TASK-028 |
| Требования | FR-069 API-011 CAL-05 |
| Проверки ТЗ | AP-21 AP-22 |
| Решения | DEC-19 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/scheduling/commands/move_groups.py`; `product/frontend/features/group-transfer/` |

**Работы.** Реализовать move-groups-preview/apply: выбранные group_ids, оба состава, ресурсы и дельта нагрузки. А получает новое разовое событие, Б сохраняет исходный ID/дату; записать transfer, source exception и перенос allocations в одной транзакции. Повторные выделения имеют одну эффективную exception и отдельные связи происхождения.

**Приёмка.** Все участники → обычный move с тем же ID; неизменённые время/ресурсы → no_change. Учебные часы группы не удваиваются; учитель при двух двухчасовых проведениях получает 4 вместо 2. Сброс exception не возвращает А без разрешения связанного события.

**Проверка.** Проверить AP-21/22, неоднократные выделения, часть подгрупп выбранной группы, stale preview, fixed, права, повтор ключа, смену формата/ресурса и полный откат при последнем конфликте. Проверить запрет изменения длительности через move-groups: оно выполняется отдельной командой; отсутствие room_id сохраняет комнату, null явно снимает её.

<a id="task-032"></a>

### TASK-032. Принять календарную часть сквозными сценариями

| Поле | Значение |
|---|---|
| Этап | 04 |
| Зависимости | TASK-026 TASK-027 TASK-028 TASK-029 TASK-031 |
| Требования | FR-028 FR-037 FR-069 |
| Проверки ТЗ | AP-19 AP-20 AP-21 AP-22 AP-23 ACC-27 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/tests/e2e/calendar/`; `product/docs/evidence/calendar.md` |

**Работы.** Выполнить пользовательский путь на живых React/API/PostgreSQL: разовое создание, три просмотра, обычный и групповой перенос, повторная генерация, онлайн без комнаты. Снять протокол изменений ID, составов и учебной/преподавательской нагрузки.

**Приёмка.** Ни один основной сценарий не считается пройденным по мокам. Пока публикация не реализована, её часть AP-20 остаётся явно ожидающей TASK-049.

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

<a id="task-033"></a>

### TASK-033. Ввести версии политики и предметное утверждение

| Поле | Значение |
|---|---|
| Этап | 05 |
| Зависимости | TASK-008 TASK-018 |
| Требования | FR-061 POLICY-01 TRACE-01 API-010 POL-19 POL-20 |
| Проверки ТЗ | AP-17 AP-18 |
| Решения | DEC-29 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/policy/`; `product/frontend/features/policy/` |

**Работы.** Создать draft/approved версии правил: область, тип, строгость, источник, категория доказательности, срок, параметры, утверждение и исключения. Утверждённая версия неизменяема; политика и конфигурация закрепляются за проверяемой редакцией.

**Приёмка.** policy.approve проверяется отдельно от административной роли. Наблюдаемая частота не означает утверждённую норму; служебные причины защищены.

**Проверка.** Проверить создание/сравнение/утверждение/смену политики, запрещённую активацию кафедрой, immutable approved и влияние смены версии на preview.

<a id="task-034"></a>

### TASK-034. Применить доступность и запреты ресурсов

| Поле | Значение |
|---|---|
| Этап | 05 |
| Зависимости | TASK-019 TASK-033 |
| Требования | FR-034 CON-02 FR-068 POL-05 |
| Проверки ТЗ | AC-D13 AP-06 |
| Решения | DEC-03 DEC-13 DEC-27 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/policy/availability/`; `product/frontend/features/availability/` |

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

**Приёмка.** Снятие одного перекрывающего запрета не снимает другой. Неизвестные применимые исторические ограничения блокируют выпуск до решения или обоснованного исключения.

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

<a id="task-035"></a>

### TASK-035. Настроить временные профили форм и уровней

| Поле | Значение |
|---|---|
| Этап | 05 |
| Зависимости | TASK-013 TASK-015 TASK-033 |
| Требования | FR-062 POLICY-03 POL-07 POL-08 |
| Проверки ТЗ | AP-07 AP-08 AP-14 AP-16 |
| Решения | DEC-23 DEC-24 |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/policy/time_profiles/`; `product/frontend/features/time-profiles/` |

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

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

**Проверка.** Тестировать утверждённые синтетические профили AP-07, пустое пересечение, неизвестную классификацию, субботу и исключения без активации неподтверждённых норм.

<a id="task-036"></a>

### TASK-036. Проверять вместимость, назначение и переходы

| Поле | Значение |
|---|---|
| Этап | 05 |
| Зависимости | TASK-014 TASK-017 TASK-033 TASK-034 |
| Требования | FR-033 FR-066 POL-14 POL-15 POL-18 |
| Проверки ТЗ | AP-12 AP-15 AP-16 |
| Решения | DEC-25 DEC-26 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/policy/rooms/`; `product/frontend/features/room-rules/` |

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

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

**Проверка.** Проверить 30 человек/24 места, дубли одной группы, неизвестную численность, обязательную лабораторию и переход 20 минут при перерыве 10; контроль исключений по роли и политике.

<a id="task-037"></a>

### TASK-037. Рассчитывать качество и полноту расписания

| Поле | Значение |
|---|---|
| Этап | 05 |
| Зависимости | TASK-026 TASK-030 TASK-033 |
| Требования | FR-063 POLICY-04 POLICY-05 POL-10 POL-11 POL-12 POL-13 POL-17 |
| Проверки ТЗ | AP-09 AP-11 AP-13 AP-14 AP-16 |
| Решения | DEC-28 |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/quality/`; `product/frontend/features/quality/` |

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

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

**Проверка.** Проверить {1}, {1,2}, {1,3,4}, {1,4}, лекцию/практику и уникальные события; локальный исходный прогон отдельно подтверждает 3571/3975 и 2859/3210.

<a id="task-038"></a>

### TASK-038. Показывать последствия ручного изменения

| Поле | Значение |
|---|---|
| Этап | 05 |
| Зависимости | TASK-027 TASK-031 TASK-034 TASK-035 TASK-036 TASK-037 |
| Требования | FR-064 API-007 API-010 |
| Проверки ТЗ | AP-10 AP-17 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/quality/preview/`; `product/frontend/features/change-preview/` |

**Работы.** Встроить в preview переносов/обмена/состава раздельные дельты качества, нагрузки и нарушения. Показывать затронутые даты/ресурсы и версии вычисления. Повторить актуальную валидацию при apply в общем сервисе команд.

**Приёмка.** Уменьшение окон группы и увеличение окон учителя видны одновременно. Конфликтующий вариант не называется допустимым; старый preview после правки правила отклоняется или пересчитывается.

**Проверка.** Сравнить локальный пересчёт с полным на синтетических переносах; проверить неизменность незатронутых событий и целостность после конкурентной правки.

<a id="task-039"></a>

### TASK-039. Принять политику и проверку готовности выпуска

| Поле | Значение |
|---|---|
| Этап | 05 |
| Зависимости | TASK-033 TASK-034 TASK-035 TASK-036 TASK-037 TASK-038 |
| Требования | FR-068 POLICY-01 TRACE-01 |
| Проверки ТЗ | AP-05 AP-06 AP-07 AP-08 AP-09 AP-10 AP-11 AP-12 AP-13 AP-15 AP-16 AP-17 AP-18 ACC-25 ACC-26 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/tests/policy/`; `product/docs/evidence/policy.md` |

**Работы.** Проверить все реализованные сценарии политики на контрольных данных, привязать POL-01–POL-20 к коду и проверкам. Добавить единый readiness-отчёт неизвестных/блокирующих правил, прав, ресурсов и состава; основания читаются по доступу.

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

**Проверка.** Прогнать положительные и отрицательные AP, сравнить опубликованную позже политику с хешем кандидата; локальные исторические AP закрывает также TASK-046.

<a id="task-040"></a>

### TASK-040. Реализовать устойчивые фоновые операции

| Поле | Значение |
|---|---|
| Этап | 01 |
| Зависимости | TASK-005 TASK-006 TASK-008 TASK-010 |
| Требования | SYS-006 NFR-006 NFR-007 API-009 |
| Проверки ТЗ | ACC-18 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/jobs/`; `product/backend/outbox/`; `product/tests/jobs/` |

**Работы.** Хранить задания и outbox в PostgreSQL, передавать в Celery только ID. Добавить состояния, прогресс, heartbeat/lease, retry, идемпотентные шаги, отмену до необратимой стадии и приватные результаты. Предметная запись и outbox фиксируются одной транзакцией.

**Приёмка.** Отказ Redis приостанавливает выполнение, но не теряет принятую операцию. Повтор доставки не повторяет эффект; завершённый результат доступен только владельцу/уполномоченному.

**Проверка.** Убить worker после commit до подтверждения сообщения, перезапустить Redis/API, восстановить просроченную lease; проверить отсутствие двойного эффекта и ложного успеха.

<a id="task-041"></a>

### TASK-041. Принять и сохранить полный исходный пакет

| Поле | Значение |
|---|---|
| Этап | 06 |
| Зависимости | TASK-004 TASK-008 TASK-040 |
| Требования | FR-056 MIG-01 SEC-010 |
| Проверки ТЗ | AC-D01 AP-01 ACC-02 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/imports/raw/`; `product/frontend/features/import-upload/` |

**Работы.** Принимать SQLite, схему и манифест с лимитом 100 МБ, сигнатурой, целостностью и разрешённой схемой. Сохранить приватный неизменяемый пакет, хеши и все исходные строки/88 полей 19 таблиц; views учитывать отдельно. Парсер не исполняет SQL/скрипты из файла.

**Приёмка.** 75 909 активных строк доступны для сверки; исходный пакет не меняется. Невалидный или неизвестный вход не изменяет рабочие предметные таблицы.

**Проверка.** Проверить исходный read-only пакет, обрезанный файл, неверную схему/счётчики, превышение размера, попытку доступа по чужому UUID и прерывание загрузки.

<a id="task-042"></a>

### TASK-042. Сопоставить справочники и происхождение полей

| Поле | Значение |
|---|---|
| Этап | 06 |
| Зависимости | TASK-011 TASK-012 TASK-013 TASK-014 TASK-041 |
| Требования | FR-050 FR-056 MIG-02 DATA-03 DATA-04 SEC-008 LEG-56 |
| Проверки ТЗ | AC-D03 AC-D05 AC-D06 AC-D07 |
| Решения | DEC-10 DEC-11 DEC-15 DEC-16 DEC-17 |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/imports/mapping/`; `product/frontend/features/import-review/` |

**Работы.** Составить полную карту 88 полей, source_identity, UUID и статусы resolution. Восстановить GroupNo=-1 через GRPPLAN, сохранить подгруппы, STREAMS, CLASSINF/ClassesInf и расхождения, field-specific -1. Добавить закрытый экран «Требует сопоставления» с поиском и причинами. Защищённый технический просмотр содержит разрешённые сущности/импортные таблицы, описания всех исходных полей, счётчики, пагинацию, сортировку, фильтры и карточки со связями; различает NULL, пустую строку, ноль, false и -1, исключает служебные таблицы и SQL-консоль. Для согласованных CSV-шаблонов справочников и планов реализовать сопоставление столбцов, построчную диагностику и тот же preview/commit с происхождением; выборка и кодировка не должны изменять числовые единицы неявно.

**Приёмка.** Не создаются дубликаты Classes из ClassesInf, фиктивные факультеты и потоки по похожим именам. Неизвестные строки остаются видимыми, исходные HTML-сущности не исполняются.

**Проверка.** Для группы 434109 проверить 79 занятий (39+40), все 554 группы и 17 727 уникальных связей; отдельно расхождение счётчика 13 и аудитории.

<a id="task-043"></a>

### TASK-043. Преобразовать подтверждённую историческую семантику

| Поле | Значение |
|---|---|
| Этап | 06 |
| Зависимости | TASK-002 TASK-015 TASK-016 TASK-023 TASK-034 TASK-042 |
| Требования | FR-056 FR-067 MIG-02 POL-04 |
| Проверки ТЗ | AC-D04 AP-03 AP-06 AP-14 ACC-03 |
| Решения | DEC-01 DEC-02 DEC-03 DEC-04 DEC-05 DEC-06 DEC-07 DEC-13 DEC-20 DEC-24 DEC-27 |
| Допуск | DEC-01 DEC-02 DEC-03 DEC-04 DEC-05 DEC-13 DEC-20 DEC-24 DEC-27 |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/imports/semantics/`; `product/docs/migration-rules/` |

**Работы.** Реализовать версионированные преобразования DayNo/OddWeek/EachWeek, единиц и ограничений только на основании принятых DEC; каждое правило имеет исходный и ожидаемый пример. До решения сохранять raw/staging и блокируемые поля без бронирований.

**Приёмка.** Код пути quarantine тестируется сразу. Применение правил к реальному снимку и закрытие задачи требуют подтверждённых решений по применимым полям; блок q не объявляется календарной неделей.

**Проверка.** Проверить 11 блоков, 23 EachWeek и 11 553 аналитических слоя отдельно от календаря; после согласования проверить ручные примеры всех режимов с диспетчером.

<a id="task-044"></a>

### TASK-044. Проверить кандидатов совместных занятий при импорте

| Поле | Значение |
|---|---|
| Этап | 06 |
| Зависимости | TASK-030 TASK-042 |
| Требования | FR-065 FR-067 |
| Проверки ТЗ | AP-04 AP-05 |
| Решения | DEC-09 DEC-10 DEC-14 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/imports/joint_review/`; `product/frontend/features/joint-review/` |

**Работы.** Показывать кандидатов объединения с полными названиями/видами, всеми ClassNo/PlanNo/SubjectNo, участниками и ресурсами. Сохранять решение диспетчера и карту нескольких планов к одному проведению; дать предпросмотр разъединения.

**Приёмка.** 638 преподавательских и 572 аудиторных клеток — кандидаты, не 638/572 автоматически разрешённых слияний. До подтверждения участники и исходные строки сохраняются раздельно.

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

<a id="task-045"></a>

### TASK-045. Применить импорт атомарно и обеспечить безопасный откат

| Поле | Значение |
|---|---|
| Этап | 06 |
| Зависимости | TASK-020 TASK-040 TASK-041 TASK-042 TASK-043 TASK-044 |
| Требования | FR-056 MIG-03 MIG-04 MIG-05 MIG-06 |
| Проверки ТЗ | AC-D02 AC-D17 ACC-04 ACC-19 |
| Решения | DEC-16 DEC-17 DEC-20 DEC-21 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/imports/commit/`; `product/frontend/features/import-commit/` |

**Работы.** Подготовить сверку, target draft и версии правил, повторяемый commit с устойчивыми UUID/происхождением; большой импорт готовить в изолированном кандидате и активировать атомарно. Откат сверяет последующие ручные изменения и предлагает компенсирующую редакцию.

**Приёмка.** Повтор пакета с теми же правилами возвращает прежний результат. Отмена до commit не меняет черновик. Откат не удаляет последующие ручные изменения и исходный пакет.

**Проверка.** Проверить повтор preview/commit, падение на последнем шаге, изменение черновика перед commit, смену правил, повторный импорт нового снимка и безопасный откат после ручного переноса.

<a id="task-046"></a>

### TASK-046. Принять перенос и аналитические контрольные числа

| Поле | Значение |
|---|---|
| Этап | 06 |
| Зависимости | TASK-041 TASK-042 TASK-043 TASK-044 TASK-045 TASK-037 |
| Требования | FR-067 DEL-001 |
| Проверки ТЗ | AP-01 AP-02 AP-03 AP-04 AP-09 AP-14 AC-D01 AC-D02 AC-D03 AC-D04 AC-D05 AC-D06 AC-D07 AC-D17 ACC-02 ACC-03 ACC-04 ACC-19 |
| Решения | DEC-01 DEC-02 DEC-03 DEC-04 DEC-05 DEC-09 DEC-10 DEC-14 DEC-16 DEC-17 DEC-20 DEC-24 DEC-27 |
| Допуск | DEC-01 DEC-02 DEC-03 DEC-04 DEC-05 DEC-09 DEC-10 DEC-14 DEC-16 DEC-17 DEC-20 DEC-24 DEC-27 |
| Размер | M |
| Усилие | xhigh |
| Область | `product/tests/migration/`; `product/docs/evidence/migration.md` |

**Работы.** В закрытом окружении прогнать неизменённый контрольный SQLite и все сверки, составить ledger: сохранено raw, нормализовано, ожидает решения, отклонено с причиной. Отдельно подписать календарную и семантическую приёмку владельцем данных.

**Приёмка.** Успешный raw-импорт не выдаётся за готовое календарное расписание. Все 88 полей покрыты; все оставшиеся неоднозначности перечислены. Полный статус done требует подтверждённой части реальной миграции.

**Проверка.** Приложить манифест/хеши, команды и счётчики AP/AC-D; сопоставить 19 таблиц, 15 111 Classes и 11 530/3 581 assigned/unassigned, включая 288 координат неназначенных.

<a id="task-047"></a>

### TASK-047. Реализовать кафедральные предложения и согласование

| Поле | Значение |
|---|---|
| Этап | 07 |
| Зависимости | TASK-008 TASK-025 TASK-033 |
| Требования | FR-051 FR-052 LEG-47 |
| Проверки ТЗ | — |
| Решения | DEC-08 DEC-22 |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/workflow/`; `product/frontend/features/chair/` |

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

**Приёмка.** Кафедра видит свою область, не редактирует чужое расписание. Исторические передачи не восстанавливаются без доказательств; Assigned не означает публикацию.

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

<a id="task-048"></a>

### TASK-048. Подготовить неизменяемый снимок публикации

| Поле | Значение |
|---|---|
| Этап | 07 |
| Зависимости | TASK-018 TASK-020 TASK-033 TASK-039 TASK-040 |
| Требования | FR-052 FR-053 CAL-07 DATA-05 |
| Проверки ТЗ | AC-D15 ACC-13 ACC-15 AP-17 AP-18 |
| Решения | DEC-22 DEC-29 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/publications/snapshots/`; `product/tests/publication/` |

**Работы.** Создать candidate/frozen snapshot событий, составов, названий, параметров, approved-политики и исключений. Выполнить полную readiness-проверку на версии агрегата; фоновая подготовка не должна замораживать долгую работу читателей.

**Приёмка.** Редактирование во время подготовки обнаруживается по версии. После freeze никакой прикладной путь не меняет снимок; изменения справочников не меняют старые подписи.

**Проверка.** Гонки freeze с изменением события, справочника и политики; сверить хеш кандидата и прежнее чтение при сбое worker.

<a id="task-049"></a>

### TASK-049. Атомарно активировать публикации разных периодов

| Поле | Значение |
|---|---|
| Этап | 07 |
| Зависимости | TASK-017 TASK-019 TASK-048 TASK-031 |
| Требования | FR-053 CON-04 |
| Проверки ТЗ | AC-D16 ACC-14 AP-20 AP-22 |
| Решения | DEC-09 DEC-22 |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/backend/publications/activation/`; `product/tests/db/publication_races/` |

**Работы.** Создать active_publication_booking по глобальным ресурсам без revision в исключающем ключе, проверку пересечения разных схем участников и блокировки организации. Атомарно заменить активный снимок; повторная активация старого снимка тоже проверяет текущие ресурсы.

**Приёмка.** Две конфликтующие публикации разных периодов не активируются вместе. Неизвестное пересечение схем блокирует выпуск. Точечный перенос публикуется новым снимком без пересоставления остальных занятий.

**Проверка.** Синхронные гонки двух публикаций, разных схем и активации со сменой политики; проверить сохранность прежней публикации при отказе и стабильность ID остальных дат AP-20.

<a id="task-050"></a>

### TASK-050. Открыть читательское и контролируемое публичное расписание

| Поле | Значение |
|---|---|
| Этап | 07 |
| Зависимости | TASK-008 TASK-026 TASK-049 |
| Требования | FR-054 FR-045 SEC-006 SEC-007 |
| Проверки ТЗ | ACC-23 AP-18 AP-23 |
| Решения | DEC-18 |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/public_api/`; `product/frontend/features/published/` |

**Работы.** Читателям показывать только целиком активный снимок; добавить выбранную архивную версию для уполномоченных. Анонимный режим включать отдельной настройкой с предпросмотром allowlist полей. Формат онлайн отображать текстом без закрытых реквизитов.

**Приёмка.** До явного включения анонимное чтение закрыто. Кэш и ссылки не смешивают версии, не раскрывают черновики, причины ограничений, заметки или закрытые файлы.

**Проверка.** Проверить выключенный/включённый режим, прямые UUID/версии и утечки в HTML/API/заголовках кэша; AP-23 выполнить для всех трёх видов.

<a id="task-051"></a>

### TASK-051. Реализовать экспорт, печать и защищённые файлы

| Поле | Значение |
|---|---|
| Этап | 07 |
| Зависимости | TASK-008 TASK-026 TASK-040 TASK-050 |
| Требования | FR-005 FR-055 FR-057 SEC-008 SEC-011 |
| Проверки ТЗ | AP-18 AP-23 ACC-16 |
| Решения | DEC-18 |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/exports/`; `product/frontend/features/print/` |

**Работы.** Сделать CSV разрешённых справочников, планов и расписания; печать дня/недели/списка по явно выбранным фильтрам и версии, локальным ассетам и корпоративным токенам. Крупные выгрузки — приватные задания с ограниченным сроком и проверкой прав на скачивание.

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

**Проверка.** Сравнить экспорт с API по ID и часам, проверить CSV-инъекцию, чужую/просроченную ссылку, несколько страниц печати с длинными предметами и текстовую онлайн-метку.

<a id="task-052"></a>

### TASK-052. Подготовить справку и инструкции рабочих ролей

| Поле | Значение |
|---|---|
| Этап | 07 |
| Зависимости | TASK-025 TASK-031 TASK-039 TASK-047 TASK-050 TASK-051 |
| Требования | FR-058 NFR-010 DEL-001 LEG-58 |
| Проверки ТЗ | — |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/docs/user/`; `product/frontend/features/help/` |

**Работы.** Описать действия диспетчера, кафедры, публикатора и администратора на реальных экранах новой версии: создать дату, выделить группу, объяснить конфликт, сопоставить импорт, утвердить политику, выпустить и напечатать.

**Приёмка.** Термины и снимки соответствуют работающему приложению; инструкции доступны автономно. Справка не содержит рабочих секретов.

**Проверка.** Незнакомый с реализацией пользователь проходит сценарии по инструкции; исправить найденные разрывы и проверить корпоративную печать/узкую ширину.

<a id="task-053"></a>

### TASK-053. Провести сквозную проверку доступа и безопасности

| Поле | Значение |
|---|---|
| Этап | 08 |
| Зависимости | TASK-045 TASK-047 TASK-049 TASK-050 TASK-051 |
| Требования | SEC-001 SEC-002 SEC-003 SEC-004 SEC-005 SEC-006 SEC-007 SEC-008 SEC-009 SEC-010 SEC-011 SEC-012 SEC-013 |
| Проверки ТЗ | ACC-16 ACC-23 AP-18 AP-23 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/tests/security/`; `product/docs/evidence/security.md` |

**Работы.** Проверить все маршруты и файловые каналы по матрице прав, CSRF, XSS/SQL и CSV-инъекции, сессии, ограничения загрузок/заданий и редактирование frozen. Проверить production-настройки Django, закрытые порты и безопасные логи.

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

**Проверка.** Автоматические HTTP-сценарии плюс инспекция конфигурации изнутри/снаружи стенда; отчёт содержит воспроизведение, исправление и повтор конкретной проверки.

<a id="task-054"></a>

### TASK-054. Подтвердить скорость и конкурентную устойчивость

| Поле | Значение |
|---|---|
| Этап | 08 |
| Зависимости | TASK-039 TASK-045 TASK-049 TASK-051 TASK-040 |
| Требования | NFR-001 NFR-002 NFR-003 NFR-004 NFR-005 NFR-006 NFR-007 NFR-013 NFR-015 |
| Проверки ТЗ | ACC-09 ACC-13 ACC-14 ACC-18 ACC-22 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/tests/load/`; `product/docs/evidence/performance.md` |

**Работы.** Создать детерминированный генератор профиля ТЗ: 250 тыс. событий, 50 тыс. в редакции, 500 правил, 1 млн аудита и пересекающиеся периоды. Прогнать 50 читателей/10 редакторов 30 минут после прогрева на 4 vCPU/8 ГиБ; отдельно измерить импорт, качество и активацию.

**Приёмка.** Выполнены p95 500 мс справочники, 1,5 с календарь, 1 с запись, 2 с локальное качество; импорт/полный quality ≤60 с, блокирующая активация ≤5 с, неожиданные 5xx <0,1%. fsync не отключён.

**Проверка.** Приложить ресурсы стенда, seed, команды, EXPLAIN, распределения p95 и SQL/lock traces. Оптимизировать измеренные узкие места и повторять только затронутые прогоны.

<a id="task-055"></a>

### TASK-055. Подготовить автономное развёртывание на сервере

| Поле | Значение |
|---|---|
| Этап | 08 |
| Зависимости | TASK-005 TASK-007 TASK-040 TASK-049 |
| Требования | SYS-001 SYS-004 SYS-005 OPS-001 OPS-002 OPS-003 OPS-004 OPS-005 OPS-006 SEC-009 SEC-013 |
| Проверки ТЗ | ACC-01 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/deploy/`; `product/docs/operations/install.md` |

**Работы.** Собрать production Compose: Nginx/TLS, Gunicorn, Django, PostgreSQL, Redis, Celery, постоянные приватные тома, health и отдельные роли. Проверить фактические ресурсы целевого сервера, DNS/домен, диски, лимиты и сосуществование с сайтом исследования. Подготовить offline-пакет установки.

**Приёмка.** Чистый сервер устанавливается по инструкции. Исследовательский rsp.nsuemdev.ru и его /data/ не заменяются новой системой по совпадению папки deploy. Нет открытых наружу БД/Redis и зависимости от облака разработчика.

**Проверка.** Установить на изолированный стенд, отключить внешний доступ для основного пользовательского сценария; проверить контейнеры без root, health и переживание перезапуска.

<a id="task-056"></a>

### TASK-056. Проверить резервное копирование и восстановление

| Поле | Значение |
|---|---|
| Этап | 08 |
| Зависимости | TASK-055 TASK-045 |
| Требования | OPS-007 OPS-008 OPS-009 |
| Проверки ТЗ | ACC-20 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/scripts/backup/`; `product/docs/operations/restore.md` |

**Работы.** Реализовать ежедневный согласованный backup PostgreSQL+приватных файлов+версий с checksum и проверкой чтения. Настроить 7 ежедневных/4 еженедельных, одну внешнюю зашифрованную копию и месячное учебное восстановление; секреты получать отдельно.

**Приёмка.** Проведено изолированное восстановление с RPO ≤24 часа и RTO ≤4 часа, входом, публикациями, исходниками и историей. Ошибка новой копии не удаляет последнюю исправную.

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

<a id="task-057"></a>

### TASK-057. Подготовить обновление, обслуживание и откат

| Поле | Значение |
|---|---|
| Этап | 08 |
| Зависимости | TASK-055 TASK-056 |
| Требования | OPS-010 OPS-011 OPS-012 NFR-006 |
| Проверки ТЗ | ACC-21 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/scripts/release/`; `product/docs/operations/upgrade.md` |

**Работы.** Описать версионированные образы и одиночный запуск миграций, expand→migrate→switch→contract, maintenance и smoke-проверки. Для каждого изменения схемы определить совместимость прошлого образа и способ восстановления данных.

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

**Проверка.** На стенде провести успешное обновление и отказ миграции/health, восстановить совместимую версию; проверить вход, тестовую запись, очередь, права и backup.

<a id="task-058"></a>

### TASK-058. Настроить диагностику, хранение и доступность

| Поле | Значение |
|---|---|
| Этап | 08 |
| Зависимости | TASK-040 TASK-055 TASK-056 |
| Требования | OPS-013 OPS-014 OPS-015 NFR-008 |
| Проверки ТЗ | ACC-18 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/backend/observability/`; `product/deploy/monitoring/`; `product/docs/operations/` |

**Работы.** Добавить безопасные структурированные логи request_id/job_id, метрики API/БД/блокировок/очереди/worker, диск, backup age и TLS. Настроить ротацию: технические логи 30 дней, аудит 365; периоды/публикации/принятые исходники автоматически не удалять.

**Приёмка.** Диагностика доступна без мессенджера. Метод расчёта целевых 99,5% и окно обслуживания согласованы; один сервер не объявлен отказоустойчивым кластером.

**Проверка.** Вызвать безопасные отказы БД/Redis/worker, просроченный backup и порог диска; проверить сигнал, request_id, восстановление и отсутствие секретов в логах.

<a id="task-059"></a>

### TASK-059. Провести полную функциональную и визуальную приёмку

| Поле | Значение |
|---|---|
| Этап | 09 |
| Зависимости | TASK-032 TASK-039 TASK-046 TASK-047 TASK-049 TASK-050 TASK-051 TASK-053 TASK-054 |
| Требования | NFR-009 NFR-010 NFR-011 NFR-012 DEL-002 |
| Проверки ТЗ | AP-01..AP-23 AC-D01..AC-D17 ACC-01..ACC-27 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | xhigh |
| Область | `product/docs/evidence/acceptance/`; `product/tests/e2e/` |

**Работы.** Свести FR, POL, AP, AC-D и ACC с реализацией и доказательствами; выполнить недостающие сквозные пути на release candidate. Проверить корпоративные страницы, формы, печать, клавиатуру, 200% и поддерживаемые браузеры; каждый дефект имеет воспроизведение.

**Приёмка.** 67 базовых FR закрыты доказательствами; FR-059/060 остаются E. Пропущенный из-за среды тест не записывается пройденным. Критические дефекты блокируют пилот.

**Проверка.** Протокол с версиями кода/БД/политики/браузеров, командами и ссылками; повтор исправленного сценария и затронутой регрессии, а не произвольное многократное тестирование всего.

<a id="task-060"></a>

### TASK-060. Собрать комплект передачи и карту старых функций

| Поле | Значение |
|---|---|
| Этап | 09 |
| Зависимости | TASK-046 TASK-052 TASK-056 TASK-057 TASK-058 TASK-059 |
| Требования | DEL-001 DEL-002 TRACE-01 |
| Проверки ТЗ | ACC-24 ACC-25 ACC-26 ACC-27 |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/docs/delivery/`; `product/docs/traceability/` |

**Работы.** Собрать исходники, lock/лицензии, OpenAPI/ER, словарь, все 88 полей, все LEG-01–59, POL-01–20, тестовые протоколы и инструкции. Для legacy-возможности указывать реализованный путь, уточнение владельца либо согласованное E, не объявляя весь старый интерфейс одинаковым.

**Приёмка.** Каждое требование связано с конкретным кодом и проверкой. Рабочие пароли передаются отдельно защищённым способом; сборка и инструкции воспроизводимы без автора.

**Проверка.** Валидировать ссылки и полноту манифеста, установить из передаваемого пакета по инструкции; сверить хеш release candidate с проверенной версией.

<a id="task-061"></a>

### TASK-061. Провести пилот с диспетчером и владельцами правил

| Поле | Значение |
|---|---|
| Этап | 09 |
| Зависимости | TASK-002 TASK-046 TASK-055 TASK-059 TASK-060 |
| Требования | FR-068 DEL-002 |
| Проверки ТЗ | ACC-05 ACC-25 ACC-26 ACC-27 |
| Решения | DEC-01..DEC-29 |
| Допуск | DEC-01..DEC-29 |
| Размер | M |
| Усилие | high |
| Область | `product/docs/pilot/`; `product/docs/decisions/` |

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

**Приёмка.** Модель готовит демонстрацию и исправления, но не подменяет предметное утверждение владельца. Открытые DEC оцениваются по применимости и не закрываются истечением времени.

**Проверка.** Подписанный протокол сценариев и перечня открытых рисков; исправленные дефекты повторены на тех же примерах, readiness выбранного периода подтверждён.

<a id="task-062"></a>

### TASK-062. Подготовить финальный переход и критерии отката

| Поле | Значение |
|---|---|
| Этап | 09 |
| Зависимости | TASK-045 TASK-049 TASK-056 TASK-057 TASK-061 |
| Требования | MIG-04 MIG-05 MIG-06 OPS-011 OPS-012 |
| Проверки ТЗ | ACC-04 ACC-19 ACC-20 ACC-21 |
| Решения | DEC-18 DEC-21 DEC-22 DEC-29 |
| Допуск | DEC-18 DEC-21 DEC-22 DEC-29 |
| Размер | M |
| Усилие | xhigh |
| Область | `product/docs/cutover/`; `product/scripts/cutover/` |

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

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

**Проверка.** Репетиция на стенде с финальным пакетом: импорт, readiness, публикация, восстановление, проверка паролей и прав; протокол подтверждает возможность запуска.

<a id="task-063"></a>

### TASK-063. Выполнить согласованный ввод и контроль после запуска

| Поле | Значение |
|---|---|
| Этап | 09 |
| Зависимости | TASK-062 |
| Требования | OPS-004 OPS-012 OPS-014 DEL-001 |
| Проверки ТЗ | ACC-01 ACC-05 ACC-20 |
| Решения | DEC-21 DEC-22 |
| Допуск | DEC-21 DEC-22 |
| Размер | M |
| Усилие | high |
| Область | `product/docs/cutover/launch-record.md`; `product/docs/operations/` |

**Работы.** Выполнить утверждённую последовательность выпуска: backup, финальный импорт, сверка, активация и smoke-сценарии с ответственными. Проверить чтение групп/преподавателей, один перенос в тестовой области, печать, роли, очередь и первый backup.

**Приёмка.** Переход выполнен только после готовности и разрешённого окна. До появления новых записей доступен согласованный быстрый откат; после них сначала анализ/сохранение данных.

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

<a id="task-064"></a>

### TASK-064. Закрыть стабилизацию и передать дальнейший backlog

| Поле | Значение |
|---|---|
| Этап | 09 |
| Зависимости | TASK-063 TASK-058 |
| Требования | NFR-008 OPS-014 OPS-015 DEL-001 DEL-002 |
| Проверки ТЗ | — |
| Решения | — |
| Допуск | — |
| Размер | M |
| Усилие | high |
| Область | `product/docs/operations/handover.md`; `product/docs/backlog/` |

**Работы.** В течение согласованного пилотом периода разобрать дефекты, проверить показатели доступности/backup, передать ответственность и известные ограничения. Отдельно сохранить идеи E: drag-and-drop, оптимизатор, SSO, видеоплатформы, дополнительные ресурсы и HA.

**Приёмка.** Объём B закрывается по критериям, а не по исчерпанию контекста модели. Длительность поддержки и SLA согласуются отдельно; расширения не подменяют незавершённые базовые требования.

**Проверка.** Итоговый протокол владельца/эксплуатации с открытыми задачами и ответственными, последним успешным восстановлением и планом очередного релиза.
