Building the bill-splitter I actually needed for a padel group
Every padel session ends the same way: someone paid for the court, someone grabbed drinks after, and now four people are doing rough mental math about who owes what. It's a small tax on every single session, and it's exactly the kind of friction PlayTab exists to remove — so rather than tell people to go split it in a separate app, PlayTab has its own Splitwise-style expense splitter built in. One app for who's playing, and one app for what everyone owes each other afterward.
What it actually does
A group holds members — some with real PlayTab accounts, some just typed in as guests until they claim their own spot — and expenses logged against it, split equally or by a custom ratio, across whichever of the group's members were actually in on that particular cost. Settle Up does the arithmetic nobody wants to do by hand and tells you exactly who owes whom.
Court fees plus drinks split three ways lands as two people each owing their share back to whoever fronted it — that's the whole feature, working exactly the way the group actually used it, not a demo case built to look nice in a screenshot.
What I deliberately built in
One control exists on purpose, off by default: a group's creator can flip a switch that restricts adding, editing, or deleting expenses to themselves alone. Most groups never touch it — a casual padel group doesn't need a gatekeeper. But the option is there for the group that's had one flaky edit too many, without forcing every group through an admin layer it doesn't want.
The bug that had already been fixed three times over, on the tables next to it
Deleting an account is supposed to clean up cleanly after itself: if you're the sole member of a group, the whole group and its history goes with you. That worked, until it didn't — for one specific, narrow case. An account that solely owned an expense group that already had at least one settled-up debt in it would fail to delete, with a foreign key violation pointing at the expense group table itself.
The actual defect was almost invisible sitting next to the tables that had it right. Three sibling tables tied to an expense group — expenses, expense group members, and one more — all explicitly declared that deleting the parent group should cascade down and take them with it. One table, holding settlement records, was written as a bare reference with no cascade rule at all, which quietly defaults to blocking the delete instead of following it. Three tables agreeing on the rule made the fourth look correct by proximity. It wasn't; it just hadn't been tested against an account that owned a group with a real settlement in it yet.
The fix is a one-line migration — add the missing cascade clause so all four tables finally agree. The habit worth keeping is the check, not the fix: any time a new table hangs a foreign key off a group table that already has siblings doing the same thing, explicitly compare the delete rule against theirs instead of assuming a bare reference defaults to something sensible. It doesn't. It defaults to blocking, silently, until the one path that exercises it finally shows up.
A smaller lesson, caught by just using it
Not every fix here came from an audit. The Delete Group button used to sit at the bottom of the group's expense list — reasonable, until that list is genuinely long, at which point the one destructive action in the whole screen is buried under a scroll a user has no reason to expect it's hiding behind. It's pinned as a sticky footer outside the scrolling content now, on this screen and everywhere else a destructive action exists in the app. Small compared to a foreign key constraint, but it's the kind of thing that never shows up until someone actually has enough expenses logged to have to scroll for it — which is exactly the account that matters most.
The honest takeaway
A round-robin scheduler and a bill-splitter sound like two different apps bolted together, and in a sense they are. But they came from the same instinct: notice the small, recurring friction a group of friends deals with every time they get together, and fold it into the one app they already have open, instead of asking them to remember a second one. The scheduling half decides who plays whom. The splitting half decides who owes whom. Neither one needed to exist outside the other.
More in this series

Why I built MyPlayTab
A scoring artifact I lost by clicking back turned into the design question this whole app answers.

Who gets to score the match? Keeping every court in sync on PlayTab
Multiple courts, multiple phones, one score that's always right — and the bug that taught me an "obviously unique" sort wasn't.

One rule, forty AI sessions: how PlayTab stayed one app instead of several
A header color got reverted because a technically-correct fix looked worse. That's the point, not a mistake.

The login bug that only hit people who'd already logged in before
A real account got bounced back to onboarding as if it had never been set up. It only ever happened mid-login, never after.