Commit Graph

138 Commits

Author SHA1 Message Date
Samuel Enocsson a6250eb76a fix: move custom layout fields to own row in tour creation form 2026-03-20 07:39:43 +01:00
Samuel Enocsson 38cc93bc1c feat: allow custom layouts when creating tours
Courses without scraped layouts can now be used in tours by entering
a layout name and par manually. The layout is saved to the database
for reuse. All courses are shown in the dropdown, not just those with
existing layouts.
2026-03-20 07:39:43 +01:00
Samuel Enocsson 2ccb018bdf feat: add async tour system
Players can create tours with selected courses/layouts and a date range.
Others join via a 6-character tour code, play the courses, and report
their total strokes. Live leaderboard with points and +/- par display.

Includes: database schema, model, service, routes, views, and styling.
2026-03-20 07:39:43 +01:00
Samuel Enocsson d567c4bca9 fix: upgrade Node 18 to 22 and fix Puppeteer compatibility
- Switch from Alpine to Debian slim for correct Chromium architecture
  (fixes ARM/Apple Silicon support)
- Upgrade Puppeteer 21 to 24, use system Chromium via PUPPETEER_EXECUTABLE_PATH
- Replace removed page.waitForTimeout() with setTimeout
- Set NODE_ENV=production in Dockerfile to prevent pino-pretty import
- Improve error logging with Pino's { err: error } pattern
- Add build: . to docker-compose for local development builds
2026-03-20 07:39:34 +01:00
shcizo 0b55aeb632 Merge pull request #3 from shcizo/release-please--branches--main--components--pdga-ratings
chore(main): release 1.0.0
2026-02-21 16:07:04 +01:00
github-actions[bot] 4ac26dfb94 chore(main): release 1.0.0 2026-02-21 15:06:19 +00:00
Samuel Enocsson 9bc71c7a37 chore: Re-trigger release-please 2026-02-21 16:05:57 +01:00
Samuel Enocsson 1163337163 chore: Trigger release-please after enabling PR permissions 2026-02-21 16:03:43 +01:00
Samuel Enocsson c7ecd231ff chore: Remove deprecated version key from docker-compose 2026-02-21 16:00:50 +01:00
Samuel Enocsson f0e68091c2 fix: Point docker-compose to GHCR image instead of local build 2026-02-21 16:00:31 +01:00
Samuel Enocsson 78cb2dc211 chore: Add CLAUDE.md project documentation 2026-02-21 15:57:48 +01:00
Samuel Enocsson 6ac32457a9 feat: Add Pino structured logging, release-please CI/CD and Docker pipeline
Replace all console.log/error with Pino logger (info/warn/error/debug/fatal)
for structured JSON logging in production and pretty-print in development.
Remove redundant header dumps and consolidate rate-limit logging.

Add GitHub Actions workflow with release-please for automated semver releases
and Docker build/push to GHCR on new releases.
2026-02-21 15:56:57 +01:00
Samuel Enocsson 371a398446 Modernize UI design with new color system, typography and layout
- Add sticky dark header with nav replacing inline text links
- Introduce CSS custom properties design system (colors, spacing, shadows)
- Use DM Sans + JetBrains Mono fonts replacing Arial
- Modernize tables with uppercase headers and subtle hover states
- Add gradient fill and rounded line to rating chart
- Unify card sections across players and courses pages
- Add backdrop blur to modals
- Clean up inline styles to use CSS variables
2026-02-19 09:12:04 +01:00
shcizo 2f73dddbd8 Merge pull request #2 from shcizo/refactor/modularize-htmx
Refactor: modularize server.js, add EJS/HTMX, stealth scraping
2026-02-19 09:01:13 +01:00
Samuel Enocsson bd33ac2901 Add puppeteer-extra stealth plugin to avoid headless browser detection
PDGA was blocking headless Chrome requests with ECONNRESET errors.
Using puppeteer-extra-plugin-stealth to mask headless browser
fingerprints (navigator.webdriver, chrome.runtime, plugins, etc).
2026-02-19 09:00:08 +01:00
Samuel Enocsson 7e5fa6cbf1 Add HTMX migration for server-rendered tables and lazy loading
- Add HTMX CDN to layout
- Replace client-side table rendering (displayRatings, displayCourses)
  with server-rendered EJS partials via hx-get
