Two purpose-built applications share a single real-time backend — a web dispatch console for coordinators and a mobile driver app for drivers in the field — connected through Convex's reactive database with Clerk-powered identity for drivers.

01 System Topology
flowchart TD DISPATCH["🖥️ Dispatch Web Console\nExpo Router · Netlify\nCoordinators"] DRIVERAPP["📱 Driver Mobile App\nExpo Router · iOS/Android\nDrivers in the Field"] CLERK["🔐 Clerk Auth\nDriver identity\nJWT tokens"] CONVEX["⚡ Convex Backend\nReal-time reactive DB\nServerless functions"] TWILIO["📨 Twilio\nSMS · Conversations API\nA2P 10DLC"] SHEETS["📊 Google Sheets\nDriver & child roster\nAdmin import source"] EXPONOTIF["🔔 Expo Push\nDriver notifications\nExpoPushToken"] NETLIFY["🌐 Netlify\nCI/CD · Production host\ngit push → deploy"] subgraph CLIENTS ["Client Applications"] DISPATCH DRIVERAPP end subgraph AUTH ["Identity Layer"] CLERK end subgraph BACKEND ["Convex Cloud — Shared Backend"] CONVEX end subgraph EXTERNAL ["External Services"] TWILIO SHEETS EXPONOTIF NETLIFY end DISPATCH -->|"ConvexProvider\nCustom auth\n(authUsers table)"| CONVEX DRIVERAPP -->|"ClerkProvider +\nConvexProviderWithClerk\nclerkId → drivers table"| CLERK CLERK -->|"JWT token\nvalidation"| CONVEX DRIVERAPP --> CONVEX CONVEX -->|"HTTP webhooks\n/twilio/inbound\n/twilio/status"| TWILIO TWILIO -->|"Inbound SMS\nDelivery receipts"| CONVEX SHEETS -->|"importFromSheet\nsheetNameMappings\nfuzzy match"| CONVEX CONVEX -->|"expoPushToken\npush notifications"| EXPONOTIF EXPONOTIF -->|"Delivery to device"| DRIVERAPP NETLIFY -->|"Hosts dispatch app\ngit push → auto deploy"| DISPATCH
02 The Two Applications
🖥️ Dispatch Console
Coordination Hub

Web-first dashboard for coordinators to schedule routes, assign drivers to children, manage SMS communications, and monitor daily operations.

  • stackExpo Router (web) · React Native · TypeScript
  • deployNetlify — git push master → auto-deploy
  • authCustom bcrypt — shared login via authUsers table
  • screensDispatch grid · CRM · SMS Switchboard · Payroll · Schools · Intake Review
  • realtimeLive route status, driver updates, SMS inbox — all via Convex reactive queries
  • publishPublic manifest URLs (/public/:slug) for sanitized daily dispatch view
  • noteClerk auth is scaffolded (comments in _layout.tsx) — ready for future upgrade
📱 Driver Mobile App
Field Operations

Native iOS/Android app for drivers to view their daily routes, log pickup status, message dispatch, and navigate to stops — fully authenticated via Clerk.

  • stackExpo Router · React Native · TypeScript · EAS Build
  • deployEAS Build → TestFlight (iOS) + Google Play (Android)
  • auth🔐 ClerkClerkProvider + ConvexProviderWithClerk · JWT in SecureStore
  • identityClerk userIddrivers.clerkId — driver record linked at first sign-in via by_clerk_id index
  • tabsRoutes · Messages · Directory · Profile
  • pushExpo Push Token stored in drivers.expoPushToken — dispatch can push to any driver
  • i18ni18next — English, Portuguese (pt-BR), Spanish. Matches driver primary language field.
03 Shared Convex Backend
Convex — Single Source of Truth
REACTIVE DATABASE · SERVERLESS FUNCTIONS · HTTP ROUTER · CRON JOBS
Both apps · One DB · Real-time sync
Core Entities
  • drivers clerkId indexed
  • children
  • parents
  • schools · districts · clients
  • vehicles
Routes & Dispatch
  • routes by_date_period
  • stops
  • dispatchEvents
  • scheduleTemplates
  • dailySummaries
  • public_manifests
SMS / Messaging
  • smsMessages
  • smsTemplates
  • smsRecipients
  • smsCampaigns
  • groupConversations
  • groupMessages
  • optouts
Operations
  • notifications
  • auditLogs
  • payrollConfig · baseRates
  • transportationRequests
  • sheetNameMappings
  • crmContacts
  • contactNames
Convex functions: queries mutations actions http.ts (Twilio webhooks) crons.ts auth.config.ts (Clerk domain)
04 Integrated Services
📨
Twilio
SMS blast + Conversations API (group threads). Inbound via HTTP webhook. CTIA-compliant STOP/START opt-out handling. A2P 10DLC registered. Bidirectional conversations stored in Convex.
🔐
Clerk Auth
Driver identity management. ConvexProviderWithClerk bridges JWT to Convex. Driver's clerkId stored in drivers table. Tokens cached in expo-secure-store for offline resilience.
📊
Google Sheets
Authoritative source for driver roster and children master sheet. importFromSheet.ts syncs to Convex with fuzzy name matching via sheetNameMappings table — resolves informal aliases like "Abdul" to canonical records.
🔔
Expo Push
Driver push notifications for schedule changes, pickups, and emergencies. Token registered at driver login and stored in drivers.expoPushToken. Dispatch triggers from coordinator actions.
🌐
Netlify
Hosts the dispatch web app. CI/CD via GitHub: git push master triggers automatic deployment. Zero-config from Expo Router's web output. Production URL for coordinator access from any browser.
05 Key Data Flows
A

Driver sign-in: Clerk authenticates driver → JWT passed to ConvexProviderWithClerk → Convex validates token → driver record fetched by drivers.by_clerk_id index → driver sees their routes.

B

Daily dispatch: Coordinator opens dispatch console → queries routes by_date_period → assigns driver to child → dispatchEvent created → SMS notification triggered to parent via Twilio.

C

Pickup confirmation: Driver taps "Picked Up" in mobile app → Convex mutation updates routes.pickedUpAt + routes.childPresentdispatchEvent emitted → parent receives SMS confirmation in real-time.

D

Roster import: Admin exports Google Sheet → importFromSheet action runs fuzzy name matching against sheetNameMappings → confirmed matches upsert driver/child records → available in both apps instantly.

E

Inbound SMS reply: Parent replies "Running late" → Twilio webhook hits Convex /twilio/inbound → message stored in smsMessages with direction: "inbound" → appears in dispatcher's SMS inbox in real-time.

F

Public manifest: Coordinator clicks "Publish" → public_manifests record created with sanitized names and a unique slug → shareable URL requires no login → school staff or parents can verify pickup roster.