Files
course-craft-service/IMPLEMENTATION.md
2026-02-06 14:53:52 +00:00

166 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Реализация проекта CourseCraft
Документ описывает техническую реализацию платформы CourseCraft — создания образовательных курсов с помощью ИИ.
---
## 1. Обзор
**CourseCraft** — монорепозиторий с тремя приложениями:
| Приложение | Назначение |
|-------------|------------|
| **web** | Фронтенд на Next.js 14 (App Router): лендинг, авторизация, дашборд, каталог, прохождение курсов, сертификаты. |
| **api** | Backend на NestJS: REST API, авторизация (Supabase + JWT), курсы, генерация, записи, прогресс, сертификаты, поиск. |
| **ai-service** | Воркер на BullMQ: очередь задач генерации курсов, вызовы OpenRouter (структура курса, контент уроков). |
Дополнительно: **PostgreSQL** (Prisma), **Redis**, **Meilisearch**. Запуск через Docker Compose из корня проекта.
---
## 2. Стек и технологии
- **Frontend:** Next.js 14, TypeScript, Tailwind CSS, shadcn/ui, TipTap (редактор/просмотр контента), Supabase Client (auth).
- **Backend:** NestJS, Prisma, JWT (обмен Supabase access token на бэкенд-токен), BullMQ, Stripe (платежи).
- **AI:** OpenRouter API (GPT-4, Claude и др.), структурированный вывод (JSON), промпты для уточняющих вопросов, outline и контент уроков.
- **Инфраструктура:** Docker Compose, pgvector, Meilisearch (поиск курсов).
---
## 3. База данных (Prisma)
Схема в `packages/database/prisma/schema.prisma`.
### Основные сущности
- **User** — пользователь (supabaseId, email, name, subscriptionTier, role). Связь с UserSettings (customAiModel, theme, language).
- **Subscription** — подписка (FREE/PREMIUM/PRO), Stripe, лимиты (coursesCreatedThisMonth).
- **Course** — курс (authorId, title, description, slug, status, tags, difficulty, estimatedHours). Связи: Chapter → Lesson.
- **Chapter** — глава (courseId, title, description, order).
- **Lesson** — урок (chapterId, title, content в TipTap JSON, order, durationMinutes). Опционально: Quiz (questions JSON).
- **CourseGeneration** — процесс генерации (userId, initialPrompt, aiModel, status, progress, questions, answers, generatedOutline, courseId, jobId).
- **Enrollment** — запись на курс (userId, courseId, progress, completedAt, certificateUrl).
- **LessonProgress** — прогресс по уроку (userId, enrollmentId, lessonId, completedAt, quizScore).
- **Review** — отзыв по курсу (userId, courseId, rating, content).
- **Certificates** — не отдельная таблица: данные для сертификата берутся из Enrollment + User + Course; certificateUrl сохраняется в Enrollment.
Дополнительно: Category, Purchase, CourseGroup, GroupMember, GroupMessage, Homework, HomeworkSubmission, SupportTicket, TicketMessage.
---
## 4. Backend (API, NestJS)
### Авторизация
- **Supabase Auth** — вход/регистрация на фронте.
- **Обмен токена:** `POST /api/auth/exchange` принимает Supabase access token, создаёт/обновляет пользователя в БД, возвращает JWT бэкенда.
- Защищённые маршруты используют **JWT Guard**; текущий пользователь — `@CurrentUser() user: User`.
### Основные модули и маршруты
| Модуль | Назначение |
|---------------|------------|
| **auth** | exchange token, привязка к Supabase. |
| **users** | профиль, настройки (в т.ч. customAiModel). |
| **courses** | CRUD курсов, глав (chapters), уроков (lessons); отдача курса с главами и уроками. |
| **generation**| Старт генерации (очередь BullMQ), ответы на уточняющие вопросы, продолжение генерации, статус/прогресс. |
| **catalog** | Публичный каталог курсов (опубликованные), фильтры. |
| **enrollment**| Запись на курс, прогресс (прохождение уроков, квизы), отзывы, рейтинги, список записей пользователя. |
| **certificates** | `GET /certificates/:courseId` — генерация/возврат сертификата (certificateUrl, html); `GET /certificates/:courseId/data` — данные для страницы сертификата (userName, courseTitle, completedAt). |
| **search** | Полнотекстовый поиск (Meilisearch). |
| **payments** | Stripe: подписки, вебхуки. |
### Сертификаты
- Доступ только при завершённом курсе (enrollment.completedAt).
- **getCertificateData(userId, courseId)** — возвращает `{ userName, courseTitle, completedAt }` для отображения на странице.
- **generateCertificate** — формирует HTML сертификата, при необходимости сохраняет certificateUrl в Enrollment, возвращает certificateUrl и html (для обратной совместимости).
---
## 5. AI Service (BullMQ + OpenRouter)
### Очередь
- Очередь **course-generation** (Redis). API добавляет задачи, воркер в ai-service их обрабатывает.
- Типы задач: **generate-course** (старт), **continue-generation** (после ответов на вопросы).
### Пайплайн генерации курса
1. **generate-course:** анализ запроса → генерация уточняющих вопросов (OpenRouter) → сохранение вопросов в CourseGeneration → статус WAITING_FOR_ANSWERS (ожидание ответов).
2. Пользователь отвечает через API → ставится задача **continue-generation** с stage `after-questions`.
3. **continue-generation:** исследование (симуляция) → генерация outline (название, описание, главы, уроки, estimatedTotalHours, difficulty, tags) → создание курса в БД (Course + Chapter + Lesson без контента) → для каждого урока вызов **generateLessonContent** → запись TipTap JSON в Lesson → обновление подписки (coursesCreatedThisMonth) → статус COMPLETED.
### OpenRouter (промпты)
- **generateClarifyingQuestions** — уточняющие вопросы, в т.ч. объём курса (короткий / средний / длинный).
- **generateCourseOutline** — структура курса по ответам (количество глав и уроков, estimatedMinutes, estimatedTotalHours). При не указанном объёме — средний/длинный (57 глав, 46 уроков в главе, не менее 25 уроков).
- **generateLessonContent** — контент урока в формате TipTap JSON (heading, paragraph, bulletList, orderedList, blockquote, codeBlock, mermaid). Промпт требует полный, подробный материал (10001500+ слов), примеры и пояснения, минимум 12 примера/кода на урок.
---
## 6. Frontend (Next.js)
### Маршруты
- **/** — лендинг.
- **/(auth)/login, register, forgot-password** — авторизация Supabase.
- **/(dashboard)/dashboard/** — дашборд (sidebar + header): главная, курсы (список, создание, просмотр/прохождение, редактирование), каталог, карточка курса каталога, мои обучения (learning), поиск, настройки, биллинг.
- **/(certificate)/certificate/[courseId]** — страница сертификата (без сайдбара): загрузка данных через `getCertificateData(courseId)`, отображение ФИО, названия курса, даты; кнопка «Печать», стили для печати (только блок сертификата).
### Авторизация на фронте
- **AuthProvider:** Supabase session → при наличии сессии вызов `/api/auth/exchange` с retry → сохранение JWT в sessionStorage и в памяти; в контексте доступны `user`, `backendUser` (id, email, name, subscriptionTier).
- Все запросы к API через общий клиент с заголовком `Authorization: Bearer <token>`.
### API-клиент (lib/api.ts)
- Базовый URL API через прокси Next.js или INTERNAL_API_URL на сервере.
- Методы: auth (exchange), users, courses, chapters, lessons, generation (start, answerQuestions, continue, status), catalog, enrollment (запись, прогресс, отзывы, мои записи), certificates (getCertificate, getCertificateData), search и др.
### Ключевые сценарии
- **Создание курса:** форма с промптом → старт генерации → опрос уточняющих вопросов → ответы → продолжение генерации → опрос статуса/прогресса до завершения → переход к курсу.
- **Просмотр/прохождение курса:** выбор урока, отображение контента (LessonContentViewer по TipTap JSON), отметка урока выполненным, квиз по уроку (LessonQuiz), обновление прогресса, при 100% — возможность открыть сертификат.
- **Сертификат:** кнопки «Получить сертификат» (страница курса, мои обучения) открывают в новой вкладке `/certificate/[courseId]`; страница запрашивает данные и рендерит сертификат с кнопкой «Печать».
---
## 7. Инфраструктура и запуск
### Docker Compose (из корня)
- **postgres** — порт 5432, pgvector.
- **redis** — порт 6395 (внешний).
- **meilisearch** — порт 7700.
- **api** — порт 3125, зависит от postgres, redis, meilisearch; переменные: DATABASE_URL, REDIS_URL, JWT_SECRET, Supabase, NEXT_PUBLIC_APP_URL и т.д.
- **ai-service** — зависит от postgres, redis; OPENROUTER_API_KEY, DATABASE_URL, REDIS_URL.
- **web** — порт 3080, INTERNAL_API_URL=http://api:3125, Next.js production build.
Запуск:
```bash
docker compose --env-file .env up -d
```
Перезапуск после изменений (например, промпты или API):
```bash
docker compose --env-file .env restart ai-service api web
```
### Переменные окружения (.env)
- **База и очереди:** DATABASE_URL, REDIS_URL.
- **Auth:** NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY, JWT_SECRET.
- **AI:** OPENROUTER_API_KEY (обязателен для ai-service).
- **Приложение:** NEXT_PUBLIC_APP_URL (для ссылок и CORS).
- **Платежи:** STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET (при использовании Stripe).
- **Поиск:** MEILISEARCH_API_KEY (в docker-compose для meilisearch).
---
## 8. Итог
Реализация покрывает: авторизацию через Supabase и JWT, создание курсов по промпту с уточняющими вопросами и генерацией структуры и контента через OpenRouter, каталог и запись на курсы, прохождение с прогрессом и квизами, выдачу сертификата с отдельной страницей для просмотра и печати, тарифы и настраиваемую AI-модель. Документация по быстрому старту и командам — в README.md.