React Native + Expo
- Version: Expo SDK ~54.0 (specifically 54.0.13)
- React Native Version: 0.81.4
- React Version: 19.1.0 (exact - required by RN 0.81.4)
- Why: Cross-platform (iOS + Android) from single codebase, managed workflow simplifies setup
- Key Features Used:
- Expo Router (file-based navigation)
- Expo SQLite (local persistence)
- Expo Notifications (push notifications)
- Expo ImagePicker (image selection)
- Expo ImageManipulator (image compression)
- Expo Auth Session (Google OAuth)
- Expo Web Browser (OAuth flow support)
TypeScript
- Version: ~5.9.2
- Why: Type safety catches bugs early, better IDE support, self-documenting code
- Configuration: Strict mode enabled
State Management
- Primary: React Context API
- Why: Sufficient for MVP scope, no need for Redux/Zustand complexity
- Implementation: AuthContext for global auth state
- Future: May migrate to Zustand if state management becomes complex
Firebase Authentication
- Email/Password authentication
- Google Sign-In (OAuth 2.0)
- Session management
- User profile storage
Cloud Firestore
- Real-time database with live listeners
- Collections:
users,conversations,messages - Optimistic local cache
- Offline persistence
Firebase Realtime Database (RTDB)
- Presence tracking with
.info/connectedandonDisconnect() - JSON tree structure:
/status/{userId} - Server-side disconnect detection (handles crashes/force-quits)
- Client-side mirroring to Firestore for UI compatibility
- Security rules:
database.rules.json - Free tier: 1GB storage, 10GB/month download
Firebase Storage
- Image uploads
- Path structure:
messages/{userId}/{filename} - Public download URLs
Firebase Cloud Messaging (FCM)
- Push notification delivery
- Device token management
- Foreground notification handling
Expo SQLite
- Version: ~13.x
- Why: Fast local queries, offline-first architecture, full SQL support
- Usage:
- Cache conversations and messages
- Offline message queue
- Deduplication and sync
Jest
- Version: ~29.x
- Coverage Goal: 70%+ overall
- What We Test:
- Utility functions (80%+ coverage)
- Business logic (70%+ coverage)
- Services (60%+ coverage)
@testing-library/react-native
- Version: ~12.x
- Why: Component testing (minimal in MVP, focus on logic)
Husky + lint-staged
- Pre-commit hooks
- Auto-run tests before commit
- Prevent broken code from entering repo
Expo Dev Tools
- Live reload / Hot Module Replacement
- Device debugging
- Network request inspection
EAS Build
- Cloud-based iOS builds (Windows can't build iOS locally)
- Android builds
- Development builds for device testing
{
"dependencies": {
"expo": "~54.0.0",
"expo-auth-session": "~7.0.0",
"expo-dev-client": "~6.0.0",
"expo-image": "~3.0.0",
"expo-image-picker": "~17.0.0",
"expo-notifications": "~0.32.0",
"expo-router": "~6.0.0",
"expo-sqlite": "~16.0.0",
"expo-status-bar": "~3.0.0",
"expo-web-browser": "~15.0.0",
"firebase": "^12.4.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-native": "0.81.4",
"@react-native-community/netinfo": "^11.4.1"
},
"devDependencies": {
"@types/jest": "^30.0.0",
"@types/react": "~19.1.0",
"dotenv": "^17.2.3",
"husky": "^9.1.7",
"jest": "^29.7.0",
"jest-expo": "^54.0.12",
"lint-staged": "^16.2.5",
"typescript": "~5.9.2"
}
}Important Version Notes:
- React 19.1.0 is required - React Native 0.81.4 will not work with React 19.2.0
- All Expo packages use
~versioning - Ensures SDK 54 compatibility - Testing libraries temporarily removed -
@testing-library/react-nativerequires React 19.2.0 - Use
npx expo installfor any new Expo packages to maintain compatibility
Node.js
- Version: 18.x or higher
- Package Manager: npm (comes with Node)
Expo CLI
- Install globally:
npm install -g expo-cli - Or use npx:
npx expo start
Android Development
- Android Studio (for emulator)
- Android SDK 33+
- Emulator configured and running
iOS Development (If on Mac)
- Xcode 15+
- iOS Simulator
- CocoaPods
Windows Limitations
- Cannot build iOS locally
- Use EAS Build for iOS:
eas build --platform ios - Can test on iOS simulator via EAS or Mac
Firebase Project
- Create project at console.firebase.google.com
- Add iOS and Android apps to project (mobile only - no web)
- Enable Authentication providers
- Create Firestore database
- Set up Firebase Storage
- Configure Cloud Messaging
Configuration Files Needed
google-services.json(Android) - Place in project rootGoogleService-Info.plist(iOS) - Place in project root.envfile with Firebase config:EXPO_PUBLIC_FIREBASE_API_KEY= EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN= EXPO_PUBLIC_FIREBASE_PROJECT_ID= EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET= EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID= EXPO_PUBLIC_FIREBASE_APP_ID= EXPO_PUBLIC_FIREBASE_MEASUREMENT_ID= # Optional: for Analytics
Google OAuth Setup
- Go to Google Cloud Console
- Create OAuth 2.0 Client IDs:
- iOS: Use bundle ID (e.g., com.messageai.app)
- Android: Use SHA-1 certificate fingerprint
- Add URL scheme to app.json
- Enable Google Sign-In in Firebase console
message-ai/
├── app/ # Expo Router screens
│ ├── (auth)/ # Authentication group
│ │ ├── login.tsx
│ │ ├── register.tsx
│ │ └── _layout.tsx
│ ├── (tabs)/ # Main app tabs
│ │ ├── index.tsx # Conversations list
│ │ ├── profile.tsx
│ │ └── _layout.tsx
│ ├── chat/
│ │ └── [id].tsx # Dynamic chat screen
│ └── _layout.tsx # Root layout
│
├── src/ # Application code
│ ├── components/ # Reusable UI components
│ │ ├── ui/ # Generic UI (buttons, inputs)
│ │ └── chat/ # Chat-specific components
│ ├── services/ # Business logic
│ │ ├── firebase/
│ │ │ ├── authService.ts
│ │ │ ├── firestoreService.ts
│ │ │ └── storageService.ts
│ │ ├── sqlite/
│ │ │ └── sqliteService.ts
│ │ ├── messaging/
│ │ │ ├── messageService.ts
│ │ │ ├── conversationService.ts
│ │ │ └── syncService.ts
│ │ └── network/
│ │ └── networkService.ts
│ ├── utils/ # Helper functions
│ │ ├── messageUtils.ts
│ │ ├── dateUtils.ts
│ │ └── validation.ts
│ ├── hooks/ # Custom React hooks
│ │ ├── useAuth.ts
│ │ ├── useMessages.ts
│ │ └── useNetworkStatus.ts
│ ├── types/ # TypeScript definitions
│ │ ├── User.ts
│ │ ├── Message.ts
│ │ └── Conversation.ts
│ ├── store/ # Context providers
│ │ └── AuthContext.tsx
│ └── config/ # Configuration
│ └── firebase.ts # Firebase initialization
│
├── __tests__/ # Unit tests (mirrors src/)
│ ├── utils/
│ ├── services/
│ └── ...
│
├── assets/ # Static assets
│ ├── images/
│ └── fonts/
│
├── planning/ # Documentation
│ ├── Phase 1 PRD.md
│ └── supporting/
│
├── tasks/ # Feature PRDs
│ ├── prd 01 - Project Setup & Infrastructure.md
│ └── ...
│
├── memory-bank/ # Project memory
│ ├── projectbrief.md
│ ├── productContext.md
│ ├── activeContext.md
│ ├── systemPatterns.md
│ ├── techContext.md (this file)
│ └── progress.md
│
├── .cursor/ # Cursor IDE config
│ └── rules/ # Project rules
│
├── .env # Environment variables (gitignored)
├── .gitignore
├── app.json # Expo configuration
├── package.json
├── tsconfig.json # TypeScript configuration
├── jest.config.js # Jest configuration
└── README.md
UI Response Times
- Message send: < 100ms perceived latency
- Screen navigation: < 300ms
- Scroll performance: 60 FPS (no dropped frames)
- App cold start: < 2.5 seconds
Network
- Message sync: < 500ms (with good connection)
- Image upload: < 10s for 5MB image
- Offline queue process: < 20s for 100 messages
Storage
- SQLite database: < 50MB (for MVP)
- Image cache: < 200MB
- Total app size: < 100MB
iOS Specifics
- HEIC images automatically converted to JPEG
- Photo library permission required
- Push notification permission required
- Different OAuth client ID than Android
Android Specifics
- Various gallery apps (need to handle different pickers)
- Storage permissions (varies by Android version)
- SHA-1 fingerprint for OAuth
- Notification channels required
Both Platforms
- Test on real devices (emulators don't show all issues)
- Handle different screen sizes
- Support dark mode (if time permits)
# Start dev server
npm start
# Run on Android
npm run android
# Run on iOS (Mac only)
npm run ios# Run all tests
npm test
# Watch mode
npm run test:watch
# Coverage report
npm run test:coverage# Build for Android
eas build --platform android --profile production
# Build for iOS
eas build --platform ios --profile production
# Submit to stores
eas submit --platform ios
eas submit --platform androidRequired in .env:
# Firebase (Required)
EXPO_PUBLIC_FIREBASE_API_KEY=
EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN=
EXPO_PUBLIC_FIREBASE_PROJECT_ID=
EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET=
EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
EXPO_PUBLIC_FIREBASE_APP_ID=
# Firebase (Optional)
EXPO_PUBLIC_FIREBASE_MEASUREMENT_ID= # For Firebase Analytics
# Post-MVP
EXPO_PUBLIC_SENTRY_DSN= # Error tracking (post-MVP)Access in code:
import Constants from 'expo-constants';
const firebaseConfig = {
apiKey: process.env.EXPO_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN,
// ...
};JAVA_HOME:
Windows requires JAVA_HOME to be set for Android builds. Android Studio includes a JDK at:
C:\Program Files\Android\Android Studio\jbr
Set permanently:
setx JAVA_HOME "C:\Program Files\Android\Android Studio\jbr"Add to PATH (restart terminal after):
setx PATH "%PATH%;%JAVA_HOME%\bin"Verify:
echo $JAVA_HOME
java -versionGradle File Locking:
cd android
./gradlew --stop
cd ..
taskkill //F //IM java.exePort Already in Use:
# Find process on port 8081
netstat -ano | grep ":8081"
# Kill process
taskkill //F //PID <process-id>Git Bash Path Issues: Use forward slashes in Git Bash:
# Good
cd /c/Users/SamExel/repos/message-ai
# Bad
cd C:\Users\SamExel\repos\message-aiMust use development build (not Expo Go) because:
- Firebase requires native modules
- Google Sign-In requires native configuration
- expo-dev-client provides development build with native modules
First build takes 5-6 minutes, subsequent builds are faster
# Build and run on Android
npx expo run:android
# This:
# 1. Generates native Android project
# 2. Installs expo-dev-client
# 3. Compiles native modules
# 4. Installs on emulator
# 5. Starts Metro bundlerIssue: Cannot build iOS locally on Windows
Workaround: Use EAS Build cloud service
eas build --platform ios --profile developmentIssue: iOS uses HEIC format by default
Workaround: expo-image-manipulator automatically converts to JPEG
Issue: Different permission models across Android versions
Workaround: expo-image-picker handles this internally
Issue: Limited Firestore reads/writes, storage
Workaround:
- Use local cache aggressively
- Batch operations
- Monitor usage in Firebase console
Issue: "The process cannot access the file" errors
Root Cause: Multiple Gradle daemons or locked files
Solution: Stop all Gradle processes before rebuilding (see Windows Development Setup above)
Issue: Incompatible React versions: react 19.2.0 and react-native-renderer 19.1.0
Root Cause: React Native 0.81.4 requires React 19.1.0 exactly, but npm installed 19.2.0
Solution:
# 1. Update package.json to lock React version
"react": "19.1.0",
"react-dom": "19.1.0",
"@types/react": "~19.1.0"
# 2. Clean install
rm -rf node_modules package-lock.json
npm install
# 3. Verify versions match
npm list react react-nativePrevention: Always check React Native release notes for exact React version requirements
Issue: Firebase config errors even with correct .env file
Root Cause: Metro bundler caches environment variables and doesn't auto-reload on .env changes
Solution:
# Always clear cache after changing .env
npm start -- --clear --reset-cachePrevention: Document that Metro restart with --clear is required after .env changes
Issue: @testing-library/react-native requires React 19.2.0, conflicts with RN 0.81.4
Root Cause: Testing libraries update faster than React Native stable releases
Solution:
- Removed testing libraries temporarily
- Focus on Jest unit tests for utilities and business logic
- Will re-add when compatible versions available or when upgrading React Native Prevention: Check peer dependency compatibility before adding testing libraries
- Message pagination (limit initial load to 100)
- Image thumbnail generation (post-MVP)
- Cloud Functions for server-side logic (post-MVP)
- Message metadata storage (prepared in schema)
- Cloud Functions for AI processing (future)
- Streaming API responses (future)
- Firestore security rules (currently test mode)
- Rate limiting
- Error monitoring (Sentry or similar)
- Analytics (Firebase Analytics or similar)
- App version checking / forced updates
Philosophy: Use battle-tested technologies, avoid bleeding edge. Simplicity and reliability over novelty.