Skip to main content
Quest Hunter is a location-based quest application built with modern React Native technologies. The architecture follows a serverless, real-time pattern that combines Expo’s mobile framework with Convex’s backend-as-a-service and Clerk’s authentication system.

Architecture Diagram

┌─────────────────────────────────────────────────────────────┐
│                      Mobile App (Expo)                      │
│  ┌──────────────────────────────────────────────────────┐  │
│  │           Expo Router (File-based Routing)           │  │
│  │  ┌────────┐  ┌────────────┐  ┌──────────────────┐   │  │
│  │  │ (auth) │  │   (tabs)   │  │  Quest Details   │   │  │
│  │  └────────┘  └────────────┘  └──────────────────┘   │  │
│  └──────────────────────────────────────────────────────┘  │
│                                                             │
│  ┌──────────────────────────────────────────────────────┐  │
│  │              UI Components Layer                      │  │
│  │  • NativeWind (Tailwind CSS)                          │  │
│  │  • RN Primitives (Accessible components)              │  │
│  │  • Custom Components (quests/, location/, ui/)        │  │
│  └──────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

                    (Real-time Sync)

┌─────────────────────────────────────────────────────────────┐
│                   Convex Backend (BaaS)                      │
│  ┌──────────────────────────────────────────────────────┐  │
│  │              Database (PostgreSQL)                    │  │
│  │  • quests          • locations                        │  │
│  │  • users           • userQuests                       │  │
│  │  • userLocations                                      │  │
│  └──────────────────────────────────────────────────────┘  │
│  ┌──────────────────────────────────────────────────────┐  │
│  │          Server Functions (TypeScript)                │  │
│  │  • Queries (Real-time data fetching)                  │  │
│  │  • Mutations (Data modifications)                     │  │
│  │  • HTTP Routes (Webhooks)                             │  │
│  └──────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

                   (JWT Validation)

┌─────────────────────────────────────────────────────────────┐
│                   Clerk (Authentication)                     │
│  • OAuth providers (Google, Apple, etc.)                    │
│  • Session management                                        │
│  • User profile management                                  │
│  • JWT token issuance                                        │
└─────────────────────────────────────────────────────────────┘

Core Architecture Principles

Serverless Backend

Convex handles all backend logic without managing servers. Queries and mutations are defined as TypeScript functions that run in Convex’s cloud.

Real-time Sync

Convex automatically keeps all connected clients in sync. When data changes, all subscribed components re-render instantly.

File-based Routing

Expo Router uses the app/ directory structure to define routes. Folder names in parentheses create layout groups.

Type-safe API

Convex generates TypeScript types from your schema, providing end-to-end type safety from database to UI.

Authentication Flow

The app uses Clerk for authentication, integrated with Convex for backend authorization:
  1. User signs in via Clerk (OAuth or email)
  2. Clerk issues JWT with user identity
  3. Mobile app receives token stored in secure storage
  4. Convex validates JWT on every request via auth.config.ts
  5. Backend functions access user via ctx.auth.getUserIdentity()
  6. Webhooks sync user data from Clerk to Convex database
The integration happens in app/_layout.tsx where ClerkProvider wraps ConvexProviderWithClerk, enabling automatic token passing to all Convex requests.

Data Flow Pattern

Query Flow (Read)

// Component subscribes to reactive query
const quests = useQuery(api.quests.listRecommended);

// Convex executes query with auth context
// Returns data + establishes subscription
// Component re-renders on any data change

Mutation Flow (Write)

// Component triggers mutation
const startQuest = useMutation(api.quests.start);
await startQuest({ questId });

// Convex validates auth, modifies data
// All subscribed queries automatically update
// All connected clients see changes instantly

Protected Routes

The app uses Expo Router’s Stack.Protected component to guard authenticated routes:
<Stack.Protected guard={isSignedIn ?? false}>
  <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
</Stack.Protected>
When users aren’t signed in, they’re automatically redirected to the (auth) group.

Key Integration Points

Convex Client Initialization

Location: lib/convex-client.ts
export const convex = new ConvexReactClient(
  process.env.EXPO_PUBLIC_CONVEX_URL
);

Clerk Authentication Config

Location: convex/auth.config.ts
export default {
  providers: [{
    domain: process.env.CLERK_JWT_ISSUER_DOMAIN!,
    applicationID: "convex",
  }],
} satisfies AuthConfig;

Root Provider Setup

Location: app/_layout.tsx The root layout wraps the entire app with:
  • ClerkProvider - Authentication state
  • ConvexProviderWithClerk - Backend connectivity + auth
  • ThemeProvider - Navigation theming
  • PortalHost - Modal/dialog rendering

Development Workflow

When you run bun dev, two processes start simultaneously:
  1. Expo development server (bun start)
    • Serves the mobile app
    • Enables hot reload
    • Provides QR code for device testing
  2. Convex development deployment (bun convex:dev)
    • Deploys backend functions
    • Watches for file changes
    • Provides real-time logs
Both processes run in parallel using mprocs, allowing you to see mobile and backend logs side-by-side.

Storage Architecture

Quest Hunter uses multiple storage mechanisms:
TypeTechnologyUse Case
DatabaseConvex TablesQuests, users, locations, progress
File StorageConvex StorageUser photos from completed locations
Secure StorageExpo SecureStoreClerk authentication tokens
CacheConvex ClientOptimistic updates, query results

Next Steps

Tech Stack Details

Learn about specific technology choices and why they were selected

Project Structure

Explore the directory organization and file conventions

Build docs developers (and LLMs) love