> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shipnative.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Mock Services

> Develop without backend credentials

Mock services activate automatically when API keys are missing. Add credentials via `yarn setup` to use real services - no code changes needed.

## How It Works

```typescript theme={null}
// Backend mock activates based on provider and credentials
export const USE_MOCK_SUPABASE = __DEV__ && isSupabase && !process.env.EXPO_PUBLIC_SUPABASE_URL
export const USE_MOCK_CONVEX = __DEV__ && isConvex && !process.env.EXPO_PUBLIC_CONVEX_URL

// RevenueCat also detects placeholder values like "your-ios-key"
// This prevents SDK credential errors when using .env.example values
const isPlaceholderKey = (key) => !key || key.startsWith("your-")
```

<Note>
  Placeholder values like `your-ios-key` from `.env.example` will also trigger mock mode. This prevents SDK credential errors - you can safely copy `.env.example` to `.env` and the app will work in mock mode.
</Note>

## Available Mocks

| Service        | Mock Behavior                                            |
| -------------- | -------------------------------------------------------- |
| **Supabase**   | Auth, database, storage, realtime - all in-memory        |
| **Convex**     | Auth, queries, mutations - all in-memory                 |
| **PostHog**    | Events logged to console, feature flags return false     |
| **Sentry**     | Errors logged to console                                 |
| **RevenueCat** | Purchases always succeed, dev menu toggle for pro status |

***

## Backend Mocks

<Tabs>
  <Tab title="Supabase">
    Full simulation of auth, database, storage, and realtime.

    ```typescript theme={null}
    import { supabase } from '@/services/supabase'

    // Same code works with mock or real Supabase
    await supabase.auth.signInWithPassword({
      email: 'test@example.com',
      password: 'password'
    })

    const { data } = await supabase
      .from('posts')
      .select('*')
      .eq('author_id', 'user-123')

    await supabase.storage
      .from('avatars')
      .upload('avatar.jpg', file)
    ```

    ### Test Accounts

    ```typescript theme={null}
    { email: 'demo@shipnative.app', password: 'demo123' }
    { email: 'test@shipnative.app', password: 'test123' }
    ```

    ### Testing Utilities

    ```typescript theme={null}
    import { mockSupabaseHelpers } from '@/services/mocks/supabase'

    // Seed test data
    mockSupabaseHelpers.seedTable('posts', [
      { id: 1, title: 'Test Post', author_id: 'user-123' },
    ])

    // Clear all mock data
    mockSupabaseHelpers.clearAll()
    ```
  </Tab>

  <Tab title="Convex">
    Full simulation of auth, queries, and mutations.

    ```typescript theme={null}
    import { useConvexAuth } from '@/hooks/convex'
    import { useQuery, useMutation } from '@/hooks/convex'

    // Auth works the same in mock mode
    const { signInWithPassword, isAuthenticated } = useConvexAuth()

    await signInWithPassword('test@example.com', 'password')

    // Queries and mutations work with mock data
    const posts = useQuery(api.posts.list)
    const createPost = useMutation(api.posts.create)
    ```

    ### Test Accounts

    ```typescript theme={null}
    { email: 'demo@shipnative.app', password: 'demo123' }
    { email: 'test@shipnative.app', password: 'test123' }
    ```

    ### Testing Utilities

    ```typescript theme={null}
    import { mockConvexHelpers } from '@/services/mocks/convex'

    // Seed test data
    mockConvexHelpers.seedTable('posts', [
      { _id: 'post-1', title: 'Test Post', authorId: 'user-123' },
    ])

    // Clear all mock data
    mockConvexHelpers.clearAll()
    ```
  </Tab>
</Tabs>

***

## Other Service Mocks

### RevenueCat

```typescript theme={null}
import { mockRevenueCat } from '@/services/mocks/revenueCat'

// Toggle pro status for testing
mockRevenueCat.setProStatus(true)

// Or use the Dev Menu (Cmd+D / Cmd+M)
```

### PostHog

Events logged to console with `[MockPostHog]` prefix. Feature flags return `false` by default.

### Sentry

Errors logged to console with `[MockSentry]` prefix instead of being sent to Sentry.

***

## Console Logging

All mock operations log to console:

```
[MockSupabase] Sign in: user@example.com
[MockConvex] Query: api.posts.list
[MockPostHog] Event: button_clicked
[MockRevenueCat] Purchase: pro_monthly
```

***

## Limitations

* Data clears on app restart
* Security policies (RLS, function auth) not enforced
* Network performance not simulated
* Realtime subscriptions simulated locally

For production testing, connect real services via `yarn setup`.

***

## Switching to Real Services

```bash theme={null}
yarn setup
```

The wizard prompts for credentials. Once configured, the app automatically uses real services - no code changes needed.

You can also manually set environment variables in `apps/app/.env`:

<Tabs>
  <Tab title="Supabase">
    ```bash theme={null}
    EXPO_PUBLIC_BACKEND_PROVIDER=supabase
    EXPO_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
    EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY=your-key
    ```
  </Tab>

  <Tab title="Convex">
    ```bash theme={null}
    EXPO_PUBLIC_BACKEND_PROVIDER=convex
    EXPO_PUBLIC_CONVEX_URL=https://your-project.convex.cloud
    ```
  </Tab>
</Tabs>

Restart Metro after changing environment variables: `yarn start --clear`
