Files
lms-sb/ROADMAP.md
T

209 lines
15 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.
# ROADMAP — LMS Second Brain
**Стек:** Next.js 16.2.2 · React 19 · PostgreSQL 16 · Prisma 7 · Better Auth 1.6 · Tailwind v4 · shadcn/ui · TipTap · Kinescope · Resend · Hetzner Object Storage
**Принцип:** один этап — одна рабочая фича. Не переходим к следующему, пока текущий не работает end-to-end.
---
## Этап 0 — Каркас, auth, роли ✅ ЗАВЕРШЁН (07.04.2026)
**Задеплоено на:** https://school.second-brain.ru
- [x] Next.js 16.2.2 (App Router, TypeScript, Tailwind v4)
- [x] Docker Compose: PostgreSQL 16 (прод на Hetzner)
- [x] Prisma 7: схема User, Session, Account + полная LMS-модель
- [x] Better Auth: вход по email/password, роли student/curator/admin
- [x] proxy.ts: защита маршрутов по сессии
- [x] Дашборды для трёх ролей
- [x] Страница входа, регистрации, подтверждения email
- [x] Seed: admin/curator/student (пароль: Password123!)
- [x] Dockerfile multi-stage + docker-compose.prod.yml
- [x] Caddy: school.second-brain.ru → порт 3010
---
## Этап 1 — Курсы → Модули → Уроки (CRUD в админке) ✅ ЗАВЕРШЁН (07.04.2026)
- [x] Prisma-схема: Course, Module, Lesson (с порядком, статусом published)
- [x] Admin: список курсов, создать / редактировать / удалить курс
- [x] Admin: список модулей внутри курса, drag-and-drop сортировка
- [x] Admin: список уроков внутри модуля, drag-and-drop сортировка
- [x] Admin: редактор урока с TipTap (заголовки, списки, цитаты, код, картинки, ссылки)
- [x] Загрузка картинок в уроке → Hetzner Object Storage (second-brain-lms, Nuremberg)
- [x] Поле для Kinescope ID в уроке (просто текстовое, без интеграции — это Этап 2)
- [x] Публикация/скрытие курса и урока (черновик / опубликован)
- [x] Управление доступом: выдать / забрать доступ к курсу для пользователя
- [x] Дизайн в стиле Second Brain: Fira Mono, #F5F5F0, Aubade-карточки
- [x] Admin: таблица пользователей (/admin/users)
---
---
## Этап 1.5 — Расширенное управление доступом
**Цель:** гибкое управление доступом: сроки, категории, пакеты, история.
- [ ] **Срок доступа:** поле `expiresAt` в `CourseEnrollment` + автоблокировка по дате
- [ ] **Категории курсов:** таблица `Category`, поле `categoryId` в `Course`, фильтрация в списке
- [ ] **Расширенный энролл:** на странице ученика — дать доступ сразу к нескольким курсам
- [ ] **История доступа:** лог выдачи/отзыва (кто, когда, метод, примечание)
**Критерий готовности:** задаю ученику доступ к 3 курсам с разными сроками, в логе вижу все операции.
---
## Этап 2 — Интеграция Kinescope, рендер уроков для ученика
**Цель:** ученик видит урок с видео Kinescope и текстом.
- [ ] Компонент `KinescopePlayer` — обёртка над `@kinescope/react-kinescope-player`
- [ ] Рендер урока для ученика: видео (если есть Kinescope ID) + текст + файлы
- [ ] Загрузка PDF/файлов к уроку (Object Storage), список для скачивания
- [ ] Страница курса для ученика: список модулей и уроков, статус прохождения
- [ ] Навигация по урокам: предыдущий / следующий
- [ ] Блокировка доступа к курсу без enrollment (middleware или server component)
- [ ] Страница «Мои курсы» в личном кабинете ученика
**Кинескоп-нюанс:** пока без DRM (бесплатный план), просто передаём `videoId` в компонент. Когда появится платный план — добавим signed URLs в отдельной задаче.
**Критерий готовности:** ученик открывает урок, смотрит видео из Kinescope, читает текст, скачивает PDF.
---
## Этап 3 — Прогресс и линейное открытие уроков
**Цель:** ученик проходит курс последовательно, прогресс сохраняется.
- [ ] Prisma: таблица `LessonProgress` (userId, lessonId, completedAt)
- [ ] Кнопка «Урок завершён» — создаёт запись в LessonProgress
- [ ] Логика блокировки: следующий урок открыт только если предыдущий завершён
- [ ] Прогресс-бар по курсу (% завершённых уроков)
- [ ] Прогресс-бар по модулю
- [ ] API: `POST /api/progress/complete` — принимает lessonId, создаёт прогресс
- [ ] Иконки статуса уроков в боковой панели: ✓ пройден / 🔒 заблокирован / → текущий
**Примечание:** если в уроке есть тест (Этап 4) или ДЗ (Этап 5) — кнопка «Завершить» появляется только после их прохождения/отправки. Эту логику дорабатываем на соответствующих этапах.
**Критерий готовности:** прохожу урок 1, нажимаю «Завершён» — открывается урок 2. Урок 3 заблокирован. Прогресс-бар показывает 33%.
---
## Этап 4 — Тесты и квизы
**Цель:** можно добавить тест к уроку, ученик проходит и получает результат.
- [ ] Prisma: Quiz, QuizQuestion, QuizOption, QuizAttempt
- [ ] Admin: создание теста к уроку (добавить вопрос → варианты ответов → отметить правильный)
- [ ] Типы вопросов: одиночный выбор, множественный выбор, короткий текст
- [ ] Рендер теста в уроке для ученика
- [ ] Авто-проверка (single/multiple choice), результат сразу
- [ ] Настройка: показывать правильные ответы после прохождения (да/нет)
- [ ] Интеграция с прогрессом: урок с тестом засчитан только после прохождения теста
**Критерий готовности:** добавляю тест из 3 вопросов к уроку, ученик проходит, видит результат, урок засчитывается.
---
## Этап 5 — Домашние задания и обратная связь куратора
**Цель:** ученик сдаёт ДЗ, куратор оставляет комментарий.
- [ ] Prisma: Homework, HomeworkSubmission, HomeworkFeedback
- [ ] Admin: добавить блок ДЗ к уроку (текст задания)
- [ ] Ученик: форма отправки ДЗ (текст + файлы → Object Storage)
- [ ] Ученик: ДЗ засчитывается **автоматически при отправке** (урок открывается сразу)
- [ ] Куратор: список ДЗ на проверку (все или по курсу), статус «новое / просмотрено»
- [ ] Куратор: просмотр ДЗ, оставить текстовый комментарий
- [ ] История обмена по ДЗ (ученик может ответить на комментарий куратора)
- [ ] Уведомление ученику когда куратор оставил комментарий (заглушка — реальные email на Этапе 7)
**Критерий готовности:** отправляю ДЗ — урок открывается. Куратор заходит в панель, видит ДЗ, оставляет комментарий. Ученик видит комментарий в карточке урока.
---
## Этап 6 — Обсуждения под уроками
**Цель:** ученики могут общаться под каждым уроком.
- [ ] Prisma: LessonComment (с поддержкой вложенных ответов — опционально)
- [ ] Рендер треда комментариев под уроком
- [ ] Форма отправки комментария (только для enrolled учеников)
- [ ] Модерация: куратор/админ может удалить комментарий
- [ ] Пагинация или infinite scroll для длинных тредов
**Критерий готовности:** ученик оставляет комментарий, другой ученик его видит, куратор может удалить.
---
## Этап 7 — Email-уведомления
**Цель:** все участники получают нужные письма через Resend.
- [ ] Базовый email-шаблон (HTML, фирменный стиль)
- [ ] Ученик: подтверждение регистрации (уже частично с Этапа 0, финализировать)
- [ ] Ученик: письмо когда куратор оставил комментарий к ДЗ
- [ ] Ученик: письмо когда ответили на его комментарий в уроке
- [ ] Куратор / Админ: новое ДЗ на проверку
- [ ] Куратор / Админ: новый комментарий в обсуждении
- [ ] Админ: зарегистрирован новый ученик
- [ ] Очередь отправки (edge case: Resend временно недоступен → retry)
**Критерий готовности:** отправляю ДЗ — куратор получает email. Куратор отвечает — ученик получает email.
---
## Этап 8 — Импорт уроков из Markdown
**Цель:** могу импортировать урок из .md-файла Obsidian одним действием.
- [ ] API: `POST /api/admin/lessons/import-md` — принимает .md-файл
- [ ] Парсинг frontmatter (title, order, kinescopeId и кастомные поля) → метаданные урока
- [ ] Конвертация Markdown-тела в TipTap JSON (через remark / rehype)
- [ ] UI в админке: кнопка «Импортировать из .md» на странице урока
- [ ] Обработка картинок в Markdown (локальные пути → Object Storage)
**Критерий готовности:** беру .md-файл из Obsidian с frontmatter и текстом → импортирую → урок создан с правильными метаданными и контентом.
---
## Этап 9 — Миграция с emdesell
**Цель:** все пользователи и контент перенесены в новую LMS.
- [ ] Скрипт импорта пользователей из CSV-экспорта emdesell (email, имя, курсы)
- [ ] Создание пользователей без пароля + письмо «установите пароль»
- [ ] Назначение доступов к курсам по данным из CSV
- [ ] Чек-лист ручного переноса контента (уроки, PDF, структура курсов)
- [ ] Скрипт проверки целостности: все enrolled пользователи имеют доступ к нужным курсам
- [ ] QA: проверить 10 случайных аккаунтов после импорта
**Критерий готовности:** все ученики из emdesell могут войти в новую LMS и продолжить обучение.
---
## Этап 10 — Telegram-бот и аналитика
**Цель:** получаю уведомления в Telegram, вижу базовую аналитику.
- [ ] Telegram-бот: уведомление куратору/админу о новом ДЗ
- [ ] Telegram-бот: уведомление об ошибках (500-е, failed email и т.д.)
- [ ] Yandex.Metrika: базовое подключение (pageviews)
- [ ] Admin: простая страница аналитики (активные ученики, прогресс по курсам)
---
## Этап 11 — Деплой на Hetzner
**Цель:** LMS работает на production-сервере по своему домену с SSL.
- [ ] `docker-compose.prod.yml`: app + PostgreSQL + Redis + Nginx
- [ ] Nginx: SSL через Let's Encrypt (certbot), reverse proxy на Next.js
- [ ] GitHub Actions: CI/CD pipeline (lint → build → push Docker image → deploy)
- [ ] Резервное копирование PostgreSQL (cron → Object Storage)
- [ ] Мониторинг uptime (UptimeRobot или аналог)
- [ ] `.env` на сервере через Hetzner Secrets Manager или vault-файл вне репозитория
- [ ] Smoke-тест: регистрация → урок → ДЗ → куратор → email
**Критерий MVP готов:** создаю курс из админки, добавляю уроки с Kinescope, импортирую ученика из emdesell, даю доступ — ученик регистрируется, проходит урок, сдаёт тест, отправляет ДЗ, получает автодоступ к следующему уроку, позже — комментарий куратора на email.
---
## Бэклог (после MVP)
- Сертификаты по окончании курса
- Геймификация (баллы, бейджи, рейтинги)
- Промокоды и интеграция с платёжными системами
- Дедлайны и расписания
- Kinescope DRM (signed URLs) — при переходе на платный план
- Водяные знаки на PDF и картинках
- Мобильное приложение