docs: итоговый отчёт и оставшиеся разрывы
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
# 08. План реализации: группы, курсы, преподаватели
|
# 08. План реализации: группы, курсы, преподаватели
|
||||||
|
|
||||||
**Статус:** план согласован, этапы 0–4 выполнены, этапы 5–6 — в работе.
|
**Статус:** план согласован, этапы 0–5 выполнены. Проверка этапа 6 выполнена
|
||||||
|
(тесты, upgrade миграций, security, deploy-runbook), но этап 6 закрыт не
|
||||||
|
полностью: остаются права преподавателя на запись, видимость активов и CI —
|
||||||
|
см. § 9.1 и [16-stage6-report.md](16-stage6-report.md).
|
||||||
**Основа:** [07-groups-courses.md](07-groups-courses.md).
|
**Основа:** [07-groups-courses.md](07-groups-courses.md).
|
||||||
**Дата решений:** 2026-10-23.
|
**Дата решений:** 2026-10-23.
|
||||||
|
|
||||||
@@ -311,12 +314,35 @@ identity V9, **academic V11**, progress V13 (+V14 при необходимос
|
|||||||
31 августа МСК и догон), жизненный цикл студента, архив группы,
|
31 августа МСК и догон), жизненный цикл студента, архив группы,
|
||||||
усиленное подтверждение удаления, блокировка входа для архивных
|
усиленное подтверждение удаления, блокировка входа для архивных
|
||||||
и выпущенных групп. Отчёт: [14-stage4-report.md](14-stage4-report.md).
|
и выпущенных групп. Отчёт: [14-stage4-report.md](14-stage4-report.md).
|
||||||
- **Этап 5 — остаётся.** UX и контент: студенческие страницы курсов,
|
- **Этап 5 — выполнен.** Студенческие страницы курсов, материалы по
|
||||||
материалы по `/learn/course/{course_no}/...` и аудитории, наследуемая
|
`/learn/course/{course_no}/...` и аудитории, публичные материалы `ALL`,
|
||||||
видимость активов, публичные материалы `ALL`.
|
скрытые материалы для преподавателя, перепроверка статуса web-сессии.
|
||||||
- **Этап 6 — остаётся.** Hardening: полная security-матрица,
|
Отчёт: [15-stage5-course-materials.md](15-stage5-course-materials.md).
|
||||||
upgrade-тест миграций, аудит, индексы/пагинация, backup/restore,
|
- **Этап 6 — проверка выполнена, закрыт не полностью.** Проверены полный
|
||||||
документация и smoke.
|
прогон тестов/линтеров, upgrade миграций с master-схемы, security-матрица,
|
||||||
|
gateway и deploy-runbook. Отчёт: [16-stage6-report.md](16-stage6-report.md).
|
||||||
|
Не закрыты: права преподавателя на запись, видимость активов, аудит
|
||||||
|
скачиваний и CI. Остальные пункты hardening (индексы, backup/restore,
|
||||||
|
документация, smoke) описаны в отчёте и чек-листе.
|
||||||
|
|
||||||
|
### 9.1. Известные пробелы после этапа 6
|
||||||
|
|
||||||
|
- **Активы публичны.** `/api/v1/content/assets/{name}` не проверяет курс и
|
||||||
|
статью; нужна проверка `article_assets → article → section → chapter` и
|
||||||
|
visibility-aware маршруты.
|
||||||
|
- **Преподаватель — в основном read-only.** Авторство лабораторных/материалов,
|
||||||
|
распределение, оценки, комментарии и защита остаются admin-only в UI/API;
|
||||||
|
ТЗ ожидает преподавательский self-service.
|
||||||
|
- **Имена групп в кабинете преподавателя.** На странице курса показывается
|
||||||
|
UUID группы, batch-разрешения имён нет.
|
||||||
|
- **Аудит.** Есть история членства и журнал повышения, но нет audit-log
|
||||||
|
скачиваний, просмотров профилей, назначений и публикаций.
|
||||||
|
- **Импорт.** Старый формат не поддерживается; ведущие нули номера группы
|
||||||
|
нормализуются (`01` → `1`).
|
||||||
|
- **JWT 30 дней.** Web перепроверяет статус каждые 45 секунд, но прямой API
|
||||||
|
с уже выданным токеном живёт до истечения.
|
||||||
|
- **CI отсутствует.** Гейт — локальный `./gradlew test ktlintCheck detekt`;
|
||||||
|
автоматического pipeline и upgrade-теста в CI нет.
|
||||||
|
|
||||||
## 10. Definition of Done
|
## 10. Definition of Done
|
||||||
|
|
||||||
|
|||||||
271
docs/16-stage6-report.md
Normal file
271
docs/16-stage6-report.md
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
# 16. Отчёт этапа 6: проверка, hardening и передача
|
||||||
|
|
||||||
|
**Дата:** 2026-10-27.
|
||||||
|
**Ветка:** `feature/groups-courses`.
|
||||||
|
**Статус:** проверка этапа 6 выполнена; этап 6 закрыт **не полностью**.
|
||||||
|
Миграции, security-матрица, upgrade-тест и deploy-runbook проверены. Открытыми
|
||||||
|
остаются права преподавателя на запись, видимость активов, аудит и CI — см.
|
||||||
|
раздел 4.
|
||||||
|
|
||||||
|
## 1. Итоговый объём этапов 0–5
|
||||||
|
|
||||||
|
| Этап | Что реализовано | Отчёт |
|
||||||
|
|---|---|---|
|
||||||
|
| 0 | Схема и контракты: identity `V4–V9`, academic `V6–V11`, progress `V13`; preflight-скрипты; ADR; контракт профиля студента курса | [10](10-stage0-report.md) |
|
||||||
|
| 1 | Роли `ADMIN/TEACHER/STUDENT`, группы-когорты и парсер имени, статусы студентов и аккаунтов, `membership_history`, импорт v2 | [11](11-stage1-report.md) |
|
||||||
|
| 2 | Курсы, `course_no` для браузерных URL, история преподавателей и групп, bootstrap курса C, привязка лабораторных к курсу, копирование лабораторных, админ-UI | [12](12-stage2-report.md) |
|
||||||
|
| 3 | Аккаунты преподавателей, курсовая область видимости, внутренние API identity с `LMS_INTERNAL_TOKEN`, кабинет преподавателя, профиль студента курса и скачивание всех попыток | [13](13-stage3-report.md) |
|
||||||
|
| 4 | Повышение (dry-run/apply/rollback, планировщик 31 августа МСК), академотпуск, отчисление, выпуск, архив/восстановление, усиленное удаление, блокировка входа | [14](14-stage4-report.md) |
|
||||||
|
| 5 | Курсовые материалы `/learn/course/{course_no}/...`, публичные глобальные материалы `ALL`, скрытые материалы для преподавателя, перепроверка статуса web-сессии | [15](15-stage5-course-materials.md) |
|
||||||
|
|
||||||
|
Ключевые инварианты, действующие после этапов 0–5:
|
||||||
|
|
||||||
|
- все лабораторные принадлежат курсу; существующие лабораторные, главы и
|
||||||
|
активные группы перенесены в курс C;
|
||||||
|
- API работает с UUID курса, браузерные URL — с `course_no`;
|
||||||
|
- преподаватель видит только активные назначенные курсы; студент — только курсы
|
||||||
|
активной группы; админ — все курсы;
|
||||||
|
- студент видит только опубликованные оценки и комментарии;
|
||||||
|
- вход закрыт для отчисленных, выпущенных и архивных студентов, а также для
|
||||||
|
архивных аккаунтов; web дополнительно перепроверяет статус;
|
||||||
|
- повышение и жизненный цикл пишут историю; применение повышения идемпотентно.
|
||||||
|
|
||||||
|
## 2. Проверка
|
||||||
|
|
||||||
|
### 2.1. Сборка, тесты и линтеры
|
||||||
|
|
||||||
|
Выполнено 2026-10-27:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew test ktlintCheck detekt
|
||||||
|
```
|
||||||
|
|
||||||
|
Результат: `BUILD SUCCESSFUL`, код возврата `0`, все модули зелёные.
|
||||||
|
|
||||||
|
Для получения актуальных счётчиков тесты запущены принудительно:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew test --rerun-tasks
|
||||||
|
```
|
||||||
|
|
||||||
|
| Модуль | Тестов | Failures | Errors | Skipped |
|
||||||
|
|---|---:|---:|---:|---:|
|
||||||
|
| identity-service | 62 | 0 | 0 | 0 |
|
||||||
|
| academic-service | 53 | 0 | 0 | 0 |
|
||||||
|
| web | 40 | 0 | 0 | 0 |
|
||||||
|
| progress-service | 12 | 0 | 0 | 0 |
|
||||||
|
| markdown | 5 | 0 | 0 | 0 |
|
||||||
|
| **Итого** | **172** | **0** | **0** | **0** |
|
||||||
|
|
||||||
|
`ktlintCheck` и `detekt` прошли без замечаний. Отдельных unit-тестов у gateway
|
||||||
|
и `common-http` в текущем дереве нет; маршрутизация gateway проверена
|
||||||
|
конфигурацией и security-матрицей ниже.
|
||||||
|
|
||||||
|
### 2.2. Upgrade-тест миграций
|
||||||
|
|
||||||
|
Проверка выполнена на одноразовом PostgreSQL 18 (Testcontainers/контейнер,
|
||||||
|
не production-БД):
|
||||||
|
|
||||||
|
1. Развёрнута схема master: identity `V1–V3`, academic `V1–V5`,
|
||||||
|
progress `V1–V9`, `V11`, `V12`.
|
||||||
|
2. Загружены синтетические данные: администратор и два студента, две группы
|
||||||
|
(`ПИ-11БО`, `ПИ-21БО`), зачисления, семестр, лабораторная, глава/раздел/
|
||||||
|
статья/актив, оценка, комментарий и попытка сдачи.
|
||||||
|
3. Поверх master применены миграции ветки:
|
||||||
|
- identity `V4–V9`;
|
||||||
|
- academic `V6–V11`;
|
||||||
|
- progress `V13`.
|
||||||
|
4. Выполнены postflight-запросы и повторное применение `V13`.
|
||||||
|
|
||||||
|
Результат: **успешно, без ошибок**.
|
||||||
|
|
||||||
|
- **identity:** группы разобраны в `stream/course/number/degree/enrollment_year`
|
||||||
|
(`ПИ-11БО` → поток `ПИ`, курс 1, номер 1, `БО`, год набора 2026; `ПИ-21БО` →
|
||||||
|
курс 2, год 2025); статус `ACTIVE`; созданы `promotion_runs`,
|
||||||
|
`promotion_run_items`; зачисления перенесены в `membership_history`
|
||||||
|
действием `ENROLL`; добавлен `accounts.status`.
|
||||||
|
- **academic:** добавлены `labs.course_id`, `chapters.course_id/audience`,
|
||||||
|
индексы `labs_number_course_uidx`, `chapters_slug_global_uidx`,
|
||||||
|
`chapters_slug_course_uidx`, `article_assets_article_idx`,
|
||||||
|
`courses_title_lower_uidx`. Курс C миграциями не создаётся — его создаёт
|
||||||
|
bootstrap после входа админа, поэтому `labs_without_course` до bootstrap
|
||||||
|
ожидаемо больше нуля.
|
||||||
|
- **progress:** `grade_comments.author_account_id` и
|
||||||
|
`lab_grades.updated_by_account_id` созданы как nullable `uuid`; индекс
|
||||||
|
`lab_grades_lab_idx` существует и валиден; старый комментарий остался без
|
||||||
|
автора, как и задумано.
|
||||||
|
- **V13 идемпотентна:** повторное применение `V13` (дважды) завершилось
|
||||||
|
сообщениями `already exists, skipping` и не изменило схему. Это же
|
||||||
|
проверяет `ProfileAuthorsMigrationTest` на Testcontainers.
|
||||||
|
- **progress V10 отсутствует:** в ветке нет
|
||||||
|
`progress-service/.../V10__profile_authors.sql`; в истории прогресса
|
||||||
|
применяются `V11`, `V12`, затем `V13`. У academic `V10` — это другой файл,
|
||||||
|
`V10__course_title_unique.sql` (уникальный индекс названия курса).
|
||||||
|
- Переход **forward-only**: после `V13` откат на сборку без неё не пройдёт
|
||||||
|
валидацию Flyway; `out-of-order` включать нельзя.
|
||||||
|
|
||||||
|
### 2.3. Security-проверки
|
||||||
|
|
||||||
|
Проверено автоматическими тестами (полный прогон 172 теста) и разбором
|
||||||
|
конфигурации gateway.
|
||||||
|
|
||||||
|
| Сценарий | Ожидание | Факт |
|
||||||
|
|---|---|---|
|
||||||
|
| Аноним → курс/материалы курса | нет доступа | `401` на `/api/v1/courses/{id}/content/tree`; `/api/v1/courses/by-no/{no}` — `401` |
|
||||||
|
| Аноним → публичные материалы | только глобальные `ALL` | публичное дерево содержит только глобальные главы с `audience = ALL`; курсовая глава через `/api/v1/content/...` — `404` |
|
||||||
|
| Админ → курс, профиль, скачивание | полный доступ | доступ к любому курсу и студенту, скачивание любой попытки курса |
|
||||||
|
| Преподаватель своего курса | курс, группы, профиль, материалы | видит опубликованные и скрытые материалы, всех студентов активной группы курса, неопубликованные оценки и все попытки |
|
||||||
|
| Преподаватель чужого курса | `403` | `403` на материалы, курс по `course_no`, состав группы и профиль |
|
||||||
|
| Студент → свой профиль | только своё и опубликованное | скрытые оценки/комментарии отсутствуют; чужой `studentId` — `403` |
|
||||||
|
| Студент → чужой курс/группа | `403` | доступ только к курсам активной группы; архивный курс — `403` |
|
||||||
|
| Чужая сдача / лаба другого курса | `403` | скачивание отклоняется; своя попытка курса скачивается ZIP |
|
||||||
|
| Внутренние API identity | только по токену | неверный/пустой `X-Internal-Token` — `403`, сравнение constant-time; неизвестный id — `404` |
|
||||||
|
| Gateway | внутренние пути не публикуются | маршрутов на `/api/v1/internal/**` нет; gateway требует JWT для всего, кроме `/actuator`, входа/setup/JWKS и публичного `/api/v1/content/**` |
|
||||||
|
| Gateway → заголовки личности | клиент не подменяет | `X-Account-Id/Login/Role` удаляются и проставляются только после проверки JWT |
|
||||||
|
| Web-сессия | быстрый отзыв доступа | статус перепроверяется не реже чем раз в 45 секунд; `active=false` или `401/403` инвалидируют сессию; недоступность identity не разлогинивает всех |
|
||||||
|
|
||||||
|
Остаточные риски перечислены в разделе 4: публичные активы и 30-дневный JWT
|
||||||
|
для прямого API.
|
||||||
|
|
||||||
|
## 3. Чек-лист деплоя
|
||||||
|
|
||||||
|
### 3.1. Перед деплоем
|
||||||
|
|
||||||
|
- [ ] **Backup обязателен.** Выполнить `./deploy/backup.sh backup` и
|
||||||
|
`./deploy/backup.sh verify <dir>`. `./deploy/deploy.sh up` сам вызывает
|
||||||
|
`backup.sh backup --if-running`; при ошибке backup деплой прерывается.
|
||||||
|
Backup на том же сервере не считается единственной защитой.
|
||||||
|
- [ ] В `.env.prod` задан **`LMS_INTERNAL_TOKEN`** — длинная случайная строка
|
||||||
|
(`openssl rand -hex 32`), одинаковая для identity, academic и progress.
|
||||||
|
Значение по умолчанию `dev-internal-token` в production не использовать.
|
||||||
|
Там же задан `LMS_DB_PASSWORD`; `.env.prod` не коммитится.
|
||||||
|
- [ ] Проверить, что на сервере нет незакоммиченных изменений и выполнен
|
||||||
|
`git pull` нужной ветки/тега.
|
||||||
|
|
||||||
|
### 3.2. Порядок выкладки
|
||||||
|
|
||||||
|
1. **Flyway.** `./deploy/deploy.sh up` собирает образы и запускает
|
||||||
|
`postgres → identity → academic → progress → gateway → web`. Миграции
|
||||||
|
применяются автоматически при старте сервисов:
|
||||||
|
identity `V4–V9`, academic `V6–V11`, progress `V13`.
|
||||||
|
Отдельный ручной запуск Flyway не нужен.
|
||||||
|
2. **Bootstrap курса C.** После входа админа открыть `/admin/courses`.
|
||||||
|
Пока курсов нет, показан блок первичной настройки. Bootstrap идемпотентно
|
||||||
|
создаёт/находит курс «Промышленное программирование на языке C»,
|
||||||
|
привязывает активные группы, переносит лабораторные и главы и, если
|
||||||
|
лабораторных без курса не осталось, выполняет
|
||||||
|
`ALTER TABLE academic.labs ALTER COLUMN course_id SET NOT NULL`.
|
||||||
|
Это **post-bootstrap шаг в рантайме, а не Flyway-миграция**. Повторный
|
||||||
|
запуск безопасен. Если в БД уже есть курс C, bootstrap не требуется.
|
||||||
|
3. **Postflight.** Выполнить
|
||||||
|
`psql -h localhost -U lms -d lms -f deploy/preflight/groups-courses-post.sql`
|
||||||
|
и проверить:
|
||||||
|
- `labs_without_course = 0`;
|
||||||
|
- `chapters_without_course = 0` (если все текущие материалы курсовые);
|
||||||
|
- ровно один курс C;
|
||||||
|
- `comments_without_author` соответствует старым комментариям;
|
||||||
|
- группы без полного разбора отсутствуют.
|
||||||
|
4. **V10 → V13 — только dev/staging.** На production/master записи
|
||||||
|
`progress V10__profile_authors.sql` нет, ничего удалять не нужно. Не путать
|
||||||
|
с academic `V10__course_title_unique.sql` — он относится к другой схеме и
|
||||||
|
должен применяться как обычно.
|
||||||
|
Если БД когда-либо применяла старую feature-миграцию V10:
|
||||||
|
- сделать backup;
|
||||||
|
- проверить `deploy/preflight/progress-v10-v13.sql` (`columns_ok` и
|
||||||
|
`index_ok` должны быть `true`);
|
||||||
|
- удалить **только строку истории** V10 (`success=true`) через
|
||||||
|
`flyway repair` или точечный `DELETE` из примера в скрипте; объекты
|
||||||
|
схемы не удалять;
|
||||||
|
- при `success=false` сначала убедиться, что частичные объекты откатились;
|
||||||
|
- не переставлять `V11`/`V12` и не включать `out-of-order`.
|
||||||
|
После `V13` переход forward-only.
|
||||||
|
|
||||||
|
### 3.3. Smoke после деплоя
|
||||||
|
|
||||||
|
- [ ] `docker compose -f docker-compose.prod.yml --env-file .env.prod ps` —
|
||||||
|
все контейнеры `running`; `curl -fsS http://127.0.0.1:8090/actuator/health`
|
||||||
|
отдаёт `UP`.
|
||||||
|
- [ ] **Админ:** вход, `/admin/courses` (курс C и счётчики), `/admin/groups`,
|
||||||
|
`/admin/labs`, `/admin/teachers`, `/admin/promotion`.
|
||||||
|
- [ ] **Преподаватель:** вход, `/teacher`, карточка своего курса, состав группы,
|
||||||
|
профиль студента, скачивание попытки, курсовые материалы.
|
||||||
|
- [ ] **Студент:** вход, дашборд, лабораторная, сдача/история, курсовые
|
||||||
|
материалы; видны только опубликованные оценки и комментарии.
|
||||||
|
- [ ] **Материалы курса:** админ и преподаватель видят скрытые статьи, студент —
|
||||||
|
только опубликованные; чужой курс даёт `403`, аноним уходит на `/login`.
|
||||||
|
- [ ] **Копирование лабораторной:** админ копирует лабораторную в другой курс;
|
||||||
|
создаётся черновик с уровнями и вариантами; оценки, сдачи, защиты и
|
||||||
|
назначения не копируются; занятый номер даёт `409`.
|
||||||
|
- [ ] **Профиль:** преподаватель своего курса видит сводку, комментарии, все
|
||||||
|
попытки и скачивает ZIP; чужой студент/курс — `403`.
|
||||||
|
- [ ] **Повышение:** `/admin/promotion` строит dry-run за год, данные не
|
||||||
|
меняются; применение — только после проверки плана; откат доступен для
|
||||||
|
завершённого запуска. На production не применять план «на всякий случай».
|
||||||
|
- [ ] Проверить логи `web`, `gateway`, `identity`, `academic`, `progress` на
|
||||||
|
`ERROR`/`WARN` после smoke.
|
||||||
|
|
||||||
|
## 4. Известные пробелы и follow-up
|
||||||
|
|
||||||
|
1. **Активы всё ещё публичны.** Прокси `/api/v1/content/assets/{name}` (и
|
||||||
|
web-прокси) не проверяет курс/статью: `article_assets` не связаны с
|
||||||
|
видимостью материала. Курсовые картинки может получить любой, кто знает
|
||||||
|
имя файла. Нужно использовать связь `article_assets → article → section →
|
||||||
|
chapter` для проверки видимости и сделать visibility-aware маршруты,
|
||||||
|
отдельный публичный путь для `ALL`. Осознанно
|
||||||
|
вынесено из этапа 5, зафиксировано в [15](15-stage5-course-materials.md).
|
||||||
|
2. **Права преподавателя в основном read-only.** Кабинет преподавателя даёт
|
||||||
|
обзор курса, групп, лабораторных и профилей. Авторство лабораторных и
|
||||||
|
материалов, распределение вариантов, выставление оценок, комментарии,
|
||||||
|
коды защиты и действия защиты остаются admin-only в UI/API. ТЗ
|
||||||
|
([07](07-groups-courses.md), раздел ролей) ожидает преподавательский
|
||||||
|
self-service; это главный функциональный разрыв.
|
||||||
|
3. **Названия групп в кабинете преподавателя.** На странице курса группа
|
||||||
|
показывается UUID: academic отдаёт `groupId`, а имя группы не входит в
|
||||||
|
контракт карточки курса. Нужен batch-запрос имён в identity или расширение
|
||||||
|
DTO. Тест `TeacherGroupTemplateTest` фиксирует fallback на id.
|
||||||
|
4. **Аудит чувствительных действий.** Есть `membership_history` (переводы,
|
||||||
|
академ, отчисление, архив, повышение) и журнал `promotion_runs/items`.
|
||||||
|
Отдельного audit-log для скачиваний файлов, просмотра профилей,
|
||||||
|
назначений преподавателей и публикаций нет. Нужна таблица `audit_events`
|
||||||
|
и запись из сервисов/BFF.
|
||||||
|
5. **Старый формат импорта не поддерживается.** Импорт принимает только
|
||||||
|
шаблон v2 (поток/курс/номер/степень/год/ФИО/№/база). Ведущие нули номера
|
||||||
|
группы нормализуются к числу (`01` → `1`), поэтому `ПИ-01БО` и `ПИ-1БО`
|
||||||
|
неразличимы; для разных когорт нужен строковый номер. Ограничение
|
||||||
|
зафиксировано в [11](11-stage1-report.md).
|
||||||
|
6. **JWT живёт до 30 дней.** Web-сессия перепроверяет статус каждые 45 секунд
|
||||||
|
и закрывает UI при отчислении/архиве, но уже выданный JWT для прямого
|
||||||
|
вызова API действует до истечения. Нужны короткий TTL + refresh,
|
||||||
|
denylist/revocation или проверка статуса на каждом API-вызове.
|
||||||
|
7. **Нет CI.** В репозитории нет pipeline (`.github` и аналогов); гейтом
|
||||||
|
служит локальный `./gradlew test ktlintCheck detekt`. Это не защищает
|
||||||
|
ветку от merge без прогона и не проверяет upgrade-тест автоматически.
|
||||||
|
|
||||||
|
## 5. Рекомендуемые следующие шаги
|
||||||
|
|
||||||
|
Приоритет — сверху вниз:
|
||||||
|
|
||||||
|
1. **Права преподавателя на запись.** Дать преподавателю своего курса
|
||||||
|
authoring лабораторных/материалов, распределение вариантов, выставление
|
||||||
|
оценок и комментариев, коды и действия защиты; закрыть negative-тестами
|
||||||
|
«свой/чужой курс». Это закрывает основной разрыв с ТЗ.
|
||||||
|
2. **Видимость активов.** Использовать связь `article_assets → article →
|
||||||
|
section → chapter`, проверять курс и публикацию при выдаче, оставить
|
||||||
|
отдельный публичный маршрут только для `ALL`.
|
||||||
|
3. **UI авторства контента.** Выбор курса и аудитории при создании глав/
|
||||||
|
статей, чтобы преподаватель и админ не работали только через импорт;
|
||||||
|
сейчас глобальные главы создаются с `ALL`, курсовые — без аудитории.
|
||||||
|
4. **Аудит.** Ввести `audit_events` для скачиваний, профилей, назначений,
|
||||||
|
публикаций, повышения и жизненного цикла; экран просмотра для админа.
|
||||||
|
5. **CI.** Пайплайн на каждый push/MR: `test ktlintCheck detekt`, отдельный
|
||||||
|
шаг upgrade-теста миграций на PostgreSQL 18, сборка `bootJar`; запрет
|
||||||
|
merge при красном статусе.
|
||||||
|
|
||||||
|
## 6. Итог
|
||||||
|
|
||||||
|
Этапы 0–5 реализованы и проверены. Security-матрица, upgrade-тест миграций и
|
||||||
|
deploy-runbook этапа 6 зелёные; отчёт и чек-лист передачи готовы. Этап 6
|
||||||
|
**нельзя считать полностью завершённым** до закрытия прав преподавателя,
|
||||||
|
видимости активов и CI. До этого релиз допустим только с пониманием, что
|
||||||
|
преподаватели работают в режиме просмотра, а активы курсовых материалов
|
||||||
|
остаются публичными.
|
||||||
@@ -22,6 +22,8 @@ Preview Mermaid Support) и в IntelliJ IDEA (плагин Mermaid).
|
|||||||
| [12-stage2-report.md](12-stage2-report.md) | Отчёт этапа 2: курсы, bootstrap курса C, привязка и копирование лабораторных, миграция V10 |
|
| [12-stage2-report.md](12-stage2-report.md) | Отчёт этапа 2: курсы, bootstrap курса C, привязка и копирование лабораторных, миграция V10 |
|
||||||
| [13-stage3-report.md](13-stage3-report.md) | Отчёт этапа 3: преподаватели, доступ к курсам, внутренние API, кабинет и профиль студента курса |
|
| [13-stage3-report.md](13-stage3-report.md) | Отчёт этапа 3: преподаватели, доступ к курсам, внутренние API, кабинет и профиль студента курса |
|
||||||
| [14-stage4-report.md](14-stage4-report.md) | Отчёт этапа 4: повышение, академотпуск, отчисление, архив, восстановление и удаление |
|
| [14-stage4-report.md](14-stage4-report.md) | Отчёт этапа 4: повышение, академотпуск, отчисление, архив, восстановление и удаление |
|
||||||
|
| [15-stage5-course-materials.md](15-stage5-course-materials.md) | Отчёт этапа 5: курсовые материалы, публичные `ALL`-главы, оставшийся разрыв по активам |
|
||||||
|
| [16-stage6-report.md](16-stage6-report.md) | Отчёт этапа 6: проверка, upgrade-тест миграций, security-матрица, чек-лист деплоя и оставшиеся пробелы |
|
||||||
| [ADR 0001](adr/0001-groups-courses-foundation.md) | Ключевые архитектурные решения: курс C, миграции, доступ, статусы, повышение |
|
| [ADR 0001](adr/0001-groups-courses-foundation.md) | Ключевые архитектурные решения: курс C, миграции, доступ, статусы, повышение |
|
||||||
|
|
||||||
## Кратко о системе
|
## Кратко о системе
|
||||||
|
|||||||
Reference in New Issue
Block a user