Files
LMS/docs/18-goal-audit.md
Vladislav Kopnin 1570196cc7 fix(import): построчные ошибки до записи
- preflight занятого логина и неактивной целевой группы
- applied=false с номером строки, без частичных студентов
- LDD-IMPORT-003; baseline 58 claims / 368 тестов
2026-10-29 19:20:16 +03:00

11 KiB
Raw Blame History

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. Что исправлено в этой итерации

  1. 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.
  2. Черновики лабораторных скрыты от студентов.

    • 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.
  3. Удалено действие «Убрать из группы».

    • Удалены endpoint, web-маршрут, API-клиент, кнопка и сервисный метод.
    • Тесты шаблонов проверяют отсутствие действия.
  4. Импорт больше не воскрешает неактивных студентов без флага.

    • 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, шаблонные тесты отчёта.
  5. Глобальные материалы STUDENTS/TEACHERS.

    • Дерево и статьи фильтруются по роли JWT; аноним — только ALL.
    • Админ выбирает аудиторию при создании и может изменить её.
    • Тесты: GlobalAudienceAccessIntegrationTest (5 сценариев).
  6. LDD gate на чистом checkout.

    • LDD-AUTH-005 теперь P0 с unit-тестом gateway; полный refresh/handshake вынесен в P1 LDD-AUTH-008 (runtime).
    • evidenceCheck без build/evidence проходит по P0; runtime P1 закрываются в release.
  7. Backup/env.

    • LMS_REFRESH_TOKEN_CLEANUP_CRON в примерах закавычен.
    • backup.sh больше не source-ит .env.prod (не исполняет cron как команду).
    • deploy.sh up после backup вызывает verify-latest.
  8. Robots/noindex.

    • robots.txt; X-Robots-Tag: noindex, nofollow для admin/teacher/student/login/api/курсовых материалов.
  9. Профиль.

    • Старые комментарии без автора показывают «автор не указан».
    • Студенческий профиль не показывает черновики лабораторных.

3. Остаточные отличия от цели

P1

  • Импорт: ошибки БД. Занятый логин и неактивная группа теперь дают row-level applied=false; неожиданные DB-ошибки вне preflight всё ещё откатывают транзакцию без построчного отчёта.
  • Догон повышения. ensureScheduledDryRun до 31 августа возвращает null и не создаёт план за предыдущий год; после долгого простоя в январе пропущенный август не догоняется.
  • Профиль: контракт. Браузерные маршруты используют UUID курса, а docs/09 обещает courseNo; часть полей variant/level/grade отличается от контракта. Нужно либо привести код к контракту, либо официально обновить контракт.
  • Backup restore на staging не подтверждён артефактом/логом.
  • Первый реальный CI pipeline на Woodpecker VM не подтверждён.

P2

  • Когорта: поля всё ещё 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 тестов, mutation CourseAccessService 75%, PromotionPlanner 69%, browser E2E 18/18, runtime/load p95 < 1 с.

6. Следующий порядок работ

  1. Закрыть P1: row-level ошибки импорта, догон повышения, контракт профиля, staging restore, первый CI pipeline.
  2. Закрыть P2: финальная миграция когорты, unarchive, пагинация, audit-тесты, визуальная регрессия.
  3. Прогнать полный release и обновить evidence/baseline-*.