Scorecard Party

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

Status
In testingRelease builds prepared for the App Store (first signed archive 1.0.1 in July 2026; repo now at 1.0.8). The web landing page and spectator leaderboard are live; not yet public on the App Store or Google Play.
Platforms
iOS, Android, Web
Role
Solo: product, design, Flutter app, Firebase backend, data pipeline, store and marketing assets
Timeline
Jun 2026 – Jul 202650 commits
Version
1.0.8 (build 14) in repo; 1.0.1 (build 2) was the first signed App Store archive

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

A 30-second commercial for the app.

02 What it does

  1. 01

    Live group scorecard: score everyone from one phone or let a friend co-score, with putts, fairways and greens in regulation

  2. 02

    Nine side games (Skins, Nassau, Match Play, Stableford, Best Ball, Vegas, Wolf, Bingo Bango Bongo, Snake) with automatic settle-up

  3. 03

    GPS rangefinder on satellite imagery with front, center and back distances, hole overlays and shot tracking for 16,845 U.S. courses

  4. 04

    Events and leagues: join by code or QR, flights and divisions, multi-round standings, tee sheets and a front-desk check-in kiosk

  5. 05

    Web spectator leaderboard that anyone can open in a browser, with no app or account

  6. 06

    Scan a printed scorecard to set up pars, handicaps, tees, ratings, slopes and yardages

  7. 07

    Stats with a WHS-style handicap index, scoring breakdown, trends and achievement badges

  8. 08

    Crews with group chat, smack talk, and lead-change and announcement push notifications

03 How it's built

AppFlutter app (iOS / Android)
Outside serviceOpenGolfAPI + OSM import pipeline
AppWeb spectator leaderboard + host pages
ServiceFirebase Auth
ServiceCloud Functions
DataPMTiles course overlays (Cloud Storage)
DataCloud Firestore
ServiceFirebase Cloud Messaging
ModelGemini on Vertex AI

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.