Skip to main content

Mobile App Architecture

Overview

The ADHD Simple mobile app is a React Native application built with Expo, designed to provide patients with an intuitive interface for managing ADHD medications and prescriptions. The app follows an offline-first architecture with robust sync capabilities.

Tech Stack

Core Framework

UI & Design

Key Dependencies

Shared Services Integration

The mobile app uses a centralized ADHD-simple-shared-services repository for all backend operations:
  • Database Schema: packages/supabase/migrations/
  • Edge Functions: packages/supabase/functions/ (45+ functions)
  • Configuration: packages/supabase/config.toml

Architecture Benefits

  • ✅ Single source of truth for database schema
  • ✅ Shared business logic between clinical and mobile apps
  • ✅ Centralized Edge Function management
  • ✅ Consistent data models across platforms

Development Workflow

# Database operations - run from shared services directory
cd packages/supabase
supabase start
supabase db reset
supabase functions serve

# Mobile app development - run from mobile app directory  
cd apps/mobile
npx expo start --dev-client

Order Storage & Mobile Sync Architecture

System Overview

The app implements a dual-storage system for orders with mobile sync functionality to ensure offline capability and data consistency:
┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   Local Device  │    │  Mobile Sync     │    │   Supabase DB   │
│                 │    │   Service        │    │                 │
│ ┌─────────────┐ │    │ ┌──────────────┐ │    │ ┌─────────────┐ │
│ │Draft Orders │◄┼────┼►│Edge Function │◄┼────┼►│order_details│ │
│ │(AsyncStorage│ │    │ │              │ │    │ │  _unified   │ │
│ │             │ │    │ │              │ │    │ │    view     │ │
│ └─────────────┘ │    │ └──────────────┘ │    │ └─────────────┘ │
│                 │    │                  │    │                 │
│ ┌─────────────┐ │    │ ┌──────────────┐ │    │ ┌─────────────┐ │
│ │Live Orders  │◄┼────┼►│Sync Service  │◄┼────┼►│order_       │ │
│ │(LocalDB)    │ │    │ │              │ │    │ │requests     │ │
│ └─────────────┘ │    │ └──────────────┘ │    │ └─────────────┘ │
└─────────────────┘    └──────────────────┘    └─────────────────┘

Local Storage Structure

Draft Orders (Pre-submission)

// Storage Key: '@adhd_app:draft_orders'
{
  id: "draft_1750409149175_obu7vnktm",  // Local UID
  order_number: 123,                    // From next_order_number
  medications: [...],
  status: "draft",
  sync_status: "pending",               // pending|syncing|synced|failed
  server_order_id: null,                // Set after submission
  created_at: "2025-01-20T10:30:00Z",
  updated_at: "2025-01-20T10:35:00Z"
}

Live Orders (Post-submission)

// Storage Key: '@adhd_app:user_data' → patient_orders
{
  order_id: "uuid-from-server",
  order_type: "order_request",
  order_number: "7272551103",           // Proper assigned number
  display_order_number: "7272551103",
  current_stage: "requested",
  stage_requested: true,
  stage_requested_at: "2025-01-20T10:40:00Z",
  // ... other unified view fields
}

Mobile Sync Flow

1. Draft Order Creation

// LocalOrderService.ts
const draftOrder = {
  id: generateLocalUID(),              // "draft_timestamp_random"
  order_number: await getNextOrderNumber(),
  sync_status: "pending"
};
await saveDraftOrder(draftOrder);

2. Order Submission

// OrderSyncService.ts
const response = await submitOrderToServer(draftOrder);
if (response.success) {
  // Delete local draft - no longer needed
  await localOrderService.deleteDraftAfterSubmission(draftOrder.id);
}

3. Live Data Sync

// Mobile Sync Edge Function
const { data: patient_orders } = await supabaseClient
  .from('order_details_unified')      // Unified view of all orders
  .select('*')
  .eq('patient_id', patient_id);

// Store in local database for offline access
await localDatabase.savePatientOrders(patient_orders);

Key Benefits

  • 📱 Offline Support: Draft orders work without internet
  • 🔄 Real-time Sync: Live orders always show current server state
  • 🗑️ Clean Separation: Drafts deleted after submission (no duplication)
  • ⚡ Performance: Local caching with smart sync
  • 🔒 Data Consistency: Single source of truth for submitted orders

Technical Implementation

Storage Services

  • LocalOrderService.ts - Draft order management
  • OrderSyncService.ts - Server submission logic
  • SyncService.ts - Mobile sync coordination
  • LocalDatabase.ts - Live order caching

Edge Functions

  • submit-order - Processes order submission
  • assign-order-number - Generates proper order numbers
  • mobile-application-patient-sync - Syncs live data

Database Views

  • order_details_unified - Combines order_requests + prescription_orders
  • Provides consistent interface for mobile app

Payment Storage & Receipt System

Payment Architecture

The app uses a multi-table payment system with Stripe integration to handle transactions and generate detailed receipts:
┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   Stripe API    │    │  Payment Tables  │    │   Receipt Data  │
│                 │    │                  │    │                 │
│ ┌─────────────┐ │    │ ┌──────────────┐ │    │ ┌─────────────┐ │
│ │Payment      │◄┼────┼►│payment_      │◄┼────┼►│Dynamic      │ │
│ │Intent       │ │    │ │intents       │ │    │ │Receipt      │ │
│ └─────────────┘ │    │ └──────────────┘ │    │ │Generation   │ │
│                 │    │                  │    │ └─────────────┘ │
│ ┌─────────────┐ │    │ ┌──────────────┐ │    │                 │
│ │Customer &   │◄┼────┼►│order_        │◄┼────┼►│Line Items   │ │
│ │Cards        │ │    │ │payments      │ │    │ │& Pricing    │ │
│ └─────────────┘ │    │ └──────────────┘ │    │ └─────────────┘ │
└─────────────────┘    └──────────────────┘    └─────────────────┘

Payment Tables Structure

payment_intents - Stripe Payment Tracking

CREATE TABLE payment_intents (
  id TEXT PRIMARY KEY,                    -- Stripe Payment Intent ID
  user_id TEXT REFERENCES auth.users(id),
  amount INTEGER NOT NULL,                -- Amount in cents
  currency TEXT NOT NULL DEFAULT 'usd',
  status TEXT NOT NULL,                   -- succeeded/failed/processing
  customer_id TEXT,                       -- Stripe Customer ID
  description TEXT,
  metadata JSONB,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

order_payments - Final Payment Records

CREATE TABLE order_payments (
  id SERIAL PRIMARY KEY,
  order_request_id UUID REFERENCES order_requests(id),
  stripe_object_id TEXT NOT NULL,        -- Payment Intent ID
  kind TEXT NOT NULL,                     -- payment/refund
  status TEXT NOT NULL,                   -- succeeded/failed
  amount DECIMAL(10,2) NOT NULL,
  currency TEXT NOT NULL DEFAULT 'GBP',
  processed_at TIMESTAMPTZ,
  patient_id UUID REFERENCES patients(id)
);

order_line_items - Receipt Line Items

CREATE TABLE order_line_items (
  id SERIAL PRIMARY KEY,
  order_request_id UUID REFERENCES order_requests(id),
  type TEXT NOT NULL,                     -- medication/delivery/script_fee
  reference_id TEXT,                      -- medication_id
  description TEXT NOT NULL,
  quantity INTEGER,
  unit_price DECIMAL(10,2) NOT NULL,
  amount DECIMAL(10,2) NOT NULL,          -- total for line
  currency TEXT NOT NULL DEFAULT 'GBP',
  pricing_source TEXT                     -- medications.regular_price
);

Payment Flow & Receipt Generation

1. Payment Processing

// StripeService creates payment intent
const paymentIntent = await stripe.paymentIntents.create({
  amount: orderTotal * 100,               // Convert to cents
  currency: 'gbp',
  customer: stripeCustomerId,
  metadata: { server_order_id: orderId }
});

// Store payment intent reference
await supabase.from('order_requests').update({
  stripe_payment_intent_id: paymentIntent.id,
  stripe_client_secret: paymentIntent.client_secret
}).eq('id', orderId);

2. Webhook Processing

// Stripe webhook updates payment status
export async function handlePaymentSucceeded(paymentIntent) {
  // Update order status
  await supabase.from('order_requests').update({
    status: 'processing',
    payment_confirmed_at: new Date().toISOString()
  }).eq('stripe_payment_intent_id', paymentIntent.id);
  
  // Create payment record
  await supabase.from('order_payments').insert({
    order_request_id: orderId,
    stripe_object_id: paymentIntent.id,
    status: 'succeeded',
    amount: paymentIntent.amount / 100,     // Convert from cents
    processed_at: new Date().toISOString()
  });
}

Key Features

Itemized Receipts - Full breakdown via order_line_items
Stripe Integration - Secure payment processing with webhooks
Payment Tracking - Complete audit trail from intent to confirmation
Dynamic Generation - No stored receipt files, built from live data
Multi-Currency - Supports GBP, USD, EUR
Member Pricing - Different rates for subscribers

Technical Implementation

Payment Services

  • StripeService.ts - Payment intent creation and processing
  • OrderSyncService.ts - Payment-order linking
  • PaymentForm.tsx - Frontend payment interface

Edge Functions

  • create-payment-intent - Generates Stripe payment intents
  • stripe-webhook-handler - Processes payment confirmations
  • update-order-payment - Links payments to orders

Local Storage

  • Payment methods cached in AsyncStorage for saved cards
  • Payment records stored locally for offline receipt access
  • Stripe customer ID synced across devices

Project Structure

apps/mobile/
├── 📱 app/                    # App screens (Expo Router)
│   ├── (tabs)/               # Tab navigation screens
│   ├── login.tsx             # Authentication
│   ├── edit-profile.tsx      # User profile management
│   ├── checkout/             # Checkout flow screens
│   ├── reorder/              # Reorder flow screens
│   ├── settings/             # Settings screens
│   └── ...
├── 🎨 components/            # Reusable UI components
├── 🔧 constants/             # App constants and config
├── 🪝 hooks/                 # Custom React hooks
├── 📚 lib/                   # Core libraries and services
│   ├── auth/                 # Authentication logic
│   ├── contexts/             # React contexts
│   ├── database/             # Local database management
│   ├── services/             # Business logic services
│   ├── types/                # TypeScript type definitions
│   └── utils/                # Utility functions
├── 🖼 assets/                # Images, fonts, icons
│   ├── fonts/               # Poppins font family
│   └── images/              # App images and icons
├── 📄 app.json              # Expo configuration
├── 📦 package.json          # Dependencies and scripts
└── 📚 README.md             # Development documentation

Configuration

App Configuration (app.json)

{
  "expo": {
    "name": "ADHD Simple Mobile",
    "slug": "adhd-simple-mobile",
    "platforms": ["ios", "android", "web"],
    "plugins": ["expo-router"]
  }
}

Available Scripts

npm start          # Start Expo development server
npm run android    # Run on Android emulator
npm run ios        # Run on iOS simulator
npm run web        # Run in web browser
npm run lint       # Run ESLint

Deployment

EAS Update

The app uses EAS Update for seamless global distribution:
# Login to Expo (one-time setup)
npx expo login

# Publish to pre-beta channel
eas update --branch pre-beta --message "Your update message"

# Publish to production
eas update --branch production --message "Production release"

Distribution Options

MethodBest ForGlobal AccessSetup Required
🔗 EAS UpdateQuick sharing, testing✅ YesExpo account
📱 Expo GoDevelopment, demos✅ YesNone
🏪 App StoresProduction release✅ YesDeveloper accounts
🌐 Web DeployBrowser access✅ YesHosting service

Core Features

Cross-Platform Support

  • 📱 iOS and Android native apps
  • 🌐 Web browser support
  • 📺 Responsive design for all screen sizes

Technical Features

  • ⚡ File-based routing with Expo Router
  • 🎭 Smooth animations with Reanimated and Moti
  • 🎨 Consistent design system
  • 🔄 Real-time sync with offline support
  • 🔐 Secure authentication and data handling

User Experience

  • 🏠 Intuitive tab-based navigation
  • 🔔 Push notification support
  • 💳 Secure payment processing
  • 📦 Order tracking and management
  • ⚙️ Comprehensive settings management