

FitZen
AppAI-powered diet and nutrition tracking.
TECHNOLOGY
Decisions from the Expo and React Native apps we build: native modules, EAS builds, RevenueCat subscriptions, Supabase and Firebase backends.
SHORT ANSWER
AMG Software Studio builds most of its mobile apps with Expo and React Native on a single codebase. FitZen and PeakUp are live on iOS and Android, GlowTira on the App Store, and in5min ships from one Expo codebase to iPhone, Mac and Vision Pro. Platform features such as widgets and Live Activities go in as native modules; subscriptions run on RevenueCat, backends on Supabase or Firebase.
Most of our mobile work is written in Expo and React Native: FitZen, GlowTira, PeakUp, HuntLine IQ, RichlyMe, Muslim Mubarak, in5min and Karaman Mobile among them. Two iOS-only products are SwiftUI: PersonaDreams (145 Swift files) and AppsPaper. We decide on how much flow the two platforms share, how deep the device integration goes and what maintenance will look like, not on screen count.
Choosing React Native does not mean giving up native code. The platform-specific part goes in as a small native module:
modules/widget-bridge writes prayer data to shared storage, and the five SwiftUI widgets under targets/widget read it.When the product’s core value is a platform-specific interaction, we say so during discovery and put the native option on the table.
HuntLine IQ’s iOS and Android apps were submitted to TestFlight and Play through EAS from a single Expo SDK 57 codebase. Push goes through the Expo Push Service with no Firebase SDK in the app; a credentials-only Firebase project supplies the FCM key to EAS.
For Karaman Mobile, the client would build for the stores from their own Expo and Firebase accounts, so no secret lives in the source. Calls to the Karaman API go through karaman-proxy, and the production profile refuses to build with mock data.
The most instructive bug appeared in FitZen’s Android 2.0.2 release. A local EAS build left the $VARIABLE placeholders from eas.json unresolved, so the RevenueCat, Firebase and Google sign-in keys entered the bundle as literal placeholder text. The fix treats any value starting with $ as empty in app.config.js and defines defaults for client keys. One item on FitZen’s release checklist comes straight from that: verify from inside the bundle that environment variables actually resolved, for local and cloud builds alike. A separate item requires keys to live in the EAS environment, not only in .env.
In FitZen, six store products were created under identical IDs in both stores, and the three subscriptions map to a single "premium" entitlement in RevenueCat. RevenueCat is the source of truth; Firebase only holds a mirror, and the server, not the client, writes it:
Firestore rules reject client writes to 18 entitlement fields. The audits left two lessons: refunds do not arrive as their own event type but as CANCELLATION with a cancel_reason, and a one-time pack with no expiry date must never count as open-ended premium.
The same pattern runs elsewhere. RichlyMe sells membership only through Apple in-app purchase, managed with RevenueCat; GlowTira and HuntLine IQ use a RevenueCat webhook. The tool can change with the product: Parent Daily runs its subscriptions on Adapty.
We have live products on both; the choice depends on the shape of the data and where the authorisation rule has to live.
On Firebase: FitZen, Wardrova, Muslim Mubarak, in5min, Garaj and Düzce Biz. In Garaj, every decision in a 1v1 quiz match is made in Cloud Functions; the client only calls and listens to the match document. The GPS-timed performance test, by security rule, can write only to the user’s own document.
On Supabase, relational data and row-level authorisation lead:
Some projects connect to an existing backend instead of rebuilding it. In Karaman, a bridge Edge Function maps karaman.com accounts to Supabase profiles; HuntLine IQ’s mobile app uses the same Supabase project as the web platform.
A mobile app rarely lives alone; it usually sits next to a web panel or a web product. The most expensive mistake then is the two sides applying the same rule differently.
In HuntLine IQ the client’s web app already existed, and there were three weeks to get the iOS and Android apps ready for the Tennessee fair window. The scope sentence was clear: exact behavioural parity with the web, plus two features contracted for native. The typed API layer, constants, date formatting and EXIF-preserving photo preparation were ported from the web repo. TanStack Query keys mirror the web cache, and design tokens were frozen from the web CSS and moved to NativeWind. The server gained only two things: a push-token registry and a RevenueCat webhook.
In PeakUp, members, trainers and the studio owner share one Expo app, with a Next.js 16 panel for the owner. The shared @peakup/shared package carries zod schemas and the VAT, absence and package-deduction rules, and the same rules are enforced by CHECK constraints in the database. Düzce Biz keeps its Expo app, Next.js 16 panels and shared types in one monorepo as well.
In FitZen, the App Review risk sat less in the code than in how the paywall was presented. Our audit of build 91 (1.2.3) found two blockers: the paywall showed "3 days free" without an eligibility check, and prices plus struck-through discounts were hard-coded by UI language rather than storefront. In the new usePaywall hook, prices and trial info come straight from the RevenueCat offering, and if eligibility is unknown no trial is promised. Review notes and a premium demo account are prepared so the reviewer can get past the paywall.
A quality gate runs before release. In PeakUp, database and RLS tests, contract checks and unit tests sit under one pnpm dogrula command, and nothing ships unless it is green. The app went out on iOS and Android as the 2.0.0 update to the existing store listing.
App Store and Google Play developer accounts are opened in the client’s name. Karaman Mobile is a typical case: the client builds from their own Expo account, and the app was delivered in September 2026 with source, setup instructions and server release notes.
Yes, and we have done it on several projects by adding native modules to the Expo codebase. In Muslim Mubarak, five WidgetKit widgets read prayer times through a native bridge module; in in5min, Live Activities and a home-screen widget were added as native modules. The native part stays limited to the platform-specific piece, and the rest of the app remains shared React Native code.
Yes. For HuntLine IQ we built iOS and Android apps with exact behavioural parity with the client’s web app on a three-week schedule. The typed API layer and date formatting were ported from the web repo, and the server gained only a push-token registry and a RevenueCat webhook. Before starting, we review the existing API, authentication and data model to define the integration scope.
On the server, not in the bundle. In GlowTira no provider key ships in the app; the trust boundary is the Edge Function. In Parent Daily the assistant chat reaches OpenAI through a Cloud Function. In FitZen, model calls go through a proxy on a Cloudflare Worker that maps retired model names to current ones, so a fix ships without waiting for store review.
No, though many of our projects use it: FitZen, GlowTira, RichlyMe, HuntLine IQ and Macsug. Parent Daily runs subscriptions on Adapty, with attribution through AppsFlyer and the Meta SDK. Whatever the tool, the rule we applied in FitZen holds: the server, not the client, writes the premium flag, and prices and trials are read from the store rather than from code.
One codebase can ship to iOS and Android together; FitZen and PeakUp are live in both stores. in5min serves iPhone, Mac and Vision Pro from one Expo codebase. GlowTira and RichlyMe target iOS only for now. Every extra platform means its own device testing and its own store review, and we plan both into the schedule.
By measuring first. FitZen’s performance audit counted 4 to 8 redundant premium checks at launch and on every tab focus; concurrent calls were merged into one request and the result cached for 60 seconds. react-native-purchases shipped about 880 KB of web fallback in the native bundle, which metro.config.js now swaps for an empty stub. Startup tasks were prioritised and a 1,300-line subscription service was split into modules.
You do. App Store and Google Play developer accounts, servers and service accounts are opened in your name. At delivery we hand over the full source code, the design files and every credential.
No. We design the user screens and the admin panel screens for your project and build them from scratch, so the panel follows your workflow.
RELATED STUDIO NOTES


AI-powered diet and nutrition tracking.

An AI beauty and style coach.


Fitness studio management and member tracking in one app.


Hunting movement insight that never exposes your exact location.


An invitation-only members’ club app where experiences are shared with proof.


Prayer times, Quran and a daily worship companion.
It starts with an intro call. We define the scope and timeline together, then send you a written proposal.
hello@amgsoftwarestudio.com