# Текущая ситуация проекта CourseCraft Документ описывает состояние репозитория и способы запуска (на хосте и в Docker). --- ## Состояние проекта ### Монорепозиторий (pnpm workspaces + Turbo) - **apps/api** — NestJS API (авторизация, курсы, генерация, платежи, поиск). Порт по умолчанию: **3125**. - **apps/web** — Next.js 14 (App Router). Порт по умолчанию: **3080**. - **apps/ai-service** — воркер AI-пайплайна (OpenRouter, BullMQ). Без своего HTTP-порта, подключается к Redis. - **packages/database** — Prisma-схема и клиент. Для `prisma db push` нужен свой `.env` в `packages/database/` с `DATABASE_URL`. - **packages/shared** — общие типы и константы. ### Порты | Сервис | Порт | Описание | |---------------|-------|-----------------------------| | API | 3125 | Бэкенд, Swagger на /api/docs | | Web | 3080 | Фронтенд | | Postgres | 5432 | БД | | Redis | 6395 | Очереди (на хосте 6395→6379)| | Meilisearch | 7700 | Поиск | ### Переменные окружения Критичные для работы: - **Supabase:** `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_ANON_KEY`, `SUPABASE_SERVICE_ROLE_KEY` - **JWT:** `JWT_SECRET` (подпись токенов после обмена с Supabase) - **БД:** `DATABASE_URL` (PostgreSQL) - **Redis:** `REDIS_URL`, `REDIS_HOST`, `REDIS_PORT` - **OpenRouter:** `OPENROUTER_API_KEY` - **Meilisearch:** `MEILISEARCH_HOST`, `MEILISEARCH_API_KEY` Корневой `.env` используется при запуске приложений на хосте и при `docker compose` (см. ниже). --- ## Запуск: два варианта ### 1. Всё в Docker (рекомендуется для сервера) Вся инфраструктура и приложения в контейнерах; после отключения от сервера процессы не падают. **Важно:** Compose и `.env` должны быть в **корне** проекта. Используется корневой `docker-compose.yml` (не `docker/docker-compose.yml`). **Шаги:** ```bash cd /usr/local/course-craft-service # или путь к репозиторию ``` Убедиться, что в корне есть `.env` с нужными ключами (Supabase, JWT_SECRET и т.д.). ```bash docker compose --env-file .env up -d --build ``` Или через pnpm (то же самое): ```bash pnpm docker:up ``` После первого запуска таблицы в БД создаются при старте API (entrypoint делает `prisma db push`). Данные БД/Redis/Meilisearch лежат в `docker/data/`. **Проверка:** - Web: `http://<хост>:3080` - API: `http://<хост>:3125/api` - Переменные в контейнере API: `docker exec coursecraft-api env | grep -E "JWT_SECRET|SUPABASE"` значения не должны быть пустыми. **Остановка:** ```bash docker compose down ``` **Логи:** ```bash docker compose logs -f # или по сервису docker logs coursecraft-api -f ``` --- ### 2. Только инфраструктура в Docker, приложения на хосте Удобно для разработки: БД, Redis, Meilisearch в Docker; API, Web и AI-service — через pnpm. **Шаги:** 1. Поднять только инфраструктуру (если используется корневой compose): ```bash cd /usr/local/course-craft-service docker compose --env-file .env up -d postgres redis meilisearch ``` Либо старый вариант только инфраструктуры из `docker/` (без api, web, ai-service). 2. Применить схему БД (один раз или после изменений в Prisma): В корне должен быть `.env` с `DATABASE_URL`. Для Prisma также нужен `packages/database/.env`: ```bash echo 'DATABASE_URL="postgresql://postgres:postgres@localhost:5432/coursecraft?schema=public"' > packages/database/.env pnpm db:push ``` 3. Запуск приложений: ```bash pnpm start ``` Или в режиме разработки: ```bash pnpm dev ``` Доступ: Web — 3080, API — 3125 (или как задано в `.env`: PORT, скрипты next). --- ## Скрипт run.sh (деплой на сервере) `run.sh` в корне репозитория: 1. Останавливает Docker Compose (старый путь `docker/docker-compose.yml`). 2. Делает `git pull`. 3. Выполняет `pnpm install` и `pnpm build`. 4. Поднимает Docker Compose. 5. В фоне запускает `pnpm start` (API, Web, AI-service на хосте). То есть он смешивает: инфраструктура через Docker, приложения — процессы на хосте. Для «всё в Docker» лучше использовать только `docker compose --env-file .env up -d` из корня (или `pnpm docker:up`), без шага с `pnpm start`. --- ## Важные моменты 1. **Корневой `.env`** При запуске `docker compose` из корня с `--env-file .env` переменные подставляются в `docker-compose.yml` и передаются в контейнеры. Без этого JWT и Supabase в API будут пустыми → 500 на `/api/auth/exchange` и т.п. 2. **Откуда запускать Compose** Запуск только из **корня проекта** (где лежит `.env` и `docker-compose.yml`). Не из папки `docker/`. 3. **Prisma в контейнере API** Используется образ на базе `node:20-slim` (не Alpine), чтобы не было ошибок с `libssl.so.1.1` у нативного движка Prisma. 4. **Прокси API во фронте** Web обращается к API по относительному пути `/api/...`; Next.js проксирует запросы на бэкенд (в Docker — на сервис `api:3125`). Один билд веба работает при любом хосте. 5. **Два compose-файла** - **Корень:** `docker-compose.yml` — основной, с `env_file: .env` и путями от корня. Использовать его для полного запуска в Docker. - **docker/docker-compose.yml** — старый вариант (можно оставить для только инфраструктуры или выровнять с корневым при необходимости). --- ## Если в Docker 500 на `/api/auth/exchange` и `/api/courses` (а через pnpm run — всё ок) Чаще всего API в контейнере не получает переменные окружения или получает их с ошибкой (например, из-за Windows). **1. Запуск обязательно с `--env-file .env` из корня проекта:** ```bash cd d:\Github\course-craft-service docker compose --env-file .env up -d --build ``` Или через pnpm: `pnpm docker:up` (если скрипт использует `--env-file .env`). **2. Проверка переменных в контейнере API:** ```bash docker exec coursecraft-api env | findstr "JWT_SECRET SUPABASE DATABASE" ``` Должны быть непустые `JWT_SECRET`, `NEXT_PUBLIC_SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, `DATABASE_URL=postgresql://postgres:postgres@postgres:5432/...`. Если что-то пустое — Compose не подхватил `.env` (запуск не из корня или не указан `--env-file .env`). **3. Windows: перевод строк в `.env`** Если `.env` сохранён с CRLF (Windows), значения могут содержать `\r` и ломать JWT/подключения. Сохраните `.env` в кодировке UTF-8 с окончаниями строк LF (в редакторе: «Save with Encoding» → UTF-8, в Git: `git config core.autocrlf input` и пересохраните файл). **4. Логи API при 500:** После правок при следующей ошибке API при старте покажет явную причину, если не задан `JWT_SECRET`. Для любых необработанных ошибок смотрите логи: ```bash docker logs coursecraft-api -f ``` Перед запросом к `/api/auth/exchange` или `/api/courses` в логах будет стек или сообщение об ошибке (БД, Supabase, JWT и т.д.). **5. Web должен проксировать на контейнер API** В контейнере `web` при старте должна быть переменная `API_URL=http://api:3125` (задаётся в `docker-compose.yml`). Тогда Next.js отправляет запросы на сервис `api`, а не на `localhost`. Проверка: ```bash docker exec coursecraft-web env | findstr API_URL ``` Ожидается: `API_URL=http://api:3125`. --- ## Краткая шпаргалка | Задача | Команда | |---------------------|--------| | Всё в Docker | `cd <корень> && docker compose --env-file .env up -d` или `pnpm docker:up` | | Только инфраструктура | `docker compose --env-file .env up -d postgres redis meilisearch` | | Схема БД (на хосте) | `packages/database/.env` с DATABASE_URL, затем `pnpm db:push` | | Приложения на хосте | `pnpm start` или `pnpm dev` | | Логи Docker | `docker compose logs -f` или `docker logs coursecraft-api -f` | | Остановить Docker | `docker compose down` |