# 10. Отчёт этапа 0: схема, контракты, preflight **Дата:** 2026-10-23. **Статус:** этап 0 выполнен на локальной копии БД; перед production нужен повторный preflight на свежей копии. ## 1. Что сделано - ADR с ключевыми решениями: [adr/0001-groups-courses-foundation.md](adr/0001-groups-courses-foundation.md). - Контракт API профиля студента: [09-teacher-student-profile.md](09-teacher-student-profile.md). - Миграции: - identity `V4–V9`: роли, группы-когорты, статусы студентов, повышение, история членства, статусы аккаунтов; - academic `V6–V9`: курсы, преподаватели, группы курса, `labs.course_id`, материалы курса/аудитории, индексы активов; - progress `V13`: автор комментария и последнего изменения оценки. - Preflight-скрипты: - `deploy/preflight/groups-courses.sql` — до миграций; - `deploy/preflight/groups-courses-post.sql` — после миграций/bootstrap; - `deploy/preflight/progress-v10-v13.sql` — переход старой feature-миграции progress V10 на V13. - UI: статус защиты в ведомости различает «готова» и «кончилось время». - Резервное копирование: - `deploy/backup.sh` — БД + решения + материалы, checksums, retention, `list`, `verify`, `restore`; - `deploy/deploy.sh up` делает обязательный backup перед обновлением; - systemd timer для ежедневного backup; - инструкция `deploy/BACKUP.md`. ## 2. Проверка на пустой БД Все миграции identity, academic и progress применены последовательно на чистой БД PostgreSQL 18. Ошибок нет. Тесты сервисов на Testcontainers проходят. ## 3. Проверка на копии локальной БД Скопирована локальная БД `lms` (41 аккаунт, 40 студентов, 2 группы, 1 лаба, 3 главы, 16 разделов, 35 статей, 6 комментариев). Preflight до миграций: - групп, не подходящих под шаблон, нет; - конфликтующих кортежей когорт нет; - дублей номеров лабораторных нет; - дублей slug глав нет; - студентов без группы нет. Миграции применены успешно. После миграций: - `labs_without_course = 1` — ожидаемо до bootstrap; - `chapters_without_course = 3` — ожидаемо до bootstrap; - `courses = 0` — ожидаемо до bootstrap; - `comments_without_author = 6` — ожидаемо для старых комментариев; - группы разобраны полностью, `enrollment_year` заполнен. ## 4. Симуляция bootstrap На копии вручную выполнено то, что будет делать bootstrap-сервис: 1. Создан курс C с владельцем-админом, `course_no = 1`. 2. Админ назначен преподавателем курса. 3. Обе активные группы привязаны к курсу. 4. Все лабы и главы получили `course_id`. 5. Выполнено `ALTER TABLE labs ALTER COLUMN course_id SET NOT NULL`. Postflight: - `labs_without_course = 0`; - `chapters_without_course = 0`; - курс C ровно один; - `comments_without_author = 6` — старые данные, ожидаемо; - группы без полного разбора отсутствуют. ## 5. Тесты и линтеры - `./gradlew :services:identity-service:test :services:academic-service:test :services:progress-service:test :web:test` — успешно. - `./gradlew ktlintCheck detekt` — успешно. - `node --check web/src/main/resources/static/js/admin-group.js` — успешно. - `bash -n deploy/backup.sh deploy/deploy.sh` — успешно. - `./deploy/backup.sh backup` на локальной БД — успешно; `verify` проверил `db.dump`, `submissions.tar.gz`, `assets.tar.gz` по SHA256. - `git diff --check` — успешно. ## 6. Что осталось на этап 2 - Реализовать bootstrap-сервис курса C (создание курса, привязка групп, назначение админа, перенос лаб/глав). - Выбрать механизм post-bootstrap `SET NOT NULL` (CLI, admin endpoint или отдельная Flyway-локация). - Связать существующие активы со статьями при миграции контента. - Повторить preflight на свежей копии production-БД перед деплоем.