Backend-Specific Rule Patterns
Backend projects have unique concerns that frontend rules don't cover: API design, error handling, database patterns, security, and logging. Good backend CLAUDE.md files encode your team's decisions on each of these.
Node.js / TypeScript Backend Rules
CLAUDE.md
## Node.js API Server (Fastify + TypeScript)
### Project Structure
- src/routes/ — Route handlers, one file per resource
- src/services/ — Business logic (no DB calls here)
- src/repositories/ — Database access layer
- src/types/ — Shared TypeScript types
### API Design
- RESTful conventions: GET (read), POST (create), PUT (replace), PATCH (update), DELETE
- Always return { data } or { error } at the top level
- Use HTTP 422 for validation errors, 401 for auth errors, 403 for permission errors
- Version prefix: /api/v1/
### Database (Prisma)
- Never call db in route handlers — go through a repository
- Use transactions for multi-step operations
- Never use `db.X.findMany()` without a `take` limit
- Soft-delete pattern: set `deletedAt` field, filter in queries
### Security
- Validate all inputs with Zod before using them
- Never interpolate user input into SQL strings
- Rate limit all public endpoints
- Never log request bodies (may contain PII)
### Error Handling
```ts
// Always wrap route handlers
export const getUser = async (req: FastifyRequest, reply: FastifyReply) => {
try {
const user = await userRepository.findById(req.params.id)
if (!user) return reply.status(404).send({ error: 'User not found' })
return reply.send({ data: user })
} catch (error) {
req.log.error(error, 'getUser failed')
return reply.status(500).send({ error: 'Internal server error' })
}
}
```Python / FastAPI Rules
CLAUDE.md
## Python API (FastAPI + SQLAlchemy)
### Style
- Type annotations on all function signatures (Python 3.11+)
- Use Pydantic v2 for request/response models
- Prefer dataclasses over plain dicts for internal data transfer
### Project Layout
- app/routers/ — FastAPI route files
- app/services/ — Business logic
- app/models/ — SQLAlchemy ORM models
- app/schemas/ — Pydantic schemas for API contracts
- app/crud/ — Database CRUD operations
### Database Patterns
```python
# Always use dependency injection for DB sessions
def get_user(user_id: int, db: Session = Depends(get_db)) -> User:
user = crud.user.get(db, id=user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
```
### Error Handling
- Raise HTTPException with specific status codes — never generic 500
- Log with structlog (not print or stdlib logging)
- Use background tasks (BackgroundTasks) for fire-and-forget operations
### Don'ts
- Don't use mutable default arguments
- Don't do sync I/O in async routes
- Don't put business logic in modelsGo Backend Rules
CLAUDE.md
## Go API Server (net/http + pgx)
### Code Style
- Error handling: always check errors explicitly, never ignore with _
- Use named return values only when they improve clarity
- Package names: lowercase, single word, no underscores
- Exported types/funcs: PascalCase; internal: camelCase
### Error Pattern
```go
// Always wrap errors with context
if err != nil {
return fmt.Errorf("getUserByID %d: %w", id, err)
}
```
### HTTP Handlers
```go
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
respondError(w, http.StatusBadRequest, "invalid user ID")
return
}
user, err := h.svc.GetUser(r.Context(), id)
if errors.Is(err, ErrNotFound) {
respondError(w, http.StatusNotFound, "user not found")
return
}
if err != nil {
h.log.Error("GetUser failed", "error", err)
respondError(w, http.StatusInternalServerError, "internal error")
return
}
respondJSON(w, http.StatusOK, user)
}
```
### Constraints
- NEVER use global variables for state (use struct fields)
- NEVER use init() functions
- ALWAYS pass context.Context as the first argument to DB callsCross-Language Backend Rules
Regardless of language, these rules apply to all our backend services:
CLAUDE.md
## Universal Backend Rules ### Logging - Structured logs only (JSON format in production) - Log at entry and error points — not throughout business logic - Never log: passwords, tokens, full credit card numbers, PII ### API Contracts - All APIs must have OpenAPI/Swagger documentation - Use semantic versioning for API versions - Deprecate endpoints for 6 months before removing ### Testing - Unit test all business logic in services/ - Integration test all API endpoints - Use table-driven tests for validation logic