Case Study
Dice Cat: Tabletop Gaming Matchmaking App
Scale
1,413
Commits
~72,300
Lines of TypeScript
87
React components
10,000+
Games in the database
86
SQL schema files
<500 ms
Match query time (from 3-5 s)
The Problem
Tabletop gamers accumulate large collections and strong preferences, but finding local players who own the same games, have overlapping schedules, and match on play style is genuinely hard. Existing options - Facebook groups, Discord servers, Meetup - require manual coordination and have no game library matching.
The core ask: build something like Tinder for board games that actually knows your library.
Overview
The product started as "Meeplr" - a UX concept with substantial research before a line of code was written.
- ·Competitive analysis of existing community and matchmaking tools
- ·User persona development - a relocated gamer with no local gaming group
- ·Three rounds of think-aloud usability testing with 15 participants
- ·Kano analysis: all planned MVP features tested as performative or attractive
- ·Renamed to Dice Cat after trademark research blocked the original name - improved recall in testing
Key Features
- ·Multi-dimensional matching: game libraries, geographic proximity, schedule overlap, and play style preferences
- ·10,000+ game database with local fuzzy search and manual addition capability
- ·Visual weekly schedule builder with overlap detection across potential matches
- ·Connection request system with mutual matching before messaging
- ·Encrypted in-app messaging for session planning
- ·Push notifications via Firebase Cloud Messaging
- ·Custom SVG avatar builder with layered component system
- ·Nearby players map view via PostGIS geospatial queries
Screenshots
Technical Architecture
Technical Highlights
Database performance
Multi-table JOIN queries for match scoring originally ran at 3-5 seconds. Strategic PostGIS indexing and query restructuring brought them under 500ms.
External API dependency failure
BoardGameGeek discontinued API access mid-development. Pivoted to building a local 10,000+ game database with community-sourced additions - better offline behavior and no future dependency risk.
Push notification permission architecture
A trigger-based approach encountered permission errors in production. Migrated the logic to Supabase Edge Functions, which resolved the permission context problem cleanly.
What I Learned
A matchmaking app is judged on whether people message each other, which turns out to be a different target from whether the matching is correct.
A compatibility score is a product decision, not a calculation
Users reported that scores sat consistently under 20%, and the effect was that nobody felt encouraged to reach out. The maths was defensible; the product was failing anyway. Rebalancing the bases and weights, so a good match reads 76% rather than 65% while weak matches still read clearly weaker, changed behaviour without changing the ranking. A score shown to a person is an invitation, not a measurement, and it has to be calibrated for the decision it is asking them to make.
Fetch-everything works until somebody is a heavy user
Conversations with over a thousand messages took about ten seconds to open. Loading the hundred most recent in descending order and reversing them for display brought that under a second, and changed nothing for short conversations. The query was fine on every account that existed when it was written, which is exactly why this class of problem ships.
A required field that is not universally required
Profile validation demanded a location from everyone, including players who only play online and have no use for one, so a whole category of user could not finish signing up. Making location conditional on the play preferences, and saying which case applies in the label rather than in a note, fixed both the block and the confusion behind it.