Golf Practice Plan
A 12-week structured golf practice tracker with cross-device sync and mobile-first UX.
The Problem
Existing golf apps track scores but not structured practice. I wanted a system that runs a weekly drill program, saves progress across devices without requiring an account, works perfectly on mobile, and costs nothing to run.
No app store, no backend server, no database subscription. Just a URL I open on my phone at the range.
What I Built
A mobile-first web app that runs a structured 12-week practice program with 26 drills across putting, chipping, approach play, and driving. Each drill has a goal, scoring type, and pass threshold. Progress is tracked per-session with a confirm workflow — you enter your number, tap the checkmark, and the result is logged.
Cross-device sync uses Cloudflare KV with a PIN-based model. On first visit, you set a practice PIN (e.g., mack2026). That PIN keys your progress in KV. Open the same URL on another device, enter the same PIN, and all your history loads instantly. No account, no OAuth, no email verification.
The app went from v1.0 to v4.2 in three days — four complete architectural rewrites driven by real usage at the driving range.
Architecture
┌─────────────────────────────────────────────────┐ │ Cloudflare Edge │ │ │ │ ┌──────────────────┐ ┌────────────────────┐ │ │ │ Workers (Hono) │───▶│ KV Namespace │ │ │ │ │ │ │ │ │ │ - TypeScript │ │ progress/[pin] │ │ │ │ - SSR HTML │ │ = [drills, hist] │ │ │ │ - API routes │ │ │ │ │ └──────────────────┘ └────────────────────┘ │ │ │ │ plan.macksportreport.com │ │ │ │ Client: │ │ - localStorage (offline fallback) │ │ - Debounced KV sync (500ms) │ │ - PIN stored in localStorage │ └─────────────────────────────────────────────────┘
Technical Deep Dive
Session Model
On page load, confirmed drills reset to made=0, confirmed=false (new session). Unconfirmed in-progress values survive page close. History entries always append — multiple sessions on the same day produce multiple rows. This means you can practice twice in a day and see both sessions in your history.
KV Merge Strategy
On load: fetch KV data, merge with local data. KV wins on conflict (it's the authoritative source), local fills gaps (for data saved offline). This simple rule handles all edge cases: phone dies mid-practice, switch devices, clear browser data — KV always has the truth.
PIN-Based Auth
Instead of OAuth or email verification, users set a PIN on first visit. The PIN becomes the KV key: progress/[pin]. It's stored in localStorage for zero-friction return visits. This is the right pattern for a personal tool — no signup flow, no password reset, no infrastructure. The tradeoff (PINs aren't secure) is acceptable for practice statistics.
Version History: v1 to v4.2 in 3 Days
- v1.0 — Basic drill list with local-only tracking. No sync.
- v3.0 — Full rewrite: progress tracking model, accuracy mode, history charts.
- v4.0 — Second rewrite: universal confirm flow for all 26 drills, session-based model.
- v4.2 — KV sync with PIN, offline fallback, merge strategy, sync status indicator.
Each version was driven by real usage at the driving range — v1's local-only storage failed when I switched phones, so v4.2 added KV sync. v3's auto-complete was frustrating when I wanted to edit, so v4 switched to explicit confirmation.
Cloudflare Products Used
Workers — Application runtime with Hono micro-framework. Routes, SSR, and API handlers in a single TypeScript file. Zero cold starts, instant deploys.
KV — Cross-device progress sync. Progress keyed by PIN, debounced writes (500ms), offline-tolerant merge on load. Sub-10ms reads globally.
Wrangler — Single-command deploy pipeline. wrangler deploy pushes to 300+ cities. No CI/CD, no Docker, no build pipeline.
What I Learned
- • Hono is the right micro-framework for Workers — lightweight, typed, zero magic, and the routing API maps directly to how you think about REST endpoints
- • PIN-based sync (instead of OAuth) is the right call for a personal tool — zero friction, all the cross-device benefit, acceptable security tradeoff for non-sensitive data
- • KV merge strategy on conflict: KV wins, local fills gaps — a simple rule that handles all edge cases without complex conflict resolution
- • Session model (confirmed vs in-progress) required careful state design — what persists vs what resets on load is a UX decision disguised as a data model question
Career Relevance
- • Real-world KV patterns for personal/SMB tools — most startups don't need a relational database for MVP state management
- • Zero-dependency TypeScript SSR demonstrates that Workers can replace an entire application backend without a framework
- • v1 to v4.2 in 3 days shows iteration velocity on the Cloudflare platform — from idea to global deployment in one command