Files
PinPoint-Golf/DEVELOPER_GUIDE.md
T

14 KiB
Raw Blame History

🛠️ PinPoint Golf — Developer & Architecture Guide

This guide is written for engineers looking to maintain, customize, or extend PinPoint Golf. It explains the full-stack architecture, user authentication flows, OAuth/SSO integration, database persistence, community benchmark mathematics, and outlines the prioritized roadmap of future features.


1. Project Directory Structure

.
├── server.ts                   # Full-stack Express server (API endpoints + Vite middleware / static files)
├── Dockerfile                  # Multi-stage production container build (Node.js -> Node.js Runner)
├── docker-compose.yaml         # Compose file with persistent volume and OAuth environment vars
├── .env.example                # Template for Google Maps, JWT, Google OAuth, and Authentik OIDC
├── index.html                  # HTML entry point with Plus Jakarta Sans & JetBrains Mono
├── package.json                # Dependencies, esbuild scripts, and npm scripts
├── vite.config.ts              # Vite 8 configuration with Tailwind v4 & path aliases
├── data/
│   └── pinpoint_db.json        # Atomic JSON persistent database (users, rounds, settings, courses)
├── src/
│   ├── main.tsx                # React root mount point
│   ├── App.tsx                 # Root coordinator, global state, persistence, sync & modal hubs
│   ├── index.css               # Tailwind CSS v4 setup & custom scrollbars
│   ├── context/
│   │   └── AuthContext.tsx     # User session state, JWT tokens, login, register, and SSO hooks
│   ├── types/
│   │   ├── golf.ts             # Core golf interfaces (Hole, Course, Round, Stats, GPS)
│   │   └── auth.ts             # User profiles, PublicGolferStats, CommunityComparison schemas
│   ├── data/
│   │   ├── courses.ts          # Default course presets (Pebble Cove, Pine Valley, St Andrews)
│   │   └── sampleRounds.ts     # Preloaded 18-hole demonstration round with full stats
│   ├── services/
│   │   ├── api.ts              # Full client HTTP client with Bearer auth headers
│   │   ├── golfApi.ts          # OpenGolfAPI client for searching 32,000+ public courses
│   │   └── weatherService.ts   # Open-Meteo Open Weather API client & GPS geolocation service
│   ├── server/
│   │   ├── db.ts               # Database manager (atomic file writes, seed golfers, user scoping)
│   │   ├── authMiddleware.ts   # JWT verification & request user injection
│   │   └── routes/
│   │       ├── authRoutes.ts   # Local register/login, user profile, settings, and SSO endpoints
│   │       ├── roundsRoutes.ts # Scoped rounds CRUD, sync-batch, and custom course endpoints
│   │       └── communityRoutes.ts # Global public leaderboard and comparative benchmark engine
│   ├── utils/
│   │   ├── golfStats.ts        # Pure statistical calculation engine & scoring formulas
│   │   ├── geoUtils.ts         # Haversine distance, bearings, green edges & hole auto-detect
│   │   └── achievements.ts     # Automated trophy & achievements evaluator (23 achievements)
│   └── components/
│       ├── Navbar.tsx          # 3-Zone top bar + user avatar profile dropdown + mobile tab bar
│       ├── AuthModal.tsx       # Tabbed modal: Local Auth (Email/Pass), Register, and SSO/Authentik
│       ├── CommunityComparisonModal.tsx # Head-to-head comparison cards & global public leaderboard
│       ├── HoleEntry.tsx       # Tactile on-course scoring UI with large touch hitboxes
│       ├── GolfGpsRangefinder.tsx # Google Maps satellite map + Front/Mid/Back digital HUD
│       ├── Scorecard.tsx       # Paper-style 18-hole digital scorecard with Out/In splits
│       ├── Analytics.tsx       # Performance dashboard (FIR radar, GIR misses, bunker saves)
│       ├── Settings.tsx        # Granular stat switchboard & 1-click tracking presets
│       ├── NewRoundModal.tsx   # Start round dialog with OpenGolfAPI search & tees
│       ├── CourseEditorModal.tsx # Builder to create new courses or duplicate existing ones
│       ├── RoundsHistoryModal.tsx # Round history, round switching, and CSV/text export
│       └── AchievementsModal.tsx # Trophy cabinet with tier filters and progress tracking

2. Authentication & Identity Architecture

