VOD Docs

High-level design

The components of VOD, what each one owns, and how they connect.

VOD splits into three planes that scale and fail independently:

  • Control plane: the FastAPI service. Small JSON requests: auth, metadata, admin actions, processing status.
  • Data plane: bulk bytes. Uploads go browser → tusd → MinIO; playback goes MinIO → Caddy → browser. Neither path passes through Python.
  • Processing plane: the Celery worker running FFmpeg, fed by a Redis-backed queue.

The frontend is a separate deployment on Vercel and talks to the backend only over HTTPS.

Architecture diagram · placeholder
Container diagram (C4 level 2): Vercel frontend, Caddy, FastAPI, Celery worker, PostgreSQL, Redis, MinIO, tusd

Show the three planes as coloured bands; arrows labelled with protocol (HTTPS, S3 API, Redis protocol, SQL, tus hooks).

Components

ComponentRuns whereOwnsTalks to
Next.js frontendVercelPages, player, admin UI, client auth stateCaddy over HTTPS
CaddyBackend VPS, host networkTLS, the single public entry point, path-based routingAPI, MinIO, tusd (loopback ports)
FastAPI APIBackend VPS, containerAuth, video metadata, status, tus hook handling, dispatching processingPostgreSQL, Redis, MinIO
Celery workerBackend VPS, container (concurrency 1 in production)Transcoding, packaging, uploading HLS outputRedis (broker), PostgreSQL, MinIO
PostgreSQL 16Backend VPS, private network onlyUsers, videos, tokens, upload sessions—
Redis 7Backend VPS, private network onlyCelery messages and results, the processing lock, upload admission slots—
MinIOBackend VPSRaw uploads, thumbnails, HLS segments and playlists—
tusdBackend VPSThe tus upload protocol; streaming chunks into MinIOMinIO (S3 multipart), API (hooks)

The API and worker are built from the same Docker image (backend/Dockerfile); they differ only in the start command (uvicorn vs celery worker).

Design principles

The main flows

FlowPathDetails
Browse and metadataBrowser → Caddy → FastAPI → PostgreSQLRequest routing
UploadBrowser (Uppy) → Caddy → tusd → MinIO, with tusd → FastAPI hooksResumable uploads
ProcessingFastAPI → Redis → Celery worker → FFmpeg → MinIO, status in PostgreSQLPipeline
PlaybackBrowser (hls.js) → Caddy → MinIOUpload to playback

Scaling characteristics

PartScales byCurrent limit
FrontendVercel's edge networkEffectively none for this traffic
APIMore Uvicorn workers or API containersOne Uvicorn process today
ProcessingMore workers, on more machinesOne worker, one video at a time, by design (why)
DeliveryA CDN in front of /storageEvery segment is served from the one server today
StorageMinIO disks, or swapping to S3/R2The server's disk

What changes at higher scale is covered in Improvements and the system design walkthrough.

On this page