## Backend API Development Guide

When the task involves backend development (Python/FastAPI, Node.js/Express, Go), follow these patterns.

### API Architecture

| Layer                 | Responsibility                     | Example                                  |
| --------------------- | ---------------------------------- | ---------------------------------------- |
| **Router/Controller** | HTTP handling, request/response    | `routes/users.py`, `controllers/user.ts` |
| **Service**           | Business logic, orchestration      | `services/user_service.py`               |
| **Repository**        | Data access, database queries      | `repositories/user_repo.py`              |
| **Model/Schema**      | Data shapes, validation            | `models/user.py`, `schemas/user.ts`      |
| **Middleware**        | Cross-cutting: auth, logging, CORS | `middleware/auth.py`                     |

### Python/FastAPI Pattern

```python
# schemas/user.py  -  Pydantic models
class UserCreate(BaseModel):
    email: EmailStr
    name: str = Field(min_length=1, max_length=100)

class UserResponse(BaseModel):
    id: int
    email: str
    name: str
    model_config = ConfigDict(from_attributes=True)

# services/user_service.py  -  business logic
class UserService:
    def __init__(self, repo: UserRepository):
        self.repo = repo

    async def create_user(self, data: UserCreate) -> User:
        existing = await self.repo.get_by_email(data.email)
        if existing:
            raise HTTPException(status_code=409, detail="Email already exists")
        return await self.repo.create(data)

# routes/users.py  -  HTTP layer
router = APIRouter(prefix="/users", tags=["users"])

@router.post("/", response_model=UserResponse, status_code=201)
async def create_user(data: UserCreate, service: UserService = Depends()):
    return await service.create_user(data)
```

### Node.js/Express Pattern

```typescript
// schemas/user.schema.ts  -  Zod validation
const createUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1).max(100),
});

// services/user.service.ts  -  business logic
export class UserService {
  constructor(private repo: UserRepository) {}

  async createUser(data: CreateUserInput): Promise<User> {
    const existing = await this.repo.findByEmail(data.email);
    if (existing) throw new ConflictError("Email already exists");
    return this.repo.create(data);
  }
}

// routes/users.ts  -  HTTP layer
router.post("/", validate(createUserSchema), async (req, res) => {
  const user = await userService.createUser(req.body);
  res.status(201).json(user);
});
```

### Error Handling

```python
# Structured error responses
class AppError(Exception):
    def __init__(self, status_code: int, detail: str, code: str):
        self.status_code = status_code
        self.detail = detail
        self.code = code

# Global error handler
@app.exception_handler(AppError)
async def app_error_handler(request, exc):
    return JSONResponse(
        status_code=exc.status_code,
        content={"error": exc.code, "detail": exc.detail}
    )
```

### Security Checklist

1. Input validation on ALL endpoints (Pydantic/Zod)
2. Authentication middleware (JWT/OAuth)
3. Authorization checks per endpoint (role-based)
4. Rate limiting on public endpoints
5. CORS properly configured (not `*` in production)
6. SQL injection prevention (parameterized queries / ORM)
7. No secrets in code  -  environment variables
8. HTTPS only
9. Request/response logging (without sensitive data)
10. Error messages don't leak internals

### Testing

```python
# Unit test  -  service layer
async def test_create_user_duplicate_email():
    repo = FakeUserRepository(existing_emails=["test@example.com"])
    service = UserService(repo)
    with pytest.raises(HTTPException, match="409"):
        await service.create_user(UserCreate(email="test@example.com", name="Test"))

# Integration test  -  full endpoint
async def test_create_user_endpoint(client: AsyncClient):
    response = await client.post("/users/", json={"email": "new@example.com", "name": "New"})
    assert response.status_code == 201
    assert response.json()["email"] == "new@example.com"
```

### Quality Checklist

1. All endpoints have input validation
2. Service layer separated from HTTP layer
3. Error responses are structured and consistent
4. Tests cover happy path + error paths + edge cases
5. No N+1 queries (check ORM usage)
6. Pagination on list endpoints
7. Health check endpoint exists
8. Environment-based configuration (no hardcoded values)
9. Logging with correlation IDs
10. API documentation (OpenAPI/Swagger auto-generated)
