# 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) - [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] Middleware: защита маршрутов по сессии - [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 - [x] Поле для Kinescope ID в уроке - [x] Публикация/скрытие курса и урока (черновик / опубликован) - [x] Управление доступом: выдать / забрать доступ к курсу для пользователя - [x] Дизайн: Fira Mono, #F5F5F0, Aubade-карточки - [x] Admin: таблица пользователей (/admin/users) --- **Доработки таблицы пользователей (добавить в рамках Этапа 9):** - [ ] Фильтры: по роли (Ученик / Куратор / Администратор), по статусу email (подтверждён/нет) - [ ] Поиск по имени / email - [ ] Пагинация + выбор кол-ва записей на странице (20/50/100) - [ ] Ховер-попап на строке: список курсов пользователя со сроками доступа + email + телефон - [ ] Быстрые действия в строке: кнопка «Выдать доступ» без перехода на страницу пользователя --- ## Этап 1.5 — Расширенное управление доступом ✅ ЗАВЕРШЁН (07.04.2026) - [x] Срок доступа: `expiresAt` в `CourseEnrollment`, просроченный подсвечивается красным - [x] Категории курсов: таблица `Category`, `/admin/categories`, привязка к курсу - [x] Расширенный энролл: `/admin/users/[userId]` — выбор нескольких курсов + срок одной операцией - [x] История доступа: `AccessLog` — каждая операция логируется (кто, когда, метод, примечание) --- ## Этап 2 — Интеграция Kinescope, рендер уроков для ученика ✅ ЗАВЕРШЁН (07.04.2026) - [x] Компонент `KinescopePlayer` — обёртка над `@kinescope/react-kinescope-player` - [x] Рендер урока для ученика: видео (если есть Kinescope ID) + текст + файлы - [x] Загрузка PDF/файлов к уроку (Object Storage), список для скачивания - [x] Страница курса для ученика: список модулей и уроков, статус прохождения - [x] Навигация по урокам: предыдущий / следующий - [x] Блокировка доступа к курсу без enrollment (layout server component) - [x] Страница «Мои курсы» в личном кабинете ученика (dashboard) - [x] Кнопки Сохранить / Просмотр в редакторе урока - [x] Иконка-статус уроков в боковой панели курса (✓ пройден) --- ## Этап 3 — Прогресс ✅ ЗАВЕРШЁН (07.04.2026) - [x] Prisma: таблица `LessonProgress` (userId, lessonId, completedAt) - [x] Кнопка «Урок завершён» — создаёт/удаляет запись в LessonProgress - [x] Прогресс-бар по курсу в боковой панели (% завершённых уроков) - [x] Прогресс-бар по курсу на дашборде студента - [x] Admin bypass: администратор видит все уроки без отметок о прогрессе --- ## Этап 5 — Домашние задания и обратная связь куратора ✅ ЗАВЕРШЁН (07.04.2026) - [x] Prisma: Homework, HomeworkSubmission, HomeworkFeedback - [x] Admin: добавить / редактировать / удалить блок ДЗ к уроку (HomeworkEditor) - [x] Ученик: форма отправки ДЗ (текст + файлы → Object Storage) - [x] Ученик: видит статус ДЗ и фидбек куратора в карточке урока - [x] Куратор / Admin: список ДЗ на проверку (`/curator/homework`) - [x] Куратор / Admin: просмотр работы, текстовый комментарий с обратной связью - [x] Admin: AdminShell на `/curator/*` маршрутах (сайдбар не пропадает) - [x] Admin: реальная статистика на дашборде (студенты, курсы, ДЗ, прогресс) **Доработки (добавить в рамках Этапа 9):** - [ ] Фильтры в списке ДЗ: по имени/email ученика, по уроку, по курсу, по статусу - [ ] Поиск по имени/email ученика - [ ] Пагинация + выбор кол-ва записей на странице (20/50/100) - [ ] Расширенные статусы: «Новое» / «Просмотрено» / «Прокомментировано» - [ ] Шаблоны ответов куратора — готовые тексты фидбека, выбираемые из списка --- ## Этап 6 — Обсуждения под уроками ✅ ЗАВЕРШЁН (07.04.2026) - [x] Prisma: LessonComment (soft-delete через поле `deleted`) - [x] Рендер списка комментариев под уроком (server-fetched, client-rendered) - [x] Форма отправки комментария (только для enrolled учеников и admin) - [x] Модерация: автор, куратор или admin может удалить комментарий - [x] Счётчик активных комментариев в заголовке секции **Не реализовано (добавить в Этап 9 или отдельно):** - [ ] `/admin/comments` — сводная таблица всех комментариев по всем урокам - Колонки: №, Имя ученика, Урок (ссылка), Время, кол-во ответов, превью текста - Удалить комментарий прямо из списка - Пагинация - Ссылка в сайдбаре AdminNav --- ## Этап 7 — Email-уведомления ✅ ЗАВЕРШЁН (07.04.2026) - [x] Базовый HTML email-шаблон (фирменный стиль Second Brain) - [x] Приветственное письмо при регистрации (`databaseHooks.user.create.after`) - [x] Письмо ученику об открытии доступа к курсу - [x] Куратор / Admin: уведомление о новом ДЗ на проверку - [x] Ученик: уведомление о полученном фидбеке - [x] Resend domain: mailsend.second-brain.ru (verified) --- ## Этап 8 — Импорт уроков из Markdown (Obsidian) ✅ ЗАВЕРШЁН (07.04.2026) - [x] API: `POST /api/admin/import-md` — принимает .md-файл - [x] Парсинг frontmatter (title, kinescopeId, order, published) через `gray-matter` - [x] Конвертация Markdown → TipTap JSON через `unified` + `remark-parse` - [x] Поддержка: заголовки, параграфы, жирный/курсив/зачёркнутый, инлайн-код, блоки кода, цитаты, списки, ссылки, изображения (HTTP), горизонтальные разделители - [x] Очистка Obsidian-синтаксиса: `![[image]]` удаляется, `[[link|alias]]` → текст - [x] UI: кнопка «Импорт .md» в редакторе урока — заполняет форму без автосохранения --- ## Этап 9 — Настройки платформы (Admin Settings) ✅ ЗАВЕРШЁН (08.04.2026) **Цель:** администратор управляет ключевыми параметрами платформы без правки кода. ### Основное - [ ] Название школы (используется в заголовке сайта, подписи писем) - [ ] Описание школы (мета-тег description) - [ ] Ключевые слова (мета-тег keywords) - [ ] Режим тех. работ: вкл/выкл (показывает заглушку всем кроме admin) - [ ] Регистрация учеников: вкл/выкл ### Оформление - [ ] Логотип школы (загрузка → Object Storage, отображается в шапке) - [ ] Фавикон (загрузка → Object Storage) - [ ] Показывать логотип: да/нет ### Уведомления - [ ] Email(ы) для системных уведомлений (кому слать письма о ДЗ, вопросах, регистрациях) - [ ] Уведомление куратору/админу о новом ДЗ: вкл/выкл - [ ] Уведомление куратору/админу о новом вопросе ученика: вкл/выкл - [ ] Уведомление админу о новой регистрации: вкл/выкл - [ ] Уведомление ученику при ответе на ДЗ/вопрос: вкл/выкл ### Данные ученика - [ ] Требовать подтверждение email перед доступом к курсам: да/нет - [ ] Фамилия при регистрации: обязательная / необязательная / выключена - [ ] Телефон при регистрации: обязательный / необязательный / выключен ### Защита - [ ] Одна активная сессия на аккаунт: вкл/выкл - [ ] CAPTCHA на форме регистрации: вкл/выкл (reCAPTCHA v3) ### Права куратора - [ ] Куратор видит ДЗ: по всем курсам / только по назначенным курсам - [ ] Куратор может отвечать на вопросы учеников: да/нет - [ ] Куратор видит список всех студентов: да/нет ### Вставка кода - [ ] Произвольный код в `` (Yandex.Metrika, Google Analytics, пиксели) - [ ] Произвольный код в `` (виджеты, чаты поддержки) ### Юридические документы - [ ] URL Политики конфиденциальности (ссылка на внешний документ) - [ ] URL Согласия на обработку персональных данных - [ ] URL Договора-оферты - [ ] Показывать чекбокс «Я принимаю условия» при регистрации: да/нет - [ ] Реквизиты организации (текстовое поле, отображается в подвале) ### Соц. сети - [ ] YouTube: одна ссылка - [ ] VK: несколько ссылок (название + URL), например «Основная группа» и «Канал» - [ ] Telegram: несколько ссылок (название + URL), например «Основной канал» и «Канал курса» (отображаются в подвале личного кабинета ученика; хранятся как JSON-массив в Settings) ### Вопросы учеников - [ ] Система вопросов глобально: вкл/выкл - [ ] Куратор/админ может написать ученику первым: да/нет - [ ] Вопросы только по курсам ученика: да/нет - [ ] Включать вопросы для новых курсов автоматически: да/нет **Хранение:** таблица `Settings` (key-value), доступна через `getSettings()` в server components. **Критерий готовности:** меняю название школы → оно появляется в заголовке. Включаю тех. работы → ученики видят заглушку. Куратор привязан к курсу — видит только его ДЗ. --- ## Этап 11 — Импорт/Экспорт учеников и миграция с emdesell **Цель:** все пользователи и контент перенесены в новую LMS. Раздел `/admin/import-export`. ### Импорт учеников (CSV) - [ ] Скачать файл-шаблон CSV (Email, Имя, Фамилия, Телефон) - [ ] Загрузка CSV, поддержка кодировок Windows-1251 и UTF-8 - [ ] Опция: подтверждать email автоматически (да/нет) - [ ] Опция: обновлять уже существующие аккаунты (да/нет) - [ ] Присвоение доступов к курсам при импорте (выбор курса + срок в днях, 0 = бессрочно) - [ ] Опция: отправить письмо-уведомление ученику (со ссылкой для установки пароля) - [ ] Предпросмотр перед применением (таблица: кто создаётся, кто обновляется, кому даётся доступ) - [ ] Применить импорт — создать пользователей, выдать доступы, отправить письма ### Экспорт учеников (CSV) - [ ] Все ученики или фильтр по конкретному курсу/доступу - [ ] Фильтр по просмотрам уроков (экспортировать только тех кто смотрел) - [ ] Выбор кодировки: Windows-1251 (для Excel) / UTF-8 - [ ] Поля: Email, Имя, Фамилия, Телефон, Дата регистрации, Курсы, Прогресс ### Миграция контента - [ ] Чек-лист ручного переноса контента (уроки, PDF, структура курсов) - [ ] Скрипт проверки целостности: все enrolled пользователи имеют доступ к нужным курсам - [ ] QA: проверить 10 случайных аккаунтов после импорта **Критерий готовности:** загружаю CSV из emdesell → предпросмотр показывает корректные данные → применяю → ученики получают письма → могут войти и продолжить обучение. --- ## Этап 12 — Telegram-бот и аналитика **Цель:** уведомления в Telegram для всех участников, базовая аналитика. **Настройки (в разделе Настройки → Telegram):** - Токен бота (вводится в админке, хранится в Settings) - Интеграция вкл/выкл глобально - Показывать кнопку «Подключить Telegram» в кабинете ученика: да/нет **Уведомления куратору/админу:** - [ ] Новое ДЗ на проверку - [ ] Новый вопрос от ученика - [ ] Новая регистрация студента - [ ] Ошибки платформы (500-е, failed email и т.д.) **Уведомления ученику:** - [ ] Получен фидбек по ДЗ - [ ] Ответ куратора на вопрос - [ ] Открыт доступ к новому курсу **Реализация:** - [ ] Ученик привязывает Telegram через `/start` в боте (сохраняется `telegramChatId` в User) - [ ] Кнопка «Подключить Telegram» в личном кабинете ученика - [ ] Админ/куратор вводит свой `chatId` в профиле или через `/start` - [ ] Настройки бота в разделе Настройки → Telegram - [ ] Yandex.Metrika: базовое подключение (pageviews) - [ ] Admin: простая страница аналитики (активные ученики, прогресс по курсам) --- ## Этап 13 — Тесты и квизы **Цель:** можно добавить тест к уроку, ученик проходит и получает результат. - [ ] Prisma: Quiz, QuizQuestion, QuizOption, QuizAttempt (схема уже есть) - [ ] Admin: создание теста к уроку (вопрос → варианты → отметить правильный) - [ ] Типы вопросов: одиночный выбор, множественный выбор, короткий текст - [ ] Рендер теста в уроке для ученика - [ ] Авто-проверка (single/multiple choice), результат сразу - [ ] Настройка: показывать правильные ответы после прохождения (да/нет) - [ ] Интеграция с прогрессом: урок с тестом засчитан только после прохождения теста **Критерий готовности:** добавляю тест из 3 вопросов к уроку, ученик проходит, видит результат, урок засчитывается. --- ## Бэклог (после MVP) - Резервное копирование PostgreSQL (cron → Object Storage) - GitHub Actions: CI/CD pipeline (lint → build → push Docker image → deploy) - Сертификаты по окончании курса - Геймификация (баллы, бейджи, рейтинги) - Промокоды и интеграция с платёжными системами - Дедлайны и расписания - Kinescope DRM (signed URLs) — при переходе на платный план - Водяные знаки на PDF и картинках - Мобильное приложение - **Вопросы учеников** — система тикетов `/admin/questions` и `/questions` для ученика: - Таблица в админке: №, Имя, Курс, Тема, Статус (Ожидает / Отвечено), Дата - Статусы отсортированы: сначала «Ожидает ответа» - Куратор/Admin может создать обращение первым (написать ученику) - Внутри тикета: история переписки, смена статуса - **База знаний** — FAQ, который ученик видит до отправки вопроса - **Шаблоны ответов** — куратор выбирает готовый ответ из списка - Email + Telegram уведомления обеим сторонам - **Главная страница ученика** — кастомизируемый экран после входа: - Приветственный баннер с описанием школы (редактируется в настройках) - Список курсов ученика с прогрессом - Блок бесплатных/открытых материалов (статьи, PDF, видео) - Анонсы ближайших событий и новых курсов - **Медиатека (Файлы)** — централизованное файловое хранилище `/admin/files`: - Prisma: `MediaFolder` (id, name, courseId?, createdAt) + `MediaFile` (id, folderId?, name, url, size, mimeType, uploadedById, createdAt) - Папки автоматически создаются по курсам + «Common» для общих файлов - Вид: грид (карточки с иконкой типа) или список — переключатель - Breadcrumb-навигация: Все файлы / Название папки - Загрузка файлов (PDF, изображения, любые) → Object Storage - Создание папки вручную - Клик на файл → диалог: имя (редактируемое), дата загрузки, размер, автор - Действия в диалоге: скопировать ссылку, скачать, удалить - Вставка файлов из медиатеки в урок (вместо повторной загрузки) - **Цифровой сад** — публичный раздел платформы для сообщества: - Методические материалы и статьи (PKM, Obsidian, Second Brain) - Рекомендованная литература с аннотациями - Записи открытых встреч и вебинаров - Календарь: предстоящие открытые уроки, запуски курсов, события - Возможно: публичный Obsidian-like граф знаний