Your health stack, finally unified.
Garmin · Hevy · Strava — one self-hosted dashboard, your data, your server.
Daily steps, resting heart rate, stress trend, body composition, recovery status, weekly training load, activity streaks — your full health picture on one page.
Pace progression across every run, monthly mileage history, VO2max trend, training zones, HR vs pace scatter, split analysis, shoe mileage tracking.
Muscle activation map (front & back) with volume by muscle group across all sessions. Exercise progression, personal records, gym frequency heatmap.
Sleep stages over time (deep, light, REM, awake), score trend, sleep schedule, HRV, blood oxygen, respiration rate, body battery, training readiness.
See exactly what synced, configure push rules (e.g. Hevy strength → Strava), and monitor the live data pipeline.
Garmin Connect ──┐
├──▶ sync/ (Python, hourly) ──▶ Neon PostgreSQL ◀── web/ (Next.js) ──▶ Vercel
Hevy API ────────┘ │
▼
Strava (push)
sync/ writes. web/ reads. That boundary never crosses.
| Service | Required | Notes |
|---|---|---|
| Neon | ✓ | Free tier works |
| Garmin Connect | ✓ | Any Garmin device |
| Hevy Pro | optional | Strength workouts |
| Strava API app | optional | Activity push |
psql "$DATABASE_URL" -f sync/schema.sqlSet Root Directory → web in Vercel, then add:
| Variable | Value |
|---|---|
DATABASE_URL |
Neon connection string |
AUTH_SECRET |
Random 32-char string (openssl rand -base64 32) |
GITHUB_CLIENT_ID |
From your GitHub OAuth app |
GITHUB_CLIENT_SECRET |
From your GitHub OAuth app |
GITHUB_OWNER_USERNAME |
Your GitHub username (only this account gets access) |
NEXT_PUBLIC_BASE_URL |
Your Vercel URL |
STRAVA_CLIENT_ID |
From your Strava API settings (optional) |
STRAVA_CLIENT_SECRET |
From your Strava API settings (optional) |
GitHub OAuth app setup: go to github.com/settings/developers → New OAuth App → set Authorization callback URL to https://your-app.vercel.app/api/auth/callback/github.
Then visit /connections to complete Strava OAuth.
GitHub Actions (recommended — free, runs in the cloud)
Add to your fork under Settings → Secrets → Actions:
| Secret | Value |
|---|---|
DATABASE_URL |
Neon connection string |
GARMIN_EMAIL |
Garmin Connect email |
GARMIN_PASSWORD |
Garmin Connect password |
HEVY_API_KEY |
Hevy API key (Pro required) |
STRAVA_CLIENT_ID |
Strava client ID |
STRAVA_CLIENT_SECRET |
Strava client secret |
TELEGRAM_BOT_TOKEN |
(optional) |
TELEGRAM_CHAT_ID |
(optional) |
Runs hourly via .github/workflows/sync.yml. Trigger manually from the Actions tab anytime.
Local cron (for home servers)
cd sync
python3 -m venv .venv && .venv/bin/pip install -e .
cp ../.env.example ../.env # fill in credentials
bash cron-setup.sh # installs hourly croncd web && npm install && npm run dev # → http://localhost:3456
cd sync && python -m src.pipeline # manual sync run



