Auch verfügbar in: 🇬🇧 English

Architektur

Inhalt

🇬🇧 English Version


Überblick

ITSWEBER Play wird als einzelner Docker-Container ausgeliefert, der genau einen Port (3000) exponiert. Eine Nginx-Instanz innerhalb des Containers multiplext eingehende Anfragen und leitet sie an den jeweils zuständigen internen Service weiter. Docker-Compose-Orchestrierung oder ein Container-Netzwerk werden nicht benötigt — alles läuft in einem Prozessbaum, der von s6-overlay verwaltet wird.


Container-Topologie

┌─────────────────────────────────────────┐
│            itsweber-play:3000           │
│  ┌──────────────────────────────────┐   │
│  │         Nginx :80 (intern)       │   │
│  └──┬──────────────┬────────────────┘   │
│     │              │                    │
│  ┌──▼──┐       ┌───▼────┐              │
│  │ Web │       │  API   │              │
│  │:3100│       │ :4000  │              │
│  └─────┘       └───┬────┘              │
│                    │                   │
│  ┌─────┐  ┌──────┐ │  ┌──────┐        │
│  │Redis│  │MinIO │ │  │Pgsql │        │
│  │:6379│  │:9000 │ │  │:5432 │        │
│  └─────┘  └──────┘ │  └──────┘        │
│                ┌───▼────┐             │
│                │ Worker │             │
│                └────────┘             │
└─────────────────────────────────────────┘

Die gesamte Inter-Service-Kommunikation läuft über 127.0.0.1. Das Web-Frontend ist eine Next.js-15-App-Router-Anwendung. Das API ist ein Fastify-Server, der tRPC-Prozeduren und Better-Auth-Endpunkte bereitstellt. Der Worker ist ein BullMQ-Consumer, der FFmpeg- und yt-dlp-Jobs ausführt.


s6-overlay Startreihenfolge

s6-overlay steuert die Startreihenfolge und startet abgestürzte Services automatisch neu:

  1. postgres-init — Legt das Postgres-Datenverzeichnis und den Cluster an, falls noch nicht vorhanden.
  2. postgres — Startet den Postgres-Server auf :5432.
  3. migrate — Führt prisma migrate deploy gegen die lokale Postgres-Instanz aus. Blockiert bis zum Abschluss.
  4. minio — Startet den MinIO-Server auf :9000 und legt Standard-Buckets an.
  5. redis — Startet den Redis-Server auf :6379.
  6. api — Startet den Fastify-API-Server auf :4000.
  7. worker — Startet den BullMQ-Worker-Prozess.
  8. web — Startet den Next.js-Server auf :3100.
  9. nginx — Startet Nginx auf :80 (intern), gemappt auf den exponierten Container-Port 3000.

Services

Service Interner Port Zweck
Nginx 80 Request-Multiplexer; leitet /api/*, /auth/*, /trpc/* ans API, alles andere ans Web
Web (Next.js) 3100 SSR-Frontend, Studio, Admin-Panel
API (Fastify) 4000 tRPC, Better Auth, Upload-Endpunkt, HLS-Signed-URLs
Worker (BullMQ) FFmpeg-Transcodierung, yt-dlp-Import, Thumbnail-Extraktion
Postgres 16 5432 Primäre Datenbank (Prisma ORM)
Redis 7 6379 BullMQ-Job-Queues, Session-Cache, Pub/Sub für Live-Fortschritt
MinIO 9000 S3-kompatibler Objektspeicher für Videos, Thumbnails, Assets

Datenflüsse

Upload

Browser → Web (tus-Chunk) → API → MinIO (raw)
                                → Worker (enqueue)
Worker → MinIO (raw pullen) → FFmpeg → HLS-Segmente → MinIO (play-videos/)
Worker → Redis Pub/Sub (Fortschrittsereignisse)
API → SSE → Browser (Live-Fortschrittsbalken)

Externer Import (yt-dlp)

  1. Nutzer gibt eine URL im Studio ein.
  2. API legt einen Video-Datensatz mit status=importing an und stellt einen Job in die Queue.
  3. Worker lädt die Quelle via yt-dlp herunter und transcodiert mit FFmpeg.
  4. Das Video wird sichtbar. Die Standard-Sichtbarkeit nach dem Import ist private — der Nutzer muss es explizit veröffentlichen.

Auth

Browser → POST /auth/sign-in → Better Auth → Session-Cookie (HTTP-only, SameSite=Lax)
Browser → GET /trpc/* → API liest Cookie → validiert Session → gibt Daten zurück

Theme-Update

Admin speichert Token-Änderung → API schreibt in DB → SSE-Ereignis wird gesendet
Browser empfängt SSE → ersetzt <style id="theme-vars"> → Live-Update, kein Reload

Speicher-Layout

MinIO organisiert die Daten in folgenden Buckets:

Bucket Inhalt
play-raw Original-Videodateien nach dem Upload (verbleiben bis Transcodierung abgeschlossen)
play-videos HLS-Segmente und Playlisten (.m3u8, .ts)
play-thumbs Automatisch generierte Thumbnail-Kandidaten und ausgewählte Thumbnails
play-assets Logo, Favicon, Kanal-Avatare, Banner

Alle Buckets sind privat. Das API generiert vorzeichenbehaftete URLs (Pre-signed URLs) für Wiedergabe und Asset-Auslieferung.


Monorepo-Pakete

Paket Zweck
apps/web Next.js-15-App-Router-Frontend
apps/api Fastify + tRPC + Better Auth Backend
apps/worker BullMQ + FFmpeg + yt-dlp Video-Pipeline
apps/remotion Demo-Video-Rendering (Remotion)
packages/db Prisma-Schema und generierter Client
packages/theme 6-Ebenen-Token-System und Live-Editor-Komponenten
packages/shared Gemeinsam genutzte TypeScript-Typen und Enums
packages/storage MinIO-Client-Wrapper
docker/all-in-one Dockerfile, s6-overlay-Service-Definitionen, Nginx-Konfiguration
docker/unraid Unraid Community Apps XML-Template