{"id":51490459,"url":"https://github.com/dettinjo/routepass","last_synced_at":"2026-07-07T11:30:25.936Z","repository":{"id":369750587,"uuid":"1211418735","full_name":"dettinjo/routepass","owner":"dettinjo","description":"Sync hub for fitness platforms — route activities between Strava, Komoot, Garmin, Intervals.icu and more via configurable pipelines and rules.","archived":false,"fork":false,"pushed_at":"2026-07-06T20:05:33.000Z","size":1558,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-06T20:11:23.182Z","etag":null,"topics":["automation","coolify","docker","fastapi","fitness-tracker","gpx","komoot","nextjs","portfolio","python","self-hosted","strava","strava-api","sync","typescript"],"latest_commit_sha":null,"homepage":"https://routepass.online","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dettinjo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-15T11:25:34.000Z","updated_at":"2026-07-06T20:05:53.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dettinjo/routepass","commit_stats":null,"previous_names":["dettinjo/routepass"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/dettinjo/routepass","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dettinjo%2Froutepass","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dettinjo%2Froutepass/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dettinjo%2Froutepass/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dettinjo%2Froutepass/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dettinjo","download_url":"https://codeload.github.com/dettinjo/routepass/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dettinjo%2Froutepass/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35226916,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-07T02:00:07.222Z","response_time":90,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","coolify","docker","fastapi","fitness-tracker","gpx","komoot","nextjs","portfolio","python","self-hosted","strava","strava-api","sync","typescript"],"created_at":"2026-07-07T11:30:23.639Z","updated_at":"2026-07-07T11:30:25.931Z","avatar_url":"https://github.com/dettinjo.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RoutePass\n\n\u003c!-- portfolio:date=2026-04-15 --\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/logo.svg\" alt=\"RoutePass logo\" width=\"160\" /\u003e\n\u003c/p\u003e\n\n## Overview\n\nRoutePass is a sync hub for fitness platforms — connect Strava, Komoot, Garmin, Intervals.icu, and more, then define pipelines that route every new activity from any source to any destination automatically. Every platform is a peer: the same activity can fan out to several destinations, or several sources can funnel into one, with per-pipeline rules (sport type, distance, elevation, name) deciding what gets transformed, renamed, or skipped along the way.\n\nIt grew out of a much narrower tool — a single-purpose Komoot→Strava sync script — into a multi-tenant FastAPI backend with a Next.js dashboard, async background workers, and a rule engine that treats \"source\" and \"destination\" as interchangeable roles rather than fixed directions.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/screenshots/landing.png\" width=\"32%\" /\u003e\n  \u003cimg src=\"docs/screenshots/integrations.png\" width=\"32%\" /\u003e\n  \u003cimg src=\"docs/screenshots/login.png\" width=\"32%\" /\u003e\n\u003c/p\u003e\n\n## Features\n\n- **Any source, any destination** — Strava, Komoot, and Intervals.icu/Runalyze/Garmin can each act as source or destination for a pipeline; no hardcoded direction.\n- **Multi-pipeline routing** — fan one source out to several destinations, or fold several sources into one, with an independent rule chain per pipe.\n- **Rule engine** — filter and transform activities per pipeline by sport type, distance, elevation, or name before they're pushed downstream.\n- **Rate-limit safe** — all outbound Strava calls go through a shared, Redis-backed rate limiter (`RateLimitGuard`) so one busy user can't exhaust the app's API quota for everyone else.\n- **Privacy by design** — Komoot credentials and Strava tokens are encrypted at rest (AES-256 Fernet); GPX downloads use short-lived presigned URLs instead of streaming through the API; GDPR data export and account deletion are built in, with an audit log that survives account deletion for compliance.\n- **Self-hostable** — MIT-licensed. `DEPLOYMENT_MODE=selfhosted` strips billing/tier gating entirely so a single-instance deploy runs with all features unlocked, using your own Strava API app.\n- **REST API + webhooks** — programmatic access via API keys, plus outbound signed webhooks and inbound Strava push-event handling for real-time sync instead of polling.\n\n## Tech stack\n\n**Backend** — FastAPI (async) · SQLAlchemy 2.0 (async, PostgreSQL) · Alembic · Redis + ARQ (background jobs) · JWT auth · Fernet encryption\n\n**Frontend** — Next.js 15 (App Router) · TypeScript · Tailwind CSS · React Query · Framer Motion\n\n**Infra** — Docker Compose · Coolify · self-hosted on Hetzner, this instance running in `selfhosted` deployment mode as a public demo\n\n## Try it\n\nThe public instance at [routepass.online](https://routepass.online) runs this repository's `main` branch in self-hosted mode: register for free, connect Strava, and set up a pipeline. Billing/tier gating is disabled on this demo — every feature is unlocked.\n\n## Quick Start (local development)\n\n### 1. Create an env file\n\n```bash\ncp .env.saas.template .env.saas\n```\n\nFill in the required variables (`SECRET_KEY`, `KOMOOT_ENCRYPTION_KEY`, `STRAVA_CLIENT_ID`/`STRAVA_CLIENT_SECRET` from a [Strava API app](https://www.strava.com/settings/api)).\n\n### 2. Start the stack\n\n```bash\nmake dev       # api + worker + db + redis + frontend\nmake dev-logs\n```\n\n### 3. Run checks\n\n```bash\nmake check     # ruff + mypy + pytest\n```\n\n## Useful Commands\n\n```bash\nmake status       # Git status + log\nmake dev          # Start docker stack\nmake dev-stop     # Stop docker stack\nmake test         # Run pytest\nmake lint         # Run ruff checks\nmake check        # lint + test\nmake migrate      # Run alembic migrations\n```\n\n## Architecture Notes\n\n- FastAPI async API with SQLAlchemy 2.0 async ORM (PostgreSQL)\n- Redis + ARQ workers for background sync jobs (`poll_user_sources`, per-connection watermarks, real-time Strava webhook ingestion)\n- All outbound Strava calls guarded by `RateLimitGuard` (shared quota, multi-app fan-out)\n- Komoot's API is unofficial and unauthenticated by OAuth — credentials are encrypted with AES-256 Fernet, never stored in plaintext\n- GPX object storage is pluggable: DB column by default (self-hosted), S3/R2-compatible for larger deployments\n\n## Repository Documentation\n\n- `AI_HANDOFF.md`: current implementation state, migration chain, test coverage\n- `IMPLEMENTATION_PLAN.md`: full launch plan (scalability, deployment, privacy, multi-directional sync)\n- `docs/setup_guide.md`: user account-linking guidance\n- `docs/PROJECT_LEGACY.md`: original single-user tool this project grew out of\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdettinjo%2Froutepass","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdettinjo%2Froutepass","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdettinjo%2Froutepass/lists"}