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

12 KiB
Raw Blame History

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

# 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:

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