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>
- 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>
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>