Skip to content

Mobile (overview)

The mobile clients are fully native: apps/ios-user + apps/android/app-user (customer) and apps/ios-agent + apps/android/app-agent (agent), built with Swift/SwiftUI and Kotlin/Compose. The earlier Expo apps (expo-user / expo-agent) and their React Native shared packages have been removed.

All mobile conventions — stack, the hand-written tRPC-over-HTTP client, cookie auth (not Bearer), generated design tokens, synced i18n, enum rules, Sentry, and per-platform build commands — live on the dedicated page:

➡️ Conventions → Mobile (Native iOS/Android)

These hold across every mobile app regardless of platform:

  • Cookie auth, never Bearer. Each app owns the Cookie: header end-to-end and sends no Origin (which is what exempts it from the server’s CSRF check). The backend (apps/api) is unchanged.
  • Generated design tokens, never hardcoded color. Read colors through the generated token layer (@Environment(\.tokens) on iOS, LocalTokens.current on Android) — never a raw hex / Color literal.
  • No hand-rolled buttons. Use each app’s shared PrimaryButton / SecondaryButton primitives.
  • Read enums from @repo/database. packages/database/src/enums.ts (values) and packages/database/src/generated/db.ts (column types) are the source of truth — Tour.status = REQUESTED, not PENDING. There are no compile-time enum types on the wire, so a wrong literal fails silently at runtime.
  • Retained deep-link schemes. The native apps keep expo-user:// (customer) and expo-agent:// (agent) — Knock deep links depend on them. The names are historical; the apps are native. They are deliberately not in Better Auth trustedOrigins: a trusted custom scheme, plus the since-removed expo() plugin, made the auth server append the session cookie to a deep-link redirect.

See the native page for everything else.