Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GarminLens

Personal, local-first, config-driven analytics & visualization platform for Garmin fitness data.

Start with world-class swimming intelligence — length-by-length timelines, SWOLF frontiers, set reconstruction, real coaching advice. Extend to running, cycling, strength — without touching core code.

Built for athletes who want truth, not marketing dashboards.


Why GarminLens

Garmin gives you raw data. Strava and Connect give you pretty graphs. You want insight:

  • What did I actually do in that set?
  • Why is my SWOLF stuck?
  • What should I change tomorrow?
  • Is this week's training working?

GarminLens turns every FIT file and export ZIP into a dense, actionable intelligence system — fully offline, fully private, fully yours.


Core Philosophy

  • Config is king — every sport rule, metric, heuristic, color, and advice lever lives in config/. Core src/ code is 100% generic.
  • Local-first & private — your data never leaves your machine (DuckDB flat file)
  • Keyboard-first UX — ⌘K command palette, ⌘U unit toggle, J/K navigation, compare mode
  • No black boxes — every number shows provenance via tooltips

Tech Stack

Layer Technologies
Backend Python 3.12+, DuckDB, Polars, Pydantic v2, FastAPI, Loguru
Frontend Next.js 15 (App Router), TypeScript, Tailwind, shadcn/ui, Radix UI, Recharts
Monorepo Turborepo

Prerequisites

  • Python 3.12+
  • Node.js 20+ / npm 10+
  • macOS, Linux, or WSL2

Setup

1. Backend

cd src/backend
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

2. Frontend

cd src/frontend
npm install

CLI Quickstart

All commands run from src/backend/ with the virtual environment activated.

# Ingest a Garmin export ZIP or FIT file
python -m garminlens.cli ingest --source ~/Downloads/export.zip

# Validate DB integrity without ingesting
python -m garminlens.cli validate

# Summarize the latest session
python -m garminlens.cli summarize --latest

# Diff two sessions
python -m garminlens.cli diff <activity_id_a> <activity_id_b>

# Export metrics to JSON/CSV
python -m garminlens.cli export --format json --output out.json

# Recompute all derived metrics
python -m garminlens.cli recompute --all

# Start the API server
python -m garminlens.cli serve
# → http://127.0.0.1:8000

API Route Index

Start the backend server with python -m garminlens.cli serve, then:

Method Route Description
GET /activities List all activities
GET /activities/{id} Activity detail
GET /activities/{id}/lengths All lengths for an activity
GET /activities/{id}/sets Reconstructed sets
GET /activities/{id}/metrics Computed session metrics
POST /ingest Ingest a FIT file
GET /analytics/trends Rolling trend series
GET /analytics/prs Personal records
GET /analytics/streak Training streak
GET /analytics/compare Metric diff between two activities
GET /analytics/quality Quality flag aggregation
GET /coaching/{id} Coaching critique for an activity
GET /coaching/notifications/all Recent coaching notifications
GET /experiments Experiment definitions
GET /experiments/{id}/weeks Weekly experiment rows
GET /config/ui-tokens UI design tokens
GET /config/defaults App defaults
GET /config/metrics Metric catalog

Swagger UI: http://127.0.0.1:8000/docs


Frontend Dev

cd src/frontend
npm run dev
# → http://localhost:3000

The Next.js dev server proxies /api/* to http://127.0.0.1:8000 automatically (see next.config.ts). Start the backend server first.


Project Structure

garminlens/
├── config/                 # ALL domain logic lives here (metrics, heuristics, UI tokens…)
│   ├── activities.yaml     # Supported activity types
│   ├── defaults.yaml       # App-wide defaults
│   ├── analytics.yaml      # Trend/consistency/frontier config
│   ├── quality_flags.yaml  # Quality flag severity mapping (high/medium/low)
│   ├── metrics/            # Metric formula YAML files (common.yaml, swim.yaml, run.yaml…)
│   ├── heuristics/         # Quality checks, set reconstruction, coaching levers
│   ├── pool.yaml           # Known pool lengths + device quirks
│   └── ui/                 # Tokens (stroke colors, activity type icons), themes, labels
├── data/                   # DuckDB at data/garminlens.db; raw_vault/ for FIT files
├── docs/                   # Architecture, data model, all module docs
├── src/
│   ├── backend/            # Python package: garminlens.*
│   │   └── garminlens/
│   │       ├── api/        # FastAPI routes + schemas
│   │       ├── analytics/  # Trends, PRs, experiments, coaching
│   │       ├── config/     # Config loader + Pydantic models
│   │       ├── db/         # DuckDB connection + migrations
│   │       ├── ingestion/  # Parser, normalizer, storage pipeline
│   │       ├── metrics/    # Formula engine + registry
│   │       └── reconstruction/ # Set segmenter, labeler, repeat detector
│   └── frontend/           # Next.js 15 App Router
│       └── src/
│           ├── app/        # Pages and layouts
│           ├── components/ # UI components (dashboard/, drawer/, charts/, ui/)
│           └── lib/        # api.ts, store.ts, types.ts, utils.ts
└── turbo.json              # Turborepo config

Config-Driven Architecture

No domain logic belongs in src/. Everything that differs between sports or preferences lives in config/:

  • Metric formulas → config/metrics/*.yaml
  • Set reconstruction rules → config/heuristics/set_reconstruction.yaml
  • Coaching levers → config/heuristics/coaching_levers.yaml
  • UI colors, activity type icons, sparkline definitions → config/ui/tokens.yaml
  • Quality check thresholds → config/heuristics/quality_checks.yaml
  • Quality flag severity → config/quality_flags.yaml

To add a new sport (e.g. cycling), add its entry to config/activities.yaml and metric definitions to config/metrics/bike.yaml. No Python or TypeScript changes needed.


Documentation

Full technical documentation lives in docs/:

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages