Mobile
Developer reference for the Expo app.
apps/mobile is THERAW, the customer-facing app. It runs Expo SDK 58 (expo ~58.0.19), React Native 0.88.0, React 19.3.0, react-native-gesture-handler 3.3, Reanimated 4.7, expo-router 58 with typed routes and native tabs from expo-router/native-tabs, @expo/ui for native sheets, menus and the date picker, uniwind + HeroUI Native, Zustand + MMKV, Convex reactive subscriptions, and Better Auth with phone OTP + Google + Apple. Version 1.10.0, package com.tipeer.projectr.
Read in order
- Structure — route groups, features, boundary rules.
- Data & Auth — subscriptions, the sign-in sheet, the account stage, session rules.
- Notifications for the pre-prompt rule, push token registration, and the Android channel.
- Commerce — cart, checkout sheet, orders.
- Releases — EAS, fingerprints, and the release command.
- Testing — Jest and Maestro.
- Environment — env.js and production invariants.
The five rules people break first
- No React Query — server state is Convex
useQuerysubscriptions; never manually refetch. - Backend changes happen in
packages/backend— validator changes re-type this app immediately; runbun run check-allafter. convex devnever runs here. It runs only frompackages/backend.- Styling is uniwind, NOT NativeWind. Never install NativeWind or
react-native-css, whichever skill or guide suggests it. Either one adds a second Tailwind runtime that conflicts with uniwind. - Money math is integer cents — parse backend decimal strings once with
toCents(src/shared/utils/money.ts), convert back only at the display boundary.
SDK 58 workarounds
SDK 58 is stable (moved 2026-10-16). A few workarounds wait on upstream releases, and each comes out at its own trigger:
- The Metro redirect of pressto's gesture-handler import to
src/shared/components/ui/utils/pressto-gesture-handler.ts, which exportsLegacyBaseButtonasBaseButton. Without it, dragging a product card or the Home banner to scroll the page on Android opens it instead. Remove it once pressto supports gesture handler 3 (pressto issue #37). - The asset registry mock in
jest-setup.ts, until jest-expo mocks React Native 0.88's private registry module itself. - The React Native Directory exclusion in
apps/mobile/package.json(expo.doctor.reactNativeDirectoryCheck.exclude). Directory marksreact-native-render-htmlunmaintained, and the entry stays until the app replaces the library. With it,bun run doctorand the CI doctor check pass all 20 checks.
Stack headers stay opaque on iOS 26 through opaqueHeaderOptions in src/shared/utils/header-styles.ts. expo-router 58.0.20 made a header transparent whenever a screen sets no header background, and our screens are laid out for an opaque bar.
One upgrade follow-up has no stable trigger. Gesture handler 3 deprecates the Gesture builder, and price-filter-sheet.tsx and notification-row.tsx still call Gesture.Pan(). Moving them to usePanGesture takes its own PR and a device check of the price thumbs inside the Android sheet and of the notification swipe.