PROJECT 005 · CASE STUDY
Goodpods
Podcast discovery and social listening for 120k active users. I lead engineering across the mobile apps, the web app, and the platform behind them.
Problem
Podcast listening is solitary by default. The big apps are built for playback, not for finding out what the people you trust are actually listening to. Goodpods set out to fix that: a podcast player where discovery is social, so you follow people rather than an algorithm.
The engineering problem underneath is that “social podcast app” means running a full podcast platform (ingesting and indexing RSS feeds, resolving episodes, tracking playback) and a full social product (follows, activity feeds, groups, comments, leaderboards) at the same time, across iOS, Android, and the web, with a small team.
What I built
I’ve led engineering across the stack since 2020, when I took over the original backend. That covers the React Native app that ships to both stores, the Next.js web app, and the Python backend that feeds them all.
- The API layer: FastAPI on Cloud Run, stateless and autoscaled, with Postgres as the single source of truth and Redis in front of it for caching and rate limiting.
- The ingestion side: background workers on Compute Engine that scrape podcast RSS feeds, resolve episodes, compress artwork, and fan out push and email notifications through a job queue.
- Search: an Elasticsearch cluster indexed from Postgres that powers podcast, episode, and profile search.
- The social layer: follows, activity feeds, groups, comments, and leaderboards, modelled relationally rather than bolted on.
- Earshot, the newest product line: podcasters pay for AI-generated marketing material for their episodes. The pipeline transcribes an episode, generates copy and media through LLM APIs, and gates the results behind Stripe subscriptions and credits.
Decisions worth explaining
This is the part portfolio sites usually skip, so it gets the most room.
Postgres for the social graph, not a graph database. Follows and activity feeds are join-shaped queries over data we already had in Postgres. A second datastore would have bought us vocabulary, not capability, and doubled the operational surface for a small team. Indexes and careful query design have held up fine at 40M+ page views a month.
Rebuild the service, keep the schema. Six years of production data makes a big-bang rewrite a bad bet. When the original backend needed replacing, the new async service (SQLAlchemy 2.0, TaskIQ workers) was built around the existing production schema instead of a fresh one. New features like payments and Earshot land on the modern stack while the old API keeps serving traffic, and nothing has to be migrated under load.
React Native, honestly. One team ships two native apps and shares most of its brain with the web codebase. The cost is real: native module upgrades and the occasional platform-specific bug hunt. But for a product whose value is features shipped per week, it has paid for itself.
Own the boring infrastructure when vendors fail you. Podcast artwork compression went through two third-party vendors before we wrote our own task-based pipeline: one was too limited, the other priced for companies ten times our size. Same story with job monitoring, where the open-source dashboard we relied on was abandoned upstream, so we forked it and maintain it ourselves. Neither was glamorous work, but both removed a recurring source of pain.
Outcome
Goodpods is live on the App Store, Google Play, and the web, with 120k active users and 40M+ page views a month. The platform runs three environments, ships through CI on every merge, and gets load-tested with Locust before big releases.
Stack
React Native and TypeScript on mobile, Next.js on the web, FastAPI and Postgres behind them, Elasticsearch for search, Redis for caching and queues, all on GCP.
FROM THE FIELD NOTES · 20 LOGS