# IGNY8 API STANDARD v1.0

**Version:** 1.0  
**Date:** 2025-01-XX  
**Status:** Active Standard  
**Purpose:** Single source of truth for IGNY8 API contract, implementation, and integration

**Applies To:**
- Django backend
- React frontend
- WordPress plugin
- 3rd-party API consumers
- Internal automations / CRON / AI functions

---

## Table of Contents

1. [Overview](#overview)
2. [API Versioning & Base URLs](#api-versioning--base-urls)
3. [Authentication & Authorization](#authentication--authorization)
4. [Response Format Standard](#response-format-standard)
5. [Error Handling Standard](#error-handling-standard)
6. [Rate Limits & Governance](#rate-limits--governance)
7. [Pagination & Query Rules](#pagination--query-rules)
8. [Standard Request & Response Shapes](#standard-request--response-shapes)
9. [Roles & Permissions Matrix](#roles--permissions-matrix)
10. [Tenant / Site / Sector Scoping](#tenant--site--sector-scoping)
11. [Module-wise Endpoint Rules](#module-wise-endpoint-rules)
12. [Logging, Request ID, and Debugging](#logging-request-id-and-debugging)
13. [Frontend and Plugin Integration Requirements](#frontend-and-plugin-integration-requirements)
14. [Migration Plan for Existing Code](#migration-plan-for-existing-code)
15. [Testing Strategy](#testing-strategy)
16. [Change Management](#change-management)

---

## Overview

The IGNY8 API Standard v1.0 establishes a unified, consistent interface for all API endpoints across the platform. This standard ensures:

- **Predictability**: All endpoints follow the same patterns
- **Security**: Consistent authentication and authorization
- **Maintainability**: Standardized error handling and logging
- **Scalability**: Rate limiting and governance controls
- **Developer Experience**: Clear documentation and integration patterns

### Key Principles

1. **Unified Response Format**: All endpoints return consistent JSON structure
2. **Layered Authorization**: Authentication → Tenant Access → Role → Site/Sector
3. **Centralized Error Handling**: All errors wrapped in unified format
4. **Scoped Rate Limiting**: Different limits for different operation types
5. **Tenant Isolation**: All resources scoped by account/site/sector
6. **Request Tracking**: Every request has a unique ID for debugging

---

## API Versioning & Base URLs

### Base URL Structure

```
Production: https://api.igny8.com/api/v1/
Development: http://localhost:8000/api/v1/
```

### Module Namespaces

All endpoints are organized under these namespaces:

```
/api/v1/
├── auth/          # Authentication and user management
├── planner/       # Keywords, clusters, content ideas
├── writer/        # Tasks, content, images
├── system/        # Settings, prompts, integrations
└── billing/       # Credits, transactions, usage
```

### Versioning Rules

- **v1** remains stable long-term
- Breaking changes require **v2**
- Deprecations allowed only with explicit timeline
- All endpoints must follow predictable REST patterns

### Endpoint Naming Conventions

- Use plural nouns: `/api/v1/planner/keywords/`
- Use snake_case for query parameters: `?site_id=1&sector_id=2`
- Use kebab-case for custom actions: `/api/v1/planner/keywords/auto-cluster/`

---

## Authentication & Authorization

### Authentication Methods

#### Primary: JWT Bearer Token

```
Authorization: Bearer <access_token>
```

**Token Characteristics:**
- Contains `user_id` and `account_id`
- Type: `access` (15-minute expiry)
- Automatically sets `request.account` via middleware
- Resolves account → tenant context automatically

**Token Payload:**
```json
{
  "user_id": 1,
  "account_id": 1,
  "type": "access",
  "exp": 1234567890
}
```

#### Fallback Methods

1. **Session Authentication** (admin panel)
   - Class: `CSRFExemptSessionAuthentication`
   - Use case: Django admin panel (`/admin/`)

2. **Basic Authentication** (debug/testing)
   - Class: `rest_framework.authentication.BasicAuthentication`
   - Use case: API testing tools (Postman, curl)

### Authentication Order

1. JWT Token Authentication (tried first)
2. Session Authentication (fallback)
3. Basic Authentication (last fallback)
4. If all fail: 401 Unauthorized

### Public Endpoints (No Authentication Required)

- `POST /api/v1/auth/register/`
- `POST /api/v1/auth/login/`
- `GET /api/v1/auth/plans/`
- `GET /api/v1/auth/industries/`
- `GET /api/v1/system/status/`
- `GET /api/ping/` (health check)

**All other endpoints require JWT authentication.**

### Authorization Layers

Every endpoint enforces layered authorization:

1. **User Authentication**: User must be authenticated
2. **Tenant Access**: User must belong to the tenant/account
3. **Role Authorization**: User must have appropriate role
4. **Site/Sector Access**: User must have access to requested site/sector

---

## Response Format Standard

### Mandatory Format

**This is the global standard for all endpoints - no exceptions.**

### Success Response

```json
{
  "success": true,
  "data": {
    // Response data (object or array)
  },
  "message": "Optional human-readable success message"
}
```

**Example:**
```json
{
  "success": true,
  "data": {
    "id": 1,
    "name": "Example Keyword",
    "status": "active"
  },
  "message": "Keyword created successfully"
}
```

### Error Response

```json
{
  "success": false,
  "error": "Readable top-level error message",
  "errors": {
    "field_name": ["Field-specific error messages"]
  },
  "request_id": "uuid-for-error-tracking"
}
```

**Example:**
```json
{
  "success": false,
  "error": "Validation failed",
  "errors": {
    "email": ["Invalid email format"],
    "password": ["Password must be at least 8 characters"]
  },
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

### Paginated Response

```json
{
  "success": true,
  "count": 120,
  "next": "http://api.igny8.com/api/v1/endpoint/?page=2",
  "previous": null,
  "results": [
    // Array of results
  ],
  "message": "Optional message"
}
```

### Response Helper Functions

**File:** `backend/igny8_core/api/response.py`

```python
from igny8_core.api.response import success_response, error_response, paginated_response

# Success response
return success_response(
    data={"id": 1, "name": "Example"},
    message="Resource created successfully",
    status_code=status.HTTP_201_CREATED
)

# Error response
return error_response(
    error="Validation failed",
    errors={"email": ["Invalid email format"]},
    status_code=status.HTTP_400_BAD_REQUEST
)

# Paginated response
paginator = CustomPageNumberPagination()
page = paginator.paginate_queryset(queryset, request)
serializer = MySerializer(page, many=True)
paginated_data = paginator.get_paginated_response(serializer.data).data
return paginated_response(paginated_data, message="Resources retrieved successfully")
```

---

## Error Handling Standard

### Centralized Exception Handler

**File:** `backend/igny8_core/api/exception_handlers.py`

All exceptions are handled by a centralized exception handler that:

- Wraps all errors in unified format
- Uses proper HTTP status codes (400, 401, 403, 404, 409, 422, 500)
- Includes sanitized validation errors under `errors`
- Always attaches `request_id` for error tracking
- Logs full exception details
- In DEBUG mode: includes traceback + request context

### Status Code Mapping

| Status Code | Meaning | Response Format |
|------------|---------|----------------|
| 200 | OK | `{ success: true, data: {...} }` |
| 201 | Created | `{ success: true, data: {...} }` |
| 400 | Bad Request | `{ success: false, error: "...", errors: {...} }` |
| 401 | Unauthorized | `{ success: false, error: "Authentication required" }` |
| 403 | Forbidden | `{ success: false, error: "Permission denied" }` |
| 404 | Not Found | `{ success: false, error: "Resource not found" }` |
| 409 | Conflict | `{ success: false, error: "Conflict" }` |
| 422 | Unprocessable Entity | `{ success: false, error: "...", errors: {...} }` |
| 429 | Too Many Requests | `{ success: false, error: "Rate limit exceeded" }` |
| 500 | Internal Server Error | `{ success: false, error: "Internal server error" }` |

### Error Response Structure

**Production Mode:**
```json
{
  "success": false,
  "error": "Internal server error",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

**Development Mode (DEBUG=True):**
```json
{
  "success": false,
  "error": "Internal server error",
  "request_id": "550e8400-e29b-41d4-a716-446655440000",
  "debug": {
    "exception_type": "ValueError",
    "exception_message": "Invalid value",
    "view": "KeywordViewSet",
    "path": "/api/v1/planner/keywords/",
    "method": "POST",
    "traceback": "Traceback (most recent call last):\n  ..."
  }
}
```

### Server-side Logging

- All 4xx errors logged as **warning**
- All 5xx errors logged as **error**
- Structured format with:
  - timestamp
  - request_id
  - endpoint
  - user_id
  - account_id
  - status_code
  - error_message
  - traceback (for 5xx)
- Rotating log files
- Sentry integration hooks for production

---

## Rate Limits & Governance

### Rate Limiting Configuration

**File:** `backend/igny8_core/settings.py`

```python
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'igny8_core.api.throttles.DebugScopedRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        # AI Functions - Expensive operations
        'ai_function': '10/min',           # AI content generation, clustering
        'image_gen': '15/min',            # Image generation
        
        # Content Operations
        'content_write': '30/min',        # Content creation, updates
        'content_read': '100/min',         # Content listing, retrieval
        
        # Authentication
        'auth': '20/min',                  # Login, register, password reset
        'auth_strict': '5/min',            # Sensitive auth operations
        
        # Planner Operations
        'planner': '60/min',               # Keyword, cluster, idea operations
        'planner_ai': '10/min',            # AI-powered planner operations
        
        # Writer Operations
        'writer': '60/min',                # Task, content management
        'writer_ai': '10/min',             # AI-powered writer operations
        
        # System Operations
        'system': '100/min',               # Settings, prompts, profiles
        'system_admin': '30/min',          # Admin-only system operations
        
        # Billing Operations
        'billing': '30/min',               # Credit queries, usage logs
        'billing_admin': '10/min',         # Credit management (admin)
        
        # Default fallback
        'default': '100/min',              # Default for endpoints without scope
    },
}
```

### Throttle Headers

All responses include rate limit information:

```
X-Throttle-Limit: 10
X-Throttle-Remaining: 9
X-Throttle-Reset: 1640995200
```

When throttled (429):
```
HTTP/1.1 429 Too Many Requests
X-Throttle-Limit: 10
X-Throttle-Remaining: 0
Retry-After: 60
```

### Soft Limits (Business Logic)

- **50 tasks** per bulk action
- **20 keywords** per cluster batch
- **1 cluster** → ideas generation
- **1 content** → image prompt extraction
- **1 image** generation per job

### Safety Checks

- Validate all IDs belong to tenant
- Validate dependent records exist
- Reject oversized payloads
- Reject invalid site/sector assignments
- Reject stale/wrong tenant tokens

### Debug Mode Bypass

Set `IGNY8_DEBUG_THROTTLE=True` or `DEBUG=True` to bypass throttling in development.

---

## Pagination & Query Rules

### Pagination Configuration

**Default Settings:**
- Default page size: **10**
- Maximum page size: **100**
- Query parameter: `page_size` (optional)
- Page parameter: `page` (default: 1)

### Query Parameters

**Pagination:**
```
?page=2&page_size=25
```

**Filtering:**
```
?status=active
?site_id=1
?sector_id=2
?cluster_id=5
```

**Search:**
```
?search=keyword
```

**Ordering:**
```
?ordering=-created_at
?ordering=name,status
```

### Pagination Response Format

```json
{
  "success": true,
  "count": 150,
  "next": "http://api.igny8.com/api/v1/planner/keywords/?page=3&page_size=25",
  "previous": "http://api.igny8.com/api/v1/planner/keywords/?page=1&page_size=25",
  "results": [
    // Array of results
  ],
  "message": "Keywords retrieved successfully"
}
```

---

## Standard Request & Response Shapes

### Request Payload Rules

All endpoints must follow:

- **snake_case** field names
- Predictable field groups
- Standardized pagination params
- Standardized filters
- Standardized bulk update patterns
- Standardized action payloads
- Standardized error messages

### Bulk Actions

**Standard Format:**
```json
{
  "ids": [1, 2, 3],
  // Additional fields as needed
}
```

**Example:**
```json
{
  "ids": [1, 2, 3],
  "status": "active"
}
```

### Filtering Patterns

**Standard Query Parameters:**
- `?search=` - Text search
- `?status=` - Status filter
- `?site_id=` - Site filter
- `?sector_id=` - Sector filter
- `?cluster_id=` - Cluster filter
- `?content_type=` - Content type filter

### Request Examples

**Create Resource:**
```json
POST /api/v1/planner/keywords/
{
  "keyword": "example keyword",
  "site_id": 1,
  "sector_id": 2,
  "status": "active"
}
```

**Bulk Update:**
```json
POST /api/v1/planner/keywords/bulk_update_status/
{
  "ids": [1, 2, 3],
  "status": "active"
}
```

**Custom Action:**
```json
POST /api/v1/planner/keywords/auto_cluster/
{
  "ids": [1, 2, 3, 4, 5],
  "sector_id": 2
}
```

---

## Roles & Permissions Matrix

### Role Hierarchy

```
owner > admin > editor > viewer > system_bot
```

### Standard Permission Classes

**File:** `backend/igny8_core/api/permissions.py`

| Permission Class | Description | Use Case |
|-----------------|------------|----------|
| `IsAuthenticatedAndActive` | User authenticated and active | Base permission for most endpoints |
| `HasTenantAccess` | User belongs to tenant/account | Tenant isolation |
| `IsViewerOrAbove` | Viewer, editor, admin, or owner | Read-only operations |
| `IsEditorOrAbove` | Editor, admin, or owner | Content operations |
| `IsAdminOrOwner` | Admin or owner only | Settings, keys, billing |

### Permission Matrix by Endpoint Type

| Endpoint Type | Required Permissions | Roles Allowed |
|--------------|---------------------|---------------|
| Public (register, login) | `AllowAny` | Anyone |
| Read-only (list, retrieve) | `IsAuthenticatedAndActive` + `HasTenantAccess` | All authenticated users |
| Content operations | `IsAuthenticatedAndActive` + `HasTenantAccess` + `IsEditorOrAbove` | Editor, Admin, Owner |
| User management | `IsAuthenticatedAndActive` + `HasTenantAccess` + `IsAdminOrOwner` | Admin, Owner |
| Billing/Transactions | `IsAuthenticatedAndActive` + `HasTenantAccess` + `IsAdminOrOwner` | Admin, Owner |
| Integration settings | `IsAuthenticatedAndActive` + `HasTenantAccess` + `IsAdminOrOwner` | Admin, Owner |

### Base ViewSet Class

**File:** `backend/igny8_core/api/viewsets.py`

```python
from igny8_core.api.viewsets import BaseTenantViewSet
from igny8_core.api.permissions import IsAuthenticatedAndActive, HasTenantAccess

class MyViewSet(BaseTenantViewSet):
    permission_classes = [
        IsAuthenticatedAndActive,
        HasTenantAccess,
    ]
    throttle_scope = 'planner'
    queryset = MyModel.objects.all()
    serializer_class = MySerializer
```

---

## Tenant / Site / Sector Scoping

### Scoping Rules

Every resource created or fetched must be scoped by:

1. **Account/Tenant** - User's account
2. **Site** - Specific site within account
3. **Sector** - Specific sector within site

### Enforcement

**Base Classes:**
- `AccountModelViewSet` - Handles account isolation
- `SiteSectorModelViewSet` - Filters queries by site/sector

**Requirements:**
- All custom actions must use `.get_queryset()` to avoid bypassing filters
- Any ID list must be verified to belong to the authenticated tenant
- Site/sector access validated based on user role

### Scoping Example

```python
class KeywordViewSet(SiteSectorModelViewSet):
    # Automatically filters by:
    # 1. account (from request.account)
    # 2. site_id (from query params or request)
    # 3. sector_id (from query params or request)
    
    queryset = Keyword.objects.all()
    serializer_class = KeywordSerializer
    
    def get_queryset(self):
        # Base class handles account/site/sector filtering
        queryset = super().get_queryset()
        # Additional filtering can be added here
        return queryset
```

---

## Module-wise Endpoint Rules

### Planner Module

**Covers:** Keywords → Clusters → Ideas

**Rules:**
- All endpoints require authentication
- Auto-cluster limited to **20 keywords/request**
- Ideas generation limited to **1 cluster/request**
- Standardized payloads for imports/exports
- Bulk actions must validate tenant ownership
- Throttle scope: `planner` (standard), `planner_ai` (AI operations)

**Key Endpoints:**
- `GET/POST /api/v1/planner/keywords/`
- `POST /api/v1/planner/keywords/auto_cluster/`
- `POST /api/v1/planner/clusters/auto_generate_ideas/`
- `POST /api/v1/planner/ideas/bulk_queue_to_writer/`

### Writer Module

**Covers:** Tasks → Content → Image Prompts → Images

**Rules:**
- 1 AI content generation per task
- 1 image generation per request
- Bulk actions max **50**
- Image prompt extraction uses unified response
- Must align with progress tracking
- Throttle scope: `writer` (standard), `writer_ai` (AI operations), `image_gen` (image generation)

**Key Endpoints:**
- `GET/POST /api/v1/writer/tasks/`
- `POST /api/v1/writer/tasks/auto_generate_content/`
- `POST /api/v1/writer/content/generate_image_prompts/`
- `POST /api/v1/writer/images/generate_images/`

### System Module

**Covers:** Prompts, Strategies, Profiles, Integrations, Task Progress

**Rules:**
- Saving prompts requires **editor/admin**
- Integration settings require **admin/owner**
- All tests (OpenAI/Runware) return unified format
- Progress endpoint returns stable JSON for progress modal
- Throttle scope: `system` (standard), `system_admin` (admin operations)

**Key Endpoints:**
- `GET/POST /api/v1/system/prompts/`
- `POST /api/v1/system/prompts/save/`
- `POST /api/v1/system/settings/integrations/{pk}/test/`
- `GET /api/v1/system/settings/task_progress/{task_id}/`

### Billing Module

**Covers:** Credit Balance, Usage Logs, Transactions

**Rules:**
- Balance/usage require authenticated tenant
- Transactions require **admin/owner**
- Unified reporting structure
- No raw model data returned
- Throttle scope: `billing` (standard), `billing_admin` (admin operations)

**Key Endpoints:**
- `GET /api/v1/billing/credits/balance/balance/`
- `GET /api/v1/billing/credits/usage/`
- `GET /api/v1/billing/credits/usage/summary/`
- `GET /api/v1/billing/credits/transactions/`

---

## Logging, Request ID, and Debugging

### Request ID Tracking

**Middleware:** `RequestIDMiddleware`

Every request gets a unique request ID:
- Generated UUID if not provided
- Included in response headers: `X-Request-ID`
- Included in all error responses
- Used for log correlation

### Backend Logging

**Structured Log Format:**
```json
{
  "timestamp": "2025-01-15T12:30:00Z",
  "request_id": "550e8400-e29b-41d4-a716-446655440000",
  "endpoint": "/api/v1/planner/keywords/",
  "method": "POST",
  "user_id": 1,
  "account_id": 1,
  "status_code": 200,
  "error_message": null,
  "traceback": null
}
```

**Log Levels:**
- **INFO**: Normal operations
- **WARNING**: 4xx errors (client errors)
- **ERROR**: 5xx errors (server errors)
- **DEBUG**: Detailed debugging (only in DEBUG mode)

**Log Files:**
- `logs/django.log` - General logs
- `logs/errors.log` - Error logs only

### Frontend Debug Panel Integration

All responses must support:

- **Request ID** - For error tracking
- **Readable error messages** - User-friendly messages
- **Consistent progress steps** - For AI functions
- **Error visibility in real time** - For debugging

### Progress Modal Standard (AI Functions)

All AI functions must output uniform progress metadata:

**Example Steps (Image Prompt Extraction):**
```
1. Smart Image Prompts
2. Checking content and image slots
3. Mapping Content for X Image Prompts
4. Writing Featured Image Prompts
5. Writing X In-article Image Prompts
6. Assigning Prompts to Slots
```

**Success Message:**
```
Featured Image and X In-article Image Prompts ready for image generation
```

**Progress Response Format:**
```json
{
  "state": "PROGRESS",
  "meta": {
    "phase": "AI_CALL",
    "percentage": 50,
    "current_step": "Writing Featured Image Prompts",
    "total_steps": 6,
    "steps": [
      "Smart Image Prompts",
      "Checking content and image slots",
      "Mapping Content for X Image Prompts",
      "Writing Featured Image Prompts",
      "Writing X In-article Image Prompts",
      "Assigning Prompts to Slots"
    ]
  }
}
```

---

## Frontend and Plugin Integration Requirements

### Frontend Integration

**Response Parsing:**
```typescript
const response = await fetchAPI('/v1/planner/keywords/');
const data = await response.json();

if (data.success) {
  // Handle success
  const keywords = data.data; // or data.results for paginated
} else {
  // Handle error
  console.error(data.error);
  if (data.errors) {
    // Handle field-specific errors
    Object.keys(data.errors).forEach(field => {
      console.error(`${field}: ${data.errors[field].join(', ')}`);
    });
  }
}
```

**Error Handling:**
- **401 Unauthorized**: Trigger logout → redirect to login
- **403 Forbidden**: Show permission alert
- **429 Too Many Requests**: Show rate limit warning with retry time
- **4xx/5xx**: Display error message from `error` field

**Pagination:**
```typescript
const response = await fetchAPI('/v1/planner/keywords/?page=1&page_size=25');
const data = await response.json();

if (data.success) {
  const keywords = data.results; // Paginated results
  const count = data.count;
  const next = data.next;
  const previous = data.previous;
}
```

**Rate Limit Handling:**
```typescript
const throttleLimit = response.headers.get('X-Throttle-Limit');
const throttleRemaining = response.headers.get('X-Throttle-Remaining');

if (parseInt(throttleRemaining) < 5) {
  showNotification('Approaching rate limit', 'warning');
}
```

### WordPress Plugin Integration

**Requirements:**
- Uses the same JWT flow
- No custom plugin-specific endpoints
- Uses the app's `/api/v1/` fully
- WP only handles mapping + meta assignment

**Authentication:**
```php
$token = get_option('igny8_api_token');
$response = wp_remote_get('https://api.igny8.com/api/v1/planner/keywords/', [
    'headers' => [
        'Authorization' => 'Bearer ' . $token,
        'Content-Type' => 'application/json',
    ],
]);
```

### 3rd-Party API Integration

**Requirements:**
- Full compatibility with unified format
- Full access where tenant/permissions allow
- No special handling needed

**Example (Python):**
```python
import requests

def get_keywords(access_token):
    url = 'https://api.igny8.com/api/v1/planner/keywords/'
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json'
    }
    
    response = requests.get(url, headers=headers)
    result = response.json()
    
    if result['success']:
        return result['data']  # or result['results'] for paginated
    else:
        raise Exception(result['error'])
```

---

## Migration Plan for Existing Code

### Phase 1: Foundation (Week 1)

1. **Create Response Utilities**
   - File: `backend/igny8_core/api/response.py`
   - Functions: `success_response()`, `error_response()`, `paginated_response()`
   - Unit tests

2. **Create Permission Classes**
   - File: `backend/igny8_core/api/permissions.py`
   - Classes: `IsAuthenticatedAndActive`, `HasTenantAccess`, `IsAdminOrOwner`, etc.
   - Unit tests

3. **Create Base ViewSet**
   - File: `backend/igny8_core/api/viewsets.py`
   - Class: `BaseTenantViewSet`
   - Automatic permission injection

4. **Create Exception Handler**
   - File: `backend/igny8_core/api/exception_handlers.py`
   - Function: `custom_exception_handler()`
   - Register in settings

5. **Configure Rate Limiting**
   - File: `backend/igny8_core/api/throttles.py`
   - Class: `DebugScopedRateThrottle`
   - Configure in settings

### Phase 2: Module Refactoring (Week 2-3)

**Refactoring Order (Least to Most Dependent):**

1. **System Module** (12 hours)
   - Refactor all ViewSets to use `BaseTenantViewSet`
   - Add throttle scopes
   - Replace Response() with helper functions

2. **Billing Module** (8 hours)
   - Same refactoring steps

3. **Planner Module** (16 hours)
   - Same refactoring steps
   - Special attention to AI functions

4. **Writer Module** (16 hours)
   - Same refactoring steps
   - Special attention to AI functions and image generation

5. **Auth Module** (12 hours)
   - Same refactoring steps
   - Keep public endpoints (register, login) as `AllowAny`

### Phase 3: Testing & Validation (Week 4)

1. **Unit Tests**
   - Test all response helpers
   - Test permission classes
   - Test exception handler
   - Test rate limiting

2. **Integration Tests**
   - Test all endpoints return unified format
   - Test error handling
   - Test rate limiting
   - Test permissions

3. **Frontend Integration Testing**
   - Test all workflows
   - Verify error handling
   - Verify rate limit warnings
   - Verify pagination

### Phase 4: Documentation & Release (Week 5)

1. **Update Documentation**
   - API usage guide
   - Backend implementation docs
   - Swagger/OpenAPI (optional)

2. **Changelog Entry**
   - Document all changes
   - Breaking changes
   - Migration guide

3. **Production Deployment**
   - Staging testing
   - Production deployment
   - Monitoring setup

### Refactoring Checklist Template

For each ViewSet:

- [ ] Inherit from `BaseTenantViewSet`
- [ ] Set appropriate `permission_classes`
- [ ] Add `throttle_scope`
- [ ] Replace `Response()` with `success_response()` or `error_response()`
- [ ] Update custom actions with explicit permissions
- [ ] Validate payloads in custom actions
- [ ] Test endpoint manually
- [ ] Verify response format matches specification
- [ ] Update documentation

---

## Testing Strategy

### Unit Tests

**File:** `backend/igny8_core/api/tests/test_response.py`

```python
def test_success_response():
    response = success_response(data={"id": 1}, message="Success")
    assert response.status_code == 200
    data = response.data
    assert data['success'] == True
    assert data['data'] == {"id": 1}
    assert data['message'] == "Success"

def test_error_response():
    response = error_response(
        error="Validation failed",
        errors={"email": ["Invalid"]}
    )
    assert response.status_code == 400
    data = response.data
    assert data['success'] == False
    assert data['error'] == "Validation failed"
    assert data['errors'] == {"email": ["Invalid"]}
```

**File:** `backend/igny8_core/api/tests/test_permissions.py`

```python
def test_has_tenant_access():
    user = User.objects.create(account=account1)
    request.user = user
    request.account = account1
    
    permission = HasTenantAccess()
    assert permission.has_permission(request, view) == True
    
    request.account = account2
    assert permission.has_permission(request, view) == False
```

### Integration Tests

**File:** `backend/igny8_core/api/tests/test_standardized_endpoints.py`

```python
class StandardizedEndpointTestCase(TestCase):
    def setUp(self):
        self.client = APIClient()
        self.user = User.objects.create_user(...)
        self.client.force_authenticate(user=self.user)
    
    def test_list_endpoint_returns_unified_format(self):
        response = self.client.get('/api/v1/planner/keywords/')
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertIn('success', data)
        self.assertTrue(data['success'])
        self.assertIn('results', data)
    
    def test_create_endpoint_returns_unified_format(self):
        response = self.client.post('/api/v1/planner/keywords/', {
            'keyword': 'test',
            'site_id': 1,
            'sector_id': 1
        })
        self.assertEqual(response.status_code, 201)
        data = response.json()
        self.assertIn('success', data)
        self.assertTrue(data['success'])
        self.assertIn('data', data)
    
    def test_error_returns_unified_format(self):
        response = self.client.post('/api/v1/planner/keywords/', {})
        self.assertEqual(response.status_code, 400)
        data = response.json()
        self.assertIn('success', data)
        self.assertFalse(data['success'])
        self.assertIn('error', data)
        self.assertIn('errors', data)
        self.assertIn('request_id', data)
```

### Manual Testing

**Postman Collection:**
- Test all CRUD operations
- Test custom actions
- Test error scenarios
- Test rate limiting
- Verify response format

**Frontend Testing:**
- Test all workflows
- Verify error messages display correctly
- Verify rate limit warnings
- Verify pagination works
- Check browser console for errors

### Test Coverage Goals

- **Unit Tests**: >90% coverage for response utilities, permissions, exception handler
- **Integration Tests**: All major endpoints tested
- **Manual Tests**: All workflows tested

---

## Change Management

### Versioning Strategy

- **v1** remains stable long-term
- Breaking changes require **v2**
- Deprecations allowed only with explicit timeline
- Non-breaking changes can be added to v1

### Breaking Changes

**Definition:** Changes that require client code updates

**Examples:**
- Removing an endpoint
- Changing response structure
- Changing authentication method
- Removing a field from response

**Process:**
1. Document breaking change
2. Provide migration guide
3. Deprecate in v1 with timeline
4. Implement in v2
5. Maintain v1 for deprecation period

### Non-Breaking Changes

**Definition:** Changes that don't require client code updates

**Examples:**
- Adding new endpoints
- Adding optional fields to response
- Adding new query parameters
- Performance improvements

**Process:**
1. Implement in v1
2. Document in changelog
3. No migration required

### Changelog Format

**File:** `CHANGELOG.md`

```markdown
## [1.1.0] - 2025-01-XX

### Added
- New endpoint: `GET /api/v1/system/health/`
- Optional field `metadata` in keyword response

### Changed
- Improved error messages for validation failures
- Rate limits increased for AI functions (10/min → 20/min)

### Deprecated
- `GET /api/v1/planner/keywords/legacy/` (will be removed in v2.0.0)

### Removed
- (None)

### Security
- Fixed authentication bypass in custom actions
```

### Communication Plan

1. **Internal Team**
   - Document changes in changelog
   - Update internal documentation
   - Notify team via Slack/email

2. **External API Consumers**
   - Update API documentation
   - Send email notification for breaking changes
   - Provide migration guide

3. **WordPress Plugin**
   - Update plugin code if needed
   - Test compatibility
   - Release plugin update

### Rollback Plan

If issues arise:

1. **Immediate Rollback**
   - Revert code changes
   - Restore previous version
   - Monitor for issues

2. **Partial Rollback**
   - Revert specific module changes
   - Keep other improvements
   - Fix issues incrementally

3. **Feature Flag**
   - Disable new features via feature flags
   - Keep code in place
   - Re-enable after fixes

---

## Success Criteria

### Definition of Done

- [ ] Every endpoint returns unified format
- [ ] All errors fully unified
- [ ] No endpoint leaks raw DRF format
- [ ] No inconsistent auth behavior
- [ ] No inconsistent pagination
- [ ] No inconsistent validation errors
- [ ] Plugin works using same exact API
- [ ] Third-party clients can implement without special rules
- [ ] Frontend debug panel reads everything correctly
- [ ] CRON + automations structured identically
- [ ] All tests pass
- [ ] Documentation complete
- [ ] Changelog updated

### Metrics

- **Coverage**: 100% of endpoints use unified format
- **Test Coverage**: >90% for core utilities
- **Documentation**: All endpoints documented
- **Breaking Changes**: Documented and migration guide provided
- **Performance**: No significant performance degradation

---

## Appendix

### Quick Reference

**Response Helpers:**
```python
from igny8_core.api.response import success_response, error_response, paginated_response
```

**Permissions:**
```python
from igny8_core.api.permissions import (
    IsAuthenticatedAndActive,
    HasTenantAccess,
    IsAdminOrOwner,
    IsEditorOrAbove,
    IsViewerOrAbove,
)
```

**Base ViewSet:**
```python
from igny8_core.api.viewsets import BaseTenantViewSet
```

**Throttle Scopes:**
- `ai_function`: 10/min
- `image_gen`: 15/min
- `content_write`: 30/min
- `auth`: 20/min
- `planner`: 60/min
- `writer`: 60/min
- `system`: 100/min
- `billing`: 30/min

### Related Documents

- `API-ENDPOINTS-ANALYSIS.md` - Complete endpoint analysis
- `API-IMPLEMENTATION-PLAN-SECTION*.md` - Detailed implementation guides (reference)

---

**Document Status:** Active Standard  
**Last Updated:** 2025-01-XX  
**Next Review:** Quarterly or as needed

