Aller au contenu principal
AnthemionStéphane
Retour aux projets

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

ComposantTechnologie
BackendPython 3.11+, FastAPI, asyncpg
FrontendNext.js 16, React 19, TypeScript
AuthBetter-Auth (email/password)
Base de donnéesPostgreSQL 15+ (Neon) + réplica NAS
VisualisationPlotly.js (client-side)
DéploiementRailway (API) + Vercel (front)
CI/CDGitHub 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