Docs📱 App🛠️ Technical🏗️ Architecture Patterns

Architecture Patterns

Service Layer

All business logic is abstracted into dedicated service modules, keeping components clean and testable.

FoodAnalysisService.ts

Purpose: AI-powered food recognition and nutritional analysis

Key Functions:

analyzeFood(imageUri: string): Promise<FoodAnalysisResult>
getNutritionalData(foodName: string): Promise<NutritionData>
searchFoodDatabase(query: string): Promise<FoodItem[]>

Responsibilities:

  • Upload photos to storage
  • Send images to OpenAI Vision API
  • Parse AI responses
  • Extract nutritional information
  • Query food database
  • Cache results for performance

WorkoutAnalysisService.ts

Purpose: Exercise recognition and calorie burn calculations

Key Functions:

analyzeWorkout(imageUri: string): Promise<WorkoutAnalysisResult>
calculateCaloriesBurned(exercise, duration, weight): number
getExerciseLibrary(): Promise<Exercise[]>

Responsibilities:

  • AI workout recognition from photos
  • MET-based calorie calculations
  • Exercise database integration
  • Workout type classification
  • Intensity estimation

HealthProfileService.ts

Purpose: User health data management and calculations

Key Functions:

getHealthProfile(userId: string): Promise<HealthProfile>
updateHealthProfile(userId, data): Promise<void>
calculateDailyCalories(profile): CalorieTargets
calculateBMI(weight, height): number

Responsibilities:

  • Fetch and update health metrics
  • BMR (Basal Metabolic Rate) calculation
  • TDEE (Total Daily Energy Expenditure) calculation
  • Goal-based calorie targets
  • Macro distribution recommendations

SubscriptionService.ts

Purpose: Payment and subscription management

Key Functions:

checkSubscriptionStatus(userId): Promise<SubscriptionStatus>
getUsageStats(userId): Promise<UsageStats>
upgradeSubscription(userId, plan): Promise<CheckoutSession>
trackAPIUsage(userId): Promise<void>

Responsibilities:

  • Stripe payment integration
  • RevenueCat subscription sync
  • API usage tracking
  • Limit enforcement
  • Subscription state management

UserEntriesService.ts

Purpose: Food and workout log management

Key Functions:

addFoodEntry(userId, entry): Promise<EntryResult>
addWorkoutEntry(userId, entry): Promise<EntryResult>
getEntriesByDate(userId, date): Promise<DailyEntries>
updateEntry(entryId, data): Promise<void>
deleteEntry(entryId, type): Promise<void>

Responsibilities:

  • CRUD operations for entries
  • Daily/weekly/monthly aggregations
  • Entry validation
  • Photo URL management
  • Data consistency

supabase.ts

Purpose: Database and authentication operations

Key Functions:

createClient(): SupabaseClient
signIn(provider): Promise<AuthResult>
signOut(): Promise<void>
query(table, filters): Promise<QueryResult>
subscribe(table, callback): Subscription

Responsibilities:

  • Supabase client initialization
  • Authentication flows
  • Database queries
  • Real-time subscriptions
  • File storage operations

Context Providers

React Context API for global state management.

ThemeProvider

Purpose: Theme management and switching

State:

{
  theme: 'light' | 'dark' | 'system',
  colors: ColorScheme,
  isDark: boolean
}

Methods:

  • setTheme(theme) - Change theme
  • toggleTheme() - Switch between light/dark
  • getColor(name) - Resolve theme-aware color

Features:

  • Persists theme preference
  • System theme detection
  • Smooth transitions
  • All components theme-aware

OnboardingProvider

Purpose: Onboarding flow state management

State:

{
  currentStep: number,
  data: OnboardingData,
  isComplete: boolean
}

Methods:

  • nextStep() - Move to next screen
  • previousStep() - Go back
  • updateData(key, value) - Save step data
  • submitOnboarding() - Complete flow

Features:

  • Multi-step form handling
  • Data validation per step
  • Progress tracking
  • Resume capability

PaymentsProvider

Purpose: Subscription and payment state

State:

{
  subscriptionStatus: SubscriptionStatus,
  usageStats: UsageStats,
  isLoading: boolean
}

Methods:

  • checkStatus() - Refresh subscription
  • upgrade(plan) - Initiate purchase
  • cancelSubscription() - End subscription
  • restorePurchases() - Restore on new device

Features:

  • Real-time subscription sync
  • Usage tracking
  • Payment flow handling
  • Receipt validation

AuthProvider

Purpose: Authentication state management

State:

{
  user: User | null,
  session: Session | null,
  isAuthenticated: boolean,
  isLoading: boolean
}

