HillsRun
Dashboard fitness pour trail runners — synchronisation Garmin Connect, métriques D+/pace/HR et readiness quotidienne.
PythonFastAPINext.jsPostgreSQLGarmin
15 janvier 2026
Le projet
Garmin Connect est puissant mais bruyant. HillsRun extrait l'essentiel pour un trail runner : dénivelé positif, allure, fréquence cardiaque et readiness quotidienne — dans une interface épurée.
L'application synchronise automatiquement les données athlète depuis Garmin Connect vers PostgreSQL, puis les présente via un dashboard minimaliste.
Architecture
Le système repose sur deux composants indépendants :
- Backend Python/FastAPI : sync engine + REST API (40+ endpoints, 11 routers)
- Frontend Next.js : dashboard PWA avec proxy API sécurisé
Garmin Connect (OAuth)
│
FastAPI (Railway)
├── SyncManager (5 fetchers)
├── REST API (40+ endpoints)
└── asyncpg → PostgreSQL (Neon)
│
Next.js (Vercel)
├── Proxy API (clé cachée server-side)
├── Auth Better-Auth
└── Charts Plotly
Stack technique
| Composant | Technologie |
|---|---|
| Backend | Python 3.11+, FastAPI, asyncpg |
| Frontend | Next.js 16, React 19, TypeScript |
| Auth | Better-Auth (email/password) |
| Base de données | PostgreSQL 15+ (Neon) + réplica NAS |
| Visualisation | Plotly.js (client-side) |
| Déploiement | Railway (API) + Vercel (front) |
| CI/CD | GitHub Actions |
Fonctionnalités
- Sync automatique : cron quotidien, données Garmin récupérées via OAuth
- Dashboard : résumé hebdomadaire, readiness, tendances
- PWA : installable sur mobile, service worker Serwist
- Sécurité : tokens OAuth chiffrés Fernet, clé API jamais exposée côté client
- Réplica NAS : réplication logique PostgreSQL vers le homelab
Ce que j'ai appris
- Gérer l'authentification OAuth Garmin (rate limiting, retry, refresh tokens)
- Concevoir une API REST structurée avec FastAPI et asyncpg
- Mettre en place un proxy API côté Next.js pour protéger les clés
- Configurer la réplication logique PostgreSQL entre Neon et un NAS