# πŸ› οΈ 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: ```typescript interface DatabaseSchema { users: Array; settings: Record; // userId -> settings rounds: Record; // userId -> rounds customCourses: Record; // 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 4. **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. 5. **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. 6. **Progressive Web App (PWA) Offline Service Worker**: - Installable on iOS/Android home screens with offline caching for courses with no cellular reception. 7. **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 8. **Golf Society & Tournament Director Mode**: - Flight divisions (A/B/C), net and gross prizes, two-man scrambles, and printable tournament scorecards. 9. **Course Review & Condition Notes**: - Golfer feedback on green speeds (Stimp reading), aerated greens notices, and course ratings. --- ## 8. Scripts Reference ```bash # 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 ``` --- ## 9. Clean Deployment & Data Integrity Rules To guarantee enterprise-grade data hygiene and tour-level integrity, PinPoint Golf enforces strict separation between development testing and production deployment: ### 1. Mock Data Elimination in Production - **Server Store**: In production (`NODE_ENV=production` or `ENABLE_MOCK_DATA!=true`), the database manager `src/server/db.ts` suppresses demo accounts (`usr_demo_golfer`) and seeded community golfers (`user_seed_*`). Only real registered users and scorecards exist. - **Client App**: The client initializes rounds state to an empty list `[]` instead of pre-seeding `SAMPLE_ROUND`. The "Load Dev Sample Round" button is stripped in production builds (`import.meta.env.PROD`). ### 2. Authentication-Gated Features The following features are exclusively unlocked for registered golfers: - **Community Benchmarks & Leaderboards**: Public comparison of handicap, FIR%, GIR%, putts, and scrambles against peers. - **Career Achievements & Trophies**: 22 tier-ranked achievements across scoring, accuracy, and short game. - **Satellite GPS Rangefinder**: Real-time Google Maps satellite flyover, Front/Center/Back green distance calculation, pin targeting, and shot distance measurement. - *Guests & Unauthenticated Users*: Can start rounds, view course scorecards, and check local play, but receive clear in-app prompts to sign in or create a free account to unlock GPS, community leaderboards, and trophies. ### 3. Achievement Lifecycle Rules - **Empty Initial State**: New registered users start with zero achievements unlocked (`unlockedIds: []`). - **Finalization Requirement**: Achievements are never awarded during live play; they are evaluated and awarded **strictly upon finishing and saving a completed round** (`isCompleted: true`). ### 4. Round Immutability & Deletion Workflow - **Confirmation Modal**: Clicking "Finalize & Save Round" triggers `SaveRoundModal`, showing a complete scoring summary and an explicit warning that the round will be permanently locked. - **Post-Save Immutability**: Once saved (`isCompleted: true`), hole scores and statistical inputs are locked against modification. - **Deletion Only**: The only permitted post-save action on a finalized round is deletion from the golfer's history with confirmation.