domain glossary, context map, ADRs (library-as-source, playout, event queue)

This commit is contained in:
2026-07-12 06:30:08 +02:00
parent f45eb38d97
commit efd15c4f53
6 changed files with 219 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
# ADR-0001: Library as single source of truth for media
## Status
Accepted
## Context
The system originally had two representations of media: MediaItem (fetched live from providers at schedule-generation time) and LibraryItem (cached in the local database for browsing). The schedule engine bypassed the library entirely and queried providers directly, creating a tight coupling to provider availability and duplicating the concept of "a piece of media."
## Decision
The local library is the single source of truth for all media in the system. Providers (Jellyfin, Plex, local files, YouTube, etc.) are sync sources only — they feed items into the library, but are never queried at runtime by the schedule engine.
One unified type — MediaItem — lives in the library. The schedule engine queries the library, not providers.
## Consequences
- Schedule generation works even when a provider is offline.
- No more two-type split (MediaItem vs LibraryItem) — one concept, one type.
- Provider adapters become sync-only: their job is to discover items and upsert them into the library.
- Stream URL resolution still needs the provider at playback time (the library stores metadata, not video files). This is the one runtime provider dependency.
- Filters (genres, decade, content type, etc.) operate on library data, not provider APIs.

View File

@@ -0,0 +1,31 @@
# ADR-0002: K-TV owns the stream via a Playout Service
## Status
Accepted
## Context
The original design proxied streaming to each provider — Jellyfin served its own HLS, local files were either served directly or transcoded individually. This made it impossible to:
- Inject SCTE-35 markers for mid-roll breaks
- Insert timed metadata for overlays
- Stitch interstitial content between program items into a continuous stream
- Guarantee consistent stream format across providers
## Decision
K-TV owns the stream end-to-end via a Playout Service. Providers expose a source URI (network URL or local file path) instead of a viewer-facing playback URL. The Playout Service reads from the source URI using FFmpeg on-demand (no full file download), and produces the HLS output with all audio/subtitle tracks, segmentation, SCTE-35, and timed metadata.
## Alternatives considered
- **Continue proxying to provider streams** — rejected because mid-roll breaks, interstitials, and overlays require playlist-level control that provider-owned streams don't offer.
- **Download files locally then transcode** — rejected because it duplicates storage and defeats the purpose of having providers manage content.
## Consequences
- Provider port changes from "give me a playback URL" to "give me a source URI."
- Every stream goes through FFmpeg — CPU cost scales with concurrent viewers. Caching segments mitigates repeat access.
- Subtitles and audio tracks come from the source container — no separate subtitle API needed.
- All viewers get a uniform HLS experience regardless of provider.
- Disk space management becomes critical — HLS segments must be cleaned up.

View File

@@ -0,0 +1,23 @@
# ADR-0003: Database-backed event queue with DLQ
## Status
Accepted
## Context
The system is moving from a single binary with in-process tokio::sync::broadcast to three separate binaries (presentation, worker, playout). In-process channels don't work across process boundaries. The operator already runs NATS with JetStream on their homelab but adding a broker dependency for the initial release is unnecessary overhead.
## Decision
Use a database-backed event queue (SQLite table) for inter-process communication. Events are written by publishers, polled by consumers. Failed events go to a dead-letter queue (DLQ) after exhausting retries.
The EventPublisher/EventConsumer ports remain abstract — swapping in a NATS JetStream adapter later is a wiring change, not a redesign.
## Consequences
- No additional infrastructure beyond SQLite.
- Polling introduces small latency (sub-second with aggressive poll interval, tunable).
- DLQ prevents poison messages from blocking the queue.
- Events must be serializable (already Clone + Debug, need Serialize/Deserialize).
- NATS migration path is clean: implement the same ports with a NATS adapter, swap in presentation/worker wiring.