This commit adds comprehensive GPX file support alongside existing FIT file support, enabling users to import activities from Strava, Komoot, and other GPS apps.
## Key Features
### Core Components
- **GpxParser**: Full GPX 1.1 parsing with Garmin TrackPointExtension support
- **GpxFileValidator**: Validation for GPX file format and structure
- **ActivityFileService**: Unified service with automatic format detection (FIT/GPX)
- **ParsedActivityData**: Common data structure for both FIT and GPX files
### GPX Parsing Capabilities
- GPS track point extraction (latitude, longitude, elevation, timestamp)
- Garmin extension data (heart rate, cadence, temperature)
- Activity type detection from GPX metadata
- Distance calculation using Haversine formula
- Elevation gain/loss calculation
- Speed calculation from consecutive GPS points
- Speed smoothing to remove GPS artifacts
- Timezone detection from GPS coordinates
- Moving time vs. stopped time analysis
### Database Changes
- Migration V15: Renamed raw_fit_file → raw_activity_file
- Added source_file_format column (FIT/GPX) with constraint
- Index on source_file_format for performance
- Updated Activity entity with new fields
### Controller & UI Updates
- ActivityController: Now handles both FIT and GPX uploads
- Upload form: Updated to accept .fit and .gpx files
- Help text: Clarified both formats are supported
### Testing
- GpxParserIntegrationTest: 9 comprehensive tests with real GPX file
- Tests cover: parsing, validation, heart rate extraction, distance calculation,
elevation metrics, speed calculation, chronological ordering, smoothing
- Fixed TrainingLoadServiceTest date issue (testDate outside 30-day window)
- All 97 unit tests passing (integration tests require Docker)
### Technical Details
- Supports GPX 1.0 and 1.1 specifications
- Handles multiple track segments
- Processes Garmin TrackPointExtension v1 and v2
- Same track simplification as FIT (Douglas-Peucker algorithm)
- Consistent JSONB storage format for track points
- Compatible with existing analytics, heatmaps, and image generation
## Testing Summary
- ✅ 9/9 GpxParserIntegrationTest tests passing
- ✅ 4/4 FitParserIntegrationTest tests passing
- ✅ 14/14 FitFileServiceTest tests passing
- ✅ 97/97 total unit tests passing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Added rebuild button to heatmap page with loading states
- Added POST /api/heatmap/me/rebuild endpoint for on-demand recalculation
- Removed HeatmapRecalculationScheduler (nightly 3 AM cron job)
- Removed @EnableScheduling annotation since no schedulers remain
- Users can now rebuild their heatmap manually instead of relying on automatic nightly recalculation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remove the registration UI page completely and use the public timeline as the default start page.
Changes:
- Delete auth/register.html template
- Remove /register route from AuthViewController
- Update HomeController to redirect / to /timeline
- Remove /register from public paths list in auth.js
Users will no longer see a registration option in the UI. Registration can only be done via direct API calls if enabled.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement configurable registration control to allow administrators to disable new user signups.
Backend changes:
- Add fitpub.registration.enabled configuration property (defaults to true)
- Update AuthController to check registration status and return 403 Forbidden when disabled
- Create GET /api/auth/registration-status endpoint to expose registration status to frontend
- Add RegistrationStatusResponse DTO
Configuration changes:
- Add REGISTRATION_ENABLED environment variable to application.yml
- Add REGISTRATION_ENABLED to Dockerfile with default value of true
- Update .env.example with REGISTRATION_ENABLED documentation
Frontend changes:
- Update registration page to check status and hide form when disabled
- Add checkRegistrationStatus() to auth.js to dynamically hide registration links
- Display user-friendly message when registration is disabled
To disable registration, set environment variable: REGISTRATION_ENABLED=false
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>