Blog

Erstellen eines persönlichen Fitness-Trackers – Next.js, Supabase und Vercel

Erstellen eines persönlichen Fitness-Trackers – Next.js, Supabase und Vercel

Erstellen eines persönlichen Fitness-Trackers – Next.js, Supabase und Vercel

Vor ein paar Monaten habe ich beschlossen, mich ernsthafter mit Fitness zu befassen. Kein Sportler oder Bodybuilder sein – sondern nur regelmäßig Sport treiben, damit der Körper durch das lange Sitzen vor dem Laptop nicht schnell ermüdet. Das Problem ist, dass die Fitness-Tracker-Anwendungen auf dem Markt scheinbar übertrieben sind. Manche erscheinen monatlich, manche sind voller Werbung, manche haben zu komplexe Funktionen, als dass man einfach sagen könnte: „Heute Liegestütze, 3 Sätze mit 12 Wiederholungen“.

Schließlich entstand die Idee: Warum nicht Ihre eigenen erstellen? Als Entwickler fühlt sich die Erstellung eigener Tools ... sinnvoller an. Außerdem können Sie unterwegs neue Technologien erlernen. So wurde dieses Projekt geboren – ein persönlicher Fitness-Tracker, der mit Next.js und Supabase erstellt und auf Vercel bereitgestellt wurde.

Das Repo ist Open Source unter github.com/adammuizweb/fitness. Ich habe es auch auf fitness.adammuiz.com für meinen eigenen Gebrauch bereitgestellt.

Hauptfunktionen

Diese Anwendung ist einfach, aber funktional gestaltet. Der Fokus liegt nicht darauf, ein Ersatz für Strava oder MyFitnessPal zu sein, sondern vielmehr auf einem täglichen Protokoll, das leicht und schnell ist und nicht viel Nachdenken erfordert.

Tägliches Trainingsprotokoll

Der Kern dieser Anwendung. Jeden Tag kann ich aufzeichnen, welche Trainingseinheiten ich absolviert habe – einfach die Übung in der Liste überprüfen, Sätze und Wiederholungen eintragen, fertig. Es ist nicht nötig, Kalorien, Dauer oder andere irrelevante Daten einzugeben.

Streak Tracker

Einer der stärksten Motivatoren, Routine zu bleiben. Die App zeigt einen Beitragskalender im GitHub-Stil an – grün-grün nach Intensität – sowie aktuelle und längste Streak-Statistiken. Wenn ein Tag versäumt wird, wird der Streak zurückgesetzt. Es ist ziemlich peinlich, wenn man Schluss macht.

Benutzerdefinierte Aktivität

Nicht für alle Übungen sind Vorlagen in der Datenbank vorhanden. Manchmal hat man plötzlich Lust auf bestimmte Dehnübungen oder neue Bewegungen. Die Funktion Benutzerdefinierte Aktivität ermöglicht eine freie Eingabe – geben Sie einfach den Namen der Aktivität ein und senden Sie sie ab. Die Aktivität wird sofort aufgezeichnet, ohne dass zuerst eine Übungsvorlage erstellt werden muss. Hilft auch automatisch dabei, den Streak aufrechtzuerhalten.

Foto-Upload + Lightbox

Manchmal sind Fotos aussagekräftiger als Zahlen – zum Beispiel Verlaufsfotos oder Formulardokumentationen. Diese Anwendung unterstützt das Hochladen von Fotos direkt vom Mobiltelefon (mit automatischer WebP-Komprimierung auf der Clientseite), die im eigenen CDN unter cdn.jyavani.com gespeichert werden. Es gibt eine modale Lightbox, um Fotos in voller Größe anzuzeigen.

Community-Teilen

Workouts können in Postform mit der Community geteilt werden, komplett mit farbigen Workout-Karten, auf denen Übungen, Sätze und Wiederholungen angezeigt werden. Geeignet für alle, die ihre Fortschritte zeigen oder einfach nur ihre Routine teilen möchten.

Technischer Stack

