Files
lms-sb/ROADMAP.md
T
admins 93e74951a7 Add balance transactions to user admin panel
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>
2026-05-07 09:24:25 +05:00

26 KiB
Raw Blame History

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
    • Создание папки вручную
    • Клик на файл → диалог: имя (редактируемое), дата загрузки, размер, автор
    • Действия в диалоге: скопировать ссылку, скачать, удалить
    • Вставка файлов из медиатеки в урок (вместо повторной загрузки)
  • Цифровой сад — публичный раздел платформы для сообщества:

    • Методические материалы и статьи (PKM, Obsidian, Second Brain)
    • Рекомендованная литература с аннотациями
    • Записи открытых встреч и вебинаров
    • Календарь: предстоящие открытые уроки, запуски курсов, события
    • Возможно: публичный Obsidian-like граф знаний