Nine pubs, one shared card. A mobile-first PWA for playing pub golf on real phones in real pubs: the host opens a round, everyone else joins with a four-letter code and no account, and scores, penalties and a synced hole timer stay live on every phone.
$ render article.mdx
Search glyn.dev
Search posts, research, projects and tags, or jump to a page.
Pub golf is nine pubs, one drink per hole, and every swallow counted as a
stroke. Lowest total wins. It runs on a paper card, which works right up
until someone loses theirs and nobody can agree what happened at hole four.
The format is not mine; I built the round out of versions I found online and
printed a card for the day. This is the version that keeps itself honest.
One host signs in with Google and opens a round. Everyone else joins with a
four-letter code and a name, backed by Supabase anonymous auth, so there is
no account, no email, and nothing to install. Guests can claim their card
with Google afterwards and keep every round already on it.
The card is shared and live. Scores, penalties and the hole timer land on
every phone in the round as they happen. The timer is a single
hole_deadline_at timestamp that each client counts down to locally, with a
separate walking phase between pubs, so when the group falls behind you
change one row and nine phones agree.
The scoreboard is the whole point, so it cannot live in the client. Every
write goes through row-level security and triggers scoped to the caller's own
session, which means the rules hold even against a hand-rolled client rather
than the app's UI. The adversarial suite in tests/db/ is what proves it.
House rules ride on a snapshot of the round's ruleset: penalties, mulligans
and handicaps are captured when the round starts, so changing the presets
later cannot rewrite a game already in progress. The board shows gross and
net, and net is what the round is won on.
The host can promote a caddy to full controls (tee off, rewind, reset the
timer), and any official can roam the marker's card to fix a hole without
moving the round on. Someone always needs to correct hole three while
standing outside hole five.
Four tiers, each rule held at the lowest layer that can hold it: pure logic
in Vitest, RLS and triggers driven through PostgREST with per-role clients,
the same tier again at full-table scale, and Playwright playing complete
multi-phone rounds on Android Chrome, iOS Safari and desktop Firefox.