โ† All projects
Full-stack

Channel Stream

Discovery layer that tells sports fans where to watch any live game.

GoNext.jsSupabaseRedisAWS ECSPlaywright

The problem

Watching live sports has become a scavenger hunt across a dozen paid streamers. Schedule pages tell you when a game is on, but rarely which service is broadcasting it. By the time a fan figures it out, the first quarter is over.

Channel Stream is a discovery layer that ingests live game data and tells you exactly where to watch โ€” in one screen, in real time.

Architecture

A Go API + ingestion worker polls ESPN's public endpoints, normalizes the broadcast metadata, and writes to PostgreSQL via Supabase. Redis caches feed responses with 90sโ€“10m TTLs depending on game state. A Next.js frontend reads the API and renders the watch-now / up-next / schedule views. Auth and per-user preferences are stored in Supabase.

Deployed as Docker images to AWS ECS Fargate, with the frontend on CloudFront. Playwright runs E2E tests against a local Supabase stack before each deploy.

Hard decisions

Polling vs. webhooks.ESPN doesn't offer webhooks for live state. I went with adaptive polling โ€” fast during active games, slow during off-hours โ€” instead of a fixed cadence. Cut API egress by ~70% without losing freshness.

Supabase over self-hosted Postgres. Auth + DB + RLS in one. Trade-off: vendor lock-in on RLS policies, but the velocity gain on the auth flow alone was worth it for a solo project.

Go for the API, not Node. Concurrent polling with goroutines is cleaner than Promise.all spaghetti, and the binary deploys to ECS without a runtime image bloat.

What I'd do next

Move ingestion to a serverless cron (EventBridge โ†’ Lambda) so the ECS task only serves the API. Add a Slack / Discord notify on user's favorite team going live. Open-source the broadcast normalization mapping since the rest of the ecosystem has the same problem.