Architecture

Navigation Flow

app/index.tsx
  │
  ├── Not authenticated ──→ auth/login.tsx ←──→ auth/signup.tsx
  │                              │
  │                              └──→ auth/adapter.tsx (change backend)
  │
  └── Authenticated ──→ (tabs)/_layout.tsx
                           ├── Blog tab (index.tsx)
                           │     └──→ blog/create.tsx
                           │     └──→ blog/[id].tsx (view/edit/delete)
                           └── Profile tab (profile.tsx)
                                 └──→ auth/adapter.tsx

Data Flow

AppProvider (context.tsx)
  │
  ├── client ────────→ SDK client instance
  ├── auth ──────────→ { isAuthenticated, user }
  ├── adapterType ───→ 'mock' | 'supabase' | 'pocketbase'
  ├── switchAdapter ─→ Rebuilds client with new adapter
  ├── signIn / signUp → client.auth.signInWithPassword / signUp
  └── signOut ───────→ client.auth.signOut

All screens access the SDK through the useApp() hook. The client is rebuilt when the adapter changes, and auth state resets.

SDK Usage Examples

Fetching Posts

const { data } = await client
  .from('posts')
  .select('*')
  .order('created_at', { ascending: false });

Creating a Post

await client.from('posts').insert({
  title: 'My New Post',
  content: 'Post body here...',
  author_id: auth.user.id,
  author_name: auth.user.email,
  created_at: new Date().toISOString(),
});

Updating a Post

await client
  .from('posts')
  .update({ title: 'Updated Title', content: 'New content' })
  .eq('id', postId);

Deleting a Post

await client
  .from('posts')
  .delete()
  .eq('id', postId);

Uploading a Profile Picture

await client.storage.createBucket('avatars', { public: true });
await client.storage.from('avatars').upload(fileName, imageUri);
const { data } = client.storage.from('avatars').getPublicUrl(fileName);

Updating Profile

await client
  .from('profiles')
  .update({ name, bio, avatar_url: avatarUri })
  .eq('id', auth.user.id);