---
description: Brief-specific code patterns and conventions
---
# Brief Code Patterns
## API Route Pattern
Every API route must:
- Use Zod for request validation (import from 'zod')
- Check authentication via authenticateApiKey() or auth() from Clerk
- Return standardized error responses (use NextResponse)
- Log errors properly (use lib/logger)
Example:
```typescript
import { z } from 'zod';
import { authenticateApiKey } from '@/lib/api/auth';
import { auth } from '@clerk/nextjs/server';
import { NextResponse } from 'next/server';
const schema = z.object({ /* ... */ });
export async function POST(req: Request) {
// API key auth (reads from headers internally)
const apiAuth = await authenticateApiKey();
if (!apiAuth.ok) {
return NextResponse.json({ error: apiAuth.error }, { status: 401 });
}
// OR session auth
const session = await auth();
if (!session.userId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const body = schema.parse(await req.json());
// ...
}
```
## Brief MCP Integration
- folder_id is REQUIRED for create_document (no default)
- ALWAYS call get_folder_tree first to find valid folder IDs
- Documents use soft delete (go to trash, recoverable)
- ASK before delete_document, delete_folder, bulk_delete
## Database Patterns
- RLS is enforced on all tables via Supabase
- Use `createAdminClient()` from `@/lib/supabase/admin` for server-side queries
- NEVER bypass RLS in application code
- Always filter by `org_id` in queries (RLS handles this automatically)
### Database Migrations (CRITICAL)
**⚠️ NEVER hand-write migration SQL files. ALWAYS use drizzle-kit generate.**
```bash
# 1. Edit schema.ts with your changes
vim lib/db/drizzle/schema.ts
# 2. Generate migration (REQUIRED - never skip this)
DRIZZLE_DATABASE_URL="postgresql://postgres:postgres@127.0.0.1:54322/postgres" pnpm db:drizzle:generate
# 3. For non-schema objects (functions, triggers, extensions):
DRIZZLE_DATABASE_URL="..." pnpm db:drizzle:generate --custom --name=my-functions
# 4. Review the generated SQL, then apply locally
DRIZZLE_DATABASE_URL="..." pnpm db:drizzle:migrate
```
**Migration Types:**
| Type | Use For | Command |
|------|---------|---------|
| Generated | Columns, tables, indexes, constraints | `pnpm db:drizzle:generate` |
| Custom | Functions, triggers, extensions, data migrations | `pnpm db:drizzle:generate --custom --name=description` |
**Why This Matters:**
- Hand-written migrations break Drizzle's state tracking (journal + snapshots)
- Without proper state, `drizzle-kit generate` regenerates the ENTIRE schema
- This causes massive migrations that recreate all 48 tables
**Full documentation:** `docs/architecture/database.md`
## Testing Requirements
- All API routes need tests (use Vitest)
- All custom hooks need tests
- Mock Supabase with test fixtures
- Mock Clerk auth in tests:
```typescript
vi.mock('@clerk/nextjs/server', () => ({
auth: vi.fn(),
}));
const mockAuth = vi.mocked(await import('@clerk/nextjs/server')).auth;
mockAuth.mockResolvedValue({ userId: 'test-user', orgId: 'test-org' });
```
- Test error paths, not just happy path
## Component Reuse & Design System
> **Deep Dive**: For typography, colors, motion, and anti-patterns, see the `brief-design` skill and its `reference/` docs.
### Design System Enforcement
**Before creating any component**:
1. Search for existing components in codebase
2. Check TailStack design system (`@/components/ui/*`)
3. Prefer composition and extension over duplication
4. Run `/design-audit` to check compliance
**TailStack Components** (`@/components/ui/*`):
- Button, Input, Card, Dialog, Select, Textarea, etc.
- ALWAYS use these over custom implementations
- Extend via composition, not duplication
**Good - Compose from design system:**
```typescript
import { Button } from '@/components/ui/button';
export function SubmitButton({ children, ...props }) {
return (
);
}
```
**Bad - Create custom button:**
```typescript
// ❌ DON'T create custom button when Button exists
export function MyButton() {
return ;
}
```
### Tailwind CSS Best Practices
- Use utility classes, not custom CSS files
- Use semantic color tokens (`bg-primary`, `text-muted-foreground`) — see `brief-design` skill
- Use spacing scale (p-4, m-2, gap-3) consistently
- Use semantic typography classes (`.title-1`, `.body`, `.callout`) — see `reference/typography.md`
- Don't create one-off font sizes, colors, or hardcode hex values
### Component Organization
**Note**: Brief has a Chrome extension. Components may be shared via `chat-ui/` package.
- `chat-ui/` - Shared components (web app + Chrome extension)
- `components/` - Web-specific components
- `chrome-extension/` - Extension-specific components
**Before creating a component**:
- Search existing components: `grep -r "ComponentName" .`
- Check if similar functionality exists in `chat-ui/` or `components/`
- Reuse or compose from existing components when possible
## File Organization
- API routes: app/api/v1/[resource]/route.ts
- Hooks: hooks/use-[resource].ts
- Shared components: chat-ui/ (web + extension)
- Web components: components/[feature]/[component].tsx
- Utilities: lib/[utility].ts
- Types: types/[domain].ts
## Documentation
- Update /docs when adding new API endpoints
- Update /docs when changing architecture
- Keep README.md in sync with setup instructions