Next.js 16 App Router, Serverkomponenten, API-Routen, Middleware – die neuesten Next.js-Funktionen.
TypeScript Strikter Modus, Typsicherheit vom Frontend bis zur Datenbank.
Supabase Auth, PostgreSQL, Sicherheit auf Zeilenebene – Backend-Lösung aus einer Hand.
Tailwind CSS v4 Nutzenorientiertheit, schnelles Prototyping, konsistentes Design.
shadcn/ui Radix-UI-Komponenten + einfach anpassbares Tailwind-Design.
TanStack-Abfrage Caching-Serverstatus, optimistische Updates, automatisches erneutes Abrufen.
Vercel Automatisierte Bereitstellung von GitHub, kostenlose, globale Leistung.
CDN (cdn.jyavani.com) Laden Sie den PHP-Handler auf den Heimserver Cloudflare Tunnel hoch und stellen Sie statische Dateien bereit.

Warum diesen Stapel wählen? Next.js bietet vollständige Flexibilität – von statischen Landingpages bis hin zu vollständig interaktiven Dashboards. Supabase macht einen eigenen Backend-Server überflüssig: PostgreSQL als Datenbank, integrierte Authentifizierung und RLS für die Sicherheit. Vercel stellt einfach eine Verbindung zu GitHub her und wird jedes Mal automatisch bereitgestellt, wenn Sie auf „Main“ klicken.

Die Geschichte hinter den Kulissen

Oberflächlich betrachtet scheint diese App einfach zu sein. Aber während der Entwicklung gab es einige ziemlich spannende technische Herausforderungen.

1. Speichern mehrerer ID-Protokolle in einem Beitrag

Die Funktion zum Teilen von Beiträgen unterstützte zunächst nur ein Trainingsprotokoll pro Beitrag – unter Verwendung des Fremdschlüssels workout_log_id in der Tabelle posts. Mit der Zeit möchte ich in der Lage sein, alle heutigen Aktivitäten, einschließlich benutzerdefinierter Aktivitäten, zu teilen.

Ideale Lösung: post_logs Pivot-Tabelle oder Array-Spalte mit Fremdschlüsseln. Es gab jedoch ein Problem: Auf die direkte PostgreSQL-Verbindung zu Supabase konnte nicht zugegriffen werden (nur IPv6, kein Passwort). Es ist nur die REST-API über den Dienstrollenschlüssel verfügbar.

Lösung: Metamarkierungen im Foto-Array

Da ich DDL (Data Definition Language – CREATE TABLE, ALTER TABLE usw.) nicht ausführen kann, habe ich die vorhandene Spalte photos TEXT[] verwendet. Jede Protokoll-ID wird als Markierungszeichenfolge gespeichert: meta:log:uuid-log-id. Wenn der Beitrag angezeigt wird, wird die Markierung mithilfe des getPostPhotos()-Helfers von der ursprünglichen Foto-URL getrennt, dann wird das Protokoll über .in('id', logIds) abgerufen.

Es heißt „Fotos als Nachrichtenbus“ – keine bewährte Methode, aber es funktioniert perfekt innerhalb der Infrastrukturbeschränkungen. Wenn Sie später direkt auf die Datenbank zugreifen können, führen Sie eine Umgestaltung in die relationale Tabelle durch.

2. Benutzerdefinierte Aktivität als verstecktes Training

Benutzerdefinierte Aktivitäten müssen in die Tabelle workout_logs eingegeben werden, um in den Trigger Streak einbezogen zu werden. Aber workout_logs hat die Einschränkung UNIQUE(user_id, workout_id, logged_date) – was bedeutet, dass nur ein Training pro Tag protokolliert werden kann.

Die Lösung: Jede benutzerdefinierte Aktivität erstellt ein verstecktes workout (is_active=false) mit demselben Namen wie die Aktivität. Wenn der Benutzer also „Morning Stretching“ eingibt, erstellt das System automatisch ein „Morning Stretching“-Training, das nicht in der regulären Übungsliste erscheint. Die getOrCreateWorkout()-Funktion sucht nach einem Training mit diesem Namen. Wenn es nicht existiert, erstellen Sie ein neues.

3. Streak-Trigger-Funktion

