- 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.
1305 lines
32 KiB
Markdown
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§or_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
|
|
|