Good Fights
A fight-tracking app for combat-sports fans. It's live on iOS, Android and Web, and is kept current by automated systems.
- Role
- Founder · sole developer
- Platforms
- iOS · Android · Web
- Stack
- React Native (Expo), Node/Fastify in TypeScript, PostgreSQL + Prisma, Next.js, Docker on Render, a Linux VPS for the daily automations and live trackers, Cloudflare R2
- Links
- goodfights.app · App Store · Google Play



The problem
Film fans have Rotten Tomatoes. Fight fans had nothing - no place to rate an individual fight, see what the crowd thought, or see what's hyped in upcoming weeks.
Fighting Tomatoes, my earlier web version, proved people wanted this. Good Fights is the mobile-first successor, with advanced functionality and user reach.
What shipped
- iOS and Android apps from one React Native codebase.
- Migrated the legacy Fighting Tomatoes accounts onto the new platform. Good Fights users have submitted 83,957 fight ratings on 15,789 fights dating back to 1993.
- A REST API in TypeScript on PostgreSQL, shared by the apps and the Next.js web version at goodfights.app.
- Claude-based enrichment that writes fight, fighter and event detail, gated on a confidence score so nothing the model is unsure about is published - with unit tests that check its output, including one that verifies quoted material is real.
- More than 30 scheduled jobs on the VPS, each with per-job locking and failure alerts, running the scrapers, Brave Search lookups, Claude API enrichment, database backups, deduplication and content-freshness checks.
- A Remotion video pipeline that renders promo clips from live database data, with generated voice-over, plus an automated content system that writes an SEO-focused preview and results article for every numbered UFC card and refreshes a monthly fighter-rankings article from live data.
- Over-the-air updates so fixes reach users without a new store submission.
How it fits together
The big challenges
Live trackers that stay accurate
Good Fights promises to let users know exactly when the fight they want to watch is about to start. This means tracking events while they are live to determine exactly when each fight ends and the next one starts, and doing this consistently across 15+ organizations, week in, week out. So I built trackers that handle complex and changing data sources, degrade gracefully and alert me when there are any issues.
Clear the moment you open it
A first-time user has to grasp what they are looking at and what to do, without having to figure it out. This meant limiting feature creep and creating a UI optimized for immediate, intuitive understanding.
Developing functionality users actually want
Identifying valuable use cases for Good Fights and building clean solutions. Good Fights started as rating historic fights only, but has expanded to include hyping upcoming fights, comments, fighter walkout notifications and more. Each of these was built out in response to user feedback.
Outcome
- 81,208
- fight ratings submitted by users
- 1,679
- written reviews
- 16,265
- fights catalogued across 1,670 events