Streaks werden durch PostgreSQL-Trigger verwaltet, die jedes Mal ausgelöst werden, wenn in workout_logs eine neue Zeile vorhanden ist. Die Triggerfunktion update_streak() prüft last_activity_date – wenn gestern, Streak +1; wenn mehr als ein Tag, auf 1 zurücksetzen.

Es gibt einen Eckfall: Das Frontend muss 0 Streaks anzeigen, wenn der Benutzer einen Tag verpasst, aber die Triggerfunktion wird nur bei INSERT ausgeführt. Das Frontend verfügt also über zusätzliche Logik – wenn last_activity_date weder heute noch gestern ist, wird der Streak als 0 betrachtet. Genau, ohne dass ein Cron-Job oder ein Scheduler erforderlich ist.

4. CDN-Upload – Vom Mobiltelefon zum Heimserver

Die Funktion zum Hochladen von Fotos erfordert eine clientseitige Komprimierung (um Bandbreite auf Vercel zu sparen), einen Next.js-API-Endpunkt, der die Weiterleitung an den Heimserver durchführt, und einen PHP-Handler auf dem Heimserver, der die Datei validiert und speichert. Der Ablauf:

Hape → Kompresi WebP (max 1200px, target ≤300KB)
     → Next.js API Route (/api/upload)
         → Forward ke cdn.jyavani.com/upload.php
             → Simpan ke uploads/media/img/fitness/
             → Balikin URL
         → Catat ke tabel upload_logs (rate limit 2MB/hari)
     → URL masuk ke photos[]

Anwendungsansicht

Hier sind einige Screenshots der laufenden Anwendung:

Dashboard Fitness Tracker
Haupt-Dashboard – zeigt Streak, die heutige Aktivität und die Navigation in der Seitenleiste an.
Trainingsprotokollseite
Trainingsprotokollseite – Kreuzen Sie Übungen an, geben Sie Sätze/Wiederholungen ein oder geben Sie benutzerdefinierte Aktivitäten ein.
Community-Beitrag mit Trainingskarten
Community-Beiträge – jedes Training wird als farbige Karte mit einer Kapitelnummer angezeigt.
Streak Calendar
12-Monats-Streak-Kalender – GitHub-Beitragsdiagrammstil.

Was Sie lernen sollten

Dieses Projekt hat mir viel beigebracht:

  • Next.js App Router – Serverkomponenten, Clientkomponenten, Routengruppen, API-Routen, Middleware für Authentifizierungsschutz
  • Supabase SSR – Einrichten von Cookies für serverseitige Sitzungen, Sicherheit auf Zeilenebene, Dienstrolle für Administratorvorgänge
  • PostgreSQL-Trigger – plpgsql-Funktion zur Streak-Automatisierung, automatische Profilerstellung bei der Registrierung
  • Kreative Problemlösung – Datenbankzugriffsbeschränkungen mit Metamarkierungen in vorhandenen Arrays umgehen
  • CDN-Pipeline – von der Bildkomprimierung im Browser, dem Hochladen über die API bis zur Bereitstellung vom Heimserver über Cloudflare Tunnel
  • PWA – Servicemitarbeiter mit @serwist/next, manifest.json, Offline-Unterstützung

Schließung

Der Bau eines eigenen Fitness-Trackers ist eines der persönlich lohnendsten Projekte. Sie erhalten nicht nur die Anwendung, die Ihren Anforderungen entspricht, sondern lernen dabei auch jede Menge neue Technologien kennen. Manchmal besteht die beste Lösung nicht darin, teure Produkte zu kaufen, sondern darin, eigene Produkte herzustellen – und gleichzeitig etwas Neues zu lernen.

Öffnen Sie den Quellcode auf GitHub. Wenn Sie Anregungen haben, Ideen für Features haben oder Fehler finden, öffnen Sie bitte ein Issue oder eine Pull-Anfrage. Auf die App kann auch unter fitness.adammuiz.com zugegriffen werden. Beachten Sie jedoch, dass es sich hierbei um ein persönliches Projekt handelt, sodass die Registrierung möglicherweise eingeschränkt ist.

Viel Spaß beim Training! 💪