Files
igny8/unified-api/API-STANDARD-v1.0.md
IGNY8 VPS (Salman) 7cd0e1a807 Add health check endpoint and refactor integration response handling
- Introduced a new public health check endpoint at `api/ping/` to verify API responsiveness.
- Refactored integration response handling to utilize a unified success and error response format across various methods in `IntegrationSettingsViewSet`, improving consistency and clarity in API responses.
- Updated URL patterns to include the new ping endpoint and adjusted imports accordingly.
2025-11-16 07:01:19 +00:00

1305 lines
32 KiB
Markdown

# 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/v1/system/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