Files
LMS/README.md
Vladislav Kopnin 5e60cc3819 Phase 6: accordion in /learn; README feature notes; tests green
- collapse chapters/sections via styled <details> with chevrons
- identity testcontainers smoke passes on JDK 21
- README: student UX, comments, JDK note (logback ThrowableProxy in
  fat-jars → restart recovery), data dirs
2026-09-12 02:00:45 +03:00

93 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# LMS
Микросервисная система для проведения практических занятий (Kotlin + Spring Boot + PostgreSQL 18).
## Модули
- `libs/common-http` — общий формат ошибок и обработчик исключений.
- `libs/security-jwt` — выпуск/проверка JWT (RSA) и `PasswordEncoder`.
- `libs/markdown` — серверный рендер markdown со спойлерами и санитизацией.
- `libs/test-support` — общая тестовая инфраструктура (Testcontainers, `postgres:18`).
- `services/identity-service` — аккаунты, студенты, группы, зачисления (схема `identity`).
- `services/academic-service` — курсы, статьи, лабораторные, уровни, варианты (схема `academic`).
- `services/progress-service` — уровни студентов, распределение вариантов, работы, оценки (схема `progress`).
- `services/gateway` — Spring Cloud Gateway, маршрутизация и проверка JWT.
- `web` — серверный веб-интерфейс (Thymeleaf + htmx), BFF.
## Требования
- JDK 21 (runtime) + Docker (для PostgreSQL 18). Gradle сам скачает toolchain 21 для сборки.
- **Не запускать сервисы на JAVA_HOME=Java 25**: на 25 ломается logback внутри
fat-jar (NoClassDefFoundError `ThrowableProxy`), что роняет потоки Tomcat.
Скрипт `run.sh` использует JDK 21 автоматически.
## Запуск
```bash
./gradlew bootJar -x test # собрать все сервисы
./run.sh start # поднять БД + все 5 сервисов на JDK 21
./run.sh status # проверить здоровье
./run.sh logs web # посмотреть лог сервиса
./run.sh stop | restart
```
Можно и без скрипта: `docker compose up -d postgres`, затем
`/usr/lib/jvm/java-21-openjdk/bin/java -jar <jar>` для каждого сервиса,
или `./gradlew :services:identity-service:bootRun` и т.д. по одному.
Порты по умолчанию: gateway `:8080`, identity `:8081`, academic `:8082`,
progress `:8083`, web `:8090`. Интерфейс: `http://localhost:8090`.
## Текущий функционал
Открыть `http://localhost:8090`. При первом запуске создаётся аккаунт
администратора (`/setup`); далее — вход по логину и паролю.
- **Доступ**: JWT (RSA, ключи identity генерирует при первом старте и хранит в БД),
проверка токена на gateway, роли ADMIN/STUDENT, CSRF на всех POST-формах,
session fixation-защита; вход студента с обязательной сменой пароля.
- **Группы и студенты**: создание groups, импорт `.xls/.xlsx/.csv`, ручное
добавление студента (генерация пароля), выгрузка логинов XLSX/CSV, сброс пароля;
на странице группы — баллы по каждой лабе и средний балл.
- **Лабораторные**: импорт ZIP (`lab.yaml` + `README.md` + `variants/*.md` c
front-matter) и старого JSON; создание через UI с произвольным числом уровней;
просмотр/редактирование условия (markdown), вариантов, дат; статусы
draft/published (клик по бейджу меняет); даты выводятся в московском времени.
- **Распределение вариантов**: по уровню студента на лабу (по умолчанию — самый
простой), round-robin с уникальностью в группе; ручное назначение варианта.
- **Материалы** (`/learn`, публичная читалка): главы → разделы → статьи в
markdown (код, спойлеры, картинки; санитизация OWASP); импорт ZIP
(`chapters/N-глава/N-раздел/N-статья.md` + `assets/`); создание/переименование/
удаление глав, разделов, статей; перенос статей между разделами.
- **Студент**: дашборд успеваемости (сдано, средний балл, лучшая/слабая оценка),
карточки опубликованных лаб, страница лабы: условие, свой вариант, сдача
файлов (zip/.c, переотправка до дедлайна, история, скачивание последней),
комментарий преподавателя к оценке, защита по одноразовому коду (30 мин).
- **Комментарии к оценкам**: тональность (pos/neu/neg), хранятся в БД,
автоподсказки при вводе ранжируются по частоте использования; видны студенту чипсами.
- UI: светлая/тёмная тема (сохраняется в localStorage), модальные окна вместо
отдельных страниц, аккордеоны глав/разделов в `/learn`, фавиконка,
адаптивная вёрстка без inline-стилей.
## Примечания
- **JDK 21 обязателен для runtime**. В связке Spring Boot 4.0.x + fat-jar logback
не находит `ThrowableProxy`, и это падает при любом исключении в потоке ответа.
Если после деплоя сервис вдруг «висит» на страницах (а `/actuator/health` даёт 200) —
лечится перезапуском (`./run.sh restart`).
- Даты хранятся в UTC (instant), а в UI конвертируются в Europe/Moscow
(`DateUtils`); формы datetime-local отправляются в московском времени.
- Капча/rate-limit на входе отсутствует — для учебного стендома оставлено;
пароли студентов показываются один раз при выдаче.
- `lms.submissions.dir` (default ./data/submissions) и `lms.content.assets-dir`
держите на постоянном томе при деплое.
## Сборка и тесты
```bash
./gradlew build # сборка всех модулей
./gradlew check # тесты и проверки
```
Переменные окружения для БД: `LMS_DB_URL`, `LMS_DB_USER`, `LMS_DB_PASSWORD`.