Skip to content

lousydropout/message-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

57 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

MessageAI

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.

🎯 Project Goals & Persona

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

✨ Features

Core Messaging Infrastructure

  • 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

Friends & Online Presence

  • 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

AI-Powered Translation & Communication

  • 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

πŸ“Š Performance Metrics

Achieved Performance Targets

  • 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

Architecture Performance

  • 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

πŸš€ Quick Start

Prerequisites

  • Node.js 22
  • Firebase project with Firestore enabled
  • iPhone and/or Android device with Expo Go app installed

Installation

  1. Clone and install dependencies

    git clone <repository-url>
    cd rn-firebase-hello-world
    npm install
  2. Configure Firebase

    • Create a Firebase project at console.firebase.google.com
    • Enable Firestore Database and Authentication (email/password)
    • Copy .env.template to .env and fill in your Firebase config:
    cp .env.template .env

    Then edit .env with 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
  3. Deploy Firestore Security Rules

    firebase deploy --only firestore:rules
  4. Deploy Firestore Indexes

    firebase deploy --only firestore:indexes
  5. Start the development server

    npx expo start --clear
  6. Open on device

    • Scan QR code with Expo Go (iOS/Android)
    • Press r to refresh all connected devices

πŸ”§ Troubleshooting

Common Issues

Firebase Connection Issues

  • Ensure Firebase project has Firestore and Authentication enabled
  • Verify all environment variables in .env.local are correct
  • Check Firebase console for any quota limits or billing issues
  • Run firebase deploy --only firestore:rules to ensure rules are deployed

Expo Go Connection Issues

  • Make sure device and computer are on the same network
  • Try npx expo start --clear to clear cache
  • Restart Expo Go app if QR code scanning fails
  • Use tunnel mode: npx expo start --tunnel for 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)

Debug Tools

  • 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

πŸ—οΈ Architecture

Unified Queue-First Architecture

MessageAI implements a sophisticated unified queue-first architecture that ensures reliable message delivery and optimal performance across all network conditions.

Core Architecture Overview

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    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 β”‚     β”‚ β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Three-Tier Data Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    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

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    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/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

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    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

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    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

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    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          β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ” Advanced AI Translation Architecture

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.

Security-First Design

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    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                           β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

API Server Features

  • 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

Advanced Translation Flow

  1. User Input: User taps message to translate in MessageAI app
  2. Authentication: App sends Firebase ID token with translation request
  3. Server Validation: API Server verifies token using Firebase Admin SDK
  4. Exploratory Phase: AI analyzes message and conversation history
  5. Tool Calling Decision: AI either translates directly or requests more context
  6. RAG Search (if needed): SQLite FTS5 search for relevant conversation context
  7. Execution Phase: AI translates with full context and cultural awareness
  8. Response: Server returns translation, cultural notes, and confidence score
  9. Display: MessageAI shows translation with progress indicators and cultural context

MiniGraph AI Orchestrator

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                          β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

State Machine Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    Tool Call     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    Enhanced     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  TRANSLATE  β”‚ ───────────────► β”‚   SEARCH    β”‚ ──────────────► β”‚  TRANSLATE  β”‚
β”‚ (Exploratory)β”‚                 β”‚             β”‚                 β”‚ (Execution) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚                                                               β”‚
       β”‚ Direct Translation                                            β”‚
       β”‚ (High Confidence)                                             β”‚
       β–Ό                                                               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    DONE     β”‚ ◄──────────────────────────────────────────────── β”‚    DONE     |β”‚             |                                                   |             |
β”‚             β”‚                                                   β”‚             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Features

  • 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

Environment Configuration

The API Server URL is configured in your .env file:

# From the AWS CDK deployment in `server/`
EXPO_PUBLIC_API_URL=your-api-server-url

For detailed API Server setup and deployment, see the server/README.md.

Technology Stack

  • 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

Project Structure

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

πŸ—„οΈ Data Structures

Friends Subcollection & Online Presence

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

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)

Recent Major Accomplishments

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

πŸ”§ Development

Script

npx expo start --clear          # Start Expo development server

Environment Variables

Copy the template file and fill in your Firebase configuration:

cp .env.template .env

Then 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

Firebase Setup

  1. 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]);
      }
    }
  }
}
  1. 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": []
}

⚠️ Known Issues

Current Limitations

  • Google OAuth: Not implemented (email/password auth only)

🀝 Contributing

Development Setup

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Follow the existing code style and patterns
  4. Add tests for new functionality
  5. Update documentation as needed
  6. Submit a pull request

Code Style

  • 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

Reporting Issues

  • 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

πŸ”’ Security Notice

βœ… 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.

About

No description, website, or topics provided.

Resources

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published