Skip to main content

Mobile overview

Status: Scaffolded 2026-09-24

vegan-grove-mobile is an Expo SDK 57 app with expo-router and TypeScript, built for iOS and Android from one codebase through EAS. It is the primary member surface: places on a map, events, the feed, messages, and the companion. It holds almost nothing on the device and never sends the device's location to the server.

Stack​

ConcernChoice
RuntimeExpo SDK 57, React Native 0.86, React 19
Routingexpo-router, file-based, route groups (auth) and (tabs)
Map@maplibre/maplibre-react-native with the OpenFreeMap liberty style
Server dataTanStack Query
Auth statezustand, one store
Secrets on deviceexpo-secure-store for the session token
Imagesexpo-image-picker then expo-image-manipulator re-encode to strip EXIF
Locationexpo-location, when-in-use, used only to center the map client-side
Pushexpo-notifications
Lint, formatBiome, shared config

No analytics SDK, no crash reporter with PII, no NativeWind, no form library. Styling is StyleSheet with tokens from src/theme/tokens.ts, the mobile mirror of the --vg-* values in the tech stack.

Layout​

app/
_layout.tsx providers, AuthGate, theme
(auth)/ welcome, login, register, magic-link
(tabs)/ index (home), places, events, feed, messages
profile/ index, edit, settings, privacy, account (hidden from the tab bar)
companion.tsx modal
src/
constants/api.ts EXPO_PUBLIC_API_BASE_URL and the ENDPOINTS registry
lib/api/client.ts fetch wrapper: Bearer, timeout, normalized errors
lib/stores/authStore.ts
lib/images/stripExif.ts
theme/tokens.ts
scripts/
check-prod-ready.sh the release guard
gen-brand-assets.mjs regenerates the placeholder brand PNGs
eas-build-pre-install.sh EAS lifecycle hook that reruns the guard on store profiles
app.config.ts bundle id org.vegangrove.app, scheme vegangrove, plugins, env-sourced values
eas.json development, preview, production, testflight, playstore

Details: navigation, state and data, API client, build and release.

Why a development client​

MapLibre is native code, so Expo Go cannot run this app. Day-to-day development uses a development build from the development EAS profile installed on a simulator or device, then npm start (which runs expo start --dev-client). The build is made once per native dependency change, not per code change; JavaScript still hot-reloads.

ios/ and android/ are gitignored and never generated in the repo. Native configuration lives in app.config.ts and config plugins (the MapLibre plugin, expo-notifications, expo-secure-store, expo-location), and EAS generates the native projects on its build machine. See mobile deployment.

What the scaffold contains​

Every screen file above exists and renders a placeholder with the right title. The places tab renders the map centered on Southern California and queries GET /api/places?bbox= through TanStack Query as the viewport settles. Auth screens call the API client and store the session; AuthGate redirects. Profile, feed, events, messages, and the companion are stubs that will be filled per milestone. validate (Biome, tsc --noEmit, check:prod) passes on a fresh clone.