diff --git a/CLAUDE.md b/CLAUDE.md index 5323d18..9f1d4e0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -127,7 +127,7 @@ cd ai-agent && python main.py start # Setup script (universal installer/doctor) ./setup.sh # Interactive menu -./setup.sh dev # Update + launch dev server (auto LAN, kill old processes) +./setup.sh dev # Kill old + pull + deps + containers + wait healthy + prisma + run ./setup.sh install # Full first-time setup (auto-generates passwords) ./setup.sh update # git pull + npm install + prisma + rebuild ./setup.sh doctor # Diagnose & auto-fix common issues @@ -172,17 +172,18 @@ DEV_ACCESS_KEY=mySecretKey123 ## Prisma 7 Notes -- `prisma.config.ts` in project root (required by Prisma 7) -- `url = env("DATABASE_URL")` in schema datasource — standard approach, works with CLI and PrismaClient -- `new PrismaClient()` without arguments — URL resolved from schema's `env("DATABASE_URL")` +- `prisma.config.ts` in project root — `migrate.url()` provides DATABASE_URL for CLI commands (`prisma db push`, `prisma migrate`) +- **No `url` in schema datasource** — Prisma 7 forbids it, only `provider` allowed +- `PrismaClient` uses `@prisma/adapter-pg` (driver adapter) — `new PrismaClient({ adapter })` with `PrismaPg({ connectionString })` +- `new PrismaClient()` without adapter **will crash** in Prisma 7 (no datasourceUrl/datasources support) - Use `-- --webpack` flag for `next build` on Windows (Turbopack WASM issue) ## Auth Notes - `better-auth` handles registration/login via `/api/auth/[...all]` catch-all route - **Client:** `auth-client.ts` uses `createAuthClient()` without `baseURL` — auto-detects current origin (works from any IP/domain) -- **Server:** `auth.ts` uses `BETTER_AUTH_URL` for `baseURL` and `BETTER_AUTH_TRUSTED_ORIGINS` (comma-separated) for CSRF origin validation. Without `BETTER_AUTH_TRUSTED_ORIGINS`, auto-allows `localhost`/`127.0.0.1` on ports 3000–3010 + `LAN_HOST` if set -- First admin: register normally, then promote via `./setup.sh admin` or manually in DB +- **Server:** `auth.ts` uses `BETTER_AUTH_URL` for `baseURL` and `BETTER_AUTH_TRUSTED_ORIGINS` (comma-separated) for CSRF origin validation. Without `BETTER_AUTH_TRUSTED_ORIGINS`, auto-detects all machine IPs via `os.networkInterfaces()` + localhost on ports 3000–3010 +- First admin: first registered user automatically becomes ADMIN (via `databaseHooks.user.create.before` in `auth.ts`) - **No `"type"` field in `package.json`** — removed to fix Turbopack ESM/CJS conflict in dev mode. Next.js handles ESM in `.ts/.tsx` automatically ## Agent Orchestration diff --git a/PROMPT.md b/PROMPT.md index 83253d8..6bacb3a 100644 --- a/PROMPT.md +++ b/PROMPT.md @@ -16,7 +16,7 @@ Key differentiators: - **Backend:** Node.js (Next.js Route Handlers). LiveKit Server Node SDK (`livekit-server-sdk`) for token generation and room management. - **Authentication:** `better-auth` with Prisma adapter. Email/Password for Hosts and Admins. Guests join without auth (name-only entry), with a `user_id` column reserved for future LMS account linking. - **AI Module:** Python — LiveKit Agents framework (`livekit-agents`). Real-time STT via `livekit-plugins-deepgram` (streaming, low latency). Post-lecture summarization via OpenAI GPT API (`livekit-plugins-openai`). -- **Database:** PostgreSQL with Prisma 7 ORM. Config in `prisma.config.ts` (Prisma 7 pattern — no `url` in schema datasource). +- **Database:** PostgreSQL with Prisma 7 ORM. Config in `prisma.config.ts` (`migrate.url()` for CLI). Runtime connection via `@prisma/adapter-pg` driver adapter — no `url` in schema datasource (Prisma 7 forbids it). - **Storage:** S3-compatible storage (MinIO self-hosted on Proxmox, or AWS S3) for recordings, shared files, and chat attachments. - **Reverse Proxy:** Traefik v3 with automatic Let's Encrypt SSL (production). Local dev runs on direct ports without proxy. - **PDF Export:** `@react-pdf/renderer` for generating downloadable lecture summaries. diff --git a/README.md b/README.md index 0b17484..75a5ea3 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,18 @@ ```bash git clone && cd LiveServer-M1 -bash setup.sh +chmod +x setup.sh + +# Первоначальная установка (интерактивная) +./setup.sh install + +# Ежедневная разработка (одна команда: pull + deps + containers + prisma + run) +./setup.sh dev ``` -Скрипт проведёт через все шаги: проверит зависимости, спросит настройки, сгенерирует `.env`, поднимет Docker, применит миграции, создаст S3 bucket. Работает для локальной разработки и production. +Скрипт `./setup.sh install` проведёт через все шаги: проверит зависимости, спросит настройки, сгенерирует `.env`, поднимет Docker, применит миграции, создаст S3 bucket, создаст первого администратора. + +`./setup.sh dev` — автоматически обновляет код, ставит зависимости, поднимает контейнеры, ждёт их готовности, синхронизирует схему БД, освобождает порт 3000 и запускает dev-сервер. ## Быстрый старт (ручной) @@ -54,7 +62,7 @@ cp .env.example .env ### 3. Запустить базу данных ```bash -docker compose up -d postgres minio redis +docker compose up -d postgres minio redis pgbouncer ``` Поднимет PostgreSQL (`localhost:5432`), MinIO (`localhost:9000`, консоль: `9001`), Redis (`localhost:6379`), PgBouncer (`localhost:6432`). @@ -79,6 +87,8 @@ npm run dev Приложение: `http://localhost:3000` +**Первый администратор:** первый зарегистрированный пользователь автоматически получает роль ADMIN. + ### 6. (Опционально) AI Agent ```bash @@ -139,19 +149,30 @@ Traefik автоматически получит SSL-сертификат че ## Команды ```bash -# Разработка +# Setup script (рекомендуемый способ) +./setup.sh # Интерактивное меню +./setup.sh dev # Обновить + запустить dev-сервер (one command) +./setup.sh install # Первоначальная установка +./setup.sh update # git pull + npm install + prisma + rebuild +./setup.sh doctor # Диагностика и автоисправление +./setup.sh status # Статус всех сервисов +./setup.sh admin # Создать администратора +./setup.sh restart # Перезапуск контейнеров +./setup.sh logs [service] # Логи сервиса (default: app) +./setup.sh reset # Полный сброс (с подтверждением) + +# Разработка (ручной запуск) npm run dev # Next.js dev server npm run lint # TypeScript type-check (tsc --noEmit) -npm run build -- --webpack # Production build +npm run build -- --webpack # Production build (Webpack, не Turbopack — WASM на Windows) # База данных -npx prisma migrate dev # Создать/применить миграцию +npx prisma generate # Регенерация Prisma Client npx prisma db push # Синхронизировать схему без миграции npx prisma studio # GUI для БД -npx prisma generate # Регенерация Prisma Client # Docker -docker compose up -d # Локалка (postgres + minio) +docker compose up -d postgres minio redis pgbouncer # Инфра для dev docker compose up -d --build # Локалка с билдом app docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build # Прод docker compose logs -f app # Логи приложения diff --git a/setup.sh b/setup.sh index 25a7f24..3987373 100644 --- a/setup.sh +++ b/setup.sh @@ -1325,8 +1325,35 @@ cmd_reset() { cmd_dev() { log_step "Dev Server — обновление и запуск" - # 1. Git pull (без интерактива — stash автоматически) - log_step "1/7 — Обновление кода" + # 1. Убить старые процессы Next.js + освободить порт 3000 + log_step "1/8 — Очистка старых процессов" + local killed=0 + # Убить все процессы next + for pid in $(pgrep -f "next dev" 2>/dev/null || true); do + kill -9 "$pid" 2>/dev/null && ((killed++)) || true + done + for pid in $(pgrep -f "next-server" 2>/dev/null || true); do + kill -9 "$pid" 2>/dev/null && ((killed++)) || true + done + # Убить всё на портах 3000-3005 + for p in $(seq 3000 3005); do + local port_pid + port_pid=$(lsof -ti :"$p" 2>/dev/null || true) + if [[ -n "$port_pid" ]]; then + kill -9 $port_pid 2>/dev/null && ((killed++)) || true + fi + done + # Удалить lock-файл Next.js + rm -rf .next/dev 2>/dev/null || true + if [[ $killed -gt 0 ]]; then + log_ok "Убито процессов: $killed" + sleep 1 + else + log_ok "Старых процессов нет" + fi + + # 2. Git pull (без интерактива — stash автоматически) + log_step "2/8 — Обновление кода" if [[ -d .git ]]; then if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then git stash push -m "auto-stash before dev $(date +%Y%m%d_%H%M%S)" 2>&1 @@ -1336,14 +1363,48 @@ cmd_dev() { log_ok "git pull завершён" fi - # 2. npm install - log_step "2/7 — Зависимости" + # 3. npm install + log_step "3/8 — Зависимости" npm install 2>&1 | tail -3 log_ok "npm install завершён" - # 3. Prisma - log_step "3/7 — Prisma" + # 4. Prisma generate (не требует БД) + log_step "4/8 — Prisma generate" npx prisma generate 2>&1 | tail -2 + log_ok "Prisma Client сгенерирован" + + # 5. Контейнеры + ожидание здоровья + log_step "5/8 — Контейнеры" + docker compose up -d postgres minio redis pgbouncer 2>&1 | tail -5 + log_ok "Инфра-контейнеры запущены" + + # Ждём PostgreSQL (макс 30 сек) + local waited=0 + while [[ $waited -lt 30 ]]; do + if docker compose exec -T postgres pg_isready -U postgres &>/dev/null; then + log_ok "PostgreSQL ready" + break + fi + sleep 2 + waited=$((waited + 2)) + done + if [[ $waited -ge 30 ]]; then + log_warn "PostgreSQL не готов за 30 сек — продолжаю" + fi + + # Ждём Redis (макс 10 сек) + waited=0 + while [[ $waited -lt 10 ]]; do + if docker compose exec -T redis redis-cli ping 2>/dev/null | grep -q PONG; then + log_ok "Redis ready" + break + fi + sleep 1 + waited=$((waited + 1)) + done + + # 6. Prisma db push (теперь БД точно запущена) + log_step "6/8 — Синхронизация схемы БД" if docker compose exec -T postgres pg_isready -U postgres &>/dev/null; then npx prisma db push --skip-generate --accept-data-loss 2>&1 | tail -3 log_ok "Схема БД синхронизирована" @@ -1351,62 +1412,8 @@ cmd_dev() { log_warn "PostgreSQL недоступен — миграция пропущена" fi - # 4. Инфраструктурные контейнеры - log_step "4/7 — Контейнеры" - docker compose up -d postgres minio redis pgbouncer 2>&1 | tail -5 - log_ok "Инфра-контейнеры запущены" - - # Ждём здоровья сервисов (макс 30 сек) - log_info "Ожидаю готовности сервисов..." - local waited=0 - while [[ $waited -lt 30 ]]; do - local all_ok=true - for svc in postgres redis pgbouncer; do - local st - st=$(check_service "$svc") - if [[ "$st" != "ok" ]]; then - all_ok=false - break - fi - done - if $all_ok; then - log_ok "Все сервисы healthy" - break - fi - sleep 2 - waited=$((waited + 2)) - done - if [[ $waited -ge 30 ]]; then - log_warn "Таймаут ожидания — некоторые сервисы могут быть unhealthy" - log_info "Запусти ./setup.sh doctor для диагностики" - fi - - # 5. Убить старые процессы Next.js - log_step "5/7 — Очистка старых процессов" - local killed=0 - for pid in $(pgrep -f "next dev" 2>/dev/null || true); do - kill "$pid" 2>/dev/null && ((killed++)) || true - done - # Убить процесс на порту 3000 - local port_pid - port_pid=$(lsof -ti :3000 2>/dev/null || true) - if [[ -n "$port_pid" ]]; then - kill "$port_pid" 2>/dev/null && ((killed++)) || true - fi - if [[ $killed -gt 0 ]]; then - log_ok "Убито процессов: $killed" - sleep 1 - else - log_ok "Старых процессов нет" - fi - - # 6. Очистка .next кеша - log_step "6/7 — Очистка кеша" - [[ -d ".next" ]] && rm -rf .next - log_ok "Кеш очищен" - # 7. MinIO bucket - log_step "7/7 — MinIO bucket" + log_step "7/8 — MinIO bucket" local bucket bucket=$(env_get S3_BUCKET) bucket="${bucket:-liveserver}" @@ -1416,6 +1423,15 @@ cmd_dev() { local minio_pass minio_pass=$(env_get MINIO_ROOT_PASSWORD) minio_pass="${minio_pass:-minioadmin}" + # Ждём MinIO (макс 15 сек) + waited=0 + while [[ $waited -lt 15 ]]; do + if docker compose exec -T minio mc alias set local http://localhost:9000 "$minio_user" "$minio_pass" &>/dev/null; then + break + fi + sleep 1 + waited=$((waited + 1)) + done if docker compose exec -T minio mc alias set local http://localhost:9000 "$minio_user" "$minio_pass" &>/dev/null; then if docker compose exec -T minio mc ls "local/${bucket}" &>/dev/null; then log_ok "Bucket '${bucket}' существует" @@ -1428,9 +1444,29 @@ cmd_dev() { log_warn "MinIO ещё не готов — bucket создастся при следующем запуске" fi + # 8. Очистка .next кеша + log_step "8/8 — Очистка кеша" + [[ -d ".next" ]] && rm -rf .next + log_ok "Кеш очищен" + + # Автоопределение LAN IP для auth + local lan_ip + lan_ip=$(hostname -I 2>/dev/null | awk '{print $1}' || true) + if [[ -n "$lan_ip" ]]; then + if ! grep -q "^LAN_HOST=" .env 2>/dev/null; then + echo "LAN_HOST=${lan_ip}" >> .env + log_ok "LAN_HOST=${lan_ip} добавлен в .env" + fi + fi + + # Проверка порта 3000 + if lsof -ti :3000 &>/dev/null; then + log_warn "Порт 3000 всё ещё занят — Next.js выберет другой" + fi + # Запуск echo "" - log_ok "${GREEN}${BOLD}Готово! Запускаю dev-сервер...${NC}" + log_ok "${GREEN}${BOLD}Готово! Запускаю dev-сервер на порту 3000...${NC}" echo "" exec npm run dev }