← Dev log

frontend

Expo-managed React Native, solo

Expo-managed React Native, solo

Bare React Native means managing native iOS and Android project files directly — real power, real complexity, a heavy maintenance burden for one person. Expo's managed workflow abstracts that: write React Native and TypeScript, Expo handles the native build pipeline, provides pre-built wrappers for camera, push, filesystem and secure storage without native code, and gives OTA updates for JS-only changes with no store resubmission.

Push notifications go through expo-server-sdk server-side. The app registers on launch, gets a device push token, sends it to the backend, which stores it in device_push_tokens keyed to the user with a platform field and an is_active flag. When something needs to go out, the outbox processor picks up the event and calls the SDK with the stored tokens.

const messages = tokens.map((token) => ({
  to: token,
  sound: "default",
  title: notification.title,
  body: notification.body,
  data: notification.payload_json,
}));
await expo.sendPushNotificationsAsync(messages);

Tokens live in their own table rather than a field on users because a user can have multiple active devices — phone and tablet, or a reinstall generating a new token while the old one's still registered somewhere. is_active lets the app send to every valid device and mark stale ones inactive when Expo reports a token as dead.

A few mobile realities that don't exist on web

  • App store review cycles mean a native binary change — a new module, a permission change — takes days of lead time, unlike a web deploy live in minutes. That's exactly why OTA updates matter: JS-only fixes ship instantly, anything touching native code can't.
  • Background and foreground state — a mobile app gets killed or loses connectivity far more unpredictably than a browser tab, so realtime features need explicit reconnect-on-foreground handling a web app mostly gets for free.
  • Dark mode and RTL have to be first-class, not inherited — mobile can't reuse web's CSS the way a responsive layout can, so every visual adjustment has to be deliberately mirrored in the React Native styling layer.

Mobile release is a genuinely different pipeline from the web apps' Docker build-push-deploy flow — Expo's build service and store submission, nothing in common with a Docker image push — which is why it's a completely separate workflow.