12 KiB
12 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. Сводка
| Область | Статус | Что осталось |
|---|---|---|
| Роли, группы-когорты, статусы, история | partial | Финальные NOT NULL/полная уникальность когорты; группа не восстанавливается из архива; история членства не показана в UI |
| Академический отпуск | исправлено | Вход read-only, сдача/защиты заблокированы на progress-service |
| Черновики лабораторных | исправлено | Студент не видит черновик в списке/деталях/по UUID |
| «Убрать из группы» | исправлено | Действие удалено из UI и API; остались перевод/академ/отчисление/архив |
| Импорт v2 | partial | Есть флаг восстановления неактивных; row-level отчёт для DB-конфликтов неполный; legacy-группы с NULL-полями |
| Курсы, преподаватели, группы курса | implemented | — |
| Материалы и активы | implemented | Глобальные STUDENTS/TEACHERS теперь работают; импорт глобальных глав всё ещё создаёт только ALL |
| Профиль студента | partial | Браузерный URL использует UUID вместо courseNo; часть полей контракта 09 отличается; нет лимита/пагинации попыток; нет SQL-теста «без N+1» |
| Повышение | partial | Догон при старте ищет только текущий год, не предыдущий; нет теста apply-конфликта |
| Аудит | partial | Добавлены GROUP_CREATE, STUDENT_CREATE, GROUP_IMPORT, GROUP_ENROLL; отдельных тестов на эти события пока нет |
| Backup/deploy | partial | deploy.sh теперь проверяет последний backup; restore на staging не подтверждён; первый деплой без backup — документированное исключение |
| CI | partial | Конфигурация Woodpecker и локальные прогоны есть; первый реальный pipeline на VM не подтверждён |
| Производительность | partial | Keyset-аудит, пакетные лабы и группы курса есть; списки материалов/групп без пагинации; сдачи в ведомости по выбранной лабе |
| LDD | implemented | 58 claims (27 P0 / 31 P1), 58/58 proven после release; 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/курсовых материалов.
-
Профиль.
- Старые комментарии без автора показывают «автор не указан».
- Студенческий профиль не показывает черновики лабораторных.
-
Импорт: ошибки до записи.
- Занятый логин и неактивная целевая группа возвращают
applied=falseс номером строки и не создают частичных записей. - Тесты:
GroupServiceIntegrationTest#import reports occupied login...,#import reports inactive target group....
- Занятый логин и неактивная целевая группа возвращают
3. Остаточные отличия от цели
P1
- Профиль: контракт. Браузерные маршруты используют UUID курса, а docs/09
обещает
courseNo; часть полейvariant/level/gradeотличается от контракта. Нужно либо привести код к контракту, либо официально обновить контракт. - Backup restore на staging не подтверждён артефактом/логом.
- Первый реальный CI pipeline на Woodpecker VM не подтверждён.
Осознанные границы
- Автоматический догон повышения за предыдущий календарный год не делаем.
Планировщик не может безопасно восстановить историческое состояние групп:
текущие
courseуже могут быть изменены. Догон в том же году после 31 августа работает; для прошлого года админ запускает dry-run с явным годом и проверяет план вручную. Это защищает от повторного повышения по устаревшему состоянию.
P2
- Импорт: гонка и XLSX-отчёт. Preflight закрывает известные конфликты, но гонка с параллельной вставкой логина всё ещё даёт общий 409; XLSX-строки новых preflight-тестов не покрыты (CSV покрыт).
- Когорта: поля всё ещё nullable, уникальность частичная; нужен preflight и
финальный
SET NOT NULL/полный unique index после ручного разбора legacy. - Нет восстановления группы из архива (сейчас архив односторонний).
- Нет пагинации списков материалов и групп (аудит и профиль уже лучше).
- Попытки сдачи в профиле не ограничены/не пагинированы.
- Сдачи в ведомости запрашиваются по выбранной лабораторной, а не пакетно.
- Нет визуальной регрессии и полного мобильного набора E2E.
- Нет тестов на audit-события
GROUP_CREATE/STUDENT_CREATE/GROUP_IMPORT/GROUP_ENROLL. - 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, 58 claims (27 P0 / 31 P1). ./gradlew test ktlintCheck detekt evidenceCheck— зелёный; P0 gaps = 0../scripts/ldd-release.sh— PASS: 58/58 claims, 368 тестов, mutationCourseAccessService75%,PromotionPlanner69%, browser E2E 18/18, runtime/load p95 < 1 с.
6. Следующий порядок работ
- Закрыть P1: row-level ошибки импорта, догон повышения, контракт профиля, staging restore, первый CI pipeline.
- Закрыть P2: финальная миграция когорты, unarchive, пагинация, audit-тесты, визуальная регрессия.
- Прогнать полный release и обновить
evidence/baseline-*.