Cue: Technical Documentation

Architecture Overview

iOS app. React Native + Expo. Supabase for backend. RevenueCat for subscriptions.

Production-ready.


Tech Stack

Frontend

TechnologyPurpose
React NativeCross-platform mobile
ExpoDev and build tooling
TypeScriptType-safe JavaScript
ZustandGlobal state management
React QueryServer state and caching
Expo RouterFile-based navigation
AsyncStorageLocal data persistence

Backend

TechnologyPurpose
SupabaseBackend-as-a-Service
PostgreSQLPrimary database
Supabase AuthAuthentication
Edge FunctionsServerless API (Deno)
Row Level SecurityData access control

AI & Services

TechnologyPurpose
OpenAI APIGPT-4 for coaching
RevenueCatSubscription management
Expo NotificationsPush notifications
expo-secure-storeCredential storage

Architecture Diagram

+------------------+     +-------------------+     +------------------+
|                  |     |                   |     |                  |
|   React Native   |<--->|     Supabase      |<--->|    OpenAI API    |
|   (Expo) App     |     |   (PostgreSQL)    |     |    (GPT-4)       |
|                  |     |                   |     |                  |
+------------------+     +-------------------+     +------------------+
        |                         |
        |                         |
        v                         v
+------------------+     +-------------------+
|                  |     |                   |
|   RevenueCat     |     |  Edge Functions   |
|  (Subscriptions) |     |     (Deno)        |
|                  |     |                   |
+------------------+     +-------------------+

Database Schema

Core Tables

user_profiles

CREATE TABLE user_profiles (
  id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
  email TEXT NOT NULL,
  display_name TEXT,
  avatar_url TEXT,
  subscription_status TEXT DEFAULT 'free'
    CHECK (subscription_status IN ('free', 'premium')),
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

user_goals

CREATE TABLE user_goals (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users NOT NULL,
  coach_id TEXT NOT NULL,
  coach_type TEXT NOT NULL CHECK (coach_type IN ('core', 'custom')),
  short_term_goal TEXT,
  long_term_goal TEXT,
  current_challenge TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(user_id, coach_id)
);

custom_coaches

CREATE TABLE custom_coaches (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users NOT NULL,
  name TEXT NOT NULL,
  emoji TEXT NOT NULL,
  description TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

conversations

CREATE TABLE conversations (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users NOT NULL,
  coach_id TEXT NOT NULL,
  pinned BOOLEAN DEFAULT false,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

messages

CREATE TABLE messages (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  conversation_id UUID REFERENCES conversations ON DELETE CASCADE NOT NULL,
  role TEXT NOT NULL CHECK (role IN ('user', 'assistant')),
  content TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

notification_settings

CREATE TABLE notification_settings (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users NOT NULL,
  coach_id TEXT NOT NULL,
  enabled BOOLEAN DEFAULT true,
  frequency INT DEFAULT 1 CHECK (frequency >= 1 AND frequency <= 7),
  times JSONB DEFAULT '["08:00"]'::jsonb,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(user_id, coach_id)
);

Row Level Security

All tables implement RLS. Users can only access their own data.

CREATE POLICY "Users can view own conversations" ON conversations
  FOR SELECT USING (auth.uid() = user_id);

CREATE POLICY "Users can insert own conversations" ON conversations
  FOR INSERT WITH CHECK (auth.uid() = user_id);

Edge Functions

chat-completion

Handles AI coaching responses.

Endpoint: POST /functions/v1/chat-completion

Process:

  1. Validate authentication
  2. Check message limits (free: 15/day)
  3. Load coach prompt + user context
  4. Call OpenAI with full context
  5. Store message
  6. Return response

generate-notification

Generates personalized notification content.

Endpoint: POST /functions/v1/generate-notification

refine-goals

AI-assisted goal refinement.

Endpoint: POST /functions/v1/refine-goals

send-notifications

Cron-triggered notification sender.


RevenueCat Integration

Setup

import Purchases from 'react-native-purchases';

export const initializePurchases = async (userId: string) => {
  Purchases.configure({
    apiKey: REVENUECAT_IOS_KEY,
  });

  await Purchases.logIn(userId);
};

Entitlement Check

export const checkPremiumStatus = async (): Promise<boolean> => {
  const customerInfo = await Purchases.getCustomerInfo();
  return customerInfo.entitlements.active['premium'] !== undefined;
};

Products

Product IDTypePrice
cue_monthlySubscription$9.99/month
cue_annualSubscription$59.99/year
cue_lifetimeNon-consumable$149.99

Authentication Flow

1. App Launch
   ├── Check Supabase session
   │   ├── Valid → Load user → Main App
   │   └── Invalid → Auth Screen

2. Sign Up
   ├── Email/Password registration
   ├── Create user_profiles record
   ├── Initialize RevenueCat
   └── Begin onboarding

3. Onboarding
   ├── Select coaches to focus on
   ├── Set goals per coach
   ├── Configure notifications
   └── Complete → Main App

Local-First Architecture

Optimistic Updates

  • Messages appear instantly before server confirmation
  • Failed messages show retry UI

Local Cache

  • AsyncStorage for persistence
  • Zustand hydration on app launch
  • React Query for server state sync

Security

  • Supabase Auth with secure sessions
  • JWT with auto-refresh
  • expo-secure-store for credentials
  • RLS on all tables
  • HTTPS everywhere

Deployment

EAS Build

# Production
eas build --profile production --platform ios

# Submit
eas submit --platform ios

Built by Aaryan Sharma.


← Business Proposal | Back to Home →