c647b29712
- md-to-tiptap.ts: remark-based converter (headings, lists, blockquotes, code blocks, bold/italic/strike, links, images, hr) - Obsidian ![[wikilink]] stripped, [[link|alias]] → plain text - POST /api/admin/import-md: parses frontmatter (gray-matter) + converts content - LessonEditor: "Импорт .md" button populates editor without auto-save - ROADMAP: marked Stages 2, 3, 5, 6, 7, 8 as complete, fixed numbering Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
167 lines
11 KiB
Markdown
167 lines
11 KiB
Markdown
# 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)
|
||
|
||
---
|
||
|
||
## Этап 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: реальная статистика на дашборде (студенты, курсы, ДЗ, прогресс)
|
||
|
||
---
|
||
|
||
## Этап 6 — Обсуждения под уроками ✅ ЗАВЕРШЁН (07.04.2026)
|
||
|
||
- [x] Prisma: LessonComment (soft-delete через поле `deleted`)
|
||
- [x] Рендер списка комментариев под уроком (server-fetched, client-rendered)
|
||
- [x] Форма отправки комментария (только для enrolled учеников и admin)
|
||
- [x] Модерация: автор, куратор или admin может удалить комментарий
|
||
- [x] Счётчик активных комментариев в заголовке секции
|
||
|
||
---
|
||
|
||
## Этап 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 — Миграция с 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 — Тесты и квизы
|
||
**Цель:** можно добавить тест к уроку, ученик проходит и получает результат.
|
||
|
||
- [ ] 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 и картинках
|
||
- Мобильное приложение
|