My Role
Product Designer & Builder
Type
Live product
Period
2-4 weeks
The Stack
React + Vite • IndexedDB (Dexie.js) • Supabase • Recharts
A health tracker built on one insight: removing sign-up friction beats adding features. It works fully offline with no account. Your weight, BMI, and body composition stay on your device and sync only when you choose.
Live and offline-first. Full tracking with no sign-up, and data stays on the device until you choose to sync.
"Privacy-first doesn't mean feature-poor. Guest Mode plus offline-first architecture delivers a premium UX with zero account friction."
The Problem
Most fitness apps share one flaw: they want an account before you can do anything. Your data lives on their servers, behind their subscription, under their privacy policy. For anyone privacy-conscious, or just not ready to commit before trying, that's a dealbreaker.
The second problem: they're cloud-dependent. No internet means no access to your own history.
Architecture: Local-First
The core decision was to make IndexedDB the primary data layer instead of a remote database. That means:
- The app loads and works instantly. No auth, no network request, no spinner.
- Everything lives on the device by default.
- Supabase sync is opt-in, and only kicks in when you create an account.
I used Dexie.js as the IndexedDB wrapper for its clean promise-based API and live query hooks that re-render React components when data changes. It behaves like Supabase's real-time, but fully offline.
The Dual-Mode Pattern
Guest Mode → IndexedDB only → Zero account friction
Sync Mode → IndexedDB + Supabase → Multi-device access
Switching from Guest to Sync migrates your local data to the cloud, so nothing is lost. You get to try the whole product before committing to anything.

Key Features
Weight & BMI Tracking
Daily weight logs stored locally, with BMI calculated automatically. The trend chart uses Recharts with a custom gradient fill and reference lines for goal weight and rolling average.
Designing the Forecast States
A naive forecast engine will happily tell a plateauing user "goal in 4,000 days." Forecasts fail in predictable ways, so rather than let those failures surface as nonsense numbers, I turned each one into a designed state:
- Not enough data (under 7 days): asks you to keep logging instead of guessing
- Plateau (under 0.01kg/day change): called out honestly as stagnant, not projected forward
- Off track (trending away from goal): flagged plainly instead of showing a receding date
- Unrealistic horizon (over 730 days): reads "Long Term Goal" instead of a fake-precise date
The forecast earns trust precisely because it admits when it shouldn't be trusted.
On-Device Macro Targets
Macro targets are calculated on the device with the Mifflin-St Jeor BMR formula. No third-party nutrition API, no cloud round-trip, all in keeping with the privacy-first architecture. Inputs: weight, height, age, gender, activity level, goal. Output: daily calories, protein, carbs, and fat in grams.

Body Measurements
Waist, chest, hips, and arms tracked over time, since scale weight alone is a poor read on body composition.
Google Fit Integration
Optional sync with Google Fit through its API, so Form slots into an existing health setup instead of replacing it.
CSV Import / Export
Full data portability. Import history from other apps (if they export CSV) and export your Form data whenever you like. No lock-in.
What I Learned
Building local-first made me treat data ownership as a design constraint, not just a technical one. Every schema decision had to answer two questions: what happens when this data needs to sync, and what happens when local and remote disagree?
The Guest/Sync split also taught me that cutting friction at the top of the funnel beats adding features. In early testing, the biggest driver of retention was letting people start tracking without an account.
Privacy-first doesn't mean feature-poor. Guest Mode plus offline-first gives you a premium experience with zero account friction.