Skip to content
CASE STUDY

MOVINIGHT

Real-time bilingual group movie tracker with voting, a roulette picker, and a Hall of Fame leaderboard. Live at whopickedthis.app.

MOVINIGHT
MOVINIGHT, screenshot 1 of 10
01/10

Key Metrics

11
Schema tables
5
CI stages

Problem

Group movie nights routinely die in an ignored group chat or a spreadsheet nobody opens again. There was no shared, low-friction way for a crew to track what they want to watch and actually land on a decision.

My Role

Solo product engineer, from the realtime data model to the roulette interaction that forces a final decision.

Approach

Convex powers realtime sync so every crew member sees watchlist votes and schedule changes live, no manual refresh, no optimistic-update plumbing needed since any mutation touching a table automatically re-pushes to every subscriber. Vote ranking happens server-side inside the query itself, so the list re-sorts live as votes land. When a group can't agree, the roulette picker turns the shortlist into a spin: the wheel computes real pie-sector geometry and reverse-engineers its final rotation so the winning slice lands under the pointer, and the pick only commits to the database after the spin animation resolves. Join codes are normalized and checked for collisions server-side; email invites run on a token with a 7-day expiry.

Tradeoffs

Chose Convex over a traditional REST-plus-database setup to get realtime updates without hand-rolling websockets or a presence layer. The roulette is uniform random, not vote-weighted, on purpose: the votes already ranked the shortlist, the spin's job is to end the argument, not re-litigate it. Deliberately skipped Zod and React Hook Form for product forms in favor of shadcn's Field primitives with local state, less machinery for forms that don't need heavy validation. Test coverage is intentionally narrow, 13 unit tests on the logic most likely to break silently (org code normalization, rate-limit bucket math, query-length guards) rather than broad integration coverage, with lint, typecheck, and build all gating merges in CI.

FIG. 07 · REALTIME LOOP

vote → sync → decide

Indecision is the actual failure mode a group chat has. The roulette exists to end it.

Outcomes

  • Shipped and live at whopickedthis.app
  • Full bilingual support with realtime sync across every crew member
  • Roulette mechanic turns group indecision into a decision in one spin
  • Multi-tenant org model retrofitted onto the original single-crew schema without breaking existing users

Tech Stack

NX
RX
CVX
TW
SHDCN
TM
INTL
FM
RSD

Want to talk about this project or a similar problem?

Get in touch

Mohammad Al-Sadah · Case study