Introduces BalanceTransaction model to track per-user balance history (prepayments, refunds, partner credits). Admin can add/delete transactions; current balance is computed as the running sum. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
26 KiB
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)
- Next.js 16.2.2 (App Router, TypeScript, Tailwind v4)
- Docker Compose: PostgreSQL 16 (прод на Hetzner)
- Prisma 7: схема User, Session, Account + полная LMS-модель
- Better Auth: вход по email/password, роли student/curator/admin
- Middleware: защита маршрутов по сессии
- Дашборды для трёх ролей
- Страница входа, регистрации, подтверждения email
- Seed: admin/curator/student (пароль: Password123!)
- Dockerfile multi-stage + docker-compose.prod.yml
- Caddy: school.second-brain.ru → порт 3010
Этап 1 — Курсы → Модули → Уроки (CRUD в админке) ✅ ЗАВЕРШЁН (07.04.2026)
- Prisma-схема: Course, Module, Lesson (с порядком, статусом published)
- Admin: список курсов, создать / редактировать / удалить курс
- Admin: список модулей внутри курса, drag-and-drop сортировка
- Admin: список уроков внутри модуля, drag-and-drop сортировка
- Admin: редактор урока с TipTap (заголовки, списки, цитаты, код, картинки, ссылки)
- Загрузка картинок в уроке → Hetzner Object Storage
- Поле для Kinescope ID в уроке
- Публикация/скрытие курса и урока (черновик / опубликован)
- Управление доступом: выдать / забрать доступ к курсу для пользователя
- Дизайн: Fira Mono, #F5F5F0, Aubade-карточки
- Admin: таблица пользователей (/admin/users)
Доработки таблицы пользователей (добавить в рамках Этапа 9):
- Фильтры: по роли (Ученик / Куратор / Администратор), по статусу email (подтверждён/нет)
- Поиск по имени / email
- Пагинация + выбор кол-ва записей на странице (20/50/100)
- Ховер-попап на строке: список курсов пользователя со сроками доступа + email + телефон
- Быстрые действия в строке: кнопка «Выдать доступ» без перехода на страницу пользователя
Этап 1.5 — Расширенное управление доступом ✅ ЗАВЕРШЁН (07.04.2026)
- Срок доступа:
expiresAtвCourseEnrollment, просроченный подсвечивается красным - Категории курсов: таблица
Category,/admin/categories, привязка к курсу - Расширенный энролл:
/admin/users/[userId]— выбор нескольких курсов + срок одной операцией - История доступа:
AccessLog— каждая операция логируется (кто, когда, метод, примечание)
Этап 2 — Интеграция Kinescope, рендер уроков для ученика ✅ ЗАВЕРШЁН (07.04.2026)
- Компонент
KinescopePlayer— обёртка над@kinescope/react-kinescope-player - Рендер урока для ученика: видео (если есть Kinescope ID) + текст + файлы
- Загрузка PDF/файлов к уроку (Object Storage), список для скачивания
- Страница курса для ученика: список модулей и уроков, статус прохождения
- Навигация по урокам: предыдущий / следующий
- Блокировка доступа к курсу без enrollment (layout server component)
- Страница «Мои курсы» в личном кабинете ученика (dashboard)
- Кнопки Сохранить / Просмотр в редакторе урока
- Иконка-статус уроков в боковой панели курса (✓ пройден)
Этап 3 — Прогресс ✅ ЗАВЕРШЁН (07.04.2026)
- Prisma: таблица
LessonProgress(userId, lessonId, completedAt) - Кнопка «Урок завершён» — создаёт/удаляет запись в LessonProgress
- Прогресс-бар по курсу в боковой панели (% завершённых уроков)
- Прогресс-бар по курсу на дашборде студента
- Admin bypass: администратор видит все уроки без отметок о прогрессе
Этап 5 — Домашние задания и обратная связь куратора ✅ ЗАВЕРШЁН (07.04.2026)
- Prisma: Homework, HomeworkSubmission, HomeworkFeedback
- Admin: добавить / редактировать / удалить блок ДЗ к уроку (HomeworkEditor)
- Ученик: форма отправки ДЗ (текст + файлы → Object Storage)
- Ученик: видит статус ДЗ и фидбек куратора в карточке урока
- Куратор / Admin: список ДЗ на проверку (
/curator/homework) - Куратор / Admin: просмотр работы, текстовый комментарий с обратной связью
- Admin: AdminShell на
/curator/*маршрутах (сайдбар не пропадает) - Admin: реальная статистика на дашборде (студенты, курсы, ДЗ, прогресс)
Доработки (добавить в рамках Этапа 9):
- Фильтры в списке ДЗ: по имени/email ученика, по уроку, по курсу, по статусу
- Поиск по имени/email ученика
- Пагинация + выбор кол-ва записей на странице (20/50/100)
- Расширенные статусы: «Новое» / «Просмотрено» / «Прокомментировано»
- Шаблоны ответов куратора — готовые тексты фидбека, выбираемые из списка
Этап 6 — Обсуждения под уроками ✅ ЗАВЕРШЁН (07.04.2026)
- Prisma: LessonComment (soft-delete через поле
deleted) - Рендер списка комментариев под уроком (server-fetched, client-rendered)
- Форма отправки комментария (только для enrolled учеников и admin)
- Модерация: автор, куратор или admin может удалить комментарий
- Счётчик активных комментариев в заголовке секции
Не реализовано (добавить в Этап 9 или отдельно):
/admin/comments— сводная таблица всех комментариев по всем урокам- Колонки: №, Имя ученика, Урок (ссылка), Время, кол-во ответов, превью текста
- Удалить комментарий прямо из списка
- Пагинация
- Ссылка в сайдбаре AdminNav
Этап 7 — Email-уведомления ✅ ЗАВЕРШЁН (07.04.2026)
- Базовый HTML email-шаблон (фирменный стиль Second Brain)
- Приветственное письмо при регистрации (
databaseHooks.user.create.after) - Письмо ученику об открытии доступа к курсу
- Куратор / Admin: уведомление о новом ДЗ на проверку
- Ученик: уведомление о полученном фидбеке
- Resend domain: mailsend.second-brain.ru (verified)
Этап 8 — Импорт уроков из Markdown (Obsidian) ✅ ЗАВЕРШЁН (07.04.2026)
- API:
POST /api/admin/import-md— принимает .md-файл - Парсинг frontmatter (title, kinescopeId, order, published) через
gray-matter - Конвертация Markdown → TipTap JSON через
unified+remark-parse - Поддержка: заголовки, параграфы, жирный/курсив/зачёркнутый, инлайн-код, блоки кода, цитаты, списки, ссылки, изображения (HTTP), горизонтальные разделители
- Очистка Obsidian-синтаксиса:
![[image]]удаляется,[[link|alias]]→ текст - UI: кнопка «Импорт .md» в редакторе урока — заполняет форму без автосохранения
Этап 9 — Настройки платформы (Admin Settings) ✅ ЗАВЕРШЁН (08.04.2026)
Цель: администратор управляет ключевыми параметрами платформы без правки кода.
Основное
- Название школы (используется в заголовке сайта, подписи писем)
- Описание школы (мета-тег description)
- Ключевые слова (мета-тег keywords)
- Режим тех. работ: вкл/выкл (показывает заглушку всем кроме admin)
- Регистрация учеников: вкл/выкл
Оформление
- Логотип школы (загрузка → Object Storage, отображается в шапке)
- Фавикон (загрузка → Object Storage)
- Показывать логотип: да/нет
Уведомления
- Email(ы) для системных уведомлений (кому слать письма о ДЗ, вопросах, регистрациях)
- Уведомление куратору/админу о новом ДЗ: вкл/выкл
- Уведомление куратору/админу о новом вопросе ученика: вкл/выкл
- Уведомление админу о новой регистрации: вкл/выкл
- Уведомление ученику при ответе на ДЗ/вопрос: вкл/выкл
Данные ученика
- Требовать подтверждение email перед доступом к курсам: да/нет
- Фамилия при регистрации: обязательная / необязательная / выключена
- Телефон при регистрации: обязательный / необязательный / выключен
Защита
- Одна активная сессия на аккаунт: вкл/выкл
- CAPTCHA на форме регистрации: вкл/выкл (reCAPTCHA v3)
Права куратора
- Куратор видит ДЗ: по всем курсам / только по назначенным курсам
- Куратор может отвечать на вопросы учеников: да/нет
- Куратор видит список всех студентов: да/нет
Вставка кода
- Произвольный код в
<head>(Yandex.Metrika, Google Analytics, пиксели) - Произвольный код в
<body>(виджеты, чаты поддержки)
Юридические документы
- 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)
-
Миграция email-шаблонов на React Email 6 + Resend CLI 2.0 (Resend Launch Week 6, 24.04.2026):
- React Email 6: новые шаблоны для auth и ecommerce flows (welcome, password reset, purchase confirmation, course progress) — можно взять за основу вместо своих
- Resend CLI 2.0: локальный preview и тестирование шаблонов (
resend send --local ...), 50+ команд - Embeddable open-source editor (в одну строку) — отложить, пока не требуется
- Сейчас Этап 7 (Email-уведомления) завершён на базовой связке, задача — рефакторинг на React Email
-
Самостоятельная регистрация + автоматический онбординг — два сценария входа и воронка после регистрации:
Сценарии регистрации:
- С лендинга через покупку — пользователь оплачивает курс, аккаунт создаётся автоматически, письмо с доступом приходит сразу
- Прямой вход на платформу — пользователь приходит по реферальной ссылке, из соцсетей, от партнёров — регистрируется сам без покупки
Автоматический онбординг после регистрации:
- Автоназначение вводных / вотер-модулей курсов (бесплатные превью, чтобы зацепить)
- Доступ к базовой библиотеке материалов по умолчанию (статьи, шаблоны, гайды — определяется в настройках)
- Приветственная воронка: серия писем / уведомлений, которая ведёт к первой покупке
- Уведомление администратора о новой регистрации (email + Telegram)
Что нужно проработать:
- Публичная страница регистрации (+ CAPTCHA, опционально)
- Настройка в Этапе 9: «Регистрация открыта: да/нет» + выбор вводных курсов/модулей, которые назначаются автоматически
- Интеграция с платёжной системой: оплата на лендинге → автосоздание аккаунта → автовыдача доступа к купленному курсу
- Разграничение: что видит гость / зарегистрированный без покупки / купивший курс
-
Резервное копирование 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
- Создание папки вручную
- Клик на файл → диалог: имя (редактируемое), дата загрузки, размер, автор
- Действия в диалоге: скопировать ссылку, скачать, удалить
- Вставка файлов из медиатеки в урок (вместо повторной загрузки)
- Prisma:
-
Цифровой сад — публичный раздел платформы для сообщества:
- Методические материалы и статьи (PKM, Obsidian, Second Brain)
- Рекомендованная литература с аннотациями
- Записи открытых встреч и вебинаров
- Календарь: предстоящие открытые уроки, запуски курсов, события
- Возможно: публичный Obsidian-like граф знаний