React Native App Planning Document
Overview
This document outlines the plan for building a React Native version of HiveJournal, allowing users to journal on iOS and Android devices while sharing the same backend infrastructure.
Current Architecture
Web App (Next.js)
- Frontend: Next.js 14 (App Router), TypeScript, Tailwind CSS
- Backend: Node.js/Express API (Railway)
- Database & Auth: Supabase (PostgreSQL + Auth)
- Storage: Supabase Storage
- Payments: Stripe
- Email: Resend
Key Features
- Authentication: Email/password, magic links, OAuth
- Journal Entries: Create, read, update, delete entries
- Dashboard: Infinite scroll, search, filters
- Entry Viewer: Rich text display with custom fonts, backgrounds
- Entry Editor: Rich text editing with auto-save
- Notebooks: Organize entries into notebooks
- AI Features: Custom background image generation
- Settings: User preferences, themes, fonts
- Admin Panel: User management, impersonation
- Positive Notes: Random gratitude/positive notes display
- Stream View: Alternative entry viewing mode
- Goals: Accountability goals and check-ins
React Native Architecture
Recommended Stack
apps/
├── frontend/ # Next.js web app (existing)
├── backend/ # Express API (existing)
└── mobile/ # React Native app (new)
├── src/
│ ├── screens/ # Screen components
│ ├── components/ # Reusable components
│ ├── navigation/ # Navigation setup
│ ├── services/ # API clients, Supabase
│ ├── hooks/ # Custom hooks
│ ├── contexts/ # React contexts
│ ├── utils/ # Utility functions
│ └── types/ # TypeScript types
├── ios/ # iOS native code
├── android/ # Android native code
└── package.json
Technology Choices
-
React Native Framework:
- Expo (recommended) - Easier setup, OTA updates, managed workflow
- OR React Native CLI - More control, bare workflow
-
Navigation:
- React Navigation (v6+) - Industry standard, TypeScript support
-
State Management:
- React Context + Hooks (for simple state)
- Zustand or Jotai (if needed for complex state)
- React Query (for server state/caching)
-
UI Components:
- React Native Paper or NativeBase (component library)
- React Native Reanimated (animations)
- React Native Gesture Handler (gestures)
-
Styling:
- StyleSheet API (built-in)
- Styled Components or Emotion (CSS-in-JS)
- Tailwind Native (if you want Tailwind-like syntax)
-
Supabase Integration:
- @supabase/supabase-js (same as web)
- @react-native-async-storage/async-storage (for session storage)
-
Forms:
- React Hook Form (form validation)
- Zod (schema validation)
-
Date Handling:
- date-fns (same as web, works in RN)
-
Image Handling:
- expo-image or react-native-fast-image (performance)
-
Rich Text Editing:
- react-native-pell-rich-editor or @react-native-richtexteditor/richtexteditor
Shared Code Strategy
Option 1: Monorepo with Shared Packages (Recommended)
packages/
├── shared/
│ ├── types/ # Shared TypeScript types
│ ├── utils/ # Shared utilities (date formatting, etc.)
│ ├── constants/ # Shared constants
│ └── api-client/ # Shared API client (if possible)
└── ui/ # Shared UI components (if using React Native Web)
Benefits:
- Type safety across platforms
- Single source of truth for business logic
- Easier maintenance
Challenges:
- Some utilities may need platform-specific implementations
- UI components can't be fully shared (web vs native)
Option 2: Copy and Adapt
- Copy relevant utilities and adapt for React Native
- Less coupling but more maintenance
Navigation Structure
App Navigator (Stack)
├── Auth Stack
│ ├── Sign In
│ ├── Sign Up
│ └── Forgot Password
│
└── Main Stack (Tab Navigator)
├── Dashboard Tab
│ ├── Dashboard (list of entries)
│ ├── Entry Detail
│ └── Entry Editor (new/edit)
│
├── Stream Tab (optional)
│ └── Stream View
│
├── Notebooks Tab (optional)
│ ├── Notebooks List
│ └── Notebook Detail
│
├── Goals Tab (optional)
│ ├── Goals List
│ └── Goal Detail
│
└── Settings Tab
├── Settings
├── Profile
└── Admin (if admin)
Key Screens & Components
1. Authentication Screens
- Sign In: Email/password, magic link option
- Sign Up: Registration form
- Session Management: Auto-refresh, secure storage
2. Dashboard Screen
- Entry Cards: Similar to web, optimized for mobile
- Infinite Scroll: Use
FlatListwithonEndReached - Search Bar: Sticky header with search
- Filters: Drawer or modal for filters
- Pull to Refresh: Native refresh gesture
3. Entry Detail Screen
- Rich Text Display: Custom fonts, backgrounds
- Actions: Edit, delete, share, AI background
- Navigation: Swipe between entries (optional)
- Back Button: Preserve scroll position
4. Entry Editor Screen
- Rich Text Editor: Formatting toolbar
- Auto-save: Save drafts locally + sync
- Title Input: Separate from content
- Tags Input: Chip-based tag selector
- Mood Selector: Quick mood picker
- Font/Background Picker: Modal selectors
- AI Panel: Same as web for background generation
5. Settings Screen
- Profile: Avatar, name, email
- Preferences: Theme, default font, etc.
- Account: Password change, delete account
- Subscription: Payment management (Stripe SDK)
API Integration
Supabase Client Setup
// apps/mobile/src/services/supabase.ts
import { createClient } from '@supabase/supabase-js'
import AsyncStorage from '@react-native-async-storage/async-storage'
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL!
const supabaseKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY!
export const supabase = createClient(supabaseUrl, supabaseKey, {
auth: {
storage: AsyncStorage,
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false, // Not needed for mobile
},
})
Backend API Client
// apps/mobile/src/services/api.ts
import { supabase } from './supabase'
const API_URL = process.env.EXPO_PUBLIC_API_URL!
export async function apiRequest<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const { data: { session } } = await supabase.auth.getSession()
const headers: Record<string, string> = {
...(options.headers as Record<string, string>),
}
if (session?.access_token) {
headers['Authorization'] = `Bearer ${session.access_token}`
}
if (options.body && !(options.body instanceof FormData)) {
headers['Content-Type'] = 'application/json'
}
const response = await fetch(`${API_URL}${endpoint}`, {
...options,
headers,
})
if (!response.ok) {
const error = await response.json().catch(() => ({ message: 'An error occurred' }))
throw new Error(error.message || 'Request failed')
}
const text = await response.text()
if (!text) return {} as T
try {
return JSON.parse(text) as T
} catch {
return text as T
}
}
Authentication Flow
- Sign In/Up: Use Supabase Auth (same as web)
- Session Persistence: AsyncStorage (handled by Supabase client)
- Token Refresh: Automatic via Supabase client
- Deep Linking: Handle auth callbacks (magic links, OAuth)
Deep Linking Setup
// Handle OAuth/magic link callbacks
import * as Linking from 'expo-linking'
useEffect(() => {
const handleDeepLink = async (url: string) => {
// Extract tokens from URL
const { data, error } = await supabase.auth.getSessionFromUrl(url)
if (error) {
console.error('Auth error:', error)
}
}
Linking.addEventListener('url', ({ url }) => {
handleDeepLink(url)
})
// Check initial URL (app opened from link)
Linking.getInitialURL().then((url) => {
if (url) handleDeepLink(url)
})
}, [])
Platform-Specific Considerations
iOS
- App Store Guidelines: Privacy policies, subscription handling
- Face ID/Touch ID: Biometric authentication (optional)
- Haptic Feedback: Enhanced UX
- Share Sheet: Native sharing of entries
- Widgets: Home screen widgets (future)
Android
- Material Design: Follow Material Design guidelines
- Back Button: Handle Android back button
- Permissions: Storage, camera (if needed)
- Share Intent: Native sharing
- Widgets: Android widgets (future)
Offline Support
Strategy
- Local Storage: Store entries in AsyncStorage/SQLite
- Sync Queue: Queue API calls when offline
- Conflict Resolution: Last-write-wins or manual merge
- Indicators: Show sync status, offline badge
Implementation
- Use @react-native-async-storage/async-storage for simple data
- Use react-native-sqlite-storage or watermelondb for complex queries
- Use @tanstack/react-query with offline support
UI/UX Adaptations
Mobile-First Design
- Touch Targets: Minimum 44x44pt (iOS), 48dp (Android)
- Swipe Gestures: Swipe to delete, swipe between entries
- Pull to Refresh: Native refresh pattern
- Bottom Navigation: Tab bar at bottom (iOS/Android standard)
- Floating Action Button: Quick "New Entry" button
Dark Mode
- Use React Native's
AppearanceAPI - Match web app's dark mode implementation
- System preference + manual toggle
Typography
- Load custom fonts (same as web)
- Responsive font sizes based on screen size
- Support for user's system font size preferences
Images
- Lazy loading for entry images
- Placeholder images while loading
- Optimize image sizes for mobile
Development Roadmap
Phase 1: Foundation (Week 1-2)
- Set up Expo/React Native project
- Configure navigation (React Navigation)
- Set up Supabase client
- Set up API client
- Implement authentication screens
- Set up shared types package
Phase 2: Core Features (Week 3-4)
- Dashboard screen with entry list
- Entry detail screen
- Entry editor screen (basic)
- Infinite scroll and pagination
- Search functionality
- Pull to refresh
Phase 3: Enhanced Features (Week 5-6)
- Rich text editor
- Custom fonts and backgrounds
- Tags and mood selection
- Notebooks support
- Settings screen
- Profile management
Phase 4: Advanced Features (Week 7-8)
- AI background generation
- Offline support
- Image uploads
- Push notifications (optional)
- Deep linking
- Share functionality
Phase 5: Polish & Testing (Week 9-10)
- UI/UX refinements
- Performance optimization
- Error handling
- Testing on iOS and Android
- App Store preparation
- Beta testing
Environment Variables
# .env (mobile app)
EXPO_PUBLIC_SUPABASE_URL=your_supabase_url
EXPO_PUBLIC_SUPABASE_ANON_KEY=your_anon_key
EXPO_PUBLIC_API_URL=https://your-backend.railway.app
Testing Strategy
- Unit Tests: Jest for utilities and hooks
- Component Tests: React Native Testing Library
- E2E Tests: Detox or Maestro
- Manual Testing: TestFlight (iOS), Internal Testing (Android)
Deployment
iOS
- Apple Developer Account: Required ($99/year)
- App Store Connect: Create app listing
- Build:
eas build --platform ios - Submit:
eas submit --platform ios
Android
- Google Play Console: Create app listing
- Build:
eas build --platform android - Submit:
eas submit --platform android
OTA Updates (Expo)
- Use Expo Updates for over-the-air updates
- Push updates without app store review
- Rollback capability
Challenges & Solutions
Challenge 1: Rich Text Editing
Solution: Use react-native-pell-rich-editor or build custom with WebView
Challenge 2: Custom Fonts
Solution: Load fonts in native projects, use fontFamily in styles
Challenge 3: Background Images
Solution: Use ImageBackground component, cache images
Challenge 4: Infinite Scroll Performance
Solution: Use FlatList with getItemLayout, removeClippedSubviews
Challenge 5: Offline Sync
Solution: Implement queue system, use React Query's offline support
Next Steps
- Decision: Expo vs React Native CLI
- Set up project structure
- Create shared types package
- Implement authentication flow
- Build first screen (Dashboard)