OTT Platform — 9 Platforms, 1 Monorepo

Prachyam Sangam is the ground-up rewrite of Prachyam Studios' OTT platform — a project I inherited as a broken, 18-developer codebase and rebuilt solo into a 21-package Nx TypeScript monorepo targeting 9 distinct platforms: Next.js web, React Native iOS and Android, Apple TV, Android TV, Tizen (Samsung), webOS (LG), a Tauri desktop admin panel, and a docs site. A Roku app was also scaffolded but not completed before the engagement wound down.
The previous platform (see Prachyam Legacy) had accumulated 1,669 commits of technical debt across incompatible stacks. Sangam is the clean-room successor — designed from the monorepo boundary outward, with every cross-platform contract defined at the package layer before a single UI component was written.
The core problem with multi-platform OTT is that each target has fundamentally different rendering, input, and DRM models. A TV remote is not a touchscreen. Roku's SceneGraph XML is not React. Tizen and webOS each have their own app packaging and certification requirements. The naive approach — write one UI, bolt on platform shims — produces an unmaintainable mess at exactly the scale the previous platform had reached.
The constraint I set: shared business logic, typed contracts, zero copy-paste between platform packages.
There was a second, harder constraint: the only development machine was a 16 GB / 512 GB M1 iMac — not enough to run seven Docker-backed apps concurrently alongside the monorepo build. Rather than cut scope or rent a bigger machine, I meshed three machines over Tailscale and offloaded Docker services to two peer nodes while the iMac handled active development. Every service ran at a stable *.dev.prachyam.local HTTPS subdomain via dnsmasq and Caddy — production-mimicking the target VPS at zero production cost.
The monorepo is structured in three layers:
Core packages — @repo/shared, @repo/api-client, @repo/auth (Better Auth), @repo/database (Drizzle + Postgres), @repo/streaming (player state) — define domain models, API client, auth, and player state as pure TypeScript with no DOM or RN dependencies. Every platform imports from here.
Shared UI packages split by rendering target — @repo/ui (React + Tailwind, web/desktop) and @repo/native-ui (React Native + NativeWind, mobile/TV). Platform-specific components extend shared primitives; none duplicate logic.
Platform apps (apps/web, apps/ios, apps/android, apps/apple-tv, apps/android-tv, apps/roku, apps/tizen, apps/webos, apps/admin) are thin shells that wire platform entry points to the shared packages.
Nx handles task orchestration, build caching, and affected-project detection. A change to @repo/shared triggers rebuilds only for packages that depend on it — not the full workspace.
Roku was scaffolded but not completed — SceneGraph XML with BrightScript scripting is a completely different mental model from component trees, and the app shell was stood up without a full player integration or device-testing pass before the engagement wound down.
Tizen and webOS share a React-based renderer but have divergent packaging, signing, and store submission requirements. Both target smart TV input models (D-pad navigation, long-press, focus rings) that need custom focus management — React's synthetic event model doesn't map cleanly to TV remotes.
Apple TV and Android TV use the React Native TV fork with tvOS/leanback-specific navigation. Focus management is handled through a custom useTVFocus hook that wraps the platform's native APIs.
Tauri admin is the desktop management panel for studio staff — content ingestion, scheduling, analytics, and the DRM key management interface.
23 custom Model Context Protocol servers (~280 tools) give Claude Code live read access to the Postgres schema, BullMQ job queues, MinIO buckets, Docker service state, and Prometheus metrics across the stack. This compressed the CLAUDE.md context by 69% and allowed AI-assisted debugging without manually pasting database state into prompts.
Nx over Turborepo — Nx's task graph and affected detection are more granular for a workspace this large. Turborepo's simpler model would have required more manual cache configuration at 21 packages.
Elysia over Express — Elysia's native Bun runtime throughput plus end-to-end type safety (request → response → client SDK) via the treaty plugin eliminated an entire class of runtime errors between the API and platform consumers.
Bun as runtime — The monorepo toolchain runs entirely on Bun. Script execution and test runs are meaningfully faster than Node across 21 packages, which compounds over hundreds of daily builds.
Dragonfly over Redis — Redis-protocol compatible, so not a line of application code changed. Dragonfly's multi-threaded engine uses roughly 30% less memory at equivalent cache hit rates — material on a budget VPS with limited RAM.
Sprint-numbered commits with priority tags — Every non-trivial change carries a sprint number and a p0–p3 priority in the commit subject. Writing the route-readiness audit took under an hour because every route's last relevant sprint was instantly traceable in git log --oneline — methodology, not just history.
Sangam reached MVP across 9 platforms in roughly five months of solo development — 152 commits, ~972K lines of TypeScript/TSX/JS, 21 shared packages, 10 MCP servers. The Tailscale mesh removed any hardware-upgrade requirement during the build. The standalone docker-compose.standalone.yml makes the full stack deployable to a single VPS without a DevOps hire, which also positions the monorepo as a sellable ThemeForest starter kit once the partnership engagement wraps. The real result isn't the platform count — it's that a clean package boundary made nine targets a maintenance problem instead of nine codebases.
Nx workspace
~972K LOC
Claude Code integration
Forensic stabilisation and feature expansion of a production streaming platform across web, mobile, and TV
550+ components across web, mobile, TV, and admin
Revenue-share HTML5 game hub embedded into the Prachyam OTT platform via Flutter WebView and React
Did this resonate?