A React Native messaging smart phone application with AI-powered features for international communicators. Built with Firebase, Zustand, and SQLite for robust offline-first messaging.
Target Persona: International Communicator
- Professionals, students, and travelers who regularly communicate across language barriers
- Need real-time translation, cultural context hints, and formality adjustment
- Require reliable messaging with offline support for global connectivity
- Real-time Messaging: Sub-200ms message delivery with Firestore onSnapshot listeners
- User Authentication: Email/password authentication with comprehensive debugging and error handling
- Contact Management: Friend requests, user search, contact lists, and blocking functionality
- Online Presence: Real-time online status with heartbeat mechanism and app lifecycle integration
- Group Messaging: Support for 3+ users in conversations with participant management
- Message Features: Real-time read receipts, typing indicators, message attribution, and unread counts
- Offline Support: SQLite message queuing with automatic sync on reconnection
- Network Visibility: Discreet status indicator with detailed information modal and manual controls
- Cross-platform: Works consistently on iOS and Android
- Performance: FlashList optimization for smooth scrolling through 1000+ messages
- Android Compatibility: Comprehensive fix for text cutoff issues
- Diagnostics: Comprehensive logging system with SQLite persistence and console integration
- Architecture: Unified queue-first architecture with three-tier data flow and sequential message processing
- Scalable Friend Management: O(1) friend lookups using Firestore subcollections
- Real-time Online Status: See when friends are online/offline with heartbeat mechanism
- App Lifecycle Integration: Automatic presence updates on background/foreground transitions
- Crash-Resistant Design: 40-second timeout for reliable offline detection
- Audit Trail: Complete friend request history preserved for compliance
- Minimal Storage: Friend documents store only essential data, profiles cached in SQLite
- Context-Aware Translation: AI analyzes conversation history for accurate translations
- Tool Calling System: AI can request additional context when confidence is low
- RAG Integration: SQLite-based retrieval system for conversation context
- Cultural Context Hints: Automatic cultural notes and formality guidance
- Language Detection: Automatic source language detection
- Two-Phase Translation: Exploratory phase determines if more context is needed
- Real-time Progress: Live status updates during translation process
- Confidence Scoring: AI provides confidence levels for translation accuracy
- Reference Analysis: Identifies and explains references to earlier messages
- Message Delivery: <200ms on good network (Firestore real-time listeners)
- App Launch: <2s to chat screen (optimized initialization)
- Memory Usage: Bounded to 100 messages per conversation (windowed Zustand)
- Offline Sync: <1s after reconnection (incremental sync)
- Database Operations: 99.7% improvement in conversation loading (6,900ms β 18ms)
- Cross-platform: Consistent experience on iOS, Android, and Web
- Firestore Operations: 50% reduction with subcollection architecture
- Read Receipts: Real-time behavior with proper timing (entry vs exit)
- Friend Management: O(1) friend lookups with subcollection architecture
- Online Presence: 30-second heartbeat with 40-second timeout for reliability
- Three-tier Data Flow: Firestore (Authoritative) β SQLite (Cache) β Zustand (Memory)
- Unified Queue-First: All messages queue first, process immediately if online
- Sequential Processing: Messages processed one by one to maintain order and prevent race conditions
- UUID-based Idempotency: Prevents duplicate messages throughout lifecycle
- Incremental Sync: Only fetch new messages using
getMessagesSince() - Memory Management: Conversation lifecycle with load/unload patterns
- Scalable Friends: Subcollection-based friend management for millions of users
- Presence Tracking: Heartbeat mechanism with app lifecycle integration
- Node.js 22
- Firebase project with Firestore enabled
- iPhone and/or Android device with Expo Go app installed
-
Clone and install dependencies
git clone <repository-url> cd rn-firebase-hello-world npm install
-
Configure Firebase
- Create a Firebase project at console.firebase.google.com
- Enable Firestore Database and Authentication (email/password)
- Copy
.env.templateto.envand fill in your Firebase config:
cp .env.template .env
Then edit
.envwith your Firebase project details:# Firebase Configuration EXPO_PUBLIC_FIREBASE_PROJECT_ID= EXPO_PUBLIC_FIREBASE_API_KEY=your-api-key-here EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com EXPO_PUBLIC_FIREBASE_PROJECT_ID=your-project-id EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project.appspot.com EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=123456789 EXPO_PUBLIC_FIREBASE_APP_ID=your-app-id EXPO_PUBLIC_FIREBASE_MEASUREMENT_ID=your-measurement-id EXPO_PUBLIC_DATABASE_URL=your-firestore-url # From the AWS CDK deployment in `server/` EXPO_PUBLIC_API_URL=your-api-server-url
-
Deploy Firestore Security Rules
firebase deploy --only firestore:rules
-
Deploy Firestore Indexes
firebase deploy --only firestore:indexes
-
Start the development server
npx expo start --clear
-
Open on device
- Scan QR code with Expo Go (iOS/Android)
- Press
rto refresh all connected devices
Firebase Connection Issues
- Ensure Firebase project has Firestore and Authentication enabled
- Verify all environment variables in
.env.localare correct - Check Firebase console for any quota limits or billing issues
- Run
firebase deploy --only firestore:rulesto ensure rules are deployed
Expo Go Connection Issues
- Make sure device and computer are on the same network
- Try
npx expo start --clearto clear cache - Restart Expo Go app if QR code scanning fails
- Use tunnel mode:
npx expo start --tunnelfor network issues
Message Sync Issues
- Check network status indicator (top-right corner)
- Use Diagnostics tab to view detailed logs
- Force sync by tapping refresh button in network modal
- Check SQLite database in Diagnostics for queued messages
Performance Issues
- Monitor memory usage in Diagnostics tab (in dev mode)
- Diagnostics Tab: Comprehensive logging system with SQLite persistence and copy functionality
- Network Status: Real-time connection monitoring with manual controls and Firebase state tracking
- Console Logs: All application logs automatically appear in console with try-catch safety
- SQLite Inspector: View local database state, queued messages, and log history
- Authentication Debugging: Complete authentication flow tracking with error context
- Log Filtering: Filter logs by level (Verbose, Error, Warning, Info, Debug)
- Export Logs: Copy formatted logs to clipboard for external analysis
MessageAI implements a sophisticated unified queue-first architecture that ensures reliable message delivery and optimal performance across all network conditions.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MESSAGEAI ARCHITECTURE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β UI Layer β β State Mgmt β β Services β β
β β β β β β β β
β β β’ React βββββΊβ β’ Zustand βββββΊβ β’ Firebase β β
β β Native β β β’ SQLite β β β’ Message β β
β β β’ Expo β β β’ Async β β β’ Auth β β
β β Router β β Storage β β β’ User β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β β β β
β βΌ βΌ βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β UNIFIED QUEUE-FIRST FLOW β β
β β β β
β β User Types Message β Always Queue First β Process Queue β β
β β β β
β β βββββββββββββββ βββββββββββββββ βββββββββββββββ β β
β β β Online β β Offline β β Reconnect β β β
β β β β β β β β β β
β β β Queue β β β Queue β β β Queue β β β β
β β β Process β β Wait β β Process + β β β
β β β Immediately β β β β Sync Missed β β β
β β βββββββββββββββ βββββββββββββββ βββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DATA FLOW ARCHITECTURE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β FIRESTORE (Authoritative Truth) β β
β β β β
β β β’ Real-time subscriptions (onSnapshot) β β
β β β’ Incremental sync (getMessagesSince) β β
β β β’ Server-side persistence & conflict resolution β β
β β β’ Expensive operations (minimize queries) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β SQLITE (Persistent Cache) β β
β β β β
β β β’ ALL messages stored locally β β
β β β’ Full-text search (FTS5) β β
β β β’ Message queuing (offline scenarios) β β
β β β’ Sync metadata (lastSyncedAt per conversation) β β
β β β’ Optimized indexes for fast queries β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β ZUSTAND (In-Memory Window) β β
β β β β
β β β’ Last 100 messages per conversation β β
β β β’ Real-time UI updates β β
β β β’ Conversation lifecycle management β β
β β β’ Memory-bounded (prevents bloat) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MESSAGE LIFECYCLE FLOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β 1. USER TYPES MESSAGE β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Generate UUID (Crypto.randomUUID()) β β
β β β’ Same ID used throughout entire lifecycle β β
β β β’ Prevents duplicates & enables idempotency β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β 2. ALWAYS QUEUE FIRST (Unified Flow) β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β SQLite Queue Operations: β β
β β β’ INSERT INTO queued_messages β β
β β β’ Optimistic UI update (immediate display) β β
β β β’ Status: "sending" β "sent" β "failed" β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β 3. PROCESS QUEUE (If Online) β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Firestore Operations: β β
β β β’ Check existing.exists() before setDoc() (idempotency) β β
β β β’ setDoc() with UUID (idempotent) β β
β β β’ Update conversation (lastMessage, unreadCounts) β β
β β β’ Remove from queue on success β β
β β β’ Update retry count on failure β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β 4. REAL-TIME DISTRIBUTION β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Firestore onSnapshot β All Participants: β β
β β β’ Real-time message delivery (<200ms) β β
β β β’ SQLite cache update (INSERT OR REPLACE) β β
β β β’ Zustand state update (if conversation loaded) β β
β β β’ UI re-render with new message β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β OFFLINE/ONLINE SYNC FLOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β OFFLINE SCENARIO β β
β β β β
β β User Types Message β Queue in SQLite β Wait β β
β β β β
β β β’ Message stored with UUID in queued_messages table β β
β β β’ Optimistic UI update (shows "sending" status) β β
β β β’ Network status indicator shows "offline" β β
β β β’ No Firestore operations attempted β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β RECONNECTION β β
β β β β
β β Network Status: Offline β Online β β
β β β β
β β β’ Connection store detects network change β β
β β β’ Triggers processQueue() (send queued messages) β β
β β β’ Triggers syncMissedMessages() (fetch new messages) β β
β β β’ Updates sync metadata (lastSyncedAt) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β SYNC OPERATIONS β β
β β β β
β β 1. Process Queue: β β
β β β’ Send queued messages to Firestore β β
β β β’ Remove from queue on success β β
β β β’ Update retry count on failure β β
β β β β
β β 2. Sync Missed Messages (Incremental query): β β
β β β’ getMessagesSince(lastSyncedAt) for each conversation β β
β β β’ Batch save to SQLite (INSERT OR REPLACE) β β
β β β’ Add new messages to Zustand (if conversation loaded) β β
β β β’ Update lastSyncedAt timestamp β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MEMORY MANAGEMENT STRATEGY β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β CONVERSATION LIFECYCLE β β
β β β β
β β User Opens Conversation: β β
β β β β β
β β βΌ β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β loadConversationMessages(conversationId): β β β
β β β β β β
β β β β’ Load last MAX_MESSAGES_IN_MEMORY (100) messages β β β
β β β from SQLite β β β
β β β β’ Add to Zustand state β β β
β β β β’ Subscribe to Firestore real-time updates β β β
β β β β’ Background sync for any missed messages β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β
β β User Closes Conversation: β β
β β β β β
β β βΌ β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β unloadConversationMessages(conversationId): β β β
β β β β β β
β β β β’ Remove messages from Zustand state β β β
β β β β’ Unsubscribe from Firestore listeners β β β
β β β β’ Free memory (messages remain in SQLite cache) β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β MEMORY BOUNDARIES β β
β β β β
β β β’ Zustand: 100 messages Γ N conversations (bounded) β β
β β β’ SQLite: ALL messages (persistent, unlimited) β β
β β β’ Firestore: Authoritative source (server-side) β β
β β β β
β β Benefits: β β
β β β’ Fast UI performance (limited memory usage) β β
β β β’ Complete offline access (SQLite cache) β β
β β β’ Reliable sync (Firestore authoritative) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SUBSCRIPTION ARCHITECTURE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β CONVERSATIONS SUBSCRIPTION β β
β β β β
β β When: App Start (User Login) β β
β β Where: ConversationsList.tsx β β
β β Purpose: Monitor conversation list changes β β
β β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β useEffect(() => { β β β
β β β if (user) { β β β
β β β loadConversations(user.uid); β β β
β β β subscribeToConversations(user.uid); β β β
β β β } β β β
β β β }, [user]); β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β
β β On Updates: β β
β β β’ New conversations appear in list β β
β β β’ Conversation metadata updates (lastMessage, unread) β β
β β β’ Triggers UI refresh of conversations list β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β MESSAGES SUBSCRIPTION β β
β β β β
β β When: Enter Conversation (ConversationView mount) β β
β β Where: ConversationView.tsx β β
β β Purpose: Real-time message updates for active conversation β β
β β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β useEffect(() => { β β β
β β β loadConversationMessages(conversationId); β β β
β β β return () => { β β β
β β β unloadConversationMessages(conversationId); β β β
β β β }; β β β
β β β }, [conversationId]); β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β
β β On Updates: β β
β β β’ New messages appear instantly (<200ms) β β
β β β’ Read receipt updates propagate β β
β β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β Message Callback Handler: β β β
β β β β β β
β β β 1. Save ALL messages to SQLite (upsert) β β β
β β β await sqliteService.saveMessagesBatch(messages) β β β
β β β β β β
β β β 2. Update Zustand state (conversation view) β β β
β β β β’ Find new messages (not in current state) β β β
β β β β’ Update read receipts for existing messages β β β
β β β β’ Merge and limit to 100 messages β β β
β β β β’ Trigger UI re-render β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β SUBSCRIPTION LIFECYCLE β β
β β β β
β β App Start: β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β User Login β ConversationsList mounts β β β
β β β β subscribeToConversations() (persistent) β β β
β β β β Monitor conversation list changes β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β
β β Enter Conversation: β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β User taps conversation β ConversationView mounts β β β
β β β β loadConversationMessages() β β β
β β β β Load MAX_MESSAGES_IN_MEMORY (100) messages from SQLiteβ β β
β β β β subscribeToMessages() (conversation-specific) β β β
β β β β Real-time message updates β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β
β β Leave Conversation: β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β User navigates away β ConversationView unmounts β β β
β β β β unloadConversationMessages() β β β
β β β β Unsubscribe from messages β β β
β β β β Clear Zustand state (free memory) β β β
β β β β Messages remain in SQLite cache β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β
β β App Close: β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β User logout β clearAllData() β β β
β β β β Unsubscribe from conversations β β β
β β β β Clear all subscriptions β β β
β β β β Clear all state β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ERROR HANDLING & RETRY LOGIC β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β QUEUE PROCESSING β β
β β β β
β β processQueue() with Mutex Protection: β β
β β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β if (queueProcessingMutex) return; // Prevent concurrent β β β
β β β queueProcessingMutex = true; β β β
β β β β β β
β β β try { β β β
β β β for (const queuedMessage of queuedMessages) { β β β
β β β try { β β β
β β β await messageService.sendMessage(messageId, β β |
β β β conversationId, senderId, text) β β β
β β β await sqliteService.removeQueuedMessage(id) β β β
β β β } catch (error) { β β β
β β β await sqliteService.updateQueuedMessageRetry( β β β
β β β id, error.message, retryCount + 1 β β β
β β β ) β β β
β β β } β β β
β β β } β β β
β β β } finally { β β β
β β β queueProcessingMutex = false; β β β
β β β } β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β RETRY STRATEGY β β
β β β β
β β β’ Max Retry Count: 3 attempts β β
β β β’ Exponential Backoff: 1s, 2s, 4s delays β β
β β β’ Error Tracking: Store error message in SQLite β β
β β β’ User Feedback: Show "failed" status in UI β β
β β β’ Manual Retry: User can tap failed message to retry β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
MessageAI implements a sophisticated AI translation system with tool calling and RAG (Retrieval-Augmented Generation) capabilities that protects API keys while providing context-aware translation and cultural guidance for international communicators.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SECURE AI TRANSLATION FLOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β MESSAGEAI APP β β
β β β β
β β User Types Message β Translation Request β API Server β β
β β β β
β β β’ No API keys stored in app β β
β β β’ Firebase ID token for authentication β β
β β β’ Secure HTTPS communication β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β API SERVER (AWS Lambda) β β
β β β β
β β 1. Firebase Admin Authentication β β
β β β’ Verifies Firebase ID token β β
β β β’ Confirms user is authenticated β β
β β β β
β β 2. OpenAI API Integration β β
β β β’ Secure API key storage (server-side only) β β
β β β’ GPT-4.1-mini for translation + cultural context β β
β β β β
β β 3. Response Format β β
β β β’ Translation result β β
β β β’ Cultural context and formality notes β β
β β β’ JSON response to MessageAI β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Firebase Admin Authentication: Verifies user identity using Firebase ID tokens
- Secure API Key Management: OpenAI API key stored server-side, never exposed to client
- Tool Calling System: AI can request additional context when confidence is low
- Two-Phase Translation: Exploratory and execution phases for optimal accuracy
- RAG Integration: Context retrieval from conversation history
- Cultural Context & Formality: Uses GPT-4.1-mini for accurate translations with cultural notes
- Language Detection: Automatic source language identification
- Confidence Scoring: AI provides confidence levels for translation accuracy
- AWS Lambda Deployment: Serverless architecture for cost-effective scaling
- HTTPS Security: All communication encrypted in transit
- User Input: User taps message to translate in MessageAI app
- Authentication: App sends Firebase ID token with translation request
- Server Validation: API Server verifies token using Firebase Admin SDK
- Exploratory Phase: AI analyzes message and conversation history
- Tool Calling Decision: AI either translates directly or requests more context
- RAG Search (if needed): SQLite FTS5 search for relevant conversation context
- Execution Phase: AI translates with full context and cultural awareness
- Response: Server returns translation, cultural notes, and confidence score
- Display: MessageAI shows translation with progress indicators and cultural context
MessageAI uses a custom MiniGraph implementation (inspired by LangGraph) to orchestrate complex AI workflows. The orchestrator manages the two-phase translation process with intelligent context retrieval and tool calling capabilities.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MINIGRAPH AI ORCHESTRATOR β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β TRANSLATION CONTEXT β β
β β β β
β β β’ Message to translate β β
β β β’ Conversation history (last 5 messages) β β
β β β’ Speaker and audience information β β
β β β’ Target language preference β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β NODE: TRANSLATE β β
β β β β
β β Phase: Exploratory β β
β β Action: Call /translate/explore β β
β β β β
β β AI Decision: β β
β β β’ High confidence (>95%) β Direct translation β β
β β β’ Low confidence (<95%) β Request more context β β
β β β β
β β Response Types: β β
β β βββββββββββββββββββ βββββββββββββββββββ β β
β β β Translation β β Tool Call β β β
β β β Response β β Response β β β
β β β β β β β β
β β β β’ translated β β β’ search_terms β β β
β β β β’ cultural_notesβ β β’ reason β β β
β β β β’ confidence β β β’ confidence β β β
β β βββββββββββββββββββ βββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β NODE: SEARCH β β
β β β β
β β Trigger: Tool Call Response β β
β β Action: SQLite FTS5 Search β β
β β β β
β β Process: β β
β β 1. Extract search terms from AI response β β
β β 2. Perform FTS5 search in SQLite database β β
β β 3. Retrieve relevant conversation context β β
β β 4. Format context for AI consumption β β
β β β β
β β Context Enhancement: β β
β β β’ Find messages containing search terms β β
β β β’ Include speaker names and timestamps β β
β β β’ Limit to 5 most relevant results β β
β β β’ Deduplicate and sort by relevance β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β NODE: TRANSLATE β β
β β β β
β β Phase: Execution β β
β β Action: Call /translate/execute β β
β β β β
β β Enhanced Context: β β
β β β’ Original message β β
β β β’ Conversation history β β
β β β’ Additional context from FTS5 search β β
β β β’ Speaker and audience information β β
β β β β
β β AI Processing: β β
β β β’ Analyze full context for cultural nuances β β
β β β’ Identify references to earlier messages β β
β β β β’ Adjust formality based on conversation tone β β
β β β β’ Provide cultural context and explanations β β
β β β β’ Generate confidence score for translation β β
β β β β
β β Final Response: β β
β β β’ translated_text: Final translation β β
β β β’ cultural_notes: Cultural context and guidance β β
β β β’ references_earlier: Boolean flag β β
β β β’ reference_detail: Explanation of references β β
β β β’ confidence: AI confidence score (0-100) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β NODE: DONE β β
β β β β
β β Action: Stop execution β β
β β Result: Return translation to user β β
β β β β
β β User Experience: β β
β β β’ Translation displayed in MessageBubble β β
β β β’ Cultural notes shown in modal β β
β β β’ Reference explanations provided β β
β β β’ Confidence indicator displayed β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββ Tool Call βββββββββββββββ Enhanced βββββββββββββββ
β TRANSLATE β ββββββββββββββββΊ β SEARCH β βββββββββββββββΊ β TRANSLATE β
β (Exploratory)β β β β (Execution) β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β β
β Direct Translation β
β (High Confidence) β
βΌ βΌ
βββββββββββββββ βββββββββββββββ
β DONE β βββββββββββββββββββββββββββββββββββββββββββββββββ β DONE |β | | |
β β β β
βββββββββββββββ βββββββββββββββ
- Intelligent Decision Making: AI determines when additional context is needed
- Context-Aware Translation: Uses conversation history and cultural context
- Tool Calling System: AI can request specific information from the database
- RAG Integration: SQLite FTS5 search provides relevant conversation context
- Confidence Scoring: AI provides confidence levels for translation accuracy
- Reference Analysis: Identifies and explains references to earlier messages
- Cultural Intelligence: Provides cultural notes and formality guidance
- Error Handling: Graceful fallbacks and retry logic built into the graph
The API Server URL is configured in your .env file:
# From the AWS CDK deployment in `server/`
EXPO_PUBLIC_API_URL=your-api-server-urlFor detailed API Server setup and deployment, see the server/README.md.
- Frontend: React Native 0.81.4 + Expo ~54.0.13
- Backend: Firebase (Firestore, Auth, Cloud Functions)
- State Management: Zustand 5.0.8
- Local Database: SQLite (expo-sqlite) + AsyncStorage
- Navigation: Expo Router ~6.0.12 (file-based routing)
- Real-time: Firestore onSnapshot listeners
- AI Integration: OpenAI GPT-4.1-mini (via secure API Server)
- AI Orchestration: MiniGraph (LangGraph-style state machine)
- RAG System: SQLite FTS5 full-text search
- Tool Calling: Two-phase translation with context retrieval
- Performance: FlashList for optimized list rendering
- TypeScript: Full type safety throughout
app/ # Expo Router pages
βββ _layout.tsx # Root layout with auth initialization
βββ (tabs)/ # Tab navigation
β βββ index.tsx # Home (ConversationsList)
β βββ contacts.tsx # Contact management
β βββ profile.tsx # User profile
βββ conversation/[id].tsx # Dynamic conversation route
βββ auth/login.tsx # Authentication
βββ profile/edit.tsx # Profile editing
components/ # Reusable UI components
βββ ConversationsList.tsx # Main conversations list
βββ ConversationView.tsx # Chat interface
βββ MessageBubble.tsx # Individual message component
βββ ContactsList.tsx # Contact/friend list
βββ UserSearch.tsx # User search functionality
βββ TypingIndicator.tsx # Real-time typing status
βββ NetworkStatusBar.tsx # Network status indicator
βββ ui/ # Shared UI components
stores/ # Zustand state management
βββ authStore.ts # Authentication state
βββ messagesStore.ts # Real-time message management
βββ contactsStore.ts # Contact and friend management
βββ connectionStore.ts # Network connection status
services/ # Business logic
βββ authService.ts # Authentication operations
βββ messageService.ts # Message CRUD operations
βββ conversationService.ts # Conversation management
βββ friendService.ts # Friend request operations with subcollection management
βββ presenceService.ts # Online presence and heartbeat management
βββ userService.ts # User profile operations
βββ sqliteService.ts # Local database operations
types/ # TypeScript interfaces
βββ Message.ts # Message interface
βββ Conversation.ts # Conversation interface
βββ User.ts # User interface with online and heartbeat fields
βββ Friend.ts # Friend interface for subcollection documents
βββ FriendRequest.ts # Friend request interface
New Data Architecture:
// User documents with presence tracking
interface User {
id: string;
email: string;
displayName: string;
// ... existing fields
online: boolean; // Real-time online status
heartbeat: Timestamp; // Last heartbeat (30s intervals)
}
// Friends subcollection: /users/{userId}/friends/{friendId}
interface Friend {
id: string; // Friend's user ID
addedAt: Timestamp; // When friendship was established
}
// Friend requests preserved for audit trail
interface FriendRequest {
// ... existing fields (unchanged)
}Architecture Benefits:
- O(1) Friend Lookups: Subcollection queries instead of O(n) collection scans
- Minimal Storage: Friend documents store only essential data
- Audit Trail: friendRequests collection preserved for compliance
- Real-time Presence: 30-second heartbeat with 40-second timeout
- Scalable: Works efficiently with millions of users
Current Status: Core messaging infrastructure complete
- β Core Messaging Infrastructure (Epic 1.1-1.8 Complete)
- β Data Management & Sync (Epic 3.2 Complete)
- β Logger Console Integration (Complete)
- β Firestore Rules Optimization (Complete)
- β Firestore Subcollection Architecture (Complete)
- β Read Receipt Timing Fix (Complete)
- β Authentication Debugging (Complete)
- β Friends Subcollection & Online Presence (Epic 1.6 Complete)
- β Mobile Lifecycle Management (Epic 2.1 Complete)
- β Performance Optimization (Epic 2.2 - Next Phase)
- β AI Features Implementation (Epic 5.1 - 80% Complete)
- β Documentation & Deployment (Epic 4)
AI Features with Tool Calling & RAG β
- Context-Aware Translation: AI analyzes conversation history for accurate translations
- Tool Calling System: AI can request additional context when confidence is low (>95% threshold)
- RAG Integration: SQLite FTS5 search for relevant conversation context
- Two-Phase Translation: Exploratory phase determines if more context is needed
- MiniGraph Orchestration: LangGraph-style state machine for complex AI workflows
- Cultural Context: Automatic cultural notes and formality guidance
- Language Detection: Automatic source language identification
- Confidence Scoring: AI provides confidence levels for translation accuracy
- Reference Analysis: Identifies and explains references to earlier messages
- Real-time Progress: Live status updates during translation process
npx expo start --clear # Start Expo development serverCopy the template file and fill in your Firebase configuration:
cp .env.template .envThen edit .env with your Firebase project details:
# Firebase Configuration
EXPO_PUBLIC_FIREBASE_API_KEY=your-api-key-here
EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
EXPO_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project.appspot.com
EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=123456789
EXPO_PUBLIC_FIREBASE_APP_ID=your-app-id
EXPO_PUBLIC_FIREBASE_MEASUREMENT_ID=your-measurement-id- Firestore Security Rules (production-ready configuration):
β Note: The following rules implement proper security with Principle of Least Privilege. These are production-ready security rules.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Users can only read/write their own profile
match /users/{userId} {
allow read: if request.auth != null;
allow write: if request.auth != null && request.auth.uid == userId;
// Friends subcollection - users can read their own friends
match /friends/{friendId} {
allow read: if request.auth != null && request.auth.uid == userId;
allow write: if request.auth != null && request.auth.uid == userId;
}
}
// Friend requests - users can read their own requests
match /friendRequests/{requestId} {
allow read: if request.auth != null &&
(request.auth.uid == resource.data.fromUserId ||
request.auth.uid == resource.data.toUserId);
allow create: if request.auth != null &&
request.auth.uid == request.resource.data.fromUserId;
allow update: if request.auth != null &&
(request.auth.uid == resource.data.fromUserId ||
request.auth.uid == resource.data.toUserId);
allow delete: if request.auth != null &&
request.auth.uid == resource.data.fromUserId;
}
// Conversations - only participants can access
match /conversations/{conversationId} {
allow read: if request.auth != null &&
resource.data.participants.hasAny([request.auth.uid]);
allow create: if request.auth != null &&
request.resource.data.participants.hasAny([request.auth.uid]);
allow update: if request.auth != null &&
resource.data.participants.hasAny([request.auth.uid]);
// Typing indicators subcollection - only accessible by conversation participants
match /typing/{userId} {
// Everyone in the conversation can read who's typing
allow read: if request.auth != null &&
get(/databases/$(database)/documents/conversations/$(conversationId))
.data.participants.hasAny([request.auth.uid]);
// Only the owner can write their own typing doc
allow write: if request.auth != null &&
request.auth.uid == userId &&
get(/databases/$(database)/documents/conversations/$(conversationId))
.data.participants.hasAny([request.auth.uid]);
}
// Messages subcollection - inherits conversation access
match /messages/{messageId} {
allow read, write: if request.auth != null &&
get(/databases/$(database)/documents/conversations/$(conversationId)).data.participants
.hasAny([request.auth.uid]);
}
}
}
}- Firestore Indexes (optimized for production queries):
Index Optimization Summary:
- Conversations: Optimized for user conversation lists and direct conversation lookups
- Friend Requests: Optimized for incoming, outgoing, and bidirectional request queries
- Automatic Indexes: Single-field indexes (email, displayName, id, updatedAt, isTyping) are handled automatically by Firestore
- Minimal Configuration: Only composite indexes that Firestore cannot auto-generate are manually defined
- Removed: Obsolete "notes" collection indexes (not used in current implementation)
Index Strategy:
- Single-field queries: Firestore automatically creates ascending/descending indexes
- Range queries: Work with automatic single-field indexes (e.g.,
where("email", ">=", term)) - Composite queries: Manual indexes required for equality + array-contains combinations
- Subcollection queries: Already scoped to specific conversation, no parent document fields needed
{
"indexes": [
{
"collectionGroup": "conversations",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "participants", "arrayConfig": "CONTAINS" },
{ "fieldPath": "updatedAt", "order": "DESCENDING" }
]
},
{
"collectionGroup": "conversations",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "type", "order": "ASCENDING" },
{ "fieldPath": "participants", "arrayConfig": "CONTAINS" }
]
},
{
"collectionGroup": "friendRequests",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "toUserId", "order": "ASCENDING" },
{ "fieldPath": "status", "order": "ASCENDING" }
]
},
{
"collectionGroup": "friendRequests",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "fromUserId", "order": "ASCENDING" },
{ "fieldPath": "status", "order": "ASCENDING" }
]
},
{
"collectionGroup": "friendRequests",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "fromUserId", "order": "ASCENDING" },
{ "fieldPath": "toUserId", "order": "ASCENDING" }
]
}
],
"fieldOverrides": []
}- Google OAuth: Not implemented (email/password auth only)
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Follow the existing code style and patterns
- Add tests for new functionality
- Update documentation as needed
- Submit a pull request
- Use TypeScript for all new code
- Follow existing naming conventions
- Add JSDoc comments for public functions
- Use the existing logging system (
logger.info(),logger.error()) - Test on both iOS and Android devices
- Use the Diagnostics tab to gather logs
- Include device information and steps to reproduce
- Check existing issues before creating new ones
- Provide console logs and SQLite database state when possible
β
Production-Ready Security: This project implements comprehensive security with Principle of Least Privilege. See firestore.rules for production-ready security rules.
Security Features Implemented:
- β Firestore Security Rules: Production-ready rules with proper access controls
- β User Authentication: Firebase Auth with email/password authentication
- β API Key Protection: OpenAI API keys stored server-side only
- β Data Access Control: Users can only access their own data and conversations they participate in
- β Friend Management: Secure friend subcollection with proper permissions
- β Message Security: Messages only accessible by conversation participants
- β Typing Indicators: Secure typing status with participant-only access
Additional Security Considerations:
- Configure Firebase App Check for additional security
- Monitor Firestore usage and set up alerts
- Regular security audits and rule reviews
- Implement rate limiting for API endpoints
For detailed security guidelines, see docs/SECURITY.md and firestore.rules.