Methods:

  • signIn(provider) - OAuth login
  • signOut() - Logout user
  • refreshSession() - Token refresh
  • updateProfile(data) - Update user info

Features:

  • Automatic token refresh
  • Session persistence
  • Multi-device support
  • Secure token storage

Component Structure

Atomic Design Principles

Atoms (Basic UI Elements)

components/ui/
├── Button.tsx
├── Input.tsx
├── Text.tsx
├── Icon.tsx
├── Badge.tsx
└── Avatar.tsx

Characteristics:

  • Single responsibility
  • Highly reusable
  • No business logic
  • Theme-aware
  • Accessible

Molecules (Simple Combinations)

components/
├── Card.tsx
├── ListItem.tsx
├── FormField.tsx
├── PostCard.tsx
└── StatCard.tsx

Characteristics:

  • Combine atoms
  • Specific purpose
  • Reusable patterns
  • Props-driven
  • Composable

Organisms (Complex Sections)

components/
├── FoodPostCard.tsx
├── WorkoutPostCard.tsx
├── AnalyticsChart.tsx
├── OnboardingStep.tsx
└── NavigationBar.tsx

Characteristics:

  • Complete UI sections
  • May include business logic
  • Context-aware
  • Feature-specific
  • Self-contained

Templates (Page Layouts)

components/layouts/
├── AuthLayout.tsx
├── MainLayout.tsx
├── OnboardingLayout.tsx
└── ModalLayout.tsx

Characteristics:

  • Page structure
  • Consistent layouts
  • Navigation integration
  • Header/footer management

Pages (Complete Screens)

app/(tabs)/
├── index.tsx
├── analytics.tsx
├── profile.tsx
└── add-post/

Characteristics:

  • Full screens
  • Data fetching
  • Route handling
  • SEO/metadata

Type-Safe Props

Every component has TypeScript interfaces:

interface FoodPostCardProps {
  post: FoodPost;
  onLike?: () => void;
  onComment?: () => void;
  showActions?: boolean;
}
 
export function FoodPostCard({
  post,
  onLike,
  onComment,
  showActions = true
}: FoodPostCardProps) {
  // Component implementation
}

Benefits:

  • Compile-time error checking
  • IntelliSense support
  • Self-documenting code
  • Refactoring safety

Theme-Aware Styling

All components use theme-aware styles:

import { useTheme } from '@/contexts/ThemeProvider';
 
export function MyComponent() {
  const { colors, isDark } = useTheme();
 
  return (
    <View style={{
      backgroundColor: colors.background,
      borderColor: colors.border
    }}>
      {/* Content */}
    </View>
  );
}

Data Flow Patterns

Unidirectional Data Flow

User Action → Service Call → State Update → UI Re-render

Optimistic Updates

// Immediate UI update
setLocalState(newValue);
 
// Background sync
try {
  await service.update(newValue);
} catch (error) {
  // Revert on failure
  setLocalState(oldValue);
  showError();
}

Real-Time Subscriptions

useEffect(() => {
  const subscription = supabase
    .from('food_entries')
    .on('INSERT', handleNewEntry)
    .on('UPDATE', handleUpdatedEntry)
    .subscribe();
 
  return () => subscription.unsubscribe();
}, []);

Error Handling

Service Layer Errors

All services throw typed errors:

try {
  const result = await FoodAnalysisService.analyzeFood(uri);
} catch (error) {
  if (error.code === 'RATE_LIMIT_EXCEEDED') {
    // Show upgrade prompt
  } else if (error.code === 'NETWORK_ERROR') {
    // Show retry
  } else {
    // Generic error
  }
}

Error Boundaries

React Error Boundaries catch component errors:

<ErrorBoundary fallback={<ErrorScreen />}>
  <App />
</ErrorBoundary>

Performance Optimizations

React.memo for Expensive Components

export const ExpensiveComponent = React.memo(
  ({ data }) => {
    // Render logic
  },
  (prevProps, nextProps) => {
    // Custom comparison
    return prevProps.data.id === nextProps.data.id;
  }
);

useMemo for Expensive Calculations

const sortedData = useMemo(() => {
  return data.sort((a, b) => a.calories - b.calories);
}, [data]);

useCallback for Stable Function References

const handlePress = useCallback(() => {
  doSomething(item.id);
}, [item.id]);

FlatList for Long Lists

<FlatList
  data={entries}
  renderItem={renderEntry}
  keyExtractor={(item) => item.id}
  windowSize={10}
  maxToRenderPerBatch={10}
  removeClippedSubviews={true}
/>