Mobile App
The Klaxon mobile app is built with Expo (React Native) and supports iOS and Android.
Features
- Item list with pull-to-refresh, level badges, and cursor pagination
- Full-text search with debounced input
- Channel filtering — tap a channel to filter the items list
- Item detail with action buttons (ack, dismiss, archive)
- Form answering with 15 field types (draft persistence across app backgrounds)
- Snooze picker (1h, 4h, Tomorrow)
- Comments (view thread + add)
- FCM push notifications with deep linking to item detail
- Settings: server URL, login/logout, quiet hours (start/end/allow levels)
Running Locally
cd apps/klaxon-mobile
npx expo startScan the QR code with Expo Go, or press i for iOS simulator / a for Android emulator.
Stack
| Library | Purpose |
|---|---|
| Expo SDK 54 | Framework |
| Expo Router 6 | File-based navigation |
| TanStack Query 5 | Server state + caching |
| expo-secure-store | Token persistence |
| @react-native-firebase/messaging | FCM push notifications |
@ottercoders/klaxon-protocol | Shared Zod types |
Authentication
The app stores the bearer token in expo-secure-store (encrypted device storage). The Settings tab provides server URL configuration and email + org login.
Magic link login: the mobile app requests a magic link, user receives email, taps the link which opens the app and creates a session.
Push Notifications (FCM)
Firebase Cloud Messaging handles both Android and iOS (FCM routes to APNs):
- App requests notification permission on login
- FCM device token registered with server (
POST /api/push/register) - Token refresh handled automatically
- Tap notification → deep link to
/item/:id
Requires google-services.json (Android) and GoogleService-Info.plist (iOS) from Firebase console. Configure via EAS Build secrets for production.
Deep Linking
The app registers the klaxon:// URL scheme. Push notifications deep-link to item detail:
klaxon://item/<uuid>Search
The Items tab has a search input at the top. Search is debounced (300ms) and uses the server's full-text search (?q= parameter with PostgreSQL plainto_tsquery).
Channel Filtering
Tap a channel in the Channels tab to filter the Items list. A "Filtered by #channel" chip appears with a clear button.
Form Field Types
15 of 22 field types are supported on mobile. Deferred to v2:
fileupload(needs native camera/gallery/file pickers)diffapproval(needs syntax-highlighted diff renderer)markdown(needs React Native markdown renderer)
Form drafts are persisted to localStorage — users don't lose progress if the app backgrounds.
Quiet Hours
Settings tab includes notification controls:
- Toggle quiet hours on/off
- Start/end time (HH:MM format)
- Allow levels during quiet hours (comma-separated, e.g. "error,warning")
Settings sync to the server via PUT /api/settings/:key.