Architecture
Inhalt
Overview
ITSWEBER Play ships as a single Docker container that exposes one port (3000). An Nginx instance inside the container multiplexes incoming requests and routes them to the appropriate internal service. There is no need for Docker Compose orchestration or a container network — everything runs in one process tree managed by s6-overlay.
Container Topology
┌─────────────────────────────────────────┐
│ itsweber-play:3000 │
│ ┌──────────────────────────────────┐ │
│ │ Nginx :80 (internal) │ │
│ └──┬──────────────┬────────────────┘ │
│ │ │ │
│ ┌──▼──┐ ┌───▼────┐ │
│ │ Web │ │ API │ │
│ │:3100│ │ :4000 │ │
│ └─────┘ └───┬────┘ │
│ │ │
│ ┌─────┐ ┌──────┐ │ ┌──────┐ │
│ │Redis│ │MinIO │ │ │Pgsql │ │
│ │:6379│ │:9000 │ │ │:5432 │ │
│ └─────┘ └──────┘ │ └──────┘ │
│ ┌───▼────┐ │
│ │ Worker │ │
│ └────────┘ │
└─────────────────────────────────────────┘
All inter-service communication uses 127.0.0.1. The Web frontend is a Next.js 15 App Router application. The API is a Fastify server exposing tRPC procedures and Better Auth endpoints. The Worker is a BullMQ consumer that runs FFmpeg and yt-dlp jobs.
s6-overlay Init Order
s6-overlay manages the startup sequence and restarts any crashed service automatically:
postgres-init— Creates the Postgres data directory and cluster if it does not exist.postgres— Starts the Postgres server on:5432.migrate— Runsprisma migrate deployagainst the local Postgres instance. Blocks until complete.minio— Starts the MinIO server on:9000and creates default buckets.redis— Starts the Redis server on:6379.api— Starts the Fastify API server on:4000.worker— Starts the BullMQ worker process.web— Starts the Next.js server on:3100.nginx— Starts Nginx on:80(internal), which is mapped to the container's exposed port3000.
Services
| Service | Internal Port | Purpose |
|---|---|---|
| Nginx | 80 | Request multiplexer; routes /api/*, /auth/*, /trpc/* to API, everything else to Web |
| Web (Next.js) | 3100 | SSR frontend, Studio, Admin panel |
| API (Fastify) | 4000 | tRPC, Better Auth, upload endpoint, HLS signed URLs |
| Worker (BullMQ) | — | FFmpeg transcoding, yt-dlp import, thumbnail extraction |
| Postgres 16 | 5432 | Primary database (Prisma ORM) |
| Redis 7 | 6379 | BullMQ job queues, session cache, pub/sub for live progress |
| MinIO | 9000 | S3-compatible object storage for videos, thumbnails, assets |
Data Flows
Upload
Browser → Web (tus chunk) → API → MinIO (raw)
→ Worker (enqueue)
Worker → MinIO (pull raw) → FFmpeg → HLS segments → MinIO (play-videos/)
Worker → Redis pub/sub (progress events)
API → SSE → Browser (live progress bar)
External Import (yt-dlp)
- User submits a URL in Studio.
- API creates a Video record with
status=importing, enqueues a job. - Worker runs
yt-dlpto download the source, then transcodes with FFmpeg. - Video becomes visible. Default visibility is
private— the user must explicitly publish it.
Auth
Browser → POST /auth/sign-in → Better Auth → session cookie (HTTP-only, SameSite=Lax)
Browser → GET /trpc/* → API reads cookie → validates session → returns data
Theme Update
Admin saves token change → API writes to DB → SSE event broadcast
Browser receives SSE → replaces <style id="theme-vars"> → live update, no reload
Storage Layout
MinIO organizes data into the following buckets:
| Bucket | Contents |
|---|---|
play-raw |
Original uploaded video files (kept until transcoding completes) |
play-videos |
HLS segments and playlists (.m3u8, .ts) |
play-thumbs |
Auto-generated thumbnail candidates and selected thumbnails |
play-assets |
Logo, favicon, channel avatars, banners |
All buckets are private. The API generates pre-signed URLs for playback and asset delivery.
Monorepo Packages
| Package | Purpose |
|---|---|
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 and generated client |
packages/theme |
6-layer token system and live editor components |
packages/shared |
Shared TypeScript types and enums |
packages/storage |
MinIO client wrapper |
docker/all-in-one |
Dockerfile, s6-overlay service definitions, Nginx config |
docker/unraid |
Unraid Community Apps XML template |