- Add server-side course search with debounced hx-trigger
- Lazy-load player history and course layouts via htmx.ajax()
- Render rating chart via htmx:afterSwap with data attributes
- Add partial routes: ratings-table, course-table, player-history,
  course-layouts
2026-02-19 08:29:56 +01:00
Samuel Enocsson 20bbdbbfcf Extract inline CSS/JS, add EJS templates with shared layout
- Extract CSS into public/css/{shared,players,courses}.css
- Extract JS into public/js/{chart,tooltips,progress,players,courses}.js
- Consolidate 5 duplicated tooltip blocks into setupTooltip() helper
- Add EJS view engine with layout partial and nav partial
- Convert HTML pages to EJS templates (index.ejs, courses.ejs)
- Add /courses route with redirect from /courses.html
- Remove old monolithic HTML files (1478 + 612 lines)
2026-02-18 22:32:03 +01:00
Samuel Enocsson 33a962e6b8 Refactor: split server.js monolith into modular architecture
Extract 3410-line server.js into 12 focused modules:
- src/db.js: database init and migrations
- src/models/{player,course}.js: DB helper functions
- src/scrapers/{browser,player-http,player-puppeteer,course-puppeteer}.js
- src/services/{player-service,rating-calculator}.js
- src/routes/{players,courses,pages}.js

Remove dead code: duplicate saveRatingHistoryToDB, legacy
getPlayerCompetitionRatings/getPredictedRating/getAllRatingsWithScraping,
unused getCourseFromDB/getLatestOfficialRoundDate/testPDGARateLimit,
legacy cache Map, and POST /api/predicted-rating route.

Consolidate 5 duplicated Puppeteer launch blocks into launchBrowser().
server.js is now 28 lines: imports, middleware, mount routers, bootstrap.
2026-02-18 22:20:58 +01:00
Samuel Enocsson 10d1f88a58 Add standard deviation display for predicted ratings
- Calculate and store standard deviation during rating prediction
- Add std_dev column to players database table
- Display standard deviation tooltip on hover over predicted rating
- Show rating range (±std_dev) tooltip on hover over current rating
- Update tooltips dynamically when ratings are refreshed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-14 17:48:21 +02:00
shcizo d46f045815 Merge pull request #1 from shcizo/feature/user-self-registration-and-rate-limits
Add user self-registration and implement rate limiting for predictions
2025-10-11 18:21:04 +02:00
Samuel Enocsson c88d092b36 Add user self-registration and implement rate limiting for predictions
Allow users to add themselves to the player database through a web form,
eliminating the need for manual pdga-numbers.txt updates. Implement 24-hour
rate limiting on prediction refreshes to prevent abuse while maintaining
reasonable update frequency.

Key changes:
- Add player self-registration with PDGA number lookup and confirmation
- Store predicted ratings in database for persistence across restarts
- Implement 24-hour rate limit on prediction refresh endpoint
- Make database the single source of truth (text file only for initial seed)
- Remove "Scrape All Layouts" bulk operation button
- Update "Load All" to refresh existing players instead of text file

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-11 18:20:03 +02:00
Samuel Enocsson 4cd00e35aa Add request locking, extended timeouts, and inactive layouts accordion
- Add request locking system to prevent concurrent scrapes of same course
- Extend HTTP timeouts (10-30 min) for long-running scraping operations
- Add comprehensive logging for layout parsing to debug silent failures
- Implement accordion UI to hide layouts not played within 365 days
- Return 409 status when scrape already in progress for a course
- Add visual indicators for active vs inactive layouts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 22:25:20 +02:00
shcizo 858143d149 Add course layouts scraping and rating calculation system
Features added:
- Course directory scraping with pagination for Swedish courses
- Layout scraping from course detail pages (AJAX tabs)
- Event results scraping to calculate layout ratings
- Mean rating calculation based on players who shot par
- Last played date tracking for each layout (extracted from event pages)
- Multi-event aggregation for accurate ratings across tournaments

Database:
- Added courses table (name, link, city, last_updated)
- Added layouts table (name, par, mean_rating, rating_count, last_played)
- Added database migrations for new columns
- Foreign key relationship between courses and layouts

