You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# Coding Standards
This document defines the coding conventions and best practices for all implementations in the AI Product OS.
All engineering agents must follow these standards when generating code.
---
## Language & Framework Standards
### TypeScript
- **Required**: All new code must be written in TypeScript, not JavaScript
- Use strict mode (`"strict": true` in tsconfig.json)
- Avoid `any` types - use proper type definitions or `unknown` with type guards
- Export types alongside implementations for reusability
### Next.js App Router
- Use App Router (`app/` directory) over Pages Router for all new projects
- Organize by feature: `app/[feature]/page.tsx`, `app/api/[resource]/route.ts`
- Server Components by default, Client Components only when necessary (`"use client"`)
- API Routes must use modern `NextResponse` and `NextRequest` types
---
## Code Organization
### File Structure
```
apps/[project-name]/
� src/
� � app/ # Next.js App Router
� � � api/ # API routes
� � � [feature]/ # Feature-based pages
� � � layout.tsx # Root layout
� � components/ # Reusable UI components
� � lib/ # Utilities, clients, helpers
� public/ # Static assets
� schema.sql # Database schema (if applicable)
� package.json
� README.md
```
### Naming Conventions
- **Files**: `kebab-case.ts`, `PascalCase.tsx` (for components)
- **Components**: `PascalCase` (e.g., `TaskBoard`, `PostHogProvider`)
- **Functions**: `camelCase` (e.g., `fetchTasks`, `markDone`)
- **Constants**: `SCREAMING_SNAKE_CASE` (e.g., `PM_CATEGORIES`, `API_TIMEOUT`)
- **Types/Interfaces**: `PascalCase` (e.g., `Task`, `Category`)
---
## API Design
### Request Validation
- **Always validate inputs**: Check for `null`, `undefined`, empty strings, type mismatches
- **Enforce limits early**: Prevent abuse by validating length, count, size at the entry point
- **Return descriptive errors**: Use 400 for client errors with clear messages
```typescript
// GOOD
if (!taskText || typeof taskText !== 'string' || taskText.trim().length === 0) {
return NextResponse.json({ error: 'Task text is required' }, { status: 400 });
}
if (taskText.length > 500) {
return NextResponse.json({ error: 'Task text too long (max 500 chars)' }, { status: 400 });
}
```
### Database Queries
- **Always use `.limit()`**: Never fetch unbounded lists
- **Index primary queries**: Ensure columns used in WHERE/ORDER BY are indexed
- **Use batch operations**: Prefer `.in()` over N individual queries in loops
```typescript
// GOOD - Limited query
const { data } = await supabase
.from('tasks')
.select('*')
.order('created_at', { ascending: false })
.limit(100);
// BAD - Unbounded query
const { data } = await supabase.from('tasks').select('*');
```
---
## Async & Promises
### Serverless Function Rules
- **Never fire-and-forget**: All async operations in API routes MUST be `await`ed before returning
- **No background promises**: Serverless environments (Vercel, AWS Lambda) suspend execution immediately after HTTP response
```typescript
// GOOD
await sendWhatsAppMessage(userId, message);
return NextResponse.json({ success: true });
// BAD - Message will be dropped in production
sendWhatsAppMessage(userId, message); // Fire-and-forget
return NextResponse.json({ success: true });
```
### Concurrent Processing
- Use `Promise.all()` or `Promise.allSettled()` for independent parallel operations
- Avoid sequential `await` in loops when operations can run concurrently
```typescript
// GOOD - Concurrent execution
const results = await Promise.allSettled(
users.map(user => processUser(user))
);
// BAD - Sequential execution (slow)
for (const user of users) {
await processUser(user);
}
```
---
## Error Handling
### External API Calls
- **Classify errors**: Distinguish between transient (503, rate limit) and permanent (404, 401)
- **Implement fallbacks**: Never lose user data due to third-party failures
- **Log comprehensively**: Use structured logging with context
```typescript
try {
const result = JSON.parse(aiResponse.text);
} catch (e) {
console.error("Failed to parse AI JSON:", aiResponse.text);
// Apply fallback to prevent data loss
result = {
category: 'ops',
priority: 'medium',
title: `[Review Needed] ${input.substring(0, 30)}...`
};
}
```
### AI Response Parsing
- **Sanitize before parsing**: Strip markdown codeblocks from LLM outputs
- **Validate structure**: Ensure required fields exist and match expected types
- **Provide graceful degradation**: Save raw input if AI processing fails
```typescript
// GOOD - Defensive parsing
const cleanText = resultText.replace(/```json\n?/g, '').replace(/```\n?/g, '').trim();
const result = JSON.parse(cleanText);
if (!VALID_CATEGORIES.includes(result.category)) {
console.error("Invalid AI categorization:", result);
isFallback = true;
}
```
---
## Clipboard Operations
**Never use a silent catch block on clipboard copy.** If the user triggers a copy action during a live workflow, silent failure is equivalent to a broken product.
```typescript
// GOOD - Clipboard with fallback + error state
async function copyToClipboard(text: string): Promise {
try {
await navigator.clipboard.writeText(text);
return true;
} catch {
try {
const textarea = document.createElement('textarea');
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
return true;
} catch {
return false;
}
}
}
// In component: show inline error ("Copy failed — please select manually") if copyToClipboard returns false
```
// Added: 2026-03-19 — SMB Feature Bundling Engine
---
## Performance & Limits
### Hard Constraints
- **Input limits**: Max 500 characters for user text inputs
- **Pagination**: Default page size of 100, never exceed 1000
- **API timeouts**: 10s for AI calls, 5s for database queries
- **Cron duration**: Max 4 minutes for serverless cron jobs (stay under platform limits)
### Loop Constraints
- **External API loops**: MUST have both a page limit AND a temporal bound
- **Example**: `max 5 pages` AND `newer_than:30d` for Gmail syncing
- **Failure limits**: Implement retry counters or dead-letter queues to prevent infinite poison-pill loops
---
## Security
### Secrets Management
- **Never commit secrets**: Use `.env.local` for local dev, platform secrets for production
- **Prefix public vars**: `NEXT_PUBLIC_*` for client-safe vars only
- **Encrypt sensitive data**: Use AES-256-GCM for OAuth tokens, API keys in database
### Row Level Security (RLS)
- **Enable on all user tables**: Supabase tables must have RLS policies
- **Default deny**: Start with no access, explicitly grant permissions
- **Use auth.uid()**: Tie policies to authenticated user ID
---
## Testing
### Manual Testing Checklist
- **Happy path**: Standard valid input
- **Edge cases**: Empty strings, zero values, maximum lengths
- **Invalid inputs**: Wrong types, special characters, malformed JSON
- **Network failures**: API timeouts, 500 errors, rate limits
- **Concurrent operations**: Race conditions, optimistic UI updates
### QA Requirements
- Test all **error states** (not just success paths)
- Verify **data persistence** (especially for optimistic UI)
- Check **boundary values** (0, null, max length)
- Validate **media handling** (images, audio, non-text)
### Test Framework Setup
Add to `package.json`:
```json
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage"
}
```
Install:
```bash
npm install -D vitest @vitest/coverage-v8
```
Create `vitest.config.ts`:
```typescript
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'node',
include: ['src/**/__tests__/**/*.test.ts'],
},
});
```
---
## Dependencies
### Package Management
- Use `npm` (not yarn or pnpm) for consistency
- Lock versions in `package.json` for production stability
- Audit dependencies regularly: `npm audit`
### Common Stack
- **Frontend**: React 19+, Next.js 16+, Tailwind CSS 4+
- **Database**: Supabase (PostgreSQL), use `@supabase/supabase-js`
- **AI**: Google Gemini (`@google/genai`), OpenAI, or Anthropic
- **Analytics**: PostHog (`posthog-js` + `posthog-node`)
- **Error Tracking**: Sentry (`@sentry/nextjs`) — mandatory in all apps
- **UI Libraries**: Framer Motion, Lucide Icons, Radix UI
### Shared Utility Templates
Before writing `posthog.ts`, `db.ts`, or error handling from scratch, copy from `/libs/shared/`:
| Template | Copy to | Purpose |
|---|---|---|
| `libs/shared/posthog.ts` | `src/lib/posthog.ts` | PostHog client + server setup, captureServerEvent() |
| `libs/shared/db.ts` | `src/lib/db.ts` | Supabase client/admin, fetchList(), fetchByIds() |
| `libs/shared/error-handler.ts` | `src/lib/error-handler.ts` | API errors, AI parsing, timeout wrapper, auth validation |
These templates encode all lessons from past postmortems. Do not reinvent them.
---
## Comments & Documentation
### When to Comment
- **Complex logic**: Explain non-obvious algorithms or business rules
- **Workarounds**: Document why something is done a specific way
- **TODOs**: Mark incomplete or temporary code with `// TODO: [reason]`
### When NOT to Comment
- **Obvious code**: Don't comment what the code already says
- **Over-documentation**: Code should be self-explanatory through naming
```typescript
// GOOD - Explains WHY
// Strip markdown codeblocks because Gemini sometimes wraps JSON in ```json blocks
const cleanText = resultText.replace(/```json\n?/g, '');
// BAD - Explains WHAT (code already says this)
// Parse the JSON
const result = JSON.parse(cleanText);
```
---
## Error Tracking (Sentry)
Sentry is a mandatory dependency for all apps. It is not optional for MVP.
**Setup**:
```bash
npm install @sentry/nextjs
npx @sentry/wizard@latest -i nextjs
```
**Required files** (wizard creates these, verify they exist):
```
apps/[project]/
sentry.client.config.ts # Browser error capture
sentry.server.config.ts # Server/edge error capture
next.config.ts # Must use withSentryConfig()
```
**Minimum configuration**:
```typescript
// sentry.client.config.ts
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
environment: process.env.NODE_ENV,
});
```
**Required in every try/catch block in API routes**:
```typescript
try {
// ...
} catch (e) {
Sentry.captureException(e);
console.error("[route-name] failed:", e);
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
}
```
**Env vars** (add to `.env.local.example`):
```
NEXT_PUBLIC_SENTRY_DSN=your-dsn-here
SENTRY_AUTH_TOKEN=your-auth-token-here
```
**Rule**: An app deployed without Sentry cannot be debugged in production. Deploy-check will block if Sentry is not configured.
// Added: 2026-03-22 — Sentry integration (error tracking gap)
---
## Git Workflow
### Commit Messages
- Use conventional commits: `feat:`, `fix:`, `docs:`, `chore:`
- Keep first line under 72 characters
- Add body for complex changes explaining WHY
```
feat(clarity): add PUT endpoint for task status persistence
Implements backend persistence for optimistic UI updates to prevent
tasks from reappearing after page reload.
Fixes peer-review finding E1.
```
### Branch Strategy
- `main`: Production-ready code
- Feature branches: `feature/[issue-number]-[short-description]`
- Merge only after passing all quality gates
---
## Lessons Learned (Auto-Generated from Postmortems)
The following rules are extracted from actual production issues:
1. **Unbounded pagination loops MUST have page limits AND date bounds**
2. **AI summarization MUST use full payloads, not snippets**
3. **Cron jobs MUST use fan-out architecture for per-user processing**
4. **Third-party error handling MUST distinguish transient vs permanent failures**
5. **Database schemas MUST be verified in deploy-check before build validation**
6. **Serverless API routes MUST await all async calls before returning response**
7. **Cron jobs MUST use batch fetching and concurrent Promise resolution**
8. **Every GET/list query MUST enforce a hard limit() clause**
9. **No optimistic UI mutation without a backend persistence endpoint**
10. **Telemetry MUST be implemented during feature development, not post-QA**
11. **Unauthenticated endpoints calling paid APIs MUST specify rate limiting in the architecture spec**
12. **SessionIds used across analytics + API + DB MUST be generated before any downstream operations**
13. **AI calls on Vercel MUST use AbortController ≤ 9s and return JSON 504 on timeout**
14. **Clipboard copy MUST have navigator.clipboard → execCommand fallback + inline error state**
15. **All API route branches (success, timeout, error, rate-limit) MUST have PostHog events**
---
## Enforcement
These standards are enforced through:
- **Code Review Agent**: Checks for common violations
- **Peer Review Agent**: Adversarial architecture review
- **QA Agent**: Validates edge cases and error handling
- **Deploy Check Agent**: Verifies production readiness
All agents are expected to reference this file before generating or reviewing code.