# 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 в админке) **Цель:** могу создать полную структуру курса из браузера. - [ ] Prisma-схема: Course, Module, Lesson (с порядком, статусом published) - [ ] Admin: список курсов, создать / редактировать / удалить курс - [ ] Admin: список модулей внутри курса, drag-and-drop сортировка - [ ] Admin: список уроков внутри модуля, drag-and-drop сортировка - [ ] Admin: редактор урока с TipTap (заголовки, списки, цитаты, код, картинки, ссылки) - [ ] Загрузка картинок в уроке → Hetzner Object Storage - [ ] Поле для Kinescope ID в уроке (просто текстовое, без интеграции — это Этап 2) - [ ] Публикация/скрытие курса и урока (черновик / опубликован) - [ ] Управление доступом: выдать / забрать доступ к курсу для пользователя **Критерий готовности:** создаю курс «Obsidian PKM», добавляю 2 модуля, в каждом по 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 и картинках - Мобильное приложение