Scorecard Party
Golf scoring, side games and live leaderboards for the whole group







01 The story
A Flutter golf app for iOS and Android that keeps score for the whole group, runs side games like Skins, Nassau and Wolf, and works out who owes whom. Hosts run leagues and tournaments with a join code, and anyone can follow the live leaderboard in a browser with no app or account.
Scorecard Party came from a familiar scene on the course: one person keeps the card, someone else tries to remember the bets, and nobody agrees on who owes what at the end. The app puts the whole group on one live scorecard, scores the side games as you go, and settles up automatically.
On the course it's a fast hole-by-hole scorecard with putts, fairways and greens, net and gross scoring with handicaps, and a satellite GPS rangefinder with front, center and back distances. Nine side games update live, even when added mid-round, and settle-up produces the fewest transfers needed, with IOUs you can mark paid later. Off the course, hosts create leagues, outings, scrambles or tournaments, share a six-character code or QR invite, split the field into flights, publish tee sheets and run a front-desk check-in kiosk. Spectators open the same leaderboard on the web without signing in.
The course data was its own project. 16,845 U.S. courses with per-hole pars, handicaps and tee yardages come from the OpenGolfAPI dataset. Greens, fairways, bunkers and water are bulk-extracted from OpenStreetMap, tagged to the nearest course and packed into one self-hosted PMTiles vector-tile file (about 470 MB) that flutter_map draws over satellite imagery. Leaderboards are aggregated server-side in Cloud Functions by a port of the Dart scoring code, and tests pin both implementations to the same cases so they always agree.
It's Flutter with Riverpod and go_router on Firebase: Auth, offline-first Firestore, Storage, Messaging and Crashlytics, plus Node Cloud Functions for join codes, push, account deletion and a scorecard scanner that reads a photo of a printed card with Gemini. I went from first commit to App Store submission prep in about three weeks (June 29 to July 19, 2026), including a security pass on Firestore rules and callable functions, store copy, designed screenshots and a scripted 30-second commercial. The web landing page and spectator leaderboard are live; the App Store listing isn't public yet.
▶ Film
02 What it does
- 01
Live group scorecard: score everyone from one phone or let a friend co-score, with putts, fairways and greens in regulation
- 02
Nine side games (Skins, Nassau, Match Play, Stableford, Best Ball, Vegas, Wolf, Bingo Bango Bongo, Snake) with automatic settle-up
- 03
GPS rangefinder on satellite imagery with front, center and back distances, hole overlays and shot tracking for 16,845 U.S. courses
- 04
Events and leagues: join by code or QR, flights and divisions, multi-round standings, tee sheets and a front-desk check-in kiosk
- 05
Web spectator leaderboard that anyone can open in a browser, with no app or account
- 06
Scan a printed scorecard to set up pars, handicaps, tees, ratings, slopes and yardages
- 07
Stats with a WHS-style handicap index, scoring breakdown, trends and achievement badges
- 08
Crews with group chat, smack talk, and lead-change and announcement push notifications
03 How it's built
The app writes rounds and event scores to Firestore; Cloud Functions mirror them into server-side leaderboards that both the app and the no-login web page read in real time. Course data and map overlays are imported once and self-hosted rather than called from third-party APIs at request time.
All 10 connections, as text
- Flutter app (iOS / Android) → Firebase Auth: sign in / guest
- Flutter app (iOS / Android) → Cloud Firestore: rounds, events, games (offline-first)
- Web spectator leaderboard + host pages → Cloud Firestore: read live leaderboard
- Flutter app (iOS / Android) → Cloud Functions: join codes, scan, delete account
- Cloud Functions → Cloud Firestore: aggregate leaderboards
- Cloud Functions → Firebase Cloud Messaging: announcements, smack talk
- Cloud Functions → Gemini on Vertex AI: scorecard photos
- Flutter app (iOS / Android) → PMTiles course overlays (Cloud Storage): hole overlays
- OpenGolfAPI + OSM import pipeline → Cloud Firestore: one-time course import
- OpenGolfAPI + OSM import pipeline → PMTiles course overlays (Cloud Storage): OSM geometry to PMTiles
04 Engineering notes
Course pipeline: 16,845 U.S. courses with per-hole pars, handicaps and tee yardages from OpenGolfAPI, plus OSM golf geometry bulk-extracted, tagged to the nearest course and packed into a self-hosted PMTiles file (about 470 MB)
Side-game engine in Dart covering nine formats, with a greedy minimal-transfer algorithm that nets zero-sum balances into the fewest payments
Leaderboards aggregated server-side in Cloud Functions as a port of the Dart scoring code; tests pin both implementations to the same cases, so client fallback and server always agree
Scorecard scanning: a callable function sends photos of a printed card to Gemini 2.5 Flash on Vertex AI and returns structured holes and tees for review; a scheduled job deletes scan photos after 30 days
Security pass before release: closed profile enumeration and global crew-chat reads in Firestore rules, moved join-code and co-admin lookups into rate-limited server callables, and added in-app account deletion
69 Flutter tests and 6 Cloud Functions tests at the July 2026 release audit; ads and a Pro tier are coded but fail closed unless production IDs are supplied
05 By the numbers
- 16,845
- U.S. courses loaded
- 9
- Side-game formats
- 69 Flutter + 6 Cloud Functions
- Automated tests at the release audit
- About 3 weeks
- From first commit to App Store prep
06 Stack
App
- Flutter
- Dart
- Riverpod
- go_router
- flutter_map
- vector_map_tiles (PMTiles)
- geolocator
- fl_chart
- mobile_scanner / qr_flutter
Backend
- Firebase Auth (email, Google, Apple, anonymous)
- Cloud Firestore
- Cloud Functions (Node 22)
- Firebase Cloud Messaging
- Firebase Storage
- Gemini 2.5 Flash via Vertex AI (scorecard scanning)
Data
- OpenGolfAPI course dataset (16,845 U.S. courses, ODbL)
- OpenStreetMap golf geometry
- PMTiles on Google Cloud Storage
- Esri World Imagery satellite basemap
Infrastructure
- Firebase Hosting (web landing page and spectator leaderboard)
- Crashlytics
- Remote Config
Tooling
- Node Firestore importers
- Python data scripts
- Node store-panel generator
- scripted commercial render (ffmpeg, synthesized music, macOS voiceover)
Lines of code (approx.)
- Dart27,797
- JavaScript2,325
- HTML2,011
- Firestore rules353
- Python168
- Shell139
≈ 32,793 lines
Repositories
- scorecard-partyprivate
All 50 commits are on main (a codex/demo-tournament-ux branch holds a subset). The course-data pipeline on the SSD (opengolf-data) is dated 2026-06-26, three days before the first app commit.