PinPoint Golf supports dual-mode authentication:

  1. Local Authentication:
    • Passwords hashed with bcryptjs (salt rounds: 10).
    • Generates signed JWTs (30-day expiry) containing user id, email, and username.
    • Passwords and sensitive fields are stripped before transmitting user objects.
  2. OAuth & SSO Providers:
    • Google OAuth 2.0: Compatible with Google Identity Services. Configurable via GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.
    • Authentik (OIDC): Designed for homelab setups, enterprise Identity Providers, and Keycloak. Configurable via AUTHENTIK_ISSUER_URL, AUTHENTIK_CLIENT_ID, and AUTHENTIK_CLIENT_SECRET.
    • GitHub OAuth: Configurable via GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET.
    • Zero-Friction Test Mode: If external secrets are not yet provisioned in .env, the modal allows one-click instant testing using authentic golfer SSO credentials.

API Auth Endpoints:

Endpoint Method Auth Required Description
/api/auth/register POST No Create local account with email, username, password, handicap
/api/auth/login POST No Authenticate with email/username + password
/api/auth/me GET Bearer Retrieve profile and synchronized tracking settings
/api/auth/profile PUT Bearer Update name, handicap index, home club, avatar, or isPublic flag
/api/auth/settings GET/PUT Bearer Read or persist user tracking switchboard preferences
/api/auth/oauth/providers GET No Discovery endpoint for configured OAuth options
/api/auth/oauth/sso-login POST No Ingest OAuth token / SSO identity and return JWT

3. Persistent Database (data/pinpoint_db.json)

The datastore in src/server/db.ts uses atomic temp-file write-and-rename semantics (fs.renameSync) to ensure durability against crashes. In Docker, it mounts to the named volume pinpoint_data:/app/data.

Database Schema:

interface DatabaseSchema {
  users: Array<User & { passwordHash?: string }>;
  settings: Record<string, TrackingSettings>; // userId -> settings
  rounds: Record<string, Round[]>;            // userId -> rounds
  customCourses: Record<string, Course[]>;    // userId -> courses
  publicSeedGolfers: PublicGolferStats[];     // Seed public players for comparison
}

4. Community Benchmark & Public Comparison Engine

Users can toggle their profile between Public (default) and Private via the profile dropdown or the Community modal:

  • When isPublic: true, their rounds automatically compute into the global database metrics:
    • Scoring Average (18-hole stroke average)
    • FIR % (Fairways in Regulation)
    • GIR % (Greens in Regulation)
    • Putts Per Round (PPR)
    • Scramble % (Up & Down par saves after missing GIR)
    • Sand Save % (Greenside bunker par conversion)
    • Penalties Per Round (Strokes lost to hazards/OB)
  • The /api/community/compare endpoint calculates:
    • Global community averages across all public scorecards.
    • Handicap bracket averages: Scratch (< 5.0), Mid-Cap (5.0–15.0), and High-Cap (> 15.0).
    • Percentile rankings (0–100%) for each metric.
    • Automated coaching insights identifying the golfer's highest-leverage scoring improvements.

5. Real-Time Weather Forecast Integration (Open Weather API)

Before teeing off, golfers evaluate live environmental conditions—temperature, wind velocity, heading, and precipitation probability—to select appropriate clubs, prepare rain equipment, and adjust for air density effects on ball carry.

