{"id":46993409,"url":"https://github.com/trevordavies095/tempo","last_synced_at":"2026-05-10T05:24:45.464Z","repository":{"id":323593843,"uuid":"1093879550","full_name":"trevordavies095/tempo","owner":"trevordavies095","description":"A privacy-first, self-hosted Strava alternative. Import GPX, FIT, and CSV files from Garmin, Apple Watch, Strava, and more. Keep all your data local—no subscriptions, no cloud required.","archived":false,"fork":false,"pushed_at":"2026-03-04T23:01:03.000Z","size":7678,"stargazers_count":12,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-05T04:51:40.987Z","etag":null,"topics":["apple-watch","applewatch","exercise","garmin","homelab","running","self-hosted","strava"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trevordavies095.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"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":null,"dco":null,"cla":null}},"created_at":"2025-11-11T00:55:33.000Z","updated_at":"2026-03-04T23:01:03.000Z","dependencies_parsed_at":"2025-11-30T04:04:45.458Z","dependency_job_id":null,"html_url":"https://github.com/trevordavies095/tempo","commit_stats":null,"previous_names":["trevordavies095/tempo"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/trevordavies095/tempo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trevordavies095%2Ftempo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trevordavies095%2Ftempo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trevordavies095%2Ftempo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trevordavies095%2Ftempo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trevordavies095","download_url":"https://codeload.github.com/trevordavies095/tempo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trevordavies095%2Ftempo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30384102,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-11T14:10:17.325Z","status":"ssl_error","status_checked_at":"2026-03-11T14:09:37.934Z","response_time":84,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["apple-watch","applewatch","exercise","garmin","homelab","running","self-hosted","strava"],"created_at":"2026-03-11T14:37:47.317Z","updated_at":"2026-05-10T05:24:45.453Z","avatar_url":"https://github.com/trevordavies095.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tempo - Self-Hostable Running Tracker\n\n\u003e A privacy-first, self-hosted Strava alternative. Import GPX, FIT, and CSV files from Garmin, Apple Watch, Strava, and more. Keep all your data local—no subscriptions, no cloud required.\n\n![License](https://img.shields.io/badge/license-MIT-blue.svg)\n![Version](https://img.shields.io/badge/version-2.4.0-green.svg)\n![.NET](https://img.shields.io/badge/.NET-10.0-purple.svg)\n![Next.js](https://img.shields.io/badge/Next.js-16-black.svg)\n[![Discord](https://img.shields.io/badge/Discord-Join%20Server-5865F2?logo=discord)](https://discord.gg/9Svd99npyj)\n\n**[View Full Documentation](https://trevordavies095.github.io/tempo/)** - Complete guides for installation, configuration, usage, deployment, and more.\n\n**[Tempo on the App Store](https://apps.apple.com/us/app/tempo-self-hosted-running/id6763753229)** - Companion iOS app for your self-hosted server.\n\n## Screenshots\n\n![Dashboard](https://i.imgur.com/pURdx2e.png)\n*Dashboard view*\n\n![My Activities](https://i.imgur.com/nZEt9mN.png)\n*Activities list*\n\n![Activity Details](https://i.imgur.com/aj671gl.png)\n*Activity details view*\n\n## Quick Start\n\nGet Tempo running in minutes with Docker Compose:\n\n```bash\n# Clone the repository\ngit clone https://github.com/trevordavies095/tempo.git\ncd tempo\n\n# Start all services\ndocker-compose up -d\n```\n\nAccess the application at:\n- **Frontend**: http://localhost:3000\n- **API**: http://localhost:5001\n\nThat's it! The database migrations run automatically on first startup. For detailed setup instructions, authentication, and configuration, see the [full documentation](https://trevordavies095.github.io/tempo/).\n\n## Features\n\n- **Multi-Format Support** - Import GPX, FIT (.fit, .fit.gz), and Strava CSV files from Garmin, Apple Watch, and other devices\n- **Workout Analytics** - Track distance, pace, elevation, splits, and time series data\n- **Interactive Maps** - Visualize routes with elevation profiles\n- **Media Support** - Attach photos and videos to workouts\n- **Weather Data** - Automatic weather conditions for each workout\n- **Bulk Import** - Import multiple workouts at once via ZIP file (up to 500MB)\n- **Heart Rate Zones** - Calculate zones using Age-based, Karvonen, or Custom methods\n- **Relative Effort** - Automatic calculation of workout intensity based on heart rate zones\n- **Best Efforts** - Track your fastest times for standard distances (400m to Marathon) from any segment within workouts\n- **Shoe Tracking** - Track mileage on your running shoes and know when to replace them\n- **Workout Editing** - Crop/trim workouts and edit activity names\n- **Statistics Dashboards** - Weekly and yearly statistics with relative effort tracking\n- **Unit Preferences** - Switch between metric and imperial units\n- **100% Local** - All data stays on your machine, no cloud sync required\n\n## Tech Stack\n\n- **Frontend**: Next.js 16, React 19, TypeScript, Tailwind CSS, Tabler Icons\n- **Backend**: ASP.NET Core (.NET 10) Minimal APIs\n- **Database**: PostgreSQL 16\n- **State Management**: TanStack Query\n\n## Documentation\n\n**OpenAPI:** The canonical HTTP API contract for tools and client generation (including the planned read-only CLI) is **[docs/openapi.json](docs/openapi.json)** on the default integration branch (`develop`). After changing routes or Swagger metadata, regenerate it: run `dotnet tool restore` once at the repo root, then:\n\n```bash\ncd api \u0026\u0026 dotnet build \\\n  \u0026\u0026 ASPNETCORE_ENVIRONMENT=Development \\\n     JWT__SecretKey='local-openapi-only-not-for-production-min-32-chars!' \\\n     ConnectionStrings__DefaultConnection='Data Source=:memory:' \\\n     dotnet swagger tofile --output ../docs/openapi.json bin/Debug/net10.0/Tempo.Api.dll v1\n```\n\nUse the **Debug** output assembly (`bin/Debug/...`) so the file matches **CI**, which runs `dotnet swagger tofile` against `bin/Debug/net10.0/Tempo.Api.dll` after `dotnet build Tempo.sln`.\n\nUse **Development** (not `Testing`) for `dotnet swagger tofile`: with `Testing`, the generic host looks for a `StartupTesting` class that this app does not ship, and Swashbuckle fails. In-memory SQLite avoids needing Postgres for this one-off export.\n\nWith the API running in **Development**, you can also fetch the same document at `http://localhost:5001/swagger/v1/swagger.json`. Production deployments do not expose Swagger by default.\n\n**API keys (CLI and automation):** Protected routes accept `Authorization: Bearer` with either a JWT (browser session) or an admin-issued API key (prefix `tmp_`). The planned read-only CLI uses env such as `TEMPO_API_KEY`; it does not create keys—operators issue them in Tempo.\n\n1. **Create a key** (requires a logged-in session, not an API key). Either use **Swagger** at `/swagger` in Development, or from a shell log in with a cookie jar and create a key:\n\n```bash\nBASE=http://localhost:5001\ncurl -sS -c tempo-cookies.txt -X POST \"$BASE/auth/login\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"username\":\"your-user\",\"password\":\"your-password\",\"rememberMe\":true}'\ncurl -sS -b tempo-cookies.txt -X POST \"$BASE/auth/api-keys\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"label\":\"cli\"}'\n```\n\nThe JSON response includes the secret **`key` once**; the server stores only a hash. Copy it immediately.\n\n2. **Verify** machine access:\n\n```bash\nexport TEMPO_API_KEY='tmp_…'   # paste the key from step 1\ncurl -sS -H \"Authorization: Bearer $TEMPO_API_KEY\" http://localhost:5001/auth/me\n```\n\n3. **Security:** Do not commit keys, log them in apps, or paste them into shared channels. Revoke a compromised key (`DELETE /auth/api-keys/{id}` with the same session you used to create it) and create a new one.\n\n4. **401 on protected routes** often returns: `{\"error\":\"Invalid or expired credentials\"}` (invalid, revoked, or missing auth). Full paths and schemas: [docs/openapi.json](docs/openapi.json).\n\nComprehensive documentation is available at **[https://trevordavies095.github.io/tempo/](https://trevordavies095.github.io/tempo/)**:\n\n- **[Getting Started](https://trevordavies095.github.io/tempo/getting-started/)** - Installation, quick start, and configuration guides\n- **[User Guide](https://trevordavies095.github.io/tempo/user-guide/)** - Importing workouts, viewing analytics, managing media, and settings\n- **[Developer Documentation](https://trevordavies095.github.io/tempo/developers/)** - Architecture, local development setup, API reference, and database schema\n- **[Deployment](https://trevordavies095.github.io/tempo/deployment/)** - Production deployment, security best practices, and backup/restore procedures\n- **[Troubleshooting](https://trevordavies095.github.io/tempo/troubleshooting/)** - Common issues, solutions, and frequently asked questions\n\n## Support\n\n- **Discord**: Join our community on [Discord](https://discord.gg/9Svd99npyj) for support and discussions\n- **Issues**: Report bugs or request features on [GitHub Issues](https://github.com/trevordavies095/tempo/issues)\n- **Changelog**: See [CHANGELOG.md](CHANGELOG.md) for version history and updates\n\n## License\n\nMIT License - see LICENSE file for details\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrevordavies095%2Ftempo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrevordavies095%2Ftempo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrevordavies095%2Ftempo/lists"}