- Prisma 7 notes: adapter-pg, no url in schema - README: setup.sh commands, first admin auto-assign, pgbouncer in docker - PROMPT.md: Prisma 7 adapter-pg description - setup.sh dev: reordered (kill first, containers before prisma, healthchecks)
236 lines
12 KiB
Markdown
236 lines
12 KiB
Markdown
# CLAUDE.md
|
||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
||
## Project Overview
|
||
|
||
**LiveServer-M1** — образовательная видеоконференц-платформа на базе LiveKit.
|
||
|
||
Ключевые фичи:
|
||
- AI-ассистент: авто-подключение к комнатам, real-time транскрипция (Deepgram), суммаризация лекций (OpenAI GPT)
|
||
- Защита от Zoom-bombing: lobby/waiting room, PIN-коды, kick/ban по session fingerprint, panic button
|
||
- Пост-лекционная панель: чат, файлы, транскрипт, AI-саммари, экспорт в PDF/Google Drive
|
||
|
||
Полная спецификация: **`PROMPT.md`**
|
||
|
||
## Tech Stack
|
||
|
||
| Слой | Технологии |
|
||
|------|-----------|
|
||
| Frontend | Next.js 16 (App Router), React 19, TypeScript, Tailwind CSS v4 |
|
||
| Video | LiveKit Cloud → self-hosted, `@livekit/components-react` |
|
||
| Backend | Next.js Route Handlers, `livekit-server-sdk` |
|
||
| Auth | `better-auth` + Prisma adapter |
|
||
| AI Agent | Python, `livekit-agents`, `livekit-plugins-deepgram` (STT), `livekit-plugins-openai` (LLM) |
|
||
| DB | PostgreSQL + Prisma 7 ORM + PgBouncer (connection pooling) |
|
||
| Cache/PubSub | Redis 7 (rate limiting, lobby pub/sub, chat real-time, caching) |
|
||
| Storage | MinIO (S3-compatible) |
|
||
| Proxy | Traefik v3 + Let's Encrypt (prod only) |
|
||
|
||
## Architecture
|
||
|
||
```
|
||
├── src/
|
||
│ ├── app/
|
||
│ │ ├── api/ # 15 API route handlers
|
||
│ │ │ ├── auth/[...all]/ # better-auth catch-all
|
||
│ │ │ ├── rooms/ # CRUD, by-code lookup
|
||
│ │ │ ├── rooms/[roomId]/ # join, lobby, lobby/stream (SSE), chat, files, moderate, hand-raise, start, end
|
||
│ │ │ └── livekit/ # token generation, webhook receiver
|
||
│ │ ├── (dashboard)/ # Host/Admin pages
|
||
│ │ ├── join/[code]/ # Guest entry
|
||
│ │ ├── room/[code]/ # Video room (LiveKit)
|
||
│ │ ├── login/ & register/ # Auth pages
|
||
│ │ └── page.tsx # Landing
|
||
│ ├── components/
|
||
│ │ ├── room/ # ChatPanel, ModerationPanel
|
||
│ │ └── lobby/ # WaitingRoom, LobbyManager
|
||
│ ├── lib/ # prisma, auth, auth-helpers, livekit, redis, rate-limit, lobby-pubsub, chat-pubsub
|
||
│ ├── middleware.ts # Dev protection (DEV_ACCESS_KEY, ALLOWED_IPS)
|
||
│ └── types/
|
||
├── ai-agent/ # Python LiveKit Agent
|
||
├── prisma/schema.prisma # 9 models, 3 enums
|
||
├── docker-compose.yml # Base: postgres, minio, redis, pgbouncer, ai-agent, app
|
||
├── docker-compose.override.yml # Local dev: direct ports, no SSL
|
||
├── docker-compose.prod.yml # Traefik + Let's Encrypt
|
||
└── Dockerfile # Multi-stage Next.js standalone build
|
||
```
|
||
|
||
### Key Data Flows
|
||
|
||
1. **Guest join (with lobby):**
|
||
Guest → POST `/api/rooms/[id]/join` → LobbyEntry(PENDING) → SSE via Redis pub/sub → Host approves → LiveKit token → connect
|
||
|
||
2. **Real-time chat:**
|
||
POST message → DB + Redis PUBLISH → SSE `/api/rooms/[id]/chat/stream` → instant delivery to all participants
|
||
|
||
3. **Real-time transcription:**
|
||
Audio tracks → AI Agent (Deepgram STT) → DataChannel → Live captions
|
||
|
||
4. **Post-lecture (`room_finished` webhook):**
|
||
Transcript → OpenAI GPT → LectureArtifact → `/lectures/[id]`
|
||
|
||
### User Roles
|
||
|
||
- **ADMIN** — global panel, all rooms monitoring
|
||
- **HOST** — room creation, moderation, security
|
||
- **GUEST** — join by link, no registration required
|
||
|
||
### Security Layers
|
||
|
||
- `sessionFingerprint` (required) for bans — IP is secondary only
|
||
- PIN hashed with bcrypt, rate-limited (5 attempts/min per IP)
|
||
- Chat/files auth: verified via ParticipantHistory
|
||
- SSE lobby: verified against existing LobbyEntry
|
||
- Token generation: only room owner can get LiveKit token
|
||
- `DEV_ACCESS_KEY` middleware: protects local dev from network access
|
||
- LiveKit webhook: signature verification via `WebhookReceiver`
|
||
|
||
## Performance Architecture
|
||
|
||
```
|
||
Clients → Traefik (LB) → Next.js (x2 replicas) → PgBouncer (pool 25, max 500) → PostgreSQL
|
||
→ Redis (pub/sub, cache, rate limit)
|
||
→ LiveKit (video/audio SFU)
|
||
```
|
||
|
||
- **Redis pub/sub** replaces DB polling for lobby SSE and chat — instant delivery (<10ms)
|
||
- **PgBouncer** multiplexes 500 client connections into 25 real PostgreSQL connections
|
||
- **Chat SSE** via Redis pub/sub + optimistic UI on client — messages appear before server confirms
|
||
- **Rate limiting** via Redis INCR+EXPIRE — works across multiple app replicas
|
||
- **Chat cache** in Redis (10s TTL) — reduces DB reads during active rooms
|
||
- **Prisma select** — only fetch needed columns, not full rows
|
||
|
||
## Commands
|
||
|
||
```bash
|
||
# Dev
|
||
npm run dev # Next.js dev server (localhost:3000)
|
||
docker compose up -d postgres minio redis pgbouncer # DB + Storage + Redis + PgBouncer
|
||
npm run lint # TypeScript type-check (tsc --noEmit)
|
||
|
||
# Database
|
||
npx prisma migrate dev # Create + apply migration
|
||
npx prisma db push # Quick schema sync (no migration)
|
||
npx prisma studio # DB GUI
|
||
npx prisma generate # Regenerate Prisma Client
|
||
|
||
# Build
|
||
npm run build -- --webpack # Production build (Webpack, not Turbopack — WASM limitation on Windows)
|
||
|
||
# Docker (full stack)
|
||
docker compose up -d --build # Local
|
||
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build # Prod (with Traefik)
|
||
|
||
# AI Agent
|
||
cd ai-agent && python main.py start
|
||
|
||
# Setup script (universal installer/doctor)
|
||
./setup.sh # Interactive menu
|
||
./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
|
||
./setup.sh status # Health check all services
|
||
./setup.sh restart # Restart all containers
|
||
./setup.sh logs [service] # Tail service logs (default: app)
|
||
./setup.sh admin # Promote user to ADMIN role
|
||
./setup.sh reset # Full teardown (with confirmation)
|
||
```
|
||
|
||
## Environment Variables
|
||
|
||
See `.env.example` for all variables. Key ones:
|
||
|
||
```env
|
||
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/liveserver
|
||
LIVEKIT_URL=wss://...
|
||
LIVEKIT_API_KEY=...
|
||
LIVEKIT_API_SECRET=...
|
||
BETTER_AUTH_SECRET=...
|
||
|
||
# Auth — trusted origins for non-localhost access (comma-separated)
|
||
BETTER_AUTH_TRUSTED_ORIGINS=http://192.168.1.78:3000,http://localhost:3000
|
||
# LAN IP for auto trustedOrigins in dev (auto-detected by ./setup.sh dev)
|
||
# LAN_HOST=192.168.1.78
|
||
|
||
# Local dev protection (when DOMAIN is not set)
|
||
DEV_ACCESS_KEY=mySecretKey123
|
||
# ALLOWED_IPS=192.168.1.10,192.168.1.11
|
||
|
||
# Production
|
||
# DOMAIN=live.example.com
|
||
# ACME_EMAIL=admin@example.com
|
||
```
|
||
|
||
## Deployment Modes
|
||
|
||
| Mode | Command | Description |
|
||
|------|---------|-------------|
|
||
| **Local dev** | `docker compose up -d` | Direct ports (3000, 5432, 9000). `docker-compose.override.yml` auto-applied |
|
||
| **Production** | `docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d` | Traefik reverse proxy, auto SSL via Let's Encrypt |
|
||
|
||
## Prisma 7 Notes
|
||
|
||
- `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-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
|
||
|
||
| Task | Agent |
|
||
|------|-------|
|
||
| API routes, backend logic | `backend-architect` |
|
||
| React components, LiveKit UI | `frontend-developer` |
|
||
| DB schema, indexes, queries | `database-optimizer` |
|
||
| Python AI Agent, Deepgram/OpenAI | `ai-engineer` |
|
||
| System architecture | `software-architect` |
|
||
| UI design, components | `ui-designer` |
|
||
| UX flows, accessibility | `ux-architect` |
|
||
| Code review before commit | `code-reviewer` |
|
||
|
||
**Rule:** for tasks spanning 2+ layers — use `agents-orchestrator`.
|
||
|
||
## Post-Change Checklist (ОБЯЗАТЕЛЬНО)
|
||
|
||
После **каждого** изменения кода или конфигурации Claude **обязан** выполнить:
|
||
|
||
1. **Обновить `CLAUDE.md`** — если изменились архитектура, endpoints, модели, команды, стек или conventions
|
||
2. **Проверить `setup.sh`** — все новые сервисы/зависимости должны быть в скрипте (readiness checks, .env переменные, docker compose команды)
|
||
3. **Проверить `README.md`** — инструкции, API таблицы, структура проекта должны отражать текущее состояние
|
||
4. **Проверить `PROMPT.md`** — спецификация должна соответствовать реализации
|
||
5. **Проверить `.env.example`** — все новые переменные окружения должны быть задокументированы
|
||
|
||
Не пропускать этот чеклист. Если изменение не затрагивает файл — просто подтвердить что файл актуален.
|
||
|
||
## Known Issues & Fixes
|
||
|
||
| Issue | Cause | Fix |
|
||
|-------|-------|-----|
|
||
| White screen in dev (ESM/CJS conflict) | `"type": "module"` or `"type": "commonjs"` in package.json | Remove the `"type"` field entirely — Next.js doesn't need it |
|
||
| Auth silently fails from LAN | `auth-client.ts` had hardcoded `baseURL` → requests went to localhost from browser | Removed `baseURL`, added `trustedOrigins` config |
|
||
| `setup.sh doctor` crashes on .env check | Comments in `.env.example` parsed as variable names by `set -euo pipefail` | Fixed parsing logic |
|
||
| `setup.sh update` runs git pull after stash declined | Missing `else` branch after stash prompt | Fixed control flow |
|
||
| Auth form resets on non-localhost (no error shown) | `trustedOrigins` fallback only had `localhost:3000`, CSRF rejected other origins silently | `auth.ts` auto-allows ports 3000–3010 + `LAN_HOST`; `setup.sh dev` auto-detects LAN IP |
|
||
|
||
## Conventions
|
||
|
||
- Communication language: Russian
|
||
- Guests don't register, but `user_id` reserved for future LMS
|
||
- `sessionId` (UUID) is the cross-cutting key linking LobbyEntry, ParticipantHistory, ChatMessage, SharedFile for guests
|
||
- `Room.code` is the user-facing invite code (not the DB id)
|
||
- Files store `fileKey` (S3 object key), not full URLs
|
||
- `LectureArtifact` is 1:1 with Room
|
||
- All cascade deletes: removing Room removes all related data
|
||
- MinIO stays as S3 storage — GitHub repo archived (Feb 2026) but Docker image still maintained, no viable lightweight alternative
|