Architecture & Service Design (src/services/weatherService.ts)

  • Open Weather API Provider: Uses the Open-Meteo Meteorological API (https://api.open-meteo.com/v1/forecast), an open-source, non-commercial and commercial-ready meteorological service operated with Open Database License (ODbL).
  • Zero API-Key Requirement: Works out-of-the-box with zero paid subscription dependencies or API keys.
  • Dual Geolocation Resolution Strategy:
    1. Active Device GPS Position: Calls browser navigator.geolocation.getCurrentPosition with enableHighAccuracy: true to get the player's immediate physical coordinates.
    2. Course Location Fallback: If the player is planning a round indoors, has GPS disabled, or denies browser permission, the system automatically falls back to coordinates from the selected course's Hole 1 tee box or course center (e.g. Pebble Beach, Pine Valley, St Andrews).
    3. Seamless Toggle: Users can switch between [ 📍 My GPS ] and [ ⛳ Course GPS ] at any time with a 1-click refresh button.

Real-Time Weather Metrics Captured

Metric Unit API Parameter Relevance to Golf
Current Temperature °C (with °F converted) current.temperature_2m Ball compression and air density (colder air = less carry distance)
Feels-Like Temperature °C current.apparent_temperature Golfer comfort, layering, and thermal prep
Wind Speed km/h current.wind_speed_10m Club adjustment (rule of thumb: ~1 club per 15 km/h wind)
Wind Direction & Heading 16-point Compass (SW) + Degrees (0–360°) current.wind_direction_10m Aim lines and shot shaping (crosswind, headwind, tailwind)
Wind Intensity Category Calm / Breezy / Strong / Gusty Auto-classified based on speed Stored directly in Round summary for fast filtering
Precipitation Probability % (0–100) hourly.precipitation_probability Rain risk assessment and green speed (wet greens roll slower)
Weather Condition & WMO Code WMO 4677 code current.weather_code Mapped to UI icons (Sun, CloudSun, CloudRain, CloudLightning)
Relative Humidity % current.relative_humidity_2m Atmospheric moisture and swing comfort

Scorecard Persistence & Data Flow

When a player starts a new round via NewRoundModal:

  1. The forecast is automatically preloaded via GPS.
  2. The user can review the live weather card and make optional manual adjustments or notes.
  3. Upon clicking Tee Off, the full WeatherForecast object is attached to round.weatherData, and summary strings (weather and wind) are recorded.
  4. Saved rounds in Scorecard, RoundsHistoryModal, and exports reflect the actual weather encountered during the round.

6. How-To Guides for Extending the App

Guide A: Adding a New Tracked Stat (e.g. Approach Shot Club)

  1. Update Data Types (src/types/golf.ts): Add approachClub?: string to HoleScore and trackApproachClub: boolean to TrackingSettings.
  2. Update Settings Defaults (src/data/courses.ts): Set default in DEFAULT_TRACKING_SETTINGS.
  3. Add Toggle Switch (src/components/Settings.tsx): Add toggle under the relevant category.
  4. Add Input Controls (src/components/HoleEntry.tsx): Render input when settings.trackApproachClub is active.
  5. Scorecard & Analytics (Scorecard.tsx & golfStats.ts): Display row in scorecard and aggregate in round stats.

Guide B: Adding a New Achievement / Trophy

  1. Add definition in ALL_ACHIEVEMENTS in src/utils/achievements.ts.
  2. Add rule evaluation in evaluateAchievements().
  3. Add icon mapping in src/components/AchievementsModal.tsx.

7. 🎯 Wanted / Future Features Roadmap

Here is the prioritized list of planned future enhancements:

High Priority

  1. Strokes Gained (SG) Analytics Engine:
    • Compare shot performance against PGA Tour and scratch golfer baselines.
    • Categorize strokes gained into SG: Off-the-Tee (OTT), SG: Approach, SG: Around-the-Green (ARG), and SG: Putting.
  2. Official World Handicap System (WHS) Calculator:
    • Automatic calculation of Handicap Differential: \text{Differential} = \frac{113}{\text{Slope}} \times (\text{Adjusted Gross Score} - \text{Course Rating} - \text{PCC}).
    • Automatic 20-round scoring record maintaining the official index from the best 8 differentials.
  3. Multiplayer Live Round & Foursome Matchplay:
    • Real-time WebSockets synchronization so groups playing together can view live leaderboards, skins, match play, and stableford games hole-by-hole.

Medium Priority

  1. AI Caddie & Shot Recommender:
    • Based on user's logged club distances, live GPS yardage to the pin, wind speed, and elevation, automatically suggest club selection and target aim line.
  2. Ball Flight & Dispersion Heatmaps on GPS Green Overlays:
    • Plot approach shot landing spots visually on the satellite map green to detect left/right slice or pull patterns.
  3. Progressive Web App (PWA) Offline Service Worker:
    • Installable on iOS/Android home screens with offline caching for courses with no cellular reception.
  4. Apple Watch / Wear OS Companion App:
    • High-contrast wrist interface showing Bushnell-style Front/Center/Back yardages and quick 1-tap score increments.

Community & Social

  1. Golf Society & Tournament Director Mode:
    • Flight divisions (A/B/C), net and gross prizes, two-man scrambles, and printable tournament scorecards.
  2. Course Review & Condition Notes:
    • Golfer feedback on green speeds (Stimp reading), aerated greens notices, and course ratings.

8. Scripts Reference

# Start full-stack development server on port 3000
npm run dev

# Run TypeScript typechecks
npm run lint

# Build production bundle (client + server.cjs)
npm run build

# Clean temporary files
npm run clean