Full MVP implementation: - Next.js 16 + React 19 + TypeScript + Tailwind CSS v4 - LiveKit integration (rooms, tokens, webhooks, moderation) - better-auth (email/password, sessions, roles) - Prisma 7 + PostgreSQL (9 models, 3 enums) - 15 API routes (auth, rooms, lobby, chat, files, moderation, hand-raise) - 7 pages (landing, auth, dashboard, join, video room) - SSE-based waiting room with host approval flow - Security: PIN rate limiting, session fingerprint bans, chat/files auth - Python AI Agent (Deepgram STT + OpenAI summarization) - Docker Compose (local + production with Traefik + Let's Encrypt) - Interactive setup script (setup.sh) - Dev protection middleware (DEV_ACCESS_KEY, ALLOWED_IPS) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
51 lines
2.0 KiB
YAML
51 lines
2.0 KiB
YAML
# Продакшен — Traefik + Let's Encrypt
|
|
# Запуск: docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
|
|
|
services:
|
|
traefik:
|
|
image: traefik:v3
|
|
command:
|
|
- "--providers.docker=true"
|
|
- "--providers.docker.exposedbydefault=false"
|
|
- "--entrypoints.web.address=:80"
|
|
- "--entrypoints.websecure.address=:443"
|
|
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
|
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
|
|
- "--certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}"
|
|
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
- letsencrypt_data:/letsencrypt
|
|
restart: unless-stopped
|
|
|
|
app:
|
|
environment:
|
|
NEXT_PUBLIC_APP_URL: https://${DOMAIN}
|
|
BETTER_AUTH_URL: https://${DOMAIN}
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.app.rule=Host(`${DOMAIN}`)"
|
|
- "traefik.http.routers.app.entrypoints=websecure"
|
|
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.app.loadbalancer.server.port=3000"
|
|
|
|
minio:
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.minio-api.rule=Host(`s3.${DOMAIN}`)"
|
|
- "traefik.http.routers.minio-api.entrypoints=websecure"
|
|
- "traefik.http.routers.minio-api.tls.certresolver=letsencrypt"
|
|
- "traefik.http.routers.minio-api.service=minio-api"
|
|
- "traefik.http.services.minio-api.loadbalancer.server.port=9000"
|
|
- "traefik.http.routers.minio-console.rule=Host(`minio.${DOMAIN}`)"
|
|
- "traefik.http.routers.minio-console.entrypoints=websecure"
|
|
- "traefik.http.routers.minio-console.tls.certresolver=letsencrypt"
|
|
- "traefik.http.routers.minio-console.service=minio-console"
|
|
- "traefik.http.services.minio-console.loadbalancer.server.port=9001"
|
|
|
|
volumes:
|
|
letsencrypt_data:
|