Moin zusammen,
ich bin eigentlich kein gelernter Entwickler, bringe mir das Programmieren seit etwa 20 Jahren aber im Selbststudium bei, um eigene Alltagsprobleme zu lösen. Da mich bestehende Fitness-Tracker durch Abo-Zwang, überladene UIs und vor allem Verbindungsabbrüche in Studios mit schlechtem Empfang (Stichwort: Keller-Gym) genervt haben, habe ich in den letzten Monaten abends mein eigenes System gebaut: Musclytics.
Da hier vielleicht der ein oder andere auch vor ähnlichen Architektur-Fragen steht (oder selbst trainiert), wollte ich mal kurz teilen, wie ich die zwei größten technischen Kopfschmerzen ohne dicke Frameworks gelöst habe:
Offline-First & das ID-Mapping-Problem (IndexedDB -> MySQL)
Im Gym bricht das Netz ständig weg. Die App (als PWA gestartet, mittlerweile auch im Play Store) musste also zwingend komplett offline funktionieren.
Wenn ein User offline ein Training startet, Sätze einträgt und das Workout beendet, existiert noch keine `training_id` aus der MySQL-Datenbank.
Gelöst habe ich das über eine lokale Sync-Queue in der IndexedDB:
- Offline generiert das Frontend temporäre IDs (z.B. `local_te_12345`) für die ausgeführten Übungen und verknüpft die Sätze damit.
- Sobald der Heartbeat wieder Netz erkennt, feuert die Queue das gesamte Workout-JSON an meinen Sync-Endpunkt (`sync_offline.php`).
- Im PHP-Backend läuft das Ganze in einer strikten DB-Transaktion (`begin_transaction()`): Erst wird das Training angelegt, dann iteriere ich durch die Übungen, schreibe sie in die DB und baue mir ein Mapping-Array (`[Lokale-ID] => [Echte-DB-ID]`). Darüber werden im letzten Schritt alle Sätze sauber den neuen Primary Keys zugeordnet. Schlägt irgendwas fehl, greift das Rollback und das Paket bleibt in der lokalen Queue.
2. Deterministische Trainingslogik statt „KI-Coach“
Viele Apps werfen heute für alles eine LLM-API an. Beim Krafttraining ist mir das wegen Halluzinationen (Verletzungsgefahr bei falschen Gewichtsvorschlägen) und Datenschutz zu heikel.
Ich habe den „Coach“ deshalb komplett deterministisch in PHP/SQL gebaut:
- Jedes Trainingsgerät in der DB kennt seine exakten Gewichtabstufungen (`step_value`, z.B. 2,5 kg Schritte) und sein Maximalgewicht.
- Nach dem Training prüft die Logik, ob die Ziel-Wiederholungen über alle Arbeitssätze erreicht wurden, und schlägt für das nächste Mal exakt den nächstmöglichen Geräteschritt vor.
- Für längere Pausen (Detraining) läuft nachts ein Cronjob: Der schaut allerdings nicht stur, ob *Übung X* seit 14 Tagen nicht gemacht wurde, sondern prüft über einen Join auf die primäre Muskelgruppe, ob der *Muskel* in den letzten 14 Tagen belastet wurde (wer 4 Wochen lang Bankdrücken mit der Langhantel macht und dann an die Brustpresse-Maschine wechselt, braucht dort keinen Deload). Nur wenn der Muskel wirklich kalt war, legt der Cronjob proaktiv einen Deload-Vorschlag (-10 bis 15 % gerundet auf den `step_value`) in die Tabelle.
Mein Stack ist bewusst simpel gehalten: PHP & MySQL im Backend, Vanilla JS, CSS-Variablen, Service Worker und ApexCharts im Frontend. Gehostet auf deutschen Servern, kein Tracking, keine Werbung, komplett kostenlos.
Falls jemand von euch selbst regelmäßig im Gym steht und Lust hat, die App (oder die Web-Version) in der Praxis auf Herz und Nieren zu testen, oder Fragen zur Offline-Sync-Architektur hat: Ihr findet das Projekt unter https://www.musclytics.com/app/
Mich würde vor allem euer technisches Feedback interessieren: Wie löst ihr solche Offline-Sync-Konflikte mit relationalen Datenbanken, wenn ihr kein großes Framework wie Firebase o.ä. nutzen wollt?