2f52d869d9
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
214 lines
10 KiB
Markdown
214 lines
10 KiB
Markdown
# CLAUDE.md — LMS Second Brain
|
|
|
|
> Читай AGENTS.md перед тем как писать любой Next.js код — версия отличается от обучающих данных.
|
|
|
|
## Стек и версии
|
|
|
|
| Технология | Версия | Назначение |
|
|
|---|---|---|
|
|
| Next.js | 16.2.2 (App Router) | Full-stack фреймворк |
|
|
| Node.js | 20 LTS | Runtime |
|
|
| TypeScript | 5.x | Язык |
|
|
| React | 19 | UI |
|
|
| PostgreSQL | 16 | База данных |
|
|
| Prisma | 6.x | ORM + миграции |
|
|
| Better Auth | latest | Аутентификация и сессии |
|
|
| Tailwind CSS | 4.x (CSS-based config) | Стили (нет tailwind.config.ts) |
|
|
| shadcn/ui | latest | UI-компоненты |
|
|
| TipTap | 2.x | WYSIWYG-редактор уроков |
|
|
| @kinescope/react-kinescope-player | latest | Видеоплеер |
|
|
| Resend | latest | Email-уведомления |
|
|
| AWS SDK (S3) | 3.x | Hetzner Object Storage |
|
|
| Zod | 3.x | Валидация данных |
|
|
| Docker Compose | 2.x | Локальная разработка и деплой |
|
|
|
|
**Важно по Tailwind v4:** конфиг — только в CSS через `@import "tailwindcss"` и `@theme`. Нет `tailwind.config.ts`. Кастомизация — через CSS переменные в `globals.css`.
|
|
|
|
**Важно по Better Auth:** не NextAuth. Сессии — cookie-based. Роли через плагин `admin`. Подробнее: https://www.better-auth.com/docs
|
|
|
|
---
|
|
|
|
## Структура каталогов
|
|
|
|
```
|
|
lms-system/
|
|
├── src/
|
|
│ ├── app/ # Next.js App Router
|
|
│ │ ├── (auth)/ # Вход, регистрация, подтверждение email
|
|
│ │ │ ├── login/
|
|
│ │ │ ├── register/
|
|
│ │ │ └── verify-email/
|
|
│ │ ├── (student)/ # Личный кабинет ученика
|
|
│ │ │ ├── dashboard/
|
|
│ │ │ ├── courses/[slug]/
|
|
│ │ │ └── courses/[slug]/lessons/[lessonId]/
|
|
│ │ ├── curator/ # Панель куратора
|
|
│ │ │ ├── dashboard/
|
|
│ │ │ └── homework/
|
|
│ │ ├── admin/ # Панель администратора
|
|
│ │ │ ├── courses/
|
|
│ │ │ ├── users/
|
|
│ │ │ └── settings/
|
|
│ │ └── api/ # API-маршруты
|
|
│ │ ├── auth/ # Better Auth handler
|
|
│ │ ├── courses/
|
|
│ │ ├── lessons/
|
|
│ │ ├── progress/
|
|
│ │ ├── homework/
|
|
│ │ └── upload/
|
|
│ ├── components/
|
|
│ │ ├── ui/ # shadcn/ui (не редактировать вручную)
|
|
│ │ ├── editor/ # TipTap WYSIWYG
|
|
│ │ ├── player/ # Kinescope Player wrapper
|
|
│ │ ├── course/ # Компоненты курса
|
|
│ │ └── layout/ # Header, Sidebar, Footer
|
|
│ ├── lib/
|
|
│ │ ├── auth.ts # Better Auth config (сервер)
|
|
│ │ ├── auth-client.ts # Better Auth client (браузер)
|
|
│ │ ├── prisma.ts # Prisma singleton client
|
|
│ │ ├── s3.ts # Hetzner Object Storage клиент
|
|
│ │ ├── email.ts # Resend email helpers
|
|
│ │ └── utils.ts # cn() и прочие утилиты
|
|
│ ├── types/
|
|
│ │ └── index.ts # Общие TypeScript-типы
|
|
│ └── middleware.ts # Auth middleware (защита маршрутов)
|
|
├── prisma/
|
|
│ ├── schema.prisma # Схема БД
|
|
│ ├── seed.ts # Seed-скрипт
|
|
│ └── migrations/ # НИКОГДА не редактировать вручную
|
|
├── public/
|
|
│ └── images/
|
|
├── docker-compose.yml # Локальная разработка
|
|
├── docker-compose.prod.yml # Production
|
|
├── Dockerfile
|
|
├── .env.example # Шаблон переменных (без секретов)
|
|
├── .env.local # Локальные секреты (в .gitignore)
|
|
├── CLAUDE.md
|
|
├── ROADMAP.md
|
|
└── PROJECT_BRIEF.md
|
|
```
|
|
|
|
---
|
|
|
|
## Команды
|
|
|
|
```bash
|
|
# Разработка
|
|
npm run dev # Запустить dev-сервер (localhost:3000)
|
|
docker compose up -d # Поднять PostgreSQL локально
|
|
|
|
# Сборка и проверка
|
|
npm run build # Production build
|
|
npm run lint # ESLint
|
|
npm run type-check # TypeScript без сборки (tsc --noEmit)
|
|
|
|
# База данных (Prisma)
|
|
npx prisma migrate dev --name <название> # Создать и применить миграцию
|
|
npx prisma migrate deploy # Применить миграции в production
|
|
npx prisma studio # GUI для просмотра БД
|
|
npx prisma generate # Пересоздать клиент после изменений schema
|
|
npx prisma db seed # Запустить seed-скрипт
|
|
|
|
# Docker (production)
|
|
docker compose -f docker-compose.prod.yml up -d --build
|
|
docker compose -f docker-compose.prod.yml logs -f app
|
|
```
|
|
|
|
---
|
|
|
|
## Правила работы
|
|
|
|
### Деплой и окружение
|
|
- Production-домен: **school.second-brain.ru**
|
|
- Git-сервер: **Gitea — https://git.second-brain.ru/admins/lms-sb** (токен: в `.env.local` не хранить, спросить у пользователя)
|
|
- **После завершения каждого этапа из ROADMAP.md** — делать `git push` в Gitea
|
|
|
|
### Коммиты
|
|
- Один коммит = одна логически завершённая единица работы (маршрут, компонент, миграция)
|
|
- Сообщения коммитов — на английском, в повелительном наклонении: `Add lesson progress tracking`, `Fix auth redirect`
|
|
- Перед коммитом всегда запускать `npm run lint && npm run type-check`
|
|
|
|
### Миграции базы данных
|
|
- **НИКОГДА** не редактировать файлы в `prisma/migrations/` вручную
|
|
- **ВСЕГДА** спрашивать пользователя перед созданием миграции, меняющей или удаляющей существующие поля
|
|
- Называть миграции по-английски, snake_case: `add_lesson_progress`, `add_user_roles`
|
|
- Перед `prisma migrate deploy` на production — делать бэкап БД
|
|
|
|
### Файлы и контент
|
|
- Загружаемые файлы (ДЗ, PDF) — только через Hetzner Object Storage, никогда на диск VPS
|
|
- Секреты (API-ключи, токены, строки подключения) — **только в `.env.local`**, в коде запрещено
|
|
- `.env.example` всегда обновлять при добавлении новых переменных (без реальных значений)
|
|
|
|
### Код
|
|
- UI-строки (заголовки, кнопки, сообщения) — на **русском**
|
|
- Имена переменных, функций, файлов, комментарии в коде — на **английском**
|
|
- Компоненты shadcn/ui — добавлять через `npx shadcn@latest add <component>`, не копировать вручную
|
|
- Не добавлять абстракции "на будущее" — только то, что нужно для текущего этапа
|
|
- Server Actions — использовать для форм и мутаций (auth, прогресс, ДЗ)
|
|
|
|
### Маршруты и роли
|
|
- Защита маршрутов — через `middleware.ts` (Better Auth), не в каждом компоненте отдельно
|
|
- Роли: `student`, `curator`, `admin` — проверять через `auth()` или `authClient.useSession()`
|
|
- Admin-маршруты (`/admin/*`) доступны только роли `admin`
|
|
- Curator-маршруты (`/curator/*`) доступны ролям `curator` и `admin`
|
|
|
|
---
|
|
|
|
## Переменные окружения (`.env.example`)
|
|
|
|
```env
|
|
# База данных
|
|
DATABASE_URL="postgresql://lms_user:password@localhost:5432/lms_db"
|
|
|
|
# Better Auth
|
|
BETTER_AUTH_SECRET="generate-with-openssl-rand-base64-32"
|
|
BETTER_AUTH_URL="http://localhost:3000"
|
|
|
|
# Email (Resend)
|
|
RESEND_API_KEY=""
|
|
EMAIL_FROM="noreply@school.second-brain.ru"
|
|
|
|
# Hetzner Object Storage (S3-совместимый)
|
|
S3_ENDPOINT="https://fsn1.your-objectstorage.com"
|
|
S3_BUCKET="lms-uploads"
|
|
S3_ACCESS_KEY=""
|
|
S3_SECRET_KEY=""
|
|
S3_REGION="eu-central"
|
|
|
|
# Kinescope (добавить при получении платного плана)
|
|
# KINESCOPE_API_KEY=""
|
|
```
|
|
|
|
---
|
|
|
|
## Чек-лист перед каждым коммитом
|
|
|
|
- [ ] `npm run lint` — нет ошибок ESLint
|
|
- [ ] `npm run type-check` — нет ошибок TypeScript
|
|
- [ ] Новые `.env` переменные добавлены в `.env.example` (без значений)
|
|
- [ ] Миграция БД одобрена пользователем (если есть)
|
|
- [ ] Нет `console.log` в production-коде (только `console.error` для реальных ошибок)
|
|
- [ ] Нет захардкоженных секретов, URL-ов, ID
|
|
|
|
---
|
|
|
|
## Модель данных (основные сущности)
|
|
|
|
```
|
|
User (id, email, name, role, emailVerified) — управляется Better Auth
|
|
Session (id, userId, expiresAt, ...) — управляется Better Auth
|
|
Course (id, slug, title, description, coverImage, published)
|
|
Module (id, courseId, title, order)
|
|
Lesson (id, moduleId, title, order, content, kinescopeId, published)
|
|
CourseEnrollment (userId, courseId, enrolledAt)
|
|
LessonProgress (userId, lessonId, completedAt)
|
|
Quiz (id, lessonId)
|
|
QuizQuestion (id, quizId, text, type)
|
|
QuizOption (id, questionId, text, isCorrect)
|
|
QuizAttempt (id, userId, quizId, score, completedAt)
|
|
Homework (id, lessonId, description)
|
|
HomeworkSubmission (id, homeworkId, userId, text, files[], submittedAt)
|
|
HomeworkFeedback (id, submissionId, curatorId, text, createdAt)
|
|
LessonComment (id, lessonId, userId, text, createdAt)
|
|
```
|