Skip to content

feat: Strava Integration (OAuth, Jobs, UI)#114

Merged
0jonjo merged 15 commits into
mainfrom
feat/strava-sync-v0.1.38
Jul 18, 2026
Merged

feat: Strava Integration (OAuth, Jobs, UI)#114
0jonjo merged 15 commits into
mainfrom
feat/strava-sync-v0.1.38

Conversation

@0jonjo

@0jonjo 0jonjo commented Jul 11, 2026

Copy link
Copy Markdown
Owner

What does this PR do?

Introduces a fully featured, robust, and lightweight integration with the Strava API to automatically sync athletes' activities into Calcpace Web, extracting vital data and estimating VO2 Max natively.

Technical Highlights 🚀

This implementation intentionally avoids bloated third-party gems, favoring a lean, native Rails approach with several architectural highlights:

  • Security First: OAuth access tokens and refresh tokens are encrypted at rest using Rails 7 ActiveRecord::Encryption.
  • Zero-Bloat API Client: Built a custom Strava::Client wrapping Net::HTTP to handle OAuth flow, token refreshing, and paginated data fetching without external dependencies.
  • Resilient Background Sync: Implemented StravaSyncJob via ActiveJob/SolidQueue. It paginates up to 2,000 historical runs per sync, gracefully handling API rate limits, HTTP errors, and token expirations in the background.
  • Database Optimization (Polylines): Instead of parsing and storing thousands of GPS trackpoints per run (which inflates DB size exponentially), the app extracts Strava's summary_polyline. This encrypted string is saved in a single text column and decoded seamlessly via JavaScript on the frontend using Leaflet, delivering high-performance maps with zero storage overhead.
  • Smart Activity Importer: The Strava::ActivityImporter enforces single responsibility. It filters out non-running activities (supports Run, TrailRun, Walk), deduplicates by external_id, and maps distance/time/elevation/HR directly to the Calcpace engine for automatic VO2 Max estimation.
  • Real-time Webhooks Ready: Established the foundation for Strava Webhooks (StravaWebhooksController) with challenge validation and async job triggering, ensuring the app is ready for real-time push events.

Changes

  • db/migrate: Added StravaAccount table (with encrypted tokens) and map_polyline to activities.
  • app/models: Added StravaAccount model and updated Activity.log.
  • app/lib/strava: Created Client and ActivityImporter.
  • app/jobs: Added StravaSyncJob.
  • app/controllers: Added StravaAccountsController (OAuth callback) and StravaWebhooksController.
  • app/views: Added Connect/Disconnect UI in accounts/show using jet_ui and implemented JS Polyline decoding in _map.html.erb.

Testing

  • 100% Test Coverage: All scenarios tested using WebMock to simulate Strava API responses, token expirations, and webhook challenge validations.

How to test manually

  1. Start the server: bin/dev
  2. Navigate to Settings > Account.
  3. Click Connect with Strava and authorize the application.
  4. Observe the background job syncing activities.
  5. View an imported activity to see the generated metrics and the rendered Leaflet map.

Copilot AI review requested due to automatic review settings July 11, 2026 19:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@0jonjo
0jonjo merged commit c806ba1 into main Jul 18, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants