- профиль приведён к docs/09: variant/level, updatedBy/name, лимит попыток - V14: NOT NULL и полная уникальность когорты, preflight legacy-групп - возврат группы из архива и история членства на странице группы - пагинация групп и плоского списка материалов - пакетные сдачи ведомости одним запросом - XLSX-preflight импорта и audit-тесты ростера - LDD: 66 claims, 398 тестов, release PASS
14 KiB
18. Сверка цели и фактического состояния
Дата: 2026-10-29.
Ветка: feature/groups-courses.
Источники цели: 07-groups-courses.md, 08-groups-courses-plan.md,
09-teacher-student-profile.md, 16-stage6-report.md, 17-handoff.md.
Документ фиксирует, где приложение уже соответствует целевой модели, где
остались отличия и какие решения приняты по спорным местам. Это не отчёт
«всё готово»: статус partial означает реальный незакрытый пункт.
1. Сводка
| Область | Статус | Что осталось |
|---|---|---|
| Роли, группы-когорты, статусы, история | implemented | Финальные ограничения когорты, возврат из архива и блок истории членства на странице группы |
| Академический отпуск | исправлено | Вход read-only, сдача/защиты заблокированы на progress-service |
| Черновики лабораторных | исправлено | Студент не видит черновик в списке/деталях/по UUID |
| «Убрать из группы» | исправлено | Действие удалено из UI и API; остались перевод/академ/отчисление/архив |
| Импорт v2 | partial | Флаг восстановления и row-level отчёт для CSV/XLSX есть; гонка с параллельной вставкой логина всё ещё даёт общий 409 |
| Курсы, преподаватели, группы курса | implemented | — |
| Материалы и активы | implemented | Глобальные STUDENTS/TEACHERS теперь работают; импорт глобальных глав всё ещё создаёт только ALL |
| Профиль студента | implemented | Контракт 09 (variant/level/updatedBy/name), лимит попыток и SQL-тест «без N+1» сделаны |
| Повышение | partial | Догон при старте ищет только текущий год, не предыдущий; нет теста apply-конфликта |
| Аудит | implemented | GROUP_CREATE/STUDENT_CREATE/GROUP_IMPORT/GROUP_ENROLL/GROUP_ARCHIVE/GROUP_RESTORE проверены интеграционным тестом |
| Backup/deploy | partial | deploy.sh теперь проверяет последний backup; restore на staging не подтверждён; первый деплой без backup — документированное исключение |
| CI | partial | Конфигурация Woodpecker и локальные прогоны есть; первый реальный pipeline на VM не подтверждён |
| Производительность | partial | Keyset-аудит, пакетные лабы/группы/сдачи, пагинация групп и плоского списка материалов, лимит попыток профиля; остаются visual regression и SLA-нагрузка |
| LDD | implemented | 66 claims (27 P0 / 39 P1); check доказывает P0/unit, runtime P1 — release |
| Legacy-активы | partial | Код и UI готовы; инвентаризация на production/staging не выполнена |
| «Контингент» | out of scope | Исключён решением 2026-10-28 |
2. Что исправлено в этой итерации
-
Read-only академотпуск.
AuthResponse/MeResponseсодержатreadOnly; web-сессия хранит флаг.StudentWriteGuardв progress-service блокирует submit, start и finish защиты.- UI скрывает сдачу/защиту и показывает объяснение.
- Тесты:
StudentLifecycleIntegrationTest#academic leave login is read only,SubmissionServiceTest#academic leave student cannot submit,DefenseServiceAcademicLeaveTest#academic leave student cannot start or finish defense.
-
Черновики лабораторных скрыты от студентов.
CourseAccessService.requireLabAccessотдаёт404студенту для черновика.GET /api/v1/labsи/labs/detailsфильтруют черновики для студента.- Тесты:
LabDetailsIntegrationTest#student sees published labs but not drafts in list details or by id,CourseAccessServiceTest#student cannot access a draft lab of own course.
-
Удалено действие «Убрать из группы».
- Удалены endpoint, web-маршрут, API-клиент, кнопка и сервисный метод.
- Тесты шаблонов проверяют отсутствие действия.
-
Импорт больше не воскрешает неактивных студентов без флага.
restoreInactiveStatuses(по умолчаниюfalse),ImportResult.skipped.- Без флага сохраняются
EXPELLED/GRADUATED/ARCHIVED/ACADEMIC_LEAVE, строка попадает в отчёт. - С флагом студент активируется, архивный аккаунт разблокируется, пишется
IMPORT. - Тесты:
GroupServiceIntegrationTest#import does not resurrect...,#import restores expelled student...,#import preserves academic leave...,#import still updates an active student, шаблонные тесты отчёта.
-
Глобальные материалы
STUDENTS/TEACHERS.- Дерево и статьи фильтруются по роли JWT; аноним — только
ALL. - Админ выбирает аудиторию при создании и может изменить её.
- Тесты:
GlobalAudienceAccessIntegrationTest(5 сценариев).
- Дерево и статьи фильтруются по роли JWT; аноним — только
-
LDD gate на чистом checkout.
LDD-AUTH-005теперь P0 с unit-тестом gateway; полный refresh/handshake вынесен в P1LDD-AUTH-008(runtime).evidenceCheckбезbuild/evidenceпроходит по P0; runtime P1 закрываются в release.
-
Backup/env.
LMS_REFRESH_TOKEN_CLEANUP_CRONв примерах закавычен.backup.shбольше неsource-ит.env.prod(не исполняет cron как команду).deploy.sh upпосле backup вызываетverify-latest.
-
Robots/noindex.
robots.txt;X-Robots-Tag: noindex, nofollowдля admin/teacher/student/login/api/курсовых материалов.
-
Профиль.
- Старые комментарии без автора показывают «автор не указан».
- Студенческий профиль не показывает черновики лабораторных.
-
Браузерные URL курсов —
courseNo. Страницы преподавателя, админа, материалы и профиль студента принимают человеческий номер курса; REST API продолжает работать с UUID. -
Импорт: ошибки до записи.
- Занятый логин и неактивная целевая группа возвращают
applied=falseс номером строки и не создают частичных записей. - Тесты:
GroupServiceIntegrationTest#import reports occupied login...,#import reports inactive target group..., XLSX-варианты#xlsx import reports occupied login before writing(),#xlsx import reports inactive target group before writing().
- Занятый логин и неактивная целевая группа возвращают
-
Профиль приведён к контракту 09.
variant.id,level.id/code,grade.updatedBy,author.name.- ФИО автора берётся из identity (fallback — логин).
submissionLimit(по умолчанию 50) иsubmissionsTotal;attemptsCountостаётся полным.- SQL-тест: 10 лабораторных — не более 15 запросов.
- Тесты:
StudentProfileIntegrationTest,ProfileDtoJsonTest,StudentProfileTemplateTest,InternalControllerIntegrationTest.
-
Финальные ограничения когорты.
V14__cohort_constraints.sql:NOT NULLдля 5 полей, полный unique index, строгие check-констрейнты; legacy-строки блокируют миграцию с явной ошибкой.scripts/ldd-migration-upgrade.shпроверяетcohort_not_null=5иcohort_unique_full=1на пути master→branch.
-
Возврат группы из архива.
POST /api/v1/groups/{id}/restore, кнопка на странице группы, аудитGROUP_RESTORE; повторный возврат активной группы — 400.
-
Пагинация и пакетные сдачи.
GET /api/v1/groups?page=&limit=и страница/admin/groups.GET /api/v1/admin/content/articles?offset=&limit=.SubmissionService.latestPerStudentByLab— один запрос на все лабы ведомости вместо запроса на каждую.
-
Аудит ростера.
- Интеграционный тест проверяет шесть событий и актора.
-
История членства на странице группы.
GET /api/v1/groups/{id}/historyотдаёт студента, действие, откуда/куда и причину; шаблон показывает последние 200 событий в МСК.- Тесты:
GroupServiceIntegrationTest,AdminStage4TemplateTest.
3. Остаточные отличия от цели
P1
- Backup restore на staging не подтверждён артефактом/логом.
- Первый реальный CI pipeline на Woodpecker VM не подтверждён.
Осознанные границы
- Автоматический догон повышения за предыдущий календарный год не делаем.
Планировщик не может безопасно восстановить историческое состояние групп:
текущие
courseуже могут быть изменены. Догон в том же году после 31 августа работает; для прошлого года админ запускает dry-run с явным годом и проверяет план вручную. Это защищает от повторного повышения по устаревшему состоянию.
P2
- Импорт: гонка. Preflight закрывает известные конфликты, но гонка с параллельной вставкой логина всё ещё даёт общий 409 вместо строки отчёта.
- Визуальная регрессия. Playwright проверяет сценарии и мобильный viewport, но screenshot-diff нет.
- Mutation testing не 100%, нагрузочный smoke не SLA.
Операционные
- Инвентаризация legacy-активов на реальном хранилище.
- Установка/проверка daily backup timer на сервере.
- Первый push-MR и tag pipeline в Woodpecker.
- Restore на staging.
4. Принятые решения
ACADEMIC_LEAVE: блокировать только сдачу и защиты; чтение и скачивание своих файлов разрешены.- «Убрать из группы»: действие удалено полностью.
- Импорт терминальных/академических статусов: только по явному флагу
restoreInactiveStatuses. - Глобальные материалы:
ALL/STUDENTS/TEACHERSподдерживаются;STUDENTSвидит студент,TEACHERS— преподаватель, аноним — толькоALL. - «Контингент» остаётся вне scope.
5. LDD
- Реестр:
docs/evidence/claims.json, 66 claims (27 P0 / 39 P1). ./gradlew test ktlintCheck detekt evidenceCheck— зелёный; P0 gaps = 0../scripts/ldd-release.sh— PASS: 66/66 claims, 398 тестов, mutationCourseAccessService75%,PromotionPlanner69%, browser E2E 18/18, runtime/load p95 < 1 с.
6. Следующий порядок работ
- Остались операционные P1: restore на staging и первый реальный Woodpecker pipeline.
- P2: гонка импорта, визуальная регрессия, повышение mutation-покрытия и SLA-нагрузка.
- Перед production: ручной разбор legacy-когорт по SQL из
deploy/DEPLOY.md, затем backup и деплой. - После каждого изменения прогонять
./scripts/ldd-release.shи обновлятьdocs/evidence/baseline-2026-10-29.md.