-
-
Train — one hand, between sets. Weight, reps, RIR; no menus.
-
Body metrics — your body weight counts in the load.
-
Progress — strength on your main lifts with its normal variation band.
-
Programs — your multi-day plan, trained straight from it.
-
Plan analysis — see what your program actually trains before you start.
-
Muscles — weekly volume per muscle against a reference range.
-
Home — the numbers that matter, explained. Every one can be tapped.
-
App icon — 1024 × 1024, uncropped.
Inspiration
Logging a workout is easy. Knowing whether what you do is working is not. Every gym app stores your sets; almost none of them answers the only question that matters after three months: am I getting stronger, or did I just have a good day? Gevel started as a spreadsheet, then a Streamlit dashboard I built for myself and a handful of training partners, because the numbers we cared about — weekly volume per muscle against a reference range, effective sets, strength with its normal variation band — were nowhere to be found in the apps we paid for. The Shipaton was the push to turn that dashboard into the app it always wanted to be.
What it does
Gevel takes what you already write down — sets, reps, weight, effort — and turns it into three answers: how much you work, how it is spread out, and whether your strength is really going up.
- Log the set and keep training: weight, reps and RIR/RPE on one screen, a custom keypad with + / − to adjust on the fly, supersets, warm-ups, drop sets, sets to failure; exercises by reps, time or distance; 506 exercises with the muscles they work, plus your own.
- Your routines, not someone else's: build routines and multi-day programs, train straight from them, and see what your plan actually trains BEFORE you start — sets per muscle, frequency, split. Swap an exercise mid-workout without breaking the session. Every workout is stored with the exact version of what you did that day.
- The numbers that matter, explained: volume per muscle week by week with a reference range; effective sets (the ones close to failure); your strength on your main lifts with the band of your normal variation; push/pull/legs balance; consistency week by week. Every calculated number can be tapped to see where it comes from — and corrected if it does not fit.
- Built for the gym: dark screen, one hand, between sets. Works without signal and syncs on its own. No feed, no likes, nobody to follow.
- Your body weight counts: a pull-up is not the same load for everyone, and added weight or assistance count too.
Gevel does not tell you what to train and does not sell you a fixed plan. You decide; Gevel organises.
How we built it
One codebase, three targets. Gevel is Expo Router + React Native with NativeWind, running as a PWA on the web through react-native-web and as a native iOS app through EAS Build. Offline-first by design: every write lands in a local SQLite store (expo-sqlite) first and reaches the server through an idempotent sync queue keyed by a SHA-256 fingerprint of the workout, so a flaky gym connection never duplicates or loses a set.
The backend is FastAPI on Railway over Supabase Postgres (two schemas: transactional and pre-materialised analytics), with Supabase Auth issuing the JWT every endpoint verifies. Post-workout analytics run as a small ETL after commit.
Monetisation is RevenueCat end to end (see "How Gevel uses RevenueCat" below). Errors are watched with Sentry on both sides, PII-safe. The design system — Plus Jakarta Sans with tabular numerals, an 8-pt scale, a single brand orange on a near-black background — lives in a spec folder inside the repo and every screen is audited against it with Playwright before it ships.
How Gevel uses RevenueCat
- SDK: react-native-purchases + react-native-purchases-ui in the iOS binary. The SDK is configured at launch and the RevenueCat app user ID is set to the Supabase user ID on login (logOut on sign out), so a purchase made by one account is never attributed to another and the server can trust the mapping.
- Products: two App Store auto-renewable subscriptions in the "Gevel Pro" group — gevel_pro_monthly and gevel_pro_yearly — wired to a single entitlement, "pro", inside the "default" offering (yearly is the default package).
- Paywall: built in RevenueCat Paywalls (editor v2) and served as remote config: copy, bullets, pricing variables, brand font and icon are all changed from the dashboard without a build or a review. The screen shown to a user eligible for the launch offer (strikethrough regular price, "save 50%" chip) is a paywall rule, not app code.
- Entitlement check: every gated surface asks the SDK for the "pro" entitlement; "Restore purchases" is one tap away on the paywall.
- Server side: a RevenueCat webhook to our backend keeps the server-side access flag in sync with the customer's entitlements, so analytics endpoints enforce the same truth the client shows.
- App Store Server Notifications point at RevenueCat, so renewals, cancellations and refunds reach the customer record without us polling.
Challenges we ran into
- Turning exercise science into something you can use between sets. The literature gives you volume landmarks per muscle, effective sets close to failure, RIR/RPE autoregulation, frequency and progression rules — as tables and papers. Gevel's job is to apply them to your own log and hand back one readable answer without a lecture: a reference band instead of a number to look up, "how many of your sets actually counted" instead of a definition, a strength trend with its normal variation instead of a raw 1RM. Every formula was reviewed against the evidence before it shipped, and every figure shows the sets behind it so an advanced lifter can check the work and a newer one does not need to.
- Maximum flexibility without a maze. The people Gevel is for do not want a rigid plan: they run their own programs, swap exercises, add supersets, warm-ups, drop sets, sets to failure, exercises measured by reps, time or distance, unilateral work, body-weight work with added load or assistance. Supporting all of that — multi-day programs with an analysis of what the plan really trains before you start, mid-workout swaps that do not break the session, every workout stored with the exact version you did — while keeping a one-hand, no-menus logger was the hardest design problem in the app, and it was solved screen by screen with mockups gated against the design system before a line of code.
- Turning a dashboard into a product. Gevel began in spring 2026 as a Streamlit dashboard over a MySQL warehouse that a few training partners used every week. Good at numbers, useless in a gym. Getting to the App Store meant rebuilding it three times — a FastAPI backend that ported the domain rules, an Expo Router PWA that shipped first because it could be fixed the same day, then the native binary — without pausing the people already using it. That included moving the database to Postgres under live users, keeping the old one as a cold fallback, and later fixing a connection-pool ceiling that one analytics screen (fourteen parallel queries) blew through.
- Offline-first, for real. Every write lands in local SQLite first and reaches the server through an idempotent sync queue keyed by a SHA-256 fingerprint. The first storage library passed every build check and crashed on the first real browser session; and the query layer's default network mode silently never ran a request once the phone had gone offline — the cache only worked "by accident" on cold start until we measured the real transition (open on wifi, walk into the gym).
- Getting the numbers right before making them pretty. A pull-up is not "0 kg": body weight (interpolated for days you did not weigh yourself), added load and assistance all count. Unilateral exercises were silently halving volume until a per-set flag and a backfill fixed eight surfaces at once. Effort is RIR or RPE with imputation when missing, and the 1RM estimate adjusts for it. And we retired our own headline metric — a composite "performance index" — because the people using it could not explain what moved it.
- Native is not "the web on a phone". Two bugs existed only on iOS (inputs left without focus after navigating with the keyboard open; OTP cells not forwarding touches). Apple's first review was the standard "Information Needed" questionnaire — a full-device video and seven written answers — and as a solo developer the paperwork was the product for a week: Paid Apps agreement, tax forms, EU DSA trader details, Small Business Program. One npm script added after the build changed the runtime fingerprint and would have made the post-approval update invisible to the store binary; caught by comparing fingerprints against the live build, now a required step.
Accomplishments that we're proud of
- Maximum flexibility and deeper analytics, and the UI still feels light. That is the whole bet: the depth of the technical apps with the smoothness of the pretty ones. Dark, high-contrast, one brand orange on near-black used only for what you should touch next, Plus Jakarta Sans with tabular numerals so columns never jitter, glass headers that keep context while you scroll, an 8-pt scale everywhere. Dense screens that do not feel dense.
- Programs as flexible as a spreadsheet, as usable as a logger. Multi-day programs with any split, any exercise, supersets, warm-ups, drop sets, sets to failure, reps/time/distance, unilateral and body-weight work — analysed before you run them (sets per muscle, frequency, split), trained straight from the program, with mid-workout swaps that keep the session intact and every workout stored with the exact version you did.
- Analytics that go further and stay readable. Weekly volume per muscle against a reference range, on a front/back muscle map; effective sets; strength on your main lifts with its normal variation band, so a real gain is not confused with a good day; push/pull/legs balance; consistency week by week. Body weight is part of the load, effort is part of the estimate, and every figure opens the sets it came from and can be corrected.
- A 506-exercise library with the muscles each one works, plus your own exercises.
- A paywall that ships from the RevenueCat dashboard, in the brand's typeface, without a build, and a server-side webhook so the backend enforces the same entitlement the client shows.
- Zero-technical-debt policy: 2,200+ backend tests and 570+ frontend contract tests; every fix lands with a test that fails without it; every screen is audited against the design tokens before it ships. A small private beta has trained with it since June through forty-plus production releases without downtime.
What we learned
- Retention beats acquisition in a habit product: if someone does not come back within a week they are gone, so the first session has to deliver the "aha", not the fourth. And early users who are friends tell you about bugs, not about the market — we stopped drawing product conclusions from their retention.
- "It works on the web" says nothing about focus, keyboards, touch or storage on iOS. Measure on the device; do not reason from the code.
- Nothing is done until it is verified by content in production — a green deploy, a passing test, or a note that says "shipped" are all beliefs. We now probe the served bundle for a literal that did not exist before.
- A store listing is a promise: our screenshots are rendered from the real app with seeded data, so when the UI changes the listing regenerates instead of drifting.
- Read the rules at the source, not from memory: the Shipaton's "new apps only" clause, Apple's fiscal-month clock for the Small Business Program and the DSA's public contact fields each reordered a week of work once we read the actual text.
- Kill your own darling when users cannot read it: the metric we built the first version around was the right thing to retire.
- Science only counts if it survives the gym: a guideline the user has to look up is not a feature; a band they can read in two seconds is.
What's next
- Google Play and the web paywall through the same RevenueCat entitlement.
- Import from other logging apps (Hevy/Strong CSV), so the first analytics screen is never empty.
- The longitudinal analytics the whole project was built for: strength trends with readiness and fatigue context, per-muscle volume over months, and insights a lifter can act on — the domain brief is written and the first engine is live.
- A per-muscle view of the week, exercise media (form GIFs), shareable programs and a shareable weekly report.
- English UI (the app ships in Spanish, its first market) and the small things the beta keeps asking for.
Built With
- expo-sqlite
- expo.io
- fastapi
- nativewind
- postgresql
- python
- railway
- react-native
- react-native-purchases
- revenuecat
- sentry
- supabase
- typescript
- vercel
Log in or sign up for Devpost to join the conversation.