Files
linearvoid/docs/architecture/adr/ADR-003-tech-stack.md
T

5.8 KiB
Raw Blame History

ADR-003: Technology Stack, Languages, and Implicit Assumptions

Status: Accepted
Date: 2026-08-02
Author: AI Assistant (based on arc42 and ADR-001)
Related ADRs: ADR-001, ADR-002

Context

From ADR-001 and the arc42 documentation we have the following constraints and preferences:

  • Lightweight, cost-efficient, maintainable stack.
  • Strong preference for US-East hosting (Hetzner), Cloudflare R2/CDN, HLS.
  • Playout must be reliable and low-CPU (FFmpeg + MediaMTX/SRS).
  • Chat needs real-time WebSockets, persistence, moderation, and presence.
  • Frontend must be a minimal static SPA with good browser compatibility.
  • Operational simplicity and easy monitoring are critical.
  • Implicit assumptions include Docker for deployment, normalization of all video assets, heavy reliance on Cloudflare caching, and a focus on immutable infrastructure.

We must explicitly document language/runtime choices per module and the assumptions that were made.

Decision

Chosen Stack:

Layer Technology Language Rationale
Frontend SPA HTML + Tailwind + Alpine.js + hls.js TypeScript / JavaScript Minimal bundle, excellent HLS support, fast iteration. Vite for build.
Playout Service FFmpeg + MediaMTX (or SRS) Bash + Go (wrapper) FFmpeg is the proven tool for continuous playlist HLS. Go wrapper for reliability and monitoring.
Chat Backend Go (preferred) or Node.js + Socket.io Go High-performance WebSockets, low memory, excellent Redis/PostgreSQL clients. Node.js acceptable for rapid prototyping.
Shared Code TypeScript definitions + Go structs TS + Go Clear contracts between frontend and backend.
Infrastructure Docker, Docker Compose, Nginx, Cloudflare YAML + Bash Standard, reproducible, Cloudflare-native.
Scripts Bash (with Python helpers where needed) Bash/Python Simple, no extra runtime for normalization and R2 sync.
Monitoring Prometheus + Grafana + UptimeRobot - Standard open-source stack that integrates well with Docker.
Storage Cloudflare R2 (primary), SQLite/PostgreSQL - $0 egress, simple for chat history.

Implicit Assumptions (now made explicit):

  1. All video assets must be normalized before being added to any playlist (H.264, AAC, 30 fps constant, 2s keyframes, CRF encoding).
  2. Deployment is Docker-first; services will be containerized.
  3. Cloudflare is the primary CDN and will be configured with specific Cache Rules for HLS segments and manifests.
  4. Chat does not require end-to-end encryption in v1 (separate ADR if needed).
  5. Single VPS origin initially; multi-region is a later evolution.
  6. Monitoring focuses on playout health, cache hit ratio, and R2 operation counts.
  7. Development environment uses docker compose for local testing of playout + chat + frontend.

Decision Drivers

  • Match the low-resource, high-reliability requirements from ADR-001.
  • Minimize new language overhead (Go for performance-critical services, JS/TS for frontend and rapid scripting).
  • Leverage mature tools (FFmpeg, hls.js, Redis) rather than reinventing.
  • Keep operational complexity low (Docker + Bash scripts).

Alternatives Considered

  • Full Node.js stack: Simpler for small team but higher memory usage for WebSockets and less efficient HLS packaging.
  • Python for everything: Excellent for scripting but poor real-time WebSocket performance.
  • Rust for chat/playout: Overkill for initial velocity.
  • Separate repositories per service: Considered but rejected for early stage (monorepo with clear folders is better).

Go was chosen for the chat backend because it offers excellent concurrency, small binaries, and native performance for WebSockets and Redis.

Consequences

Positive:

  • Clear, justified choices that align with cost, performance, and maintainability goals.
  • Easy onboarding — developers know exactly which language belongs where.
  • Explicit documentation of assumptions prevents future architectural drift.

Risks:

  • Go learning curve if team is primarily JS (mitigated by allowing Node.js fallback for chat).
  • Assumption that normalization scripts will be followed (enforce via CI/validation in playout service).

Future ADRs:

  • ADR-004: Docker Compose and deployment pipeline.
  • ADR-005: Monitoring and alerting strategy.
  • ADR-006: API contracts between playout, chat, and frontend.

References

  • ADR-001 (overall architecture, HLS, Cloudflare caching, normalization requirements)
  • ADR-002 (folder structure that this stack maps into)
  • arc42 documentation (docs/architecture/README.md) – Building Block View, Deployment View, Cross-cutting Concepts
  • MediaMTX, hls.js, Go WebSocket best practices, Cloudflare R2 caching documentation