Files
LiveServer-M1/CLAUDE.md
joylessorchid f6f93c2ae9 feat: auto LAN auth + setup.sh dev command
- auth.ts: auto-allow localhost:3000-3010 + LAN_HOST for trustedOrigins
- setup.sh: new `dev` command (update + kill old processes + auto LAN IP + launch)
- next.config.ts: allowedDevOrigins for LAN HMR
2026-03-24 03:24:14 +03:00

235 lines
12 KiB
Markdown
Raw 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.
# 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 # Update + launch dev server (auto LAN, kill old processes)
./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 (required by Prisma 7)
- `datasourceUrl` passed via PrismaClient constructor, not in schema
- Schema has no `url` in datasource block — only `provider`
- 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 30003010 + `LAN_HOST` if set
- First admin: register normally, then promote via `./setup.sh admin` or manually in DB
- **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 30003010 + `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