Skip to content
Rahul Nainala
BuildingOn my own · 202608 / 15

GymTracker

A full-stack Android training app on Supabase, with an AI coach that never makes up a number.

screens across Today, Train, Nutrition, Insights and Journey
40+
components in strict TypeScript
100+
versioned SQL migrations on Supabase Postgres
40
cache layers: memory, AsyncStorage, network
3

Overview

GymTracker is the training app I use. It's Expo and React Native in strict TypeScript on a Supabase Postgres backend: 40+ screens across Today, Train, Nutrition, Insights and Journey, 100+ components, and 40 versioned SQL migrations. One rule shapes it: the AI never produces a number. Pure TypeScript engines compute progression, strength scores, nutrition targets and pacing; the models only turn those numbers into words.

Problem → built → result

Problem
Training, nutrition and progress numbers that must agree, and an AI coach that mustn't invent any.
Built
Expo + Supabase app: 40+ screens, 40 SQL migrations, pure engines for numbers, AI for prose.
Result
40+ screens · 40 migrations · Android release build

What I built

  • Expo SDK 55 and React Native in strict TypeScript on Supabase: 40+ screens across Today, Train, Nutrition, Insights and Journey, backed by 40 versioned SQL migrations
  • Reads go through a stale-while-revalidate cache over three layers (an in-memory mirror, AsyncStorage and the network) with request de-duplication, so two cards mounting together make one call
  • Two AI lanes: Llama 3.3 70B on Groq for the many small, fast calls and the Anthropic API for deep analysis; pure engines compute progression, strength scores and nutrition targets
  • Android Health Connect for steps and sessions, barcode food lookup on Open Food Facts, and kilograms stored canonically with pounds for display only
  • A schema-drift script that lists every table.column the app queries, written after a missing column made failed queries look like an empty workout history

Decisions

  1. 1

    Engines compute, the model explains.

    Progression, strength scores, nutrition targets and pacing come from pure TypeScript engines that are tested on their own. The AI only turns their output into words, so it has no way to invent a number.

  2. 2

    Cache in three layers, fetch once.

    Reads go through stale-while-revalidate over an in-memory mirror, AsyncStorage and the network, with request de-duplication: two cards that mount together make one call.

  3. 3

    Two AI lanes, picked by cost.

    Llama 3.3 70B on Groq takes the many small, fast calls; the Anthropic API is kept for deep analysis, where the extra cost buys something.

  4. 4

    Make schema drift loud.

    A missing column once made failed queries look like an empty workout history. A script now lists every table.column the app queries, so drift shows up as a list, not an empty screen.

Why it's shaped this way

A coach is only worth trusting if it can't make up your numbers. Every figure on screen comes from a deterministic engine that can be tested on its own, and the model only explains it.