Add platform settings (Stage 9)

- Settings key-value table in Prisma with migration
- getSettings() / getSetting() helpers in lib/settings.ts
- Admin UI at /admin/settings with 6 sections: General, Notifications,
  Student profile, Legal docs, Curator permissions, Code injection
- saveSettings() server action with admin-only guard
- Maintenance mode: non-admin users redirected to /maintenance page
- schoolName propagated to page metadata and all email templates
- headCode / bodyCode injected into root layout <head> and <body>

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-08 11:18:37 +05:00
parent 093e403f5f
commit e77588deb8
14 changed files with 834 additions and 29 deletions
+163 -11
View File
@@ -36,6 +36,15 @@
---
**Доработки таблицы пользователей (добавить в рамках Этапа 9):**
- [ ] Фильтры: по роли (Ученик / Куратор / Администратор), по статусу email (подтверждён/нет)
- [ ] Поиск по имени / email
- [ ] Пагинация + выбор кол-ва записей на странице (20/50/100)
- [ ] Ховер-попап на строке: список курсов пользователя со сроками доступа + email + телефон
- [ ] Быстрые действия в строке: кнопка «Выдать доступ» без перехода на страницу пользователя
---
## Этап 1.5 — Расширенное управление доступом ✅ ЗАВЕРШЁН (07.04.2026)
- [x] Срок доступа: `expiresAt` в `CourseEnrollment`, просроченный подсвечивается красным
@@ -80,6 +89,13 @@
- [x] Admin: AdminShell на `/curator/*` маршрутах (сайдбар не пропадает)
- [x] Admin: реальная статистика на дашборде (студенты, курсы, ДЗ, прогресс)
**Доработки (добавить в рамках Этапа 9):**
- [ ] Фильтры в списке ДЗ: по имени/email ученика, по уроку, по курсу, по статусу
- [ ] Поиск по имени/email ученика
- [ ] Пагинация + выбор кол-ва записей на странице (20/50/100)
- [ ] Расширенные статусы: «Новое» / «Просмотрено» / «Прокомментировано»
- [ ] Шаблоны ответов куратора — готовые тексты фидбека, выбираемые из списка
---
## Этап 6 — Обсуждения под уроками ✅ ЗАВЕРШЁН (07.04.2026)
@@ -90,6 +106,13 @@
- [x] Модерация: автор, куратор или admin может удалить комментарий
- [x] Счётчик активных комментариев в заголовке секции
**Не реализовано (добавить в Этап 9 или отдельно):**
- [ ] `/admin/comments` — сводная таблица всех комментариев по всем урокам
- Колонки: №, Имя ученика, Урок (ссылка), Время, кол-во ответов, превью текста
- Удалить комментарий прямо из списка
- Пагинация
- Ссылка в сайдбаре AdminNav
---
## Этап 7 — Email-уведомления ✅ ЗАВЕРШЁН (07.04.2026)
@@ -114,31 +137,128 @@
---
## Этап 9 — Миграция с emdesell ← СЛЕДУЮЩИЙ
**Цель:** все пользователи и контент перенесены в новую LMS.
## Этап 9 — Настройки платформы (Admin Settings) ✅ ЗАВЕРШЁН (08.04.2026)
**Цель:** администратор управляет ключевыми параметрами платформы без правки кода.
- [ ] Скрипт импорта пользователей из CSV-экспорта emdesell (email, имя, курсы)
- [ ] Создание пользователей без пароля + письмо «установите пароль»
- [ ] Назначение доступов к курсам по данным из CSV
### Основное
- [ ] Название школы (используется в заголовке сайта, подписи писем)
- [ ] Описание школы (мета-тег 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 случайных аккаунтов после импорта
**Критерий готовности:** все ученики из emdesell могут войти в новую LMS и продолжить обучение.
**Критерий готовности:** загружаю CSV из emdesell → предпросмотр показывает корректные данные → применяю → ученики получают письма → могут войти и продолжить обучение.
---
## Этап 10 — Telegram-бот и аналитика
**Цель:** получаю уведомления в Telegram, вижу базовую аналитику.
## Этап 12 — Telegram-бот и аналитика
**Цель:** уведомления в Telegram для всех участников, базовая аналитика.
- [ ] Telegram-бот: уведомление куратору/админу о новом ДЗ
- [ ] Telegram-бот: уведомление об ошибках (500-е, failed email и т.д.)
**Настройки (в разделе Настройки → Telegram):**
- Токен бота (вводится в админке, хранится в Settings)
- Интеграция вкл/выкл глобально
- Показывать кнопку «Подключить Telegram» в кабинете ученика: да/нет
**Уведомления куратору/админу:**
- [ ] Новое ДЗ на проверку
- [ ] Новый вопрос от ученика
- [ ] Новая регистрация студента
- [ ] Ошибки платформы (500-е, failed email и т.д.)
**Уведомления ученику:**
- [ ] Получен фидбек по ДЗ
- [ ] Ответ куратора на вопрос
- [ ] Открыт доступ к новому курсу
**Реализация:**
- [ ] Ученик привязывает Telegram через `/start` в боте (сохраняется `telegramChatId` в User)
- [ ] Кнопка «Подключить Telegram» в личном кабинете ученика
- [ ] Админ/куратор вводит свой `chatId` в профиле или через `/start`
- [ ] Настройки бота в разделе Настройки → Telegram
- [ ] Yandex.Metrika: базовое подключение (pageviews)
- [ ] Admin: простая страница аналитики (активные ученики, прогресс по курсам)
---
## Этап 11 — Тесты и квизы
## Этап 13 — Тесты и квизы
**Цель:** можно добавить тест к уроку, ученик проходит и получает результат.
- [ ] Prisma: Quiz, QuizQuestion, QuizOption, QuizAttempt (схема уже есть)
@@ -164,3 +284,35 @@
- 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 граф знаний