This project is designed to be reused as a production-ready starter template for AI-powered applications. It includes authentication, AI text/image generation, type-safe LLM functions, and a beautiful adaptive navigation system.
- β Authentication: Clerk + Convex with automatic profile sync
- β User Profiles: Complete user management with admin system
- β Adaptive Navigation: Desktop sidebar + mobile bottom tabs
- β Theme System: Dark/light/system mode with CSS variables
- β File Storage: Convex file storage ready to use
- β Text Generation: AI SDK with GPT-5, Claude, Gemini, etc.
- β Image Generation: FAL integration (FLUX, GPT Image, Imagen, etc.)
- β Type-Safe LLM: BAML for structured AI outputs
- β Streaming Support: Real-time text streaming
- β Automatic Fallbacks: Model chains for reliability
- β shadcn/ui: Full component library
- β Responsive Layout: Works perfectly on all devices
- β Page Context System: Dynamic headers and breadcrumbs
- β Animation: Framer Motion for smooth transitions
# Clone the template
git clone https://github.com/your-org/mocksy-template my-new-project
cd my-new-project
# Install dependencies
npm install
# Initialize Convex
npx convex devCreate a Clerk account at clerk.com and get your keys:
# Set Clerk environment variables
npx convex env set CLERK_PUBLISHABLE_KEY=pk_test_...
npx convex env set CLERK_SECRET_KEY=sk_test_...
# Also add to .env.local for Next.js
echo "NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_..." >> .env.local
echo "CLERK_SECRET_KEY=sk_test_..." >> .env.localConfigure Clerk Webhook (for profile sync):
- Go to Clerk Dashboard β Webhooks
- Add endpoint:
https://your-deployment.convex.site/webhooks/clerk - Subscribe to:
user.created,user.updated,user.deleted - Copy the webhook secret:
npx convex env set CLERK_WEBHOOK_SECRET=whsec_...You only need the providers you plan to use:
# For text generation (AI SDK)
npx convex env set OPENAI_API_KEY=sk-... # GPT models
npx convex env set ANTHROPIC_API_KEY=sk-ant-... # Claude models
npx convex env set GOOGLE_AI_API_KEY=... # Gemini models
npx convex env set OPENROUTER_API_KEY=sk-or-... # Multi-provider
# For image generation (FAL)
npx convex env set FAL_KEY=... # fal.ai API key
# For production
npx convex env set OPENROUTER_API_KEY=... --prod
npx convex env set FAL_KEY=... --prodNote: BAML uses OpenRouter by default, so OPENROUTER_API_KEY gives you access to all models in baml_src/clients.baml.
# Terminal 1: Convex backend
npx convex dev
# Terminal 2: Next.js frontend
npm run devVisit http://localhost:3000 - you're ready to build!
Edit src/app/layout.tsx:
export const metadata: Metadata = {
title: "Your App Name",
description: "Your app description",
openGraph: {
title: "Your App Name",
description: "Your app description",
images: [{ url: "/your-cover.jpg" }],
},
icons: {
icon: "/your-icon.png",
},
};Replace branding assets in public/:
your-logo-dark-mode.pngyour-logo-light-mode.pngyour-app-icon.pngyour-cover.jpg
Edit src/components/layout/Sidebar.tsx:
// Change navigation links (around line 85-110)
<Link href="/your-route" className={...}>
<YourIcon className="w-5 h-5" />
<span>Your Page</span>
</Link>Edit src/components/layout/BottomTabBar.tsx:
// Update mobile tabs (around line 14-43)
const tabs = [
{ id: 'home', label: 'Home', icon: Home, href: '/', isActive: pathname === '/' },
{ id: 'create', label: 'Create', icon: Pencil, href: '/create', isActive: pathname === '/create' },
// ... your tabs
];Update static routes in src/components/RootLayoutContent.tsx:
// Line 47: Define which routes have persistent sidebar
const staticRoutes = ['/browse', '/profile', '/settings'];Edit convex/schema.ts:
export default defineSchema({
// β
Keep this - user profiles
profiles: defineTable({ ... })
.index("by_user_id", ["userId"])
.index("by_username", ["username"]),
// π Add your tables
posts: defineTable({
profileId: v.id("profiles"),
title: v.string(),
content: v.string(),
createdAt: v.number(),
})
.index("by_profile", ["profileId"])
.index("by_created", ["createdAt"]),
// ... more tables
});Keep baml_src/clients.baml (all LLM client configs are reusable)
Replace example BAML files with your own:
# Remove Mocksy-specific BAML
rm baml_src/app-concepts.baml
rm baml_src/app-generation.baml
# Create your BAML functions
touch baml_src/your-functions.bamlExample: baml_src/blog-writer.baml
class BlogPost {
title string
excerpt string
content string
tags string[]
}
function GenerateBlogPost(topic: string, tone: string) -> BlogPost {
client GPT5
prompt #"
Write a blog post about {{ topic }} in a {{ tone }} tone.
{{ ctx.output_format }}
"#
}Generate TypeScript client:
npm run baml:generateUse in Convex:
import { b } from "../../baml_client";
export const generateBlogPost = action({
args: { topic: v.string(), tone: v.string() },
returns: v.any(),
handler: async (ctx, args) => {
const result = await b.GenerateBlogPost(args.topic, args.tone);
return result;
},
});Delete these directories:
# Convex backend
rm -rf convex/data/apps.ts
rm -rf convex/data/appScreens.ts
rm -rf convex/data/appConcepts.ts
rm -rf convex/data/appReviews.ts
rm -rf convex/features/appGeneration/
# Frontend pages
rm -rf src/app/appstore/
rm -rf src/app/apps/
rm -rf src/app/generate/
rm -rf src/app/admin/ # Or keep if you want admin features
# Components (most are Mocksy-specific)
# Keep: layout/, ui/, RootLayoutContent, ThemeProvider
# Remove: AppCard, AppConceptCard, etc.
# Stores (Zustand)
rm -rf src/stores/
# Scripts
rm -rf scripts/Keep these for reference:
docs/rules/ # Setup guides for agents
convex/utils/aisdk/ # AI text generation
convex/utils/fal/ # AI image generation
// In a Convex action
import { internal } from "./_generated/api";
export const generateContent = action({
args: { prompt: v.string() },
returns: v.string(),
handler: async (ctx, args) => {
const result = await ctx.runAction(
internal.utils.aisdk.aiSdkActions.generateTextInternal,
{
messages: [{ role: "user", content: args.prompt }],
modelPreset: "large", // or "medium", "small", "tiny", "vision"
}
);
return result.content;
},
});Available presets:
large: GPT-5 (high reasoning) - complex tasksmedium: GPT-5 (balanced) - general purposesmall: GPT-5 Mini - quick taskstiny: GPT-5 Nano - simple decisionsvision: Qwen 72B Vision - image analysis
See full docs: convex/utils/aisdk/README.md
// In a Convex action
import { api } from "./_generated/api";
export const generateImage = action({
args: { prompt: v.string() },
returns: v.string(),
handler: async (ctx, args) => {
const result = await ctx.runAction(
api.utils.fal.falImageActions.fluxTextToImage,
{
prompt: args.prompt,
model: "dev", // "schnell" | "dev" | "pro"
image_size: "landscape_4_3",
}
);
return result.images[0].url;
},
});Available models:
- FLUX (fast, high-quality)
- GPT Image (OpenAI)
- Imagen4 (Google)
- Gemini 2.5 Flash
- Nano Banana
- Qwen Image
See full docs: convex/utils/fal/README.md
1. Define your function in baml_src/:
class Recipe {
name string
ingredients string[]
instructions string[]
cookTime int
}
function GenerateRecipe(dish: string) -> Recipe {
client GPT5
prompt #"
Create a recipe for {{ dish }}.
{{ ctx.output_format }}
"#
}2. Generate TypeScript client:
npm run baml:generate3. Use in Convex:
import { b } from "../../baml_client";
export const getRecipe = action({
args: { dish: v.string() },
returns: v.any(),
handler: async (ctx, args) => {
const recipe = await b.GenerateRecipe(args.dish);
return recipe; // Fully typed!
},
});See full docs: docs/rules/baml-convex-setup.md
User signs in (Clerk)
β
Clerk webhook β convex/webhooks/clerk/handler.ts
β
Profile created/updated in Convex
β
ProfileProvider syncs client-side state
β
User profile available everywhere
RootLayoutContent (manages layout modes)
β
βββ Static Mode (browse pages)
β βββ Sidebar (always visible) + BottomTabBar (mobile)
β
βββ Overlay Mode (detail pages)
βββ TopHeader + Collapsible Sidebar
Frontend β Convex Action β AI Utils β AI Provider
β
Automatic fallback chain
(GPT-5 β Claude β Gemini)
- Files:
convex/data/profiles.ts,convex/webhooks/clerk/ - Why: Production-ready auth with Clerk sync
- Admin: Set
isAdmin: truein database for admin access
- Files:
src/components/RootLayoutContent.tsx,src/components/layout/ - Why: Handles desktop/mobile perfectly with two modes
- Usage: Set
sidebarModeand page context per route
- Files:
convex/utils/aisdk/,convex/utils/fal/ - Why: Battle-tested AI integration with fallbacks
- Portable: Can use outside Convex (see READMEs)
- Files:
src/components/ThemeProvider.tsx,src/app/globals.css - Why: CSS variable-based theming works everywhere
- Customization: Edit CSS variables in
globals.css
- Usage:
usePageHeader()hook in any page - Features: Dynamic titles, breadcrumbs, actions
- Example:
const { setTitle, setBreadcrumbs, setActions } = usePageHeader();
useEffect(() => {
setTitle("Your Page");
setBreadcrumbs([
{ label: "Home", href: "/" },
{ label: "Your Page" }
]);
setActions(<YourActionButton />);
}, []);- Convex Setup:
docs/rules/convex-rules.mdc - Clerk Setup:
docs/rules/clerk-convex-setup.mdc - BAML Setup:
docs/rules/baml-convex-setup.md - Navigation:
docs/rules/route-navigation-patterns.mdc
- All rules:
docs/rules/(AI agents read these automatically) - Repository guidelines: See root
.cursorrulesorAGENTS.md
- AI SDK:
convex/utils/aisdk/README.md - FAL Images:
convex/utils/fal/README.md
// Example: Blog writer
1. Keep: Auth, navigation, theme
2. Schema: posts, drafts, categories
3. BAML: blog-writer.baml (structured output)
4. AI: modelPreset: "large" for creative content// Example: Logo maker
1. Keep: Auth, navigation, theme
2. Schema: projects, designs, templates
3. FAL: FLUX for fast generation
4. Storage: Convex file storage for results// Example: Customer support
1. Keep: Auth, navigation, theme
2. Schema: conversations, messages
3. AI SDK: Streaming for real-time responses
4. BAML: For structured commands/data extraction// Example: Story + art generator
1. Keep: Everything
2. Schema: stories, characters, scenes
3. AI SDK: Text generation
4. FAL: Image generation
5. BAML: Structured story outlines- Check webhook URL includes
/webhooks/clerk - Verify webhook secret matches:
npx convex env get CLERK_WEBHOOK_SECRET - Check Convex logs:
npx convex logs
- Verify API keys:
npx convex env list - Check model availability (some require specific keys)
- Review logs for specific error messages
- Run
npm run baml:generateafter any BAML changes - Ensure
generators.bamlpoints to correct output directory - Check
baml_client/was generated successfully
- Verify route definitions in
RootLayoutContent.tsx - Check
staticRoutesarray includes your browse pages - Ensure sidebar links match your actual routes
npx convex deploy --prod# Build locally
npm run build
# Or deploy to Vercel
vercel --prod
# Update production environment variables
# Set all API keys in production deploymentPoint webhook to production URL: https://your-prod.convex.site/webhooks/clerk
- Clone template and install dependencies
- Set up Clerk authentication
- Configure Clerk webhook for profile sync
- Set AI provider API keys (OpenRouter, FAL, etc.)
- Update project metadata (name, description, icons)
- Customize navigation links
- Define database schema for your domain
- Replace BAML example files with your functions
- Remove Mocksy-specific code
- Test authentication flow
- Test AI text generation
- Test AI image generation
- Deploy to production
- Start Small: Get auth working, then add one AI feature at a time
- Use Presets: Start with
modelPreset: "medium"for balanced performance - Check Logs:
npx convex logsis your best friend for debugging - Test Webhooks: Use Clerk dashboard to trigger test events
- BAML First: Define types in BAML before writing Convex functions
- Mobile Testing: Navigation system shines on mobile - test it!
- Convex Docs: https://docs.convex.dev
- Clerk Docs: https://clerk.com/docs
- BAML Docs: https://docs.boundaryml.com
- AI SDK: https://sdk.vercel.ai/docs
- FAL Docs: https://fal.ai/docs
- Convex Discord: https://convex.dev/community
- Clerk Discord: https://clerk.com/discord
- GitHub Issues: [Your template repo]
This template gives you a production-ready foundation. Focus on your unique features - the infrastructure is handled.
Happy building! π