<HC />
Back to Projects
Mobile ApplicationActive Development

FitTrack — Offline-First Fitness Tracker

An offline-first cross-platform fitness tracking mobile application featuring a pre-bundled 1,324 exercise dataset, dual SQLite storage adapters (expo-sqlite on native, sql.js WASM on web), drag-to-reorder routine builders, and auto-starting rest timers with zero backend dependencies.

Expo SDK 51React Native 0.74TypeScript 5.3expo-sqlitesql.js (WASM)SQLiteZustandExpo Routerreact-native-draggable-flatlistreact-native-svgEAS

Screenshots

FitTrack — Offline-First Fitness Tracker — Library
Library

Key Metrics

Offline-First Mobile Architecture

expo-sqlite (Native) & sql.js WASM (Web)

Immediate Set Disk Writes & Cascade Foreign Keys

Zustand & AsyncStorage Persistence

EAS Android APK & Expo Web

Overview

FitTrack is a cross-platform mobile workout tracker engineered to operate in Wi-Fi dead zones with zero network dependency. Ships with a pre-bundled SQLite database containing 1,324 exercises, dual SQLite engine adapters for native mobile and WASM web targets, drag-and-drop routine builders, and real-time set logging with historical volume analytics.

Problem

Fitness tracking apps typically require active internet connections to query exercises or log sets, causing UI latency or lost data in gym Wi-Fi dead zones, while cross-platform React Native apps struggle to maintain a unified SQLite query layer across native mobile and web targets.

Solution

Built a zero-backend, offline-first mobile architecture with a single pre-populated SQLite asset (exercises.db) and a dual-adapter storage abstraction (client.native.ts with expo-sqlite and client.ts with sql.js/WASM on web). Every completed workout set is written to disk immediately to prevent data loss upon application crash.

Architecture

Cross-platform Expo SDK 51 application using Expo Router for file-based routing. Data querying is decoupled behind a unified DbAdapter interface: native builds execute synchronous queries against expo-sqlite, while web builds target WASM sql.js persisted to localStorage. In-memory state for active sessions and rest-timer countdowns is managed via Zustand stores. All SQL operations use parameterized queries with PRAGMA foreign_keys = ON and ON DELETE CASCADE.

Challenges

  • Designing a single typed query abstraction (DbAdapter) that runs unmodified across synchronous expo-sqlite native bindings and WASM sql.js on web targets.
  • Bundling a pre-seeded 1,324-row SQLite database file into Expo assets to eliminate first-launch JSON parsing and bulk insertion overhead.
  • Managing zero-latency UI updates while executing immediate disk writes for every set to guarantee mid-workout crash protection.
  • Implementing drag-to-reorder routine editing with atomic transaction writes for re-ordered exercise indices.

Lessons Learned

  • Decoupled database adapter architecture for cross-platform React Native and Web SQLite compatibility.
  • Offline-first data persistence strategies for high-reliability mobile tools.
  • Bundling pre-populated relational databases into Expo application bundles.
  • Parameterized SQL query design and cascading foreign key schema enforcement.
  • Managing active session state and background timers with Zustand.

Future Improvements

  • Proper SQLite schema version migration pipeline replacing wholesale file replacements.
  • Cloud synchronization and backup options for cross-device history export.
  • Multi-language exercise instructions UI wiring using stored dataset translations.
  • iOS build profiles and Apple App Store / Google Play Store release configurations.