Skip to main content

API Reference Overview

ZapDev uses Convex as its primary backend and API layer. Convex provides:
  • Real-time reactive queries that automatically update when data changes
  • Type-safe mutations for data modification
  • Server-side actions for background processing and external API calls
  • Built-in authentication with Clerk integration
This architecture ensures end-to-end type safety while enabling real-time data synchronization across your application.

Architecture Overview

Convex Backend

Convex provides real-time database operations with reactive queries that automatically update when data changes. Location: convex/ Core Function Types:
  • Queries: Read operations that are reactive and cached
  • Mutations: Write operations that modify database state
  • Actions: Server-side logic with external API calls (Node.js runtime)
Example Query (convex/projects.ts:282):
export const get = query({
  args: {
    projectId: v.id("projects"),
  },
  handler: async (ctx, args) => {
    const userId = await requireAuth(ctx);
    const project = await ctx.db.get(args.projectId);
    
    if (!project) {
      throw new Error("Project not found");
    }
    
    if (project.userId !== userId) {
      throw new Error("Unauthorized");
    }
    
    return project;
  },
});

API Conventions

Convex Conventions

  1. Function Syntax: Always use object-based syntax with explicit args and handler
  2. Validators: Every argument must have a v.* validator from convex/values
  3. Authentication: Use requireAuth(ctx) at the start of protected handlers
  4. Indexes: Always use withIndex() for queries - never use .filter() for performance

Database Schema

The database schema is defined in convex/schema.ts with type-safe table definitions: Core Tables:
  • projects: User projects with framework and settings
  • messages: Conversation messages for each project
  • fragments: Generated code fragments with sandbox URLs
  • attachments: Images and design files linked to messages
  • usage: Credit tracking for free/pro/unlimited tiers
  • subscriptions: Polar subscription data
  • agentRuns: AI agent execution tracking
Example Schema Definition:
projects: defineTable({
  name: v.string(),
  userId: v.string(),
  framework: frameworkEnum,
  modelPreference: v.optional(v.string()),
  createdAt: v.optional(v.number()),
  updatedAt: v.optional(v.number()),
})
  .index("by_userId", ["userId"])
  .index("by_userId_createdAt", ["userId", "createdAt"])

Client Usage

Using Convex in Client Components

'use client';
import { useQuery, useMutation } from 'convex/react';
import { api } from '@/convex/_generated/api';

export function MyComponent() {
  const projects = useQuery(api.projects.list);
  const createProject = useMutation(api.projects.create);
  
  // ... component logic
}

Using in Server Components

For Convex in server components:
import { getConvexClientWithAuth } from '@/lib/auth-server';
import { api } from '@/convex/_generated/api';

export async function MyServerComponent() {
  const convex = await getConvexClientWithAuth();
  const projects = await convex.query(api.projects.list);
  
  return <div>{/* ... */}</div>;
}

Anti-Patterns

Never do this:
  • Use .filter() in Convex queries (use indexes instead)
  • Call ctx.db inside a Convex action (use ctx.runQuery or ctx.runMutation)
  • Expose Clerk user IDs in public API responses
  • Use any type in function signatures
  • Perform side effects (API calls, emails) in queries/mutations (use actions)

Type Safety

Convex provides full end-to-end type safety by generating types from your schema definitions in convex/_generated/dataModel.d.ts and convex/_generated/api.d.ts. Use TypeScript’s type inference to get autocomplete and type checking throughout your application. All query and mutation functions are fully typed, including arguments and return values.

Next Steps

Build docs developers (and LLMs) love