This file provides universal development guidelines and rules for all WARP (warp.dev) projects.
# Install dependencies
npm install
# Development server
npm run dev
# Development server in background (for continued conversation - USE THIS)
npm run dev:background
# Full clean (removes node_modules and reinstalls)
npm run dev:full-clean
# Quick cleanup of hanging processes
npm run cleanup
# Production build
npm run build
# Start production server
npm start
# Type checking
npm run lint# ALWAYS use single quotes for commit messages (prevents shell issues)
git commit -m 'Add new feature'
git commit -m 'Fix authentication bug'
git commit -m 'Update API validation'
# FORBIDDEN - double quotes cause issues with special characters
git commit -m "Add new feature" # Don't do this# Run all tests
npm test
# Run specific test file
npm test -- --testNamePattern="test-name"
# Run with coverage
npm test -- --coverage
# Run specific test in watch mode
npm test -- --watch test-name📋 MANDATORY: All APIs must be comprehensively tested
- Rule: NO API endpoint goes to production without being added to comprehensive test suite
- Authentication: Use official testing packages for legitimate auth bypass
- Coverage: Test all endpoints with proper authentication flow
Standard Test Structure:
// Add new API tests like this:
test('Your New API Endpoint', async ({ request, context }) => {
// Setup authentication context
const authHeaders = await getAuthHeaders(context);
const response = await request.get('/api/your-endpoint', {
headers: authHeaders
});
expect(response.ok()).toBeTruthy();
const data = await response.json();
// Add your specific assertions
expect(data).toHaveProperty('expectedField');
console.log('✅ Your API:', data);
});Why This Matters:
- Production Ready: All endpoints tested with real authentication
- CI/CD Integration: Catches API breaks before deployment
- Security Validation: Ensures proper authentication on all endpoints
- Documentation: Test file serves as live API documentation
# Check all file lengths against constraints
find src -name "*.ts" -o -name "*.tsx" | xargs wc -l | sort -n
# Monitor specific file types
find src -name "*.tsx" -exec wc -l {} + | awk '$1 > 100 {print "⚠️ " $2 " exceeds 100 lines (" $1 ")"}'✅ REQUIRED:
- Use validation library (Zod, Joi, etc.) for ALL API request/response validation
- Create focused, single-purpose schemas
- Use proper schema composition (extend, pick, omit)
- Validate at route entry point
❌ FORBIDDEN:
anytypes anywhere in API code- Complex nested validation hierarchies
- Bypassing validation with raw JSON parsing
- Schema overengineering (keep simple)
Example - CORRECT:
// Simple, focused schemas
const CreateItemSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1).max(255),
value: z.number().positive()
})
const PaginationSchema = z.object({
page: z.coerce.number().int().min(1).default(1),
limit: z.coerce.number().int().min(1).max(100).default(20)
})✅ SUCCESS Response Format:
// Standard success response (adapt to your framework)
return createSuccessResponse({
data: actualData,
pagination?: { page, limit, total },
meta?: additionalInfo
})
// Or framework-specific:
// Express: res.json({ data: actualData })
// Next.js: NextResponse.json({ data: actualData })
// Fastify: reply.send({ data: actualData })✅ ERROR Response Format:
// Standard error response (adapt to your framework)
return createErrorResponse(
{ error: 'Descriptive message', code: 'ERROR_CODE' },
400
)
// Or framework-specific:
// Express: res.status(400).json({ error: 'Message', code: 'CODE' })
// Next.js: NextResponse.json({ error: 'Message' }, { status: 400 })
// Fastify: reply.status(400).send({ error: 'Message' })❌ FORBIDDEN Response Patterns:
// DON'T mix formats
{ success: true, data: {} } // Inconsistent
{ result: data } // Non-standard
data // Raw data without wrapperDatabase Fields (snake_case):
user_id,created_at,item_name- Table names:
user_sessions,audit_logs
API Requests/Responses (camelCase):
userId,createdAt,itemName- Query params:
pageSize,sortOrder
TypeScript Interfaces (PascalCase):
UserMetadata,SessionStatus,ItemRequest
Example - Database to API Transformation:
// Database query returns snake_case
const dbResult = await db.query(
'SELECT user_id, created_at, item_name FROM items'
)
// Transform to camelCase for API response
const apiResponse = dbResult.rows.map(row => ({
userId: row.user_id,
createdAt: row.created_at,
itemName: row.item_name
}))✅ REQUIRED:
- Define interfaces for all request/response types
- Use strict typing for database queries
- Proper typing for API route handlers
- Type transformations between database and API layers
❌ FORBIDDEN:
anytypes (core WARP rule)unknownwithout type guards- Casting without validation (
as SomeType) - Missing return types on functions
Example - Proper Typing:
interface DatabaseRow {
user_id: string;
created_at: string;
item_name: string;
}
interface ApiResponse {
userId: string;
createdAt: string;
itemName: string;
}
function transformDbToApi(row: DatabaseRow): ApiResponse {
return {
userId: row.user_id,
createdAt: row.created_at,
itemName: row.item_name
}
}✅ REQUIRED Pattern (adapt to your framework):
// Next.js example
export async function GET(request: NextRequest) {
return handleAuthenticatedRoute(
request,
async ({ user, query }) => {
// 1. Business logic via service layer
const data = await SomeService.getData(user.id, query)
// 2. Return standard response
return createSuccessResponse(data)
},
{
querySchema: SomeQuerySchema // Always validate
}
)
}
// Express example
app.get('/api/items', authenticate, validate(querySchema), async (req, res) => {
const data = await SomeService.getData(req.user.id, req.query)
res.json({ data })
})
// Fastify example
fastify.get('/api/items', {
preHandler: [authenticate, validate(querySchema)]
}, async (request, reply) => {
const data = await SomeService.getData(request.user.id, request.query)
reply.send({ data })
})❌ FORBIDDEN Patterns:
- Direct database calls in route handlers
- Missing authentication checks
- Inconsistent error handling
- Raw response without standards
- Skipping validation schemas
✅ Standard Pattern:
try {
const validatedData = SomeSchema.parse(rawData)
// Use validatedData (properly typed)
} catch (error) {
if (error instanceof z.ZodError) {
return createErrorResponse(
{ error: 'Validation failed', details: error.errors },
400
)
}
throw error
}- If asked to "fix navigation bug" → fix ONLY the navigation bug
- If asked to "move element left" → move ONLY the element, don't change colors/styling
- NEVER add "improvements" that weren't requested
- NEVER create elaborate systems when simple fixes work
- Button text changes require permission
- Layout modifications require permission
- Color/styling changes require permission
- Only fix the specific broken functionality
- Don't create complex schema systems unless explicitly requested
- Use simple validation, not elaborate hierarchies
- Prefer native TypeScript types over complex schemas
- Don't build "reusable validation frameworks" without permission
- Fix the exact bug reported
- Don't "refactor while you're there"
- Don't "make it more maintainable" unless asked
- Don't "future-proof" unless explicitly requested
- If it works, don't "improve" it
- Don't change styling/layout of working components
- Don't add complexity to solve non-existent problems
- Keep changes surgical and specific
Examples of BAD behavior:
- User: "Fix 404 error" → AI: Creates entire schema system and changes button layout
- User: "Move element position" → AI: Changes colors, adds padding, "improves" styling
- User: "Add endpoint" → AI: Builds validation framework, request/response schemas, complex types
Examples of GOOD behavior:
- User: "Fix 404 error" → AI: Changes only the broken navigation line
- User: "Move element position" → AI: Moves only the element position in code
- User: "Add endpoint" → AI: Adds simple endpoint with basic validation
- React Components: 100 lines max
- API Routes: 150 lines max
- Service Files: 200 lines max
- Test Files: 300 lines max
- Type Definitions: 50 lines max
- Utility Functions: 50 lines max
No exceptions - split files if they exceed limits.
- Custom authentication systems (use established libraries)
- Complex state management unless absolutely necessary
- CSS-in-JS libraries (prefer utility-first CSS)
- Component libraries (build simple, focused components)
- Path alias imports in API routes (use relative imports for API routes)
- ALWAYS use Context7 first before troubleshooting API/SDK issues
- Check official documentation via
resolve-library-id→get-library-docs - Assume request-time APIs are async in modern frameworks
- Verify framework version/router before applying solutions
- Use standard database clients when possible (avoid vendor lock-in)
- Any API route development or modification
- Schema validation implementation
- Authentication handling
- Database operations
- Third-party service integration
- Error handling or response formatting
- Framework setup or troubleshooting
- Middleware configuration
- Environment variable configuration
- Third-party SDK integration
- Type definitions for external APIs
- 404 errors in API routes
- Authentication failures
- Database connection issues
- Import/export resolution problems
- Type errors with external libraries
- Permission errors
- Version-specific API changes
Implementation Pattern:
When working on [API/integration/troubleshooting task], automatically:
1. Identify core libraries involved
2. Use: "[task description] use context7" or "use library /specific/library-id"
3. Apply Context7 recommendations within project constraints
4. Cross-reference with WARP.md standards before implementation
- RED: Write failing tests first
- GREEN: Implement minimal code to pass
- REFACTOR: Clean up while maintaining test coverage
- Never work directly on main branch
- Parameterized queries only (no SQL injection risk)
- UUID primary keys when possible
- No secrets in code or database
- Input validation at all boundaries
- Proper error handling without information leakage
- Security functions: 100% coverage (no exceptions)
- Business logic: 95% coverage
- API endpoints: 90% coverage
- React components: 80% coverage
- Use Arrange, Act, Assert pattern
- One assertion per test
- Descriptive test names
- Mock external dependencies
- Test files in standard test directory
- Always use
async/await(never callbacks or.then()) - Destructure function parameters
- Arrow functions for simple operations
- Named functions for complex logic
- TypeScript strict mode enabled (no
anytypes) - Alphabetical import ordering
- One export per file
# Find process using port
lsof -ti:PORT_NUMBER
# Kill the process
kill -9 $(lsof -ti:PORT_NUMBER)// Framework-agnostic CORS middleware pattern
// Express.js example:
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
if (req.method === 'OPTIONS') {
res.sendStatus(200)
} else {
next()
}
})
// Fastify example:
await fastify.register(require('@fastify/cors'), {
origin: true
})
// Next.js (middleware.ts):
export function middleware(request: NextRequest) {
const response = NextResponse.next()
response.headers.set('Access-Control-Allow-Origin', '*')
response.headers.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization')
return response
}# Create .env file with required variables
echo "API_KEY=your-secure-key-here" > .env
echo "NODE_ENV=development" >> .env# Generic Dockerfile pattern
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
# Environment variables set at runtime
ENV NODE_ENV=production
ENV PORT=3000
EXPOSE 3000
CMD ["npm", "start"]// File: lib/validation.js
const requestSchema = {
type: 'object',
required: ['action', 'data'],
properties: {
action: {
enum: ['create', 'update', 'delete', 'read']
},
data: {
type: 'object'
},
requestId: { type: 'string' },
options: {
type: 'object',
properties: {
timeout: { type: 'number' },
reason: { type: 'string' }
}
}
},
additionalProperties: false
}
export function validateRequest(data) {
// Basic validation implementation
if (!data.action || !data.data) {
return { valid: false, error: 'Missing required fields: action, data' }
}
const validActions = ['create', 'update', 'delete', 'read']
if (!validActions.includes(data.action)) {
return { valid: false, error: `Invalid action. Must be one of: ${validActions.join(', ')}` }
}
return { valid: true }
}// File: lib/logger-bridge.js
import logger from 'your-logger-library'
export function createLogger(category) {
return {
info: (message, ...args) => logger.info(`[${category}] ${message}`, ...args),
error: (message, ...args) => logger.error(`[${category}] ${message}`, ...args),
debug: (message, ...args) => logger.debug(`[${category}] ${message}`, ...args)
}
}- Don't overthink architecture - Start with your actual needs
- Don't optimize prematurely - Get basic functionality first
- Don't build complex systems - Simple solutions work best
- Don't create elaborate schemas - Follow the examples exactly
- Don't add features not requested - Stick to requirements
- Remember security basics - Validate all inputs
- Test error cases - Verify validation and authentication work
- Check integration points - Ensure services communicate correctly
Implementation Philosophy: Focus on mechanical implementation over clever engineering
Enhancement Philosophy: Add complexity only when justified by real usage
Goal: Reliable, maintainable applications that solve actual problems
This guide should require zero design decisions - just mechanical implementation of proven patterns.