Lokales Fitness-Dashboard mit optionalem LLM-Coach.
Eine Frage im Zentrum: „Wo werde ich besser, wo schlechter?“
Milon verbindet Garmin Connect, Health Connect, Hevy und FDDB in einer lokalen SQLite-Datenbank. Körperentwicklung, Lauffitness und Kraftfortschritt stehen im Mittelpunkt; Ernährung, Erholung und ein freiwilliger Check-in liefern Kontext. UI und Dokumentation sind deutsch, Code und Identifier englisch.
Die Anwendung und ihre Auswertungen laufen lokal. Eingerichtete Datenquellen werden über das Internet synchronisiert. Der optionale Cloud-Coach übermittelt Fragen, persönlichen Kontext und ausgewählte Kennzahlen an OpenRouter und den Modellanbieter. Details stehen unter Datenschutz und Betrieb.
| Bereich | Aktueller Funktionsumfang |
|---|---|
| Übersicht | Entwicklungskarten mit Monats-Zeitreise, lokales Monatsrückblick-Poster, Wochenjournal mit Tagesdetails, Konsistenz, freiwilliger kurzer Check-in |
| Körper | Gemeinsamer Vergleich von Bauch/Taille, Gewicht und Kraftleistung; Gewichtstrends, TDEE, Waagen-KFA mit Einordnung, manuelle Körpermaße mit Messgrafik, historische Nachträge, Einzeltrends und Messjournal |
| Laufen | Streckenatlas mit automatisch gruppierten Runden, persönliche Referenzrunde, Wochenvolumen und mechanische Belastung, Pulszonen mit dynamischer Tempo-Spanne, Bestzeiten, standardisierter Puls bei gleicher Pace, experimenteller Fitness-Trend |
| Einzelne Läufe | Eigene Detailseite: Laufziel und Anstrengung, Stationswetter, Trainingsreiz, Pulsstabilität, gekoppelte Strecke und Puls-/Tempokurve, lokale Routenwiedergabe, Laufposter als PNG/SVG, Höhenprofil, Zonen, Runden, Laufstil früh/spät und automatischer statistischer Streckenvergleich |
| Gesundheit | Schritte, Radfahren, Schlaf, interaktive Nachtansicht mit Schlafphasen und Messreihen, Schlafrhythmus, HRV, Garmin-Erholungswerte, Zusammenhänge zwischen Erholung und Leistung sowie Quellen- und Importstatus |
| Kraft | Übungen nach Muskelgruppe, Detailseiten, e1RM, Tonnage, RPE, Gesamtstärke-Index und Zusammenhang mit der Energiebilanz |
| Ernährung | Kalorien, Makros, Proteinziel und Defizit gegenüber dem geschätzten TDEE |
| Fortschritt | Foto-Timeline, Zuschnitt, mehrere Ansichten und Silhouetten als Aufnahmehilfe |
| Coach | Kurze Antworten mit Kennzahlen, persönliche Ziele, ausdrücklich übernommene Wochenmaßnahme mit Rückmeldung und Messvergleich, lokale Diagramme, Berichte, Kostenübersicht und angeforderte Bildgenerierung |
Die Laufdetails öffnen über Laufen → Dein Streckenatlas → Laufdetails eine eigene
Adresse /laufen/<Garmin-Aktivitäts-ID>. Die wichtigsten Einordnungen stehen oben;
die Analysen darunter sind direkt sichtbar. Methodik und Datenbasis bleiben einklappbar.
-
Streckenatlas: Wiederholungen werden mit mindestens 97 % Überdeckung einer festen Referenzstrecke zugeordnet. Konturen und Verlauf bleiben lokal; die Laufdetails bieten eine abspielbare Position mit synchronen Messwerten.
-
Laufposter: Drei Farbstile und sechs Ink-/Teal-Motive, mit echter Strecke und Laufwerten als 1024 × 1024 PNG oder SVG. Der Export entsteht im Browser.
-
Deine Nacht: Schlafphasen und bis zu zwei auswählbare Verläufe (Puls, Stress, Body Battery, HRV) teilen eine Zeitachse. Die 14-/30-Tage-Ansicht zeigt den Schlafrhythmus; unvollständige Phasen und Messlücken bleiben erkennbar.
-
Laufstil und Belastung: Frühe/späte Minuten werden bei ähnlichem Tempo und Gefälle verglichen, unter anderem für Schrittbremsung (SSL%), Bodenkontakt und Kadenz. Wochenbalken trennen gelaufene Kilometer von Garmins Impact Load; Hevy-Beintage erscheinen separat. Lauftoleranz wird nur gezeigt, wenn Garmin geeignete Werte liefert. Methodik.
-
Wochenjournal: Sieben abgeschlossene lokale Kalendertage mit Läufen, Krafttraining, Hauptschlaf und freiwilliger Energieangabe. Frühere Zeiträume lassen sich wochenweise aufrufen. Ein Tag öffnet seine Einheiten und direkte Links zu Lauf, Übungen und Nacht; fehlende Messwerte bleiben offen.
-
Zeitreise und Monatsrückblick: Ein Monatsregler zeigt die drei Entwicklungskarten mit den bis zum damaligen Stichtag gemessenen Daten. Sensor- und Übungswechsel begrenzen Vergleiche. Das Monats-Poster enthält Streckenkonturen, Lauf-/Gym-Bilanz und optional den Gewichtsverlauf; Export als lokales 1024 × 1024 PNG oder SVG.
-
Interaktive Verläufe: Ein Messdatum gilt gemeinsam für alle Körpermaß-Kurven; ein ausgewählter Lauf wird in Pace- und Pulsverteilung gleichzeitig hervorgehoben. Der Messassistent markiert die gewählte Messstelle kurz auf der Silhouette.
-
Streckenabschnitte: Im Atlas lassen sich 500-m-Abschnitte gegen räumlich zugeordnete Wiederholungen vergleichen. Versetzte Starts, mehrdeutige Zuordnungen und Messlücken werden ausgeschlossen; kleine Gruppen bleiben als solche sichtbar.
-
Typische Nacht: Optionales Median-/50-%-Band aus früheren vollständigen Garmin-Nächten, ausgerichtet an der Zeit seit Schlafbeginn. Mindestens sieben Vergleichsnächte und fünf Nächte je Abschnitt; Lücken werden nicht aufgefüllt.
-
Synchronisierung: Manuelles Aktualisieren nennt tatsächlich neu hinzugekommene Läufe, Nächte und Messtage, bietet direkte Links und markiert neue Einträge kurz. Kleine Übergänge unterstützen die Bedienung und beachten reduzierte Bewegung.
-
Referenzrunde: In den Laufdetails eine Runde auswählen. Die Laufübersicht sammelt passende Wiederholungen derselben Sensorperiode und Richtung. Einzelne Pulsunterschiede beschreiben Beobachtungen; sie beweisen keine Fitnessveränderung.
-
Läufe vergleichen: Automatisch alle anderen passenden Läufe derselben Sensorperiode mit mindestens 97 % Streckenüberdeckung (30 m GPS-Toleranz, gleiche Richtung und ähnliche Länge). Pace und Puls zeigen Einzelwerte, Median und Spanne; ab fünf Vergleichswerten zusätzlich die mittleren 50 %. Der ausgewählte Lauf bleibt außerhalb der Verteilung. Methodik und Grenzen.
-
Körperfortschritt: 4, 8 oder 12 Wochen auswählen. Die ersten und letzten 14 Tage bilden gemeinsame Vergleichsfenster für Bauch/Taille, Gewichtsmittel und gleiche Übungen.
-
Wochenmaßnahme: Unter Coach eine konkrete Handlung ausdrücklich übernehmen, optional einen Messwert auswählen und später kurz rückmelden. Der Coach kann bestehende Maßnahmen lesen; anlegen oder ändern kann sie nur der Nutzer.
Garmin-Stationswetter ergänzt Laufdetails mit Temperatur, Feuchte, Windrichtung und Messzeit. Die Windgeschwindigkeit bleibt wegen fehlender belegter API-Einheit ausgenommen. Wetter verändert keine berechnete Pace oder Pulsdifferenz.
Auswertungen kennzeichnen fehlende Daten und Unsicherheit. Sensorwechsel werden berücksichtigt; ältere Werte werden nicht als aktuelle Fitness ausgegeben. Ein niedriger Trainingsreiz ist nicht automatisch schlecht, eine Korrelation kein Kausalnachweis. Körperumfänge werden nicht in einen vermeintlich exakten KFA umgerechnet.
„Klar & Klinisch“: Teal, ruhige Karten, Inter / Inter Tight und abstrakte Sportler-Silhouetten. Die folgenden Bilder zeigen frühere Ansichten; der heutige Funktionsumfang ist größer.
| Quelle | Verwendung | Anbindung |
|---|---|---|
| Garmin Connect | Laufstrecken, Puls-/Temporeihen, Runden, Laufdynamik und Trainingswirkung; Schritte, Schlaf, HRV, VO₂max und verfügbare Erholungswerte | Direkter Import über die inoffizielle Bibliothek garminconnect, lokale Sitzung erforderlich |
| Health Connect | Arboleaf-Gewicht und Waagen-KFA, historische Samsung-Daten und weitere unterstützte Exportdaten | Entpackte SQLite-Exportdatei oder optional täglicher Drive-Pull |
| Hevy | Gym-Workouts mit Sätzen, Gewichten, Wiederholungen und RPE | Hevy-API, HEVY_API_KEY |
| FDDB | Kalorien und Makros | Zugangsdaten für Auto-Login oder vorhandener fddb-Cookie |
| Manuelle Eingaben | Körperumfänge, Fortschrittsfotos, Check-ins und persönliche Ziele | Direkt in Milon |
Die Quellen sind optional. Bei eingerichteter Garmin-Quellenumschaltung haben vollständige Garmin-Läufe sowie geeignete Schritte-, Schlaf- und VO₂max-Daten ab dem Stichtag Vorrang. Gespiegelte HC-Aktivitäten werden abgeglichen; historische Daten bleiben erhalten. Garmin-Ruhepuls bleibt getrennt vom bisherigen HC-Wert, da Definition und zeitliche Zuordnung noch nicht abschließend übereinstimmen. Arboleaf bleibt über Health Connect angebunden, Kraft über Hevy und Ernährung über FDDB.
Voraussetzung: Docker mit Compose, unter Windows beispielsweise Docker Desktop.
Im Hauptverzeichnis eine server/.env aus der Vorlage anlegen, falls noch keine existiert:
if (-not (Test-Path server/.env)) { Copy-Item server/.env.example server/.env }
docker compose up -d --buildAnschließend http://localhost öffnen, im vertrauten Heimnetz http://<PC-IP>.
Die API ist über /api erreichbar, ihr Schema unter /api/openapi.json.
- Nur das Frontend veröffentlicht einen Port: 80, über
WEB_PORTin der Root-.envänderbar. - Das Backend ist ausschließlich im Compose-Netz auf Port 8000 erreichbar.
data/undserver/.envliegen als Volumes auf dem Host. DB, Fotos, Coach-Bilder und Garmin-Sitzung bleiben bei einem Rebuild erhalten.- Nach Änderungen:
docker compose up -d --build. Ein vorherigesdownist unnötig. - Status:
docker compose ps; Logs:docker compose logs --tail 50.
Das Proxy-Ziel wird beim Frontend-Build eingebaut (API_PROXY_TARGET=http://server:8000).
Bei Änderungen an Code oder Zieladresse ist ein Rebuild erforderlich.
| Datei | Wichtige Einstellungen |
|---|---|
server/.env |
OPENROUTER_API_KEY, OPENROUTER_MODEL, HEVY_API_KEY, FDDB_USER / FDDB_PW oder FDDB_COOKIE, optional HC_DRIVE_FILE_ID |
server/.env |
WATCH_SOURCE_SWITCH_DATE, WATCH_SOURCE_PACKAGE und historische STEPS_SOURCE_PACKAGE; BODY_SOURCE_PACKAGE für die Waagenquelle; RUN_HR_MAX für Milons Zonen |
server/.env |
Optional DATABASE_URL, SCHEDULER_ENABLED, TIMEZONE (Default Europe/Berlin) |
data/garmin/.env |
GARMIN_SESSION_B64 mit der lokal erzeugten Garmin-Sitzung |
.env im Hauptverzeichnis |
Optional WEB_PORT; OPENAI_API_KEY nur für separate Design-Asset-Werkzeuge |
client/.env |
Nur lokale Entwicklung: optional NEXT_PUBLIC_API_URL; normalerweise bleibt der relative /api-Proxy aktiv. Docker übernimmt diese Datei nicht. |
Die Vorlage verwendet derzeit openai/gpt-6-luna als Coach-Modell. Modell, API-Key
und persönliche Coach-Ziele lassen sich in den Einstellungen ändern. Ein OpenRouter-Key
ist nur für Coach-Funktionen nötig, nicht für die lokalen Kennzahlen.
Die vollständigen Defaults stehen in config.py.
Der Importer verwendet eine bereits authentifizierte Sitzung in data/garmin/.env.
GARMIN_SESSION_B64 enthält Base64-kodiertes JSON mit di_token, di_refresh_token
und di_client_id. Das ist keine Verschlüsselung; die Datei ist ein Zugangsschlüssel.
Erneuerte Tokens werden atomar gespeichert, ein Garmin-Passwort speichert Milon nicht.
Einrichtungsstand: Das Repository enthält derzeit keinen Erstlogin-Assistenten und keinen Login-CLI-Befehl. Die Sitzung muss außerhalb der App erzeugt werden. Die technische Grundlage und Grenzen beschreibt die Garmin-Recherche; das erwartete Format steht im Importer. Die Anbindung nutzt Garmin-Consumer-Dienste, nicht das offizielle Garmin-Entwicklerprogramm.
Mit vorhandener Sitzung: Garmin aktualisieren auf der Laufseite oder Daten aktualisieren im Menü. Per API im Docker-Betrieb:
curl.exe -X POST http://localhost/api/ingest/garminDie Uhr muss zuvor mit Garmin Connect synchronisiert haben. Der Erst-/Vollabruf
prüft höchstens 1.000 Laufaktivitäten, Folgeabrufe die letzten 30. Neue Tagesdaten
werden ab dem konfigurierten Uhrenwechsel zunächst über maximal 90 Tage eingelesen.
Verfügbarkeit einzelner Werte hängt von Aufzeichnung, Gerät und Garmin ab.
Für die Garmin-Quellenumschaltung WATCH_SOURCE_PACKAGE auf
com.garmin.android.apps.connectmobile setzen und unter WATCH_SOURCE_SWITCH_DATE
das tatsächliche Wechseldatum im Format YYYY-MM-DD eintragen.
Beim manuellen Weg die Export-ZIP entpacken und die Datei als
data/incoming/health_connect_export.db ablegen. Eine unbearbeitete ZIP in diesem
Ordner reicht nicht aus. Danach im Menü aktualisieren oder:
curl.exe -X POST http://localhost/api/ingest/health-connectDer optionale Drive-Pull lädt eine freigegebene Export-ZIP über HC_DRIVE_FILE_ID,
entpackt und importiert sie. Die Freigabe macht Gesundheitsdaten für Personen mit
dem Link zugänglich. Die Datei-ID muss stabil bleiben; ein täglich neu angelegtes
Drive-Dokument wird nicht automatisch anhand seines Namens gefunden.
Milon liest Health Connect weiterhin über diesen Export, nicht direkt vom Android-Gerät.
Bei aktiviertem Scheduler gelten folgende Intervalle in der konfigurierten Zeitzone:
| Quelle | Zeitplan |
|---|---|
| Garmin | Prüfung alle 15 Minuten; Tageswerte höchstens stündlich, manueller Refresh sofort |
| Hevy | Alle 6 Stunden |
| FDDB | Täglich 04:30 |
| Health Connect, lokale Datei | Prüfung alle 10 Minuten bei neuer Datei |
| Health Connect, Drive | Täglich 05:00, wenn eingerichtet |
POST /api/ingest/refresh aktualisiert alle eingerichteten Quellen. Importe gleichen
vorhandene Datensätze ab; ?full=true erzwingt eine weitergehende Reconciliation im
jeweiligen Importumfang. Die Quellenübersicht auf Gesundheit trennt letzten
Abrufversuch, erfolgreichen Abruf und neuestes Messdatum.
Voraussetzungen: Python 3.12 oder neuer und Node.js 22. server/.env wie oben anlegen.
Unter Windows in zwei Terminals:
cd server
python -m venv .venv
.venv/Scripts/python -m pip install -e ".[dev]"
.venv/Scripts/python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000cd client
npm ci
npm run devUnter Linux/macOS heißen die Python-Pfade .venv/bin/python. Das Dashboard läuft im
Dev-Modus unter http://localhost:3000 und leitet /api an Port 8000 weiter.
Die interaktive API-Dokumentation läuft dann direkt unter http://localhost:8000/docs.
VS Code bietet dafür den Task Start: Server + Client.
Prüfungen: im Serververzeichnis .venv/Scripts/python -m pytest, im Clientverzeichnis
npm test, npx tsc --noEmit und npm run build.
flowchart LR
GC["Garmin Connect"] --> ING
HC["Health Connect Export"] --> ING
HV["Hevy API"] --> ING
FD["FDDB"] --> ING
ING["Import und Quellenabgleich"] --> DB[("Lokale SQLite-DB")]
MAN["Körpermaße und Check-ins"] --> DB
DB --> M["Gemeinsame metrics-Schicht"]
M --> REST["REST API"]
REST --> UI["Next.js Dashboard"]
M --> CO["Optionaler Coach / OpenRouter"]
M --> MCP["MCP-Server"]
FastAPI, SQLModel, pandas/numpy und APScheduler bilden das Backend. Das Frontend verwendet Next.js mit App Router, TypeScript, Tailwind v4 und lokalen SVG-Diagrammen. REST, Coach und MCP greifen auf dieselben Metrikfunktionen zu.
Der MCP-Server startet im Serververzeichnis mit .venv/Scripts/python -m app.mcp.server
über stdio (Linux/macOS: .venv/bin/python -m app.mcp.server).
Er läuft außerhalb von Docker und liest dieselbe lokale Datenbank. Die
.mcp.json und das Desktop-Beispiel
enthalten installationsspezifische absolute Pfade; vor Verwendung anpassen.
server/ API, Importe, Metriken, Coach, MCP und Scheduler
client/ Dashboard, Detailseiten und gemeinsame UI-Komponenten
design/ Design-Referenzen, Silhouetten und Asset-Werkzeuge
data/ DB, Exporte, Fotos, Coach-Bilder und Garmin-Sitzung; gitignored
docs/ Dokumentation, Recherche und README-Bilder
- Gesundheitsdaten und Zugangsdaten unter
data/sowie.env-Dateien werden nicht committet. Ein lokales Backup sollte neben der DB auch Fotos und Konfiguration umfassen und geschützt sein. - Eingerichtete Syncs kontaktieren Garmin, Hevy, FDDB und gegebenenfalls Google Drive.
- Der optionale Coach sendet Fragen, Kontext und ausgewählte Metriken/Tool-Ergebnisse an OpenRouter und den gewählten Modellanbieter. Prompts und Antworten werden lokal gespeichert.
- Coach-Diagramme werden aus validierten lokalen Daten gerendert, nicht aus beliebigem Modell-HTML. Explizit angeforderte Bilder verwenden OpenRouter und den Motivprompt.
- GPS-Strecken werden lokal ohne externe Kartenkacheln dargestellt; Coach-Tools geben keine GPS-Koordinaten aus. Ein angeschlossener MCP-Client erhält die angefragten Metriken.
- Milon hat keine Nutzeranmeldung. Das Setup ist für den eigenen Rechner und ein vertrautes Heimnetz gedacht; öffentlicher Betrieb braucht zusätzlichen Zugriffsschutz.
ARCHITECTURE.md beschreibt Methoden, Datenmodell und Quellenregeln. AGENTS.md hält die Arbeitskonventionen fest. Ideen für weitere Schritte: Laufen und Körperentwicklung, Erholung und Coach. Referenzrunde, Laufabsicht, Stationswetter, gemeinsamer Körpervergleich und Wochenmaßnahmen sind umgesetzt; die Notizen nennen auch weiter offene Vorschläge.
CC0 1.0 Universal: frei nutzbar, veränderbar und weitergebbar, ohne Gewährleistung.


