# AGENTS.md - Convex Turbo Monorepo ## Quick Reference ### Build/Lint/Test Commands ```bash # Development bun dev # Run all apps (Next.js + Expo + Backend) bun dev:next # Run Next.js + Convex backend only bun dev:expo # Run Expo + Convex backend only bun dev:backend # Run Convex backend only bun dev:expo:tunnel # Expo with tunnel for physical device # Quality bun lint # Lint all packages bun lint:fix # Lint and auto-fix bun format # Check formatting bun format:fix # Fix formatting bun typecheck # TypeScript type checking # Build bun build # Build all packages # Single Package Commands (use Turborepo filters) bun turbo run dev -F @gib/next # Single app dev bun turbo run lint -F @gib/backend # Lint single package bun turbo run typecheck -F @gib/ui # Typecheck single package # Cleanup bun clean # Clean all node_modules (git clean) bun clean:ws # Clean workspace caches ``` ## Project Structure ``` convex-monorepo/ ├── apps/ │ ├── next/ # Next.js 16 web app (@gib/next) │ └── expo/ # Expo 54 mobile app (@gib/expo) ├── packages/ │ ├── backend/ # Convex backend (@gib/backend) │ │ └── convex/ # Convex functions, schema, auth │ └── ui/ # Shared shadcn/ui components (@gib/ui) ├── tools/ │ ├── eslint/ # @gib/eslint-config │ ├── prettier/ # @gib/prettier-config │ ├── tailwind/ # @gib/tailwind-config │ └── typescript/ # @gib/tsconfig ├── docker/ # Self-hosted Convex deployment └── .env # Central environment variables ``` ## Dependency Management ### Catalogs (Single Source of Truth) All shared dependencies are defined in root `package.json` catalogs: ```json "catalog": { "prettier": "^3.6.2", "typescript": "^5.9.3", "eslint": "^9.38.0" }, "catalogs": { "convex": { "convex": "^1.28.0", "@convex-dev/auth": "^0.0.81" }, "react19": { "react": "^19.1.4", "react-dom": "19.1.4" } } ``` ### Using Catalogs in Packages ```json "dependencies": { "convex": "catalog:convex", "react": "catalog:react19", "typescript": "catalog:" }, "devDependencies": { "@gib/eslint-config": "workspace:*", "@gib/ui": "workspace:*" } ``` ### Updating Dependencies **IMPORTANT:** Do NOT use `bun update` directly - it may replace catalog: with versions. ```bash # Correct workflow: 1. Edit version in root package.json catalog section 2. Run: bun install 3. Verify with: bun lint:ws (runs sherif) ``` ## Code Style Guidelines ### Imports (via @gib/prettier-config) ```typescript // Order: Types → React → Next/Expo → Third-party → @gib/* → Local import { useState } from 'react'; import { useRouter } from 'next/navigation'; import { api } from '@/convex/_generated/api'; import { ConvexError } from 'convex/values'; import { cn } from '@gib/ui'; import type { User } from './types'; ``` ### TypeScript - Strict mode enabled (`noUncheckedIndexedAccess: true`) - Use `type` imports: `import type { X } from 'y'` - Prefix unused vars with `_`: `const _unused = ...` - Avoid `any` - use `unknown` with type guards ### Naming Conventions - Components: `PascalCase` (`UserProfile.tsx`) - Functions/variables: `camelCase` - Constants: `SCREAMING_SNAKE_CASE` - Files: `kebab-case.ts` (except components) ### Error Handling ```typescript // Convex functions - use ConvexError import { ConvexError } from 'convex/values'; throw new ConvexError('User not found.'); // Client-side - handle gracefully try { ... } catch (e) { if (e instanceof ConvexError) { /* handle */ } } ``` ### Formatting - Single quotes, trailing commas - 80 char line width, 2 space indent - Tailwind classes sorted via prettier-plugin-tailwindcss - Use `cn()` for conditional classes: `cn('base', condition && 'active')` ## Environment Variables ### Central .env (root) All env vars in `/.env`. Apps load via `with-env` script: ```json "scripts": { "dev": "bun with-env next dev --turbo", "with-env": "dotenv -e ../../.env --" } ``` ### Required Variables ```bash # Convex CONVEX_SELF_HOSTED_URL=https://api.convex.example.com CONVEX_SELF_HOSTED_ADMIN_KEY= CONVEX_SITE_URL=https://convex.example.com NEXT_PUBLIC_CONVEX_URL=https://api.convex.example.com # Auth (sync to Convex deployment) AUTH_AUTHENTIK_ID= AUTH_AUTHENTIK_SECRET= AUTH_AUTHENTIK_ISSUER= USESEND_API_KEY= ``` ### Syncing to Convex Deployment ```bash # Upload env vars to self-hosted Convex npx convex env set AUTH_AUTHENTIK_ID "value" npx convex env set AUTH_AUTHENTIK_SECRET "value" npx convex env set AUTH_AUTHENTIK_ISSUER "value" npx convex env set USESEND_API_KEY "value" npx convex env set CONVEX_SITE_URL "https://convex.example.com" ``` ## Convex Backend Patterns ### Schema (`packages/backend/convex/schema.ts`) ```typescript import { defineSchema, defineTable } from 'convex/server'; import { authTables } from '@convex-dev/auth/server'; export default defineSchema({ ...authTables, users: defineTable({ ... }).index('email', ['email']), }); ``` ### Queries & Mutations ```typescript import { v } from 'convex/values'; import { mutation, query } from './_generated/server'; export const getUser = query({ args: { userId: v.id('users') }, handler: async (ctx, args) => { return await ctx.db.get(args.userId); }, }); ``` ### Auth ```typescript import { getAuthUserId } from '@convex-dev/auth/server'; // In any query/mutation: const userId = await getAuthUserId(ctx); if (!userId) throw new ConvexError('Not authenticated.'); ``` ## Next.js Patterns ### Convex Provider Setup ```tsx // src/components/providers/ConvexClientProvider.tsx 'use client'; import { ConvexAuthNextjsProvider } from '@convex-dev/auth/nextjs'; import { ConvexReactClient } from 'convex/react'; const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!); export const ConvexClientProvider = ({ children }) => ( {children} ); ``` ### Path Aliases - `@/*` → `./src/*` (Next.js) - `~/*` → `./src/*` (Expo) ## Expo Patterns ### NativeWind (Tailwind for RN) ```tsx import '../styles.css'; // Use className like web: ``` ### Secure Storage for Auth ```typescript import * as SecureStore from 'expo-secure-store'; // Tokens stored via SecureStore, not AsyncStorage ``` ## Known Issues / Cleanup Needed 1. **Apps reference @acme/_ instead of @gib/_** - Legacy T3 template imports 2. **TRPC imports exist but no TRPC** - Replace with Convex client 3. **Expo uses better-auth** - Should use @convex-dev/auth 4. **@gib/ui uses pnpm dlx** - Should use bunx for shadcn ## Adding UI Components ```bash bun ui-add # Interactive shadcn/ui component addition ```