API endpoints:
- POST /api/scrape-courses - scrape course directory
- POST /api/scrape-layouts/:courseId - scrape layouts and events (combined)
- POST /api/scrape-all-layouts - bulk scrape all courses
- POST /api/scrape-event-results/:courseId - process event results
- GET /api/courses - fetch all courses
- GET /api/layouts/:courseId - fetch layouts for course

UI:
- New courses.html page for course/layout management
- Expandable course rows showing layouts
- Display layout par, mean rating, and last played date
- Layouts sorted by most recently played (newest first)
- Individual and bulk scraping controls

Technical details:
- Date extraction using regex pattern matching from event pages
- Proper detection of division results in details/table.results structure
- Round score and rating extraction from td.round/td.round-rating pairs
- Course location from td.views-field-field-course-location

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-30 23:45:07 +02:00
Samuel Enocsson 8c3fa04925 Add debug information display for prediction calculations
- Modified calculatePredictedRating function to collect debug logs instead of console output
- Added debug modal UI with ? icon next to predicted ratings
- Updated API responses to include detailed calculation steps
- Fixed compatibility issue with competition property in round data
- Users can now see PDGA rules, filtering, outliers, and weighting details

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-08 12:07:46 +02:00
Samuel Enocsson 74bfb7bd88 Update README with comprehensive documentation of new features
- Document database-first architecture and automatic startup population
- Add Docker setup instructions and mobile-responsive UI features
- Include API endpoint documentation and technical architecture details
- Explain optimized PDGA scraping strategy and user-controlled refresh system
- Add performance, reliability, and Docker configuration sections

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-18 13:56:58 +02:00
Samuel Enocsson 765917d495 Add automatic database population from PDGA numbers file at startup
- Read pdga-numbers.txt at server startup and check for missing players
- Automatically scrape and populate any missing players into database
- Maintain respectful 2-second delays between PDGA requests
- Add comprehensive logging for population process
- Include new API endpoints for manual database population and status checking
- Ensure database is fully populated before server accepts requests

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-18 09:49:54 +02:00
Samuel Enocsson 1a5b3b9fb4 Implement database-first architecture with user-controlled refresh
- Make database the single source of truth (no automatic cache expiration)
- Page loads now instant: read ratings + predictions directly from DB
- Remove automatic PDGA scraping on page load for performance
- Only scrape PDGA when user explicitly clicks refresh icons
- Add getPlayerDataFromDB() for fast DB-only player loading
- Separate scrapePDGARating() for explicit refresh operations only
- Remove delays from page load path (DB reads don't need rate limiting)
- Skip players not in DB rather than auto-scraping on page load
- User controls data freshness via refresh buttons

Performance: Page loads ~5+ minutes → instant DB reads
User experience: Predictable, fast, user-controlled data freshness

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-18 09:34:03 +02:00
Samuel Enocsson 351a609f41 Optimize tournament scraping with smart /details + new tournaments approach
- Use /details page as baseline for official rating rounds (source of truth)
- Only scrape tournaments played AFTER latest official round from main page
- Dramatically reduce PDGA server load: ~50+ tournaments → ~2-5 tournaments
- Add getOptimizedPlayerRounds() for efficient round collection
- Add getNewTournamentRounds() for smart tournament filtering by date
- Reduce scraping delays: 2-3s → 0.5-1s (minimal tournaments to scrape)
- Improve prediction speed: ~5+ minutes → ~30-60 seconds
- Maintain accuracy with official PDGA rating calculation methodology

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-18 09:21:29 +02:00
Samuel Enocsson 23412a8ea3 Enhance prediction system with multi-day tournament support and auto-calculation
- Fix parseDate function to handle multi-day tournament formats (e.g., "2-Sep to 3-Sep-2023")
- Integrate PDGA update date simulation using 2nd Tuesday cutoffs for accurate predictions
- Calculate and display predictions automatically from database on page load
- Update rating calculation to use proper PDGA timing windows (12/24 months before update date)
- Improve date parsing regex to correctly extract start dates from tournament ranges
- Include updated player list in pdga-numbers.txt

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-13 09:04:44 +02:00
Samuel Enocsson ef3881a0ac Add mobile optimization and PDGA update date simulation
Mobile improvements:
- Responsive table layout with hidden columns on mobile
- Touch-friendly buttons and improved spacing
- Consolidated information display for small screens
- Mobile-specific CSS with media queries

PDGA rating simulation:
- Calculate next official PDGA update date (2nd Tuesday of each month)
- Filter tournaments to only include rounds before next update
- Simulate realistic rating predictions based on PDGA schedule
- Account for rolling 12-month window and round expiration

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-12 17:22:12 +02:00
Samuel Enocsson 2994f221f7 Add cache management and smart delay optimization
- Add subtle "clear cache" link (gear icon) in top-right corner
- Implement cache clearing endpoint with user feedback
- Fix delay logic to skip delays for cached data
- Only apply rate limiting delays when actually scraping fresh data
- Add cache size reporting when clearing cache
- Improve performance for repeat visits with cached data
- Maintain server-friendly rate limiting for fresh scrapes

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-12 17:04:14 +02:00
Samuel Enocsson 55188a8269 Implement official PDGA rating calculation methodology
- Update predicted rating algorithm to match PDGA rating guide
- Focus on tournaments from last 12 months only (improved accuracy)
- Add proper outlier exclusion: rounds >2.5 std dev below average
- Implement double weighting for most recent 25% of rounds (9+ rounds)
- Apply PDGA minimum data requirements (7 rounds for outlier exclusion)
- Improve error handling and rate limiting for tournament scraping
- Add user-friendly error messages for failed calculations
- Reduce tournament scraping from 15 to 8 tournaments to avoid rate limits

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-12 16:58:00 +02:00
Samuel Enocsson af54b30c6c Add comprehensive caching for performance optimization
- Cache predicted rating calculations (24 hour duration)
- Cache rating history data to avoid repeated scraping
- Implement separate cache keys for different data types
- Add cache hit logging for monitoring effectiveness
- Update PDGA numbers list with additional players
- Significantly improve performance for repeat visitors
- Reduce load on PDGA servers with intelligent caching

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-12 16:34:36 +02:00
Samuel Enocsson 2ab4869fb9 Add expandable rating history charts with interactive tooltips
- Implement clickable player rows to expand/collapse rating history
- Add rating history scraping from PDGA history pages
- Create custom SVG line charts showing rating progression over time
- Add interactive tooltips with date and rating on hover
- Include visual highlights when hovering over data points
- Implement anti-flicker tooltip system with delayed hiding
- Add large hover areas (12px radius) for better user experience
- Show grid lines, axis labels, and responsive chart scaling
- Cache rating history data to avoid repeated API calls

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-12 12:40:15 +02:00
Samuel Enocsson 2d55651f43 Add real-time progress bar for rating loading
- Implement Server-Sent Events for live progress updates
- Add animated progress bar with percentage display
- Show real-time status: current player being loaded
- Display player names as they complete loading
- Handle errors gracefully with progress continuation
- Replace HTTP-only approach for better reliability
- Enhanced user experience with visual feedback

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-12 11:51:51 +02:00
Samuel Enocsson 2528bc4b5d Improve UI: remove refresh button and add PDGA profile links
- Remove unnecessary refresh button that only returned cached data
- Change button text from "Calculate Approx Rating" to "Predict Rating"
- Make player names clickable links to their PDGA profile pages
- Add link styling with hover effects

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-12 11:38:55 +02:00
Samuel Enocsson 8e07dc6c73 Add Docker support and fix rating change extraction
- Add Dockerfile with optimized Puppeteer configuration for containers
- Add .dockerignore for efficient builds
- Fix rating change regex to match actual PDGA format (no brackets)
- Update Puppeteer launch args for Docker compatibility
- Use new headless mode to resolve deprecation warning

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-12 11:20:51 +02:00
Samuel Enocsson deb162dc13 Initial commit: PDGA rating scraper and predictor
- Web scraping app for PDGA player ratings
- Current rating extraction from player pages
- Tournament round rating scraping for predictions
- Statistical rating prediction algorithm
- Interactive table with on-demand calculations
- Caching for performance optimization

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-12 11:13:13 +02:00