diff --git a/docs/AUTHENTICATION-GUIDE.md b/docs/AUTHENTICATION-GUIDE.md deleted file mode 100644 index db936030..00000000 --- a/docs/AUTHENTICATION-GUIDE.md +++ /dev/null @@ -1,493 +0,0 @@ -# Authentication Guide - -**Version**: 1.0.0 -**Last Updated**: 2025-11-16 - -Complete guide for authenticating with the IGNY8 API v1.0. - ---- - -## Overview - -The IGNY8 API uses **JWT (JSON Web Token) Bearer Token** authentication. All endpoints require authentication except: -- `POST /api/v1/auth/login/` - User login -- `POST /api/v1/auth/register/` - User registration - ---- - -## Authentication Flow - -### 1. Register or Login - -**Register** (if new user): -```http -POST /api/v1/auth/register/ -Content-Type: application/json - -{ - "email": "user@example.com", - "username": "user", - "password": "secure_password123", - "first_name": "John", - "last_name": "Doe" -} -``` - -**Login** (existing user): -```http -POST /api/v1/auth/login/ -Content-Type: application/json - -{ - "email": "user@example.com", - "password": "secure_password123" -} -``` - -### 2. Receive Tokens - -**Response**: -```json -{ - "success": true, - "data": { - "user": { - "id": 1, - "email": "user@example.com", - "username": "user", - "role": "owner", - "account": { - "id": 1, - "name": "My Account", - "slug": "my-account" - } - }, - "access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE3MDAxMjM0NTZ9...", - "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE3MDAxODk0NTZ9..." - }, - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -### 3. Use Access Token - -Include the `access` token in all subsequent requests: - -```http -GET /api/v1/planner/keywords/ -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... -Content-Type: application/json -``` - -### 4. Refresh Token (when expired) - -When the access token expires (15 minutes), use the refresh token: - -```http -POST /api/v1/auth/refresh/ -Content-Type: application/json - -{ - "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." -} -``` - -**Response**: -```json -{ - "success": true, - "data": { - "access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." - }, - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - ---- - -## Token Expiration - -- **Access Token**: 15 minutes -- **Refresh Token**: 7 days - -### Handling Token Expiration - -**Option 1: Automatic Refresh** -```python -def get_access_token(): - # Check if token is expired - if is_token_expired(current_token): - # Refresh token - response = requests.post( - f"{BASE_URL}/auth/refresh/", - json={"refresh": refresh_token} - ) - data = response.json() - if data['success']: - return data['data']['access'] - return current_token -``` - -**Option 2: Re-login** -```python -def login(): - response = requests.post( - f"{BASE_URL}/auth/login/", - json={"email": email, "password": password} - ) - data = response.json() - if data['success']: - return data['data']['access'] -``` - ---- - -## Code Examples - -### Python - -```python -import requests -import time -from datetime import datetime, timedelta - -class Igny8API: - def __init__(self, base_url="https://api.igny8.com/api/v1"): - self.base_url = base_url - self.access_token = None - self.refresh_token = None - self.token_expires_at = None - - def login(self, email, password): - """Login and store tokens""" - response = requests.post( - f"{self.base_url}/auth/login/", - json={"email": email, "password": password} - ) - data = response.json() - - if data['success']: - self.access_token = data['data']['access'] - self.refresh_token = data['data']['refresh'] - # Token expires in 15 minutes - self.token_expires_at = datetime.now() + timedelta(minutes=14) - return True - else: - print(f"Login failed: {data['error']}") - return False - - def refresh_access_token(self): - """Refresh access token using refresh token""" - if not self.refresh_token: - return False - - response = requests.post( - f"{self.base_url}/auth/refresh/", - json={"refresh": self.refresh_token} - ) - data = response.json() - - if data['success']: - self.access_token = data['data']['access'] - self.refresh_token = data['data']['refresh'] - self.token_expires_at = datetime.now() + timedelta(minutes=14) - return True - else: - print(f"Token refresh failed: {data['error']}") - return False - - def get_headers(self): - """Get headers with valid access token""" - # Check if token is expired or about to expire - if not self.token_expires_at or datetime.now() >= self.token_expires_at: - if not self.refresh_access_token(): - raise Exception("Token expired and refresh failed") - - return { - 'Authorization': f'Bearer {self.access_token}', - 'Content-Type': 'application/json' - } - - def get(self, endpoint): - """Make authenticated GET request""" - response = requests.get( - f"{self.base_url}{endpoint}", - headers=self.get_headers() - ) - return response.json() - - def post(self, endpoint, data): - """Make authenticated POST request""" - response = requests.post( - f"{self.base_url}{endpoint}", - headers=self.get_headers(), - json=data - ) - return response.json() - -# Usage -api = Igny8API() -api.login("user@example.com", "password") - -# Make authenticated requests -keywords = api.get("/planner/keywords/") -``` - -### JavaScript - -```javascript -class Igny8API { - constructor(baseUrl = 'https://api.igny8.com/api/v1') { - this.baseUrl = baseUrl; - this.accessToken = null; - this.refreshToken = null; - this.tokenExpiresAt = null; - } - - async login(email, password) { - const response = await fetch(`${this.baseUrl}/auth/login/`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ email, password }) - }); - - const data = await response.json(); - - if (data.success) { - this.accessToken = data.data.access; - this.refreshToken = data.data.refresh; - // Token expires in 15 minutes - this.tokenExpiresAt = new Date(Date.now() + 14 * 60 * 1000); - return true; - } else { - console.error('Login failed:', data.error); - return false; - } - } - - async refreshAccessToken() { - if (!this.refreshToken) { - return false; - } - - const response = await fetch(`${this.baseUrl}/auth/refresh/`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ refresh: this.refreshToken }) - }); - - const data = await response.json(); - - if (data.success) { - this.accessToken = data.data.access; - this.refreshToken = data.data.refresh; - this.tokenExpiresAt = new Date(Date.now() + 14 * 60 * 1000); - return true; - } else { - console.error('Token refresh failed:', data.error); - return false; - } - } - - async getHeaders() { - // Check if token is expired or about to expire - if (!this.tokenExpiresAt || new Date() >= this.tokenExpiresAt) { - if (!await this.refreshAccessToken()) { - throw new Error('Token expired and refresh failed'); - } - } - - return { - 'Authorization': `Bearer ${this.accessToken}`, - 'Content-Type': 'application/json' - }; - } - - async get(endpoint) { - const response = await fetch( - `${this.baseUrl}${endpoint}`, - { headers: await this.getHeaders() } - ); - return await response.json(); - } - - async post(endpoint, data) { - const response = await fetch( - `${this.baseUrl}${endpoint}`, - { - method: 'POST', - headers: await this.getHeaders(), - body: JSON.stringify(data) - } - ); - return await response.json(); - } -} - -// Usage -const api = new Igny8API(); -await api.login('user@example.com', 'password'); - -// Make authenticated requests -const keywords = await api.get('/planner/keywords/'); -``` - ---- - -## Security Best Practices - -### 1. Store Tokens Securely - -**❌ Don't:** -- Store tokens in localStorage (XSS risk) -- Commit tokens to version control -- Log tokens in console/logs -- Send tokens in URL parameters - -**✅ Do:** -- Store tokens in httpOnly cookies (server-side) -- Use secure storage (encrypted) for client-side -- Rotate tokens regularly -- Implement token revocation - -### 2. Handle Token Expiration - -Always check token expiration and refresh before making requests: - -```python -def is_token_valid(token_expires_at): - # Refresh 1 minute before expiration - return datetime.now() < (token_expires_at - timedelta(minutes=1)) -``` - -### 3. Implement Retry Logic - -```python -def make_request_with_retry(url, headers, max_retries=3): - for attempt in range(max_retries): - response = requests.get(url, headers=headers) - - if response.status_code == 401: - # Token expired, refresh and retry - refresh_token() - headers = get_headers() - continue - - return response.json() - - raise Exception("Max retries exceeded") -``` - -### 4. Validate Token Before Use - -```python -def validate_token(token): - try: - # Decode token (without verification for structure check) - import jwt - decoded = jwt.decode(token, options={"verify_signature": False}) - exp = decoded.get('exp') - - if exp and datetime.fromtimestamp(exp) < datetime.now(): - return False - return True - except: - return False -``` - ---- - -## Error Handling - -### Authentication Errors - -**401 Unauthorized**: -```json -{ - "success": false, - "error": "Authentication required", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Solution**: Include valid `Authorization: Bearer ` header. - -**403 Forbidden**: -```json -{ - "success": false, - "error": "Permission denied", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Solution**: User lacks required permissions. Check user role and resource access. - ---- - -## Testing Authentication - -### Using Swagger UI - -1. Navigate to `https://api.igny8.com/api/docs/` -2. Click "Authorize" button -3. Enter: `Bearer ` -4. Click "Authorize" -5. All requests will include the token - -### Using cURL - -```bash -# Login -curl -X POST https://api.igny8.com/api/v1/auth/login/ \ - -H "Content-Type: application/json" \ - -d '{"email":"user@example.com","password":"password"}' - -# Use token -curl -X GET https://api.igny8.com/api/v1/planner/keywords/ \ - -H "Authorization: Bearer YOUR_TOKEN" \ - -H "Content-Type: application/json" -``` - ---- - -## Troubleshooting - -### Issue: "Authentication required" (401) - -**Causes**: -- Missing Authorization header -- Invalid token format -- Expired token - -**Solutions**: -1. Verify `Authorization: Bearer ` header is included -2. Check token is not expired -3. Refresh token or re-login - -### Issue: "Permission denied" (403) - -**Causes**: -- User lacks required role -- Resource belongs to different account -- Site/sector access denied - -**Solutions**: -1. Check user role has required permissions -2. Verify resource belongs to user's account -3. Check site/sector access permissions - -### Issue: Token expires frequently - -**Solution**: Implement automatic token refresh before expiration. - ---- - -**Last Updated**: 2025-11-16 -**API Version**: 1.0.0 - diff --git a/docs/ERROR-CODES.md b/docs/ERROR-CODES.md deleted file mode 100644 index d5fcd9f5..00000000 --- a/docs/ERROR-CODES.md +++ /dev/null @@ -1,407 +0,0 @@ -# API Error Codes Reference - -**Version**: 1.0.0 -**Last Updated**: 2025-11-16 - -This document provides a comprehensive reference for all error codes and error scenarios in the IGNY8 API v1.0. - ---- - -## Error Response Format - -All errors follow this unified format: - -```json -{ - "success": false, - "error": "Error message", - "errors": { - "field_name": ["Field-specific errors"] - }, - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - ---- - -## HTTP Status Codes - -### 200 OK -**Meaning**: Request successful -**Response**: Success response with data - -### 201 Created -**Meaning**: Resource created successfully -**Response**: Success response with created resource data - -### 204 No Content -**Meaning**: Resource deleted successfully -**Response**: Empty response body - -### 400 Bad Request -**Meaning**: Validation error or invalid request -**Common Causes**: -- Missing required fields -- Invalid field values -- Invalid data format -- Business logic validation failures - -**Example**: -```json -{ - "success": false, - "error": "Validation failed", - "errors": { - "email": ["This field is required"], - "password": ["Password must be at least 8 characters"] - }, - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -### 401 Unauthorized -**Meaning**: Authentication required -**Common Causes**: -- Missing Authorization header -- Invalid or expired token -- Token not provided - -**Example**: -```json -{ - "success": false, - "error": "Authentication required", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -### 403 Forbidden -**Meaning**: Permission denied -**Common Causes**: -- User lacks required role -- User doesn't have access to resource -- Account/site/sector access denied - -**Example**: -```json -{ - "success": false, - "error": "Permission denied", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -### 404 Not Found -**Meaning**: Resource not found -**Common Causes**: -- Invalid resource ID -- Resource doesn't exist -- Resource belongs to different account - -**Example**: -```json -{ - "success": false, - "error": "Resource not found", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -### 409 Conflict -**Meaning**: Resource conflict -**Common Causes**: -- Duplicate resource (e.g., email already exists) -- Resource state conflict -- Concurrent modification - -**Example**: -```json -{ - "success": false, - "error": "Conflict", - "errors": { - "email": ["User with this email already exists"] - }, - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -### 422 Unprocessable Entity -**Meaning**: Validation failed -**Common Causes**: -- Complex validation rules failed -- Business logic validation failed -- Data integrity constraints violated - -**Example**: -```json -{ - "success": false, - "error": "Validation failed", - "errors": { - "site": ["Site must belong to your account"], - "sector": ["Sector must belong to the selected site"] - }, - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -### 429 Too Many Requests -**Meaning**: Rate limit exceeded -**Common Causes**: -- Too many requests in time window -- AI function rate limit exceeded -- Authentication rate limit exceeded - -**Response Headers**: -- `X-Throttle-Limit`: Maximum requests allowed -- `X-Throttle-Remaining`: Remaining requests (0) -- `X-Throttle-Reset`: Unix timestamp when limit resets - -**Example**: -```json -{ - "success": false, - "error": "Rate limit exceeded", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Solution**: Wait until `X-Throttle-Reset` timestamp before retrying. - -### 500 Internal Server Error -**Meaning**: Server error -**Common Causes**: -- Unexpected server error -- Database error -- External service failure - -**Example**: -```json -{ - "success": false, - "error": "Internal server error", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Solution**: Retry request. If persistent, contact support with `request_id`. - ---- - -## Field-Specific Error Messages - -### Authentication Errors - -| Field | Error Message | Description | -|-------|---------------|-------------| -| `email` | "This field is required" | Email not provided | -| `email` | "Invalid email format" | Email format invalid | -| `email` | "User with this email already exists" | Email already registered | -| `password` | "This field is required" | Password not provided | -| `password` | "Password must be at least 8 characters" | Password too short | -| `password` | "Invalid credentials" | Wrong password | - -### Planner Module Errors - -| Field | Error Message | Description | -|-------|---------------|-------------| -| `seed_keyword_id` | "This field is required" | Seed keyword not provided | -| `seed_keyword_id` | "Invalid seed keyword" | Seed keyword doesn't exist | -| `site_id` | "This field is required" | Site not provided | -| `site_id` | "Site must belong to your account" | Site access denied | -| `sector_id` | "This field is required" | Sector not provided | -| `sector_id` | "Sector must belong to the selected site" | Sector-site mismatch | -| `status` | "Invalid status value" | Status value not allowed | - -### Writer Module Errors - -| Field | Error Message | Description | -|-------|---------------|-------------| -| `title` | "This field is required" | Title not provided | -| `site_id` | "This field is required" | Site not provided | -| `sector_id` | "This field is required" | Sector not provided | -| `image_type` | "Invalid image type" | Image type not allowed | - -### System Module Errors - -| Field | Error Message | Description | -|-------|---------------|-------------| -| `api_key` | "This field is required" | API key not provided | -| `api_key` | "Invalid API key format" | API key format invalid | -| `integration_type` | "Invalid integration type" | Integration type not allowed | - -### Billing Module Errors - -| Field | Error Message | Description | -|-------|---------------|-------------| -| `amount` | "This field is required" | Amount not provided | -| `amount` | "Amount must be positive" | Invalid amount value | -| `credits` | "Insufficient credits" | Not enough credits available | - ---- - -## Error Handling Best Practices - -### 1. Always Check `success` Field - -```python -response = requests.get(url, headers=headers) -data = response.json() - -if data['success']: - # Handle success - result = data['data'] or data['results'] -else: - # Handle error - error_message = data['error'] - field_errors = data.get('errors', {}) -``` - -### 2. Handle Field-Specific Errors - -```python -if not data['success']: - if 'errors' in data: - for field, errors in data['errors'].items(): - print(f"{field}: {', '.join(errors)}") - else: - print(f"Error: {data['error']}") -``` - -### 3. Use Request ID for Support - -```python -if not data['success']: - request_id = data.get('request_id') - print(f"Error occurred. Request ID: {request_id}") - # Include request_id when contacting support -``` - -### 4. Handle Rate Limiting - -```python -if response.status_code == 429: - reset_time = response.headers.get('X-Throttle-Reset') - wait_seconds = int(reset_time) - int(time.time()) - print(f"Rate limited. Wait {wait_seconds} seconds.") - time.sleep(wait_seconds) - # Retry request -``` - -### 5. Retry on Server Errors - -```python -if response.status_code >= 500: - # Retry with exponential backoff - time.sleep(2 ** retry_count) - # Retry request -``` - ---- - -## Common Error Scenarios - -### Scenario 1: Missing Authentication - -**Request**: -```http -GET /api/v1/planner/keywords/ -(No Authorization header) -``` - -**Response** (401): -```json -{ - "success": false, - "error": "Authentication required", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Solution**: Include `Authorization: Bearer ` header. - -### Scenario 2: Invalid Resource ID - -**Request**: -```http -GET /api/v1/planner/keywords/99999/ -Authorization: Bearer -``` - -**Response** (404): -```json -{ - "success": false, - "error": "Resource not found", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Solution**: Verify resource ID exists and belongs to your account. - -### Scenario 3: Validation Error - -**Request**: -```http -POST /api/v1/planner/keywords/ -Authorization: Bearer -Content-Type: application/json - -{ - "seed_keyword_id": null, - "site_id": 1 -} -``` - -**Response** (400): -```json -{ - "success": false, - "error": "Validation failed", - "errors": { - "seed_keyword_id": ["This field is required"], - "sector_id": ["This field is required"] - }, - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Solution**: Provide all required fields with valid values. - -### Scenario 4: Rate Limit Exceeded - -**Request**: Multiple rapid requests - -**Response** (429): -```http -HTTP/1.1 429 Too Many Requests -X-Throttle-Limit: 60 -X-Throttle-Remaining: 0 -X-Throttle-Reset: 1700123456 - -{ - "success": false, - "error": "Rate limit exceeded", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Solution**: Wait until `X-Throttle-Reset` timestamp, then retry. - ---- - -## Debugging Tips - -1. **Always include `request_id`** when reporting errors -2. **Check response headers** for rate limit information -3. **Verify authentication token** is valid and not expired -4. **Check field-specific errors** in `errors` object -5. **Review request payload** matches API specification -6. **Use Swagger UI** to test endpoints interactively - ---- - -**Last Updated**: 2025-11-16 -**API Version**: 1.0.0 - diff --git a/docs/MIGRATION-GUIDE.md b/docs/MIGRATION-GUIDE.md deleted file mode 100644 index 9b8f139e..00000000 --- a/docs/MIGRATION-GUIDE.md +++ /dev/null @@ -1,365 +0,0 @@ -# API Migration Guide - -**Version**: 1.0.0 -**Last Updated**: 2025-11-16 - -Guide for migrating existing API consumers to IGNY8 API Standard v1.0. - ---- - -## Overview - -The IGNY8 API v1.0 introduces a unified response format that standardizes all API responses. This guide helps you migrate existing code to work with the new format. - ---- - -## What Changed - -### Before (Legacy Format) - -**Success Response**: -```json -{ - "id": 1, - "name": "Keyword", - "status": "active" -} -``` - -**Error Response**: -```json -{ - "detail": "Not found." -} -``` - -### After (Unified Format v1.0) - -**Success Response**: -```json -{ - "success": true, - "data": { - "id": 1, - "name": "Keyword", - "status": "active" - }, - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Error Response**: -```json -{ - "success": false, - "error": "Resource not found", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - ---- - -## Migration Steps - -### Step 1: Update Response Parsing - -#### Before - -```python -response = requests.get(url, headers=headers) -data = response.json() - -# Direct access -keyword_id = data['id'] -keyword_name = data['name'] -``` - -#### After - -```python -response = requests.get(url, headers=headers) -data = response.json() - -# Check success first -if data['success']: - # Extract data from unified format - keyword_data = data['data'] # or data['results'] for lists - keyword_id = keyword_data['id'] - keyword_name = keyword_data['name'] -else: - # Handle error - error_message = data['error'] - raise Exception(error_message) -``` - -### Step 2: Update Error Handling - -#### Before - -```python -try: - response = requests.get(url, headers=headers) - response.raise_for_status() - data = response.json() -except requests.HTTPError as e: - if e.response.status_code == 404: - print("Not found") - elif e.response.status_code == 400: - print("Bad request") -``` - -#### After - -```python -response = requests.get(url, headers=headers) -data = response.json() - -if not data['success']: - # Unified error format - error_message = data['error'] - field_errors = data.get('errors', {}) - - if response.status_code == 404: - print(f"Not found: {error_message}") - elif response.status_code == 400: - print(f"Validation error: {error_message}") - for field, errors in field_errors.items(): - print(f" {field}: {', '.join(errors)}") -``` - -### Step 3: Update Pagination Handling - -#### Before - -```python -response = requests.get(url, headers=headers) -data = response.json() - -results = data['results'] -next_page = data['next'] -count = data['count'] -``` - -#### After - -```python -response = requests.get(url, headers=headers) -data = response.json() - -if data['success']: - # Paginated response format - results = data['results'] # Same field name - next_page = data['next'] # Same field name - count = data['count'] # Same field name -else: - # Handle error - raise Exception(data['error']) -``` - -### Step 4: Update Frontend Code - -#### Before (JavaScript) - -```javascript -const response = await fetch(url, { headers }); -const data = await response.json(); - -// Direct access -const keywordId = data.id; -const keywordName = data.name; -``` - -#### After (JavaScript) - -```javascript -const response = await fetch(url, { headers }); -const data = await response.json(); - -// Check success first -if (data.success) { - // Extract data from unified format - const keywordData = data.data || data.results; - const keywordId = keywordData.id; - const keywordName = keywordData.name; -} else { - // Handle error - console.error('Error:', data.error); - if (data.errors) { - // Handle field-specific errors - Object.entries(data.errors).forEach(([field, errors]) => { - console.error(`${field}: ${errors.join(', ')}`); - }); - } -} -``` - ---- - -## Helper Functions - -### Python Helper - -```python -def parse_api_response(response): - """Parse unified API response format""" - data = response.json() - - if data.get('success'): - # Return data or results - return data.get('data') or data.get('results') - else: - # Raise exception with error details - error_msg = data.get('error', 'Unknown error') - errors = data.get('errors', {}) - - if errors: - error_msg += f": {errors}" - - raise Exception(error_msg) - -# Usage -response = requests.get(url, headers=headers) -keyword_data = parse_api_response(response) -``` - -### JavaScript Helper - -```javascript -function parseApiResponse(data) { - if (data.success) { - return data.data || data.results; - } else { - const error = new Error(data.error); - error.errors = data.errors || {}; - throw error; - } -} - -// Usage -const response = await fetch(url, { headers }); -const data = await response.json(); -try { - const keywordData = parseApiResponse(data); -} catch (error) { - console.error('API Error:', error.message); - if (error.errors) { - // Handle field-specific errors - } -} -``` - ---- - -## Breaking Changes - -### 1. Response Structure - -**Breaking**: All responses now include `success` field and wrap data in `data` or `results`. - -**Migration**: Update all response parsing code to check `success` and extract `data`/`results`. - -### 2. Error Format - -**Breaking**: Error responses now use unified format with `error` and `errors` fields. - -**Migration**: Update error handling to use new format. - -### 3. Request ID - -**New**: All responses include `request_id` for debugging. - -**Migration**: Optional - can be used for support requests. - ---- - -## Non-Breaking Changes - -### 1. Pagination - -**Status**: Compatible - same field names (`count`, `next`, `previous`, `results`) - -**Migration**: No changes needed, but wrap in success check. - -### 2. Authentication - -**Status**: Compatible - same JWT Bearer token format - -**Migration**: No changes needed. - -### 3. Endpoint URLs - -**Status**: Compatible - same endpoint paths - -**Migration**: No changes needed. - ---- - -## Testing Migration - -### 1. Update Test Code - -```python -# Before -def test_get_keyword(): - response = client.get('/api/v1/planner/keywords/1/') - assert response.status_code == 200 - assert response.json()['id'] == 1 - -# After -def test_get_keyword(): - response = client.get('/api/v1/planner/keywords/1/') - assert response.status_code == 200 - data = response.json() - assert data['success'] == True - assert data['data']['id'] == 1 -``` - -### 2. Test Error Handling - -```python -def test_not_found(): - response = client.get('/api/v1/planner/keywords/99999/') - assert response.status_code == 404 - data = response.json() - assert data['success'] == False - assert data['error'] == "Resource not found" -``` - ---- - -## Migration Checklist - -- [ ] Update response parsing to check `success` field -- [ ] Extract data from `data` or `results` field -- [ ] Update error handling to use unified format -- [ ] Update pagination handling (wrap in success check) -- [ ] Update frontend code (if applicable) -- [ ] Update test code -- [ ] Test all endpoints -- [ ] Update documentation -- [ ] Deploy and monitor - ---- - -## Rollback Plan - -If issues arise during migration: - -1. **Temporary Compatibility Layer**: Add wrapper to convert unified format back to legacy format -2. **Feature Flag**: Use feature flag to toggle between formats -3. **Gradual Migration**: Migrate endpoints one module at a time - ---- - -## Support - -For migration support: -- Review [API Documentation](API-DOCUMENTATION.md) -- Check [Error Codes Reference](ERROR-CODES.md) -- Contact support with `request_id` from failed requests - ---- - -**Last Updated**: 2025-11-16 -**API Version**: 1.0.0 - diff --git a/docs/RATE-LIMITING.md b/docs/RATE-LIMITING.md deleted file mode 100644 index aa729049..00000000 --- a/docs/RATE-LIMITING.md +++ /dev/null @@ -1,439 +0,0 @@ -# Rate Limiting Guide - -**Version**: 1.0.0 -**Last Updated**: 2025-11-16 - -Complete guide for understanding and handling rate limits in the IGNY8 API v1.0. - ---- - -## Overview - -Rate limiting protects the API from abuse and ensures fair resource usage. Different operation types have different rate limits based on their resource intensity. - ---- - -## Rate Limit Headers - -Every API response includes rate limit information in headers: - -- `X-Throttle-Limit`: Maximum requests allowed in the time window -- `X-Throttle-Remaining`: Remaining requests in current window -- `X-Throttle-Reset`: Unix timestamp when the limit resets - -### Example Response Headers - -```http -HTTP/1.1 200 OK -X-Throttle-Limit: 60 -X-Throttle-Remaining: 45 -X-Throttle-Reset: 1700123456 -Content-Type: application/json -``` - ---- - -## Rate Limit Scopes - -Rate limits are scoped by operation type: - -### AI Functions (Expensive Operations) - -| Scope | Limit | Endpoints | -|-------|-------|-----------| -| `ai_function` | 10/min | Auto-cluster, content generation | -| `image_gen` | 15/min | Image generation (DALL-E, Runware) | -| `planner_ai` | 10/min | AI-powered planner operations | -| `writer_ai` | 10/min | AI-powered writer operations | - -### Content Operations - -| Scope | Limit | Endpoints | -|-------|-------|-----------| -| `content_write` | 30/min | Content creation, updates | -| `content_read` | 100/min | Content listing, retrieval | - -### Authentication - -| Scope | Limit | Endpoints | -|-------|-------|-----------| -| `auth` | 20/min | Login, register, password reset | -| `auth_strict` | 5/min | Sensitive auth operations | - -### Planner Operations - -| Scope | Limit | Endpoints | -|-------|-------|-----------| -| `planner` | 60/min | Keywords, clusters, ideas CRUD | - -### Writer Operations - -| Scope | Limit | Endpoints | -|-------|-------|-----------| -| `writer` | 60/min | Tasks, content, images CRUD | - -### System Operations - -| Scope | Limit | Endpoints | -|-------|-------|-----------| -| `system` | 100/min | Settings, prompts, profiles | -| `system_admin` | 30/min | Admin-only system operations | - -### Billing Operations - -| Scope | Limit | Endpoints | -|-------|-------|-----------| -| `billing` | 30/min | Credit queries, usage logs | -| `billing_admin` | 10/min | Credit management (admin) | - -### Default - -| Scope | Limit | Endpoints | -|-------|-------|-----------| -| `default` | 100/min | Endpoints without explicit scope | - ---- - -## Rate Limit Exceeded (429) - -When rate limit is exceeded, you receive: - -**Status Code**: `429 Too Many Requests` - -**Response**: -```json -{ - "success": false, - "error": "Rate limit exceeded", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Headers**: -```http -X-Throttle-Limit: 60 -X-Throttle-Remaining: 0 -X-Throttle-Reset: 1700123456 -``` - -### Handling Rate Limits - -**1. Check Headers Before Request** - -```python -def make_request(url, headers): - response = requests.get(url, headers=headers) - - # Check remaining requests - remaining = int(response.headers.get('X-Throttle-Remaining', 0)) - - if remaining < 5: - # Approaching limit, slow down - time.sleep(1) - - return response.json() -``` - -**2. Handle 429 Response** - -```python -def make_request_with_backoff(url, headers, max_retries=3): - for attempt in range(max_retries): - response = requests.get(url, headers=headers) - - if response.status_code == 429: - # Get reset time - reset_time = int(response.headers.get('X-Throttle-Reset', 0)) - current_time = int(time.time()) - wait_seconds = max(1, reset_time - current_time) - - print(f"Rate limited. Waiting {wait_seconds} seconds...") - time.sleep(wait_seconds) - continue - - return response.json() - - raise Exception("Max retries exceeded") -``` - -**3. Implement Exponential Backoff** - -```python -import time -import random - -def make_request_with_exponential_backoff(url, headers): - max_wait = 60 # Maximum wait time in seconds - base_wait = 1 # Base wait time in seconds - - for attempt in range(5): - response = requests.get(url, headers=headers) - - if response.status_code != 429: - return response.json() - - # Exponential backoff with jitter - wait_time = min( - base_wait * (2 ** attempt) + random.uniform(0, 1), - max_wait - ) - - print(f"Rate limited. Waiting {wait_time:.2f} seconds...") - time.sleep(wait_time) - - raise Exception("Rate limit exceeded after retries") -``` - ---- - -## Best Practices - -### 1. Monitor Rate Limit Headers - -Always check `X-Throttle-Remaining` to avoid hitting limits: - -```python -def check_rate_limit(response): - remaining = int(response.headers.get('X-Throttle-Remaining', 0)) - - if remaining < 10: - print(f"Warning: Only {remaining} requests remaining") - - return remaining -``` - -### 2. Implement Request Queuing - -For bulk operations, queue requests to stay within limits: - -```python -import queue -import threading - -class RateLimitedAPI: - def __init__(self, requests_per_minute=60): - self.queue = queue.Queue() - self.requests_per_minute = requests_per_minute - self.min_interval = 60 / requests_per_minute - self.last_request_time = 0 - - def make_request(self, url, headers): - # Ensure minimum interval between requests - elapsed = time.time() - self.last_request_time - if elapsed < self.min_interval: - time.sleep(self.min_interval - elapsed) - - response = requests.get(url, headers=headers) - self.last_request_time = time.time() - - return response.json() -``` - -### 3. Cache Responses - -Cache frequently accessed data to reduce API calls: - -```python -from functools import lru_cache -import time - -class CachedAPI: - def __init__(self, cache_ttl=300): # 5 minutes - self.cache = {} - self.cache_ttl = cache_ttl - - def get_cached(self, url, headers, cache_key): - # Check cache - if cache_key in self.cache: - data, timestamp = self.cache[cache_key] - if time.time() - timestamp < self.cache_ttl: - return data - - # Fetch from API - response = requests.get(url, headers=headers) - data = response.json() - - # Store in cache - self.cache[cache_key] = (data, time.time()) - - return data -``` - -### 4. Batch Requests When Possible - -Use bulk endpoints instead of multiple individual requests: - -```python -# ❌ Don't: Multiple individual requests -for keyword_id in keyword_ids: - response = requests.get(f"/api/v1/planner/keywords/{keyword_id}/", headers=headers) - -# ✅ Do: Use bulk endpoint if available -response = requests.post( - "/api/v1/planner/keywords/bulk/", - json={"ids": keyword_ids}, - headers=headers -) -``` - ---- - -## Rate Limit Bypass - -### Development/Debug Mode - -Rate limiting is automatically bypassed when: -- `DEBUG=True` in Django settings -- `IGNY8_DEBUG_THROTTLE=True` environment variable -- User belongs to `aws-admin` account -- User has `admin` or `developer` role - -**Note**: Headers are still set for debugging, but requests are not blocked. - ---- - -## Monitoring Rate Limits - -### Track Usage - -```python -class RateLimitMonitor: - def __init__(self): - self.usage_by_scope = {} - - def track_request(self, response, scope): - if scope not in self.usage_by_scope: - self.usage_by_scope[scope] = { - 'total': 0, - 'limited': 0 - } - - self.usage_by_scope[scope]['total'] += 1 - - if response.status_code == 429: - self.usage_by_scope[scope]['limited'] += 1 - - remaining = int(response.headers.get('X-Throttle-Remaining', 0)) - limit = int(response.headers.get('X-Throttle-Limit', 0)) - - usage_percent = ((limit - remaining) / limit) * 100 - - if usage_percent > 80: - print(f"Warning: {scope} at {usage_percent:.1f}% capacity") - - def get_report(self): - return self.usage_by_scope -``` - ---- - -## Troubleshooting - -### Issue: Frequent 429 Errors - -**Causes**: -- Too many requests in short time -- Not checking rate limit headers -- No request throttling implemented - -**Solutions**: -1. Implement request throttling -2. Monitor `X-Throttle-Remaining` header -3. Add delays between requests -4. Use bulk endpoints when available - -### Issue: Rate Limits Too Restrictive - -**Solutions**: -1. Contact support for higher limits (if justified) -2. Optimize requests (cache, batch, reduce frequency) -3. Use development account for testing (bypass enabled) - ---- - -## Code Examples - -### Python - Complete Rate Limit Handler - -```python -import requests -import time -from datetime import datetime - -class RateLimitedClient: - def __init__(self, base_url, token): - self.base_url = base_url - self.headers = { - 'Authorization': f'Bearer {token}', - 'Content-Type': 'application/json' - } - self.rate_limits = {} - - def _wait_for_rate_limit(self, scope='default'): - """Wait if approaching rate limit""" - if scope in self.rate_limits: - limit_info = self.rate_limits[scope] - remaining = limit_info.get('remaining', 0) - reset_time = limit_info.get('reset_time', 0) - - if remaining < 5: - wait_time = max(0, reset_time - time.time()) - if wait_time > 0: - print(f"Rate limit low. Waiting {wait_time:.1f}s...") - time.sleep(wait_time) - - def _update_rate_limit_info(self, response, scope='default'): - """Update rate limit information from response headers""" - limit = response.headers.get('X-Throttle-Limit') - remaining = response.headers.get('X-Throttle-Remaining') - reset = response.headers.get('X-Throttle-Reset') - - if limit and remaining and reset: - self.rate_limits[scope] = { - 'limit': int(limit), - 'remaining': int(remaining), - 'reset_time': int(reset) - } - - def request(self, method, endpoint, scope='default', **kwargs): - """Make rate-limited request""" - # Wait if approaching limit - self._wait_for_rate_limit(scope) - - # Make request - url = f"{self.base_url}{endpoint}" - response = requests.request(method, url, headers=self.headers, **kwargs) - - # Update rate limit info - self._update_rate_limit_info(response, scope) - - # Handle rate limit error - if response.status_code == 429: - reset_time = int(response.headers.get('X-Throttle-Reset', 0)) - wait_time = max(1, reset_time - time.time()) - print(f"Rate limited. Waiting {wait_time:.1f}s...") - time.sleep(wait_time) - # Retry once - response = requests.request(method, url, headers=self.headers, **kwargs) - self._update_rate_limit_info(response, scope) - - return response.json() - - def get(self, endpoint, scope='default'): - return self.request('GET', endpoint, scope) - - def post(self, endpoint, data, scope='default'): - return self.request('POST', endpoint, scope, json=data) - -# Usage -client = RateLimitedClient("https://api.igny8.com/api/v1", "your_token") - -# Make requests with automatic rate limit handling -keywords = client.get("/planner/keywords/", scope="planner") -``` - ---- - -**Last Updated**: 2025-11-16 -**API Version**: 1.0.0 - diff --git a/docs/SECTION-1-2-IMPLEMENTATION-SUMMARY.md b/docs/SECTION-1-2-IMPLEMENTATION-SUMMARY.md deleted file mode 100644 index cc00223f..00000000 --- a/docs/SECTION-1-2-IMPLEMENTATION-SUMMARY.md +++ /dev/null @@ -1,495 +0,0 @@ -# Section 1 & 2 Implementation Summary - -**API Standard v1.0 Implementation** -**Sections Completed**: Section 1 (Testing) & Section 2 (Documentation) -**Date**: 2025-11-16 -**Status**: ✅ Complete - ---- - -## Overview - -This document summarizes the implementation of **Section 1: Testing** and **Section 2: Documentation** from the Unified API Standard v1.0 implementation plan. - ---- - -## Section 1: Testing ✅ - -### Implementation Summary - -Comprehensive test suite created to verify the Unified API Standard v1.0 implementation across all modules and components. - -### Test Suite Structure - -#### Unit Tests (4 files, ~61 test methods) - -1. **test_response.py** (153 lines) - - Tests for `success_response()`, `error_response()`, `paginated_response()` - - Tests for `get_request_id()` - - Verifies unified response format with `success`, `data`/`results`, `message`, `error`, `errors`, `request_id` - - **18 test methods** - -2. **test_exception_handler.py** (177 lines) - - Tests for `custom_exception_handler()` - - Tests all exception types: - - `ValidationError` (400) - - `AuthenticationFailed` (401) - - `PermissionDenied` (403) - - `NotFound` (404) - - `Throttled` (429) - - Generic exceptions (500) - - Tests debug mode behavior (traceback, view, path, method) - - **12 test methods** - -3. **test_permissions.py** (245 lines) - - Tests for all permission classes: - - `IsAuthenticatedAndActive` - - `HasTenantAccess` - - `IsViewerOrAbove` - - `IsEditorOrAbove` - - `IsAdminOrOwner` - - Tests role-based access control (viewer, editor, admin, owner, developer) - - Tests tenant isolation - - Tests admin/system account bypass logic - - **20 test methods** - -4. **test_throttles.py** (145 lines) - - Tests for `DebugScopedRateThrottle` - - Tests bypass logic: - - DEBUG mode bypass - - Environment flag bypass (`IGNY8_DEBUG_THROTTLE`) - - Admin/developer/system account bypass - - Tests rate parsing and throttle headers - - **11 test methods** - -#### Integration Tests (9 files, ~54 test methods) - -1. **test_integration_base.py** (107 lines) - - Base test class with common fixtures - - Helper methods: - - `assert_unified_response_format()` - Verifies unified response structure - - `assert_paginated_response()` - Verifies pagination format - - Sets up: User, Account, Plan, Site, Sector, Industry, SeedKeyword - -2. **test_integration_planner.py** (120 lines) - - Tests Planner module endpoints: - - `KeywordViewSet` (CRUD operations) - - `ClusterViewSet` (CRUD operations) - - `ContentIdeasViewSet` (CRUD operations) - - Tests AI actions: - - `auto_cluster` - Automatic keyword clustering - - `auto_generate_ideas` - AI content idea generation - - `bulk_queue_to_writer` - Bulk task creation - - Tests unified response format and permissions - - **12 test methods** - -3. **test_integration_writer.py** (65 lines) - - Tests Writer module endpoints: - - `TasksViewSet` (CRUD operations) - - `ContentViewSet` (CRUD operations) - - `ImagesViewSet` (CRUD operations) - - Tests AI actions: - - `auto_generate_content` - AI content generation - - `generate_image_prompts` - Image prompt generation - - `generate_images` - AI image generation - - Tests unified response format and permissions - - **6 test methods** - -4. **test_integration_system.py** (50 lines) - - Tests System module endpoints: - - `AIPromptViewSet` (CRUD operations) - - `SystemSettingsViewSet` (CRUD operations) - - `IntegrationSettingsViewSet` (CRUD operations) - - Tests actions: - - `save_prompt` - Save AI prompt - - `test` - Test integration connection - - `task_progress` - Get task progress - - **5 test methods** - -5. **test_integration_billing.py** (50 lines) - - Tests Billing module endpoints: - - `CreditBalanceViewSet` (balance, summary, limits actions) - - `CreditUsageViewSet` (usage summary) - - `CreditTransactionViewSet` (CRUD operations) - - Tests unified response format and permissions - - **5 test methods** - -6. **test_integration_auth.py** (100 lines) - - Tests Auth module endpoints: - - `AuthViewSet` (register, login, me, change_password, refresh_token, reset_password) - - `UsersViewSet` (CRUD operations) - - `GroupsViewSet` (CRUD operations) - - `AccountsViewSet` (CRUD operations) - - `SiteViewSet` (CRUD operations) - - `SectorViewSet` (CRUD operations) - - `IndustryViewSet` (CRUD operations) - - `SeedKeywordViewSet` (CRUD operations) - - Tests authentication flows and unified response format - - **8 test methods** - -7. **test_integration_errors.py** (95 lines) - - Tests error scenarios: - - 400 Bad Request (validation errors) - - 401 Unauthorized (authentication errors) - - 403 Forbidden (permission errors) - - 404 Not Found (resource not found) - - 429 Too Many Requests (rate limiting) - - 500 Internal Server Error (generic errors) - - Tests unified error format for all scenarios - - **6 test methods** - -8. **test_integration_pagination.py** (100 lines) - - Tests pagination across all modules: - - Default pagination (page size 10) - - Custom page size (1-100) - - Page parameter - - Empty results - - Count, next, previous fields - - Tests pagination on: Keywords, Clusters, Tasks, Content, Users, Accounts - - **10 test methods** - -9. **test_integration_rate_limiting.py** (120 lines) - - Tests rate limiting: - - Throttle headers (`X-Throttle-Limit`, `X-Throttle-Remaining`, `X-Throttle-Reset`) - - Bypass logic (admin/system accounts, DEBUG mode) - - Different throttle scopes (read, write, ai) - - 429 response handling - - **7 test methods** - -### Test Statistics - -- **Total Test Files**: 13 -- **Total Test Methods**: ~115 -- **Total Lines of Code**: ~1,500 -- **Coverage**: 100% of API Standard components - -### What Tests Verify - -1. **Unified Response Format** - - All responses include `success` field (true/false) - - Success responses include `data` (single object) or `results` (list) - - Error responses include `error` (message) and `errors` (field-specific) - - All responses include `request_id` (UUID) - -2. **Status Codes** - - Correct HTTP status codes (200, 201, 400, 401, 403, 404, 429, 500) - - Proper error messages for each status code - - Field-specific errors for validation failures - -3. **Pagination** - - Paginated responses include `count`, `next`, `previous`, `results` - - Page size limits enforced (max 100) - - Empty results handled correctly - - Default page size (10) works correctly - -4. **Error Handling** - - All exceptions wrapped in unified format - - Field-specific errors included in `errors` object - - Debug info (traceback, view, path, method) in DEBUG mode - - Request ID included in all error responses - -5. **Permissions** - - Role-based access control (viewer, editor, admin, owner, developer) - - Tenant isolation (users can only access their account's data) - - Site/sector scoping (users can only access their assigned sites/sectors) - - Admin/system account bypass (full access) - -6. **Rate Limiting** - - Throttle headers present in all responses - - Bypass logic for admin/developer/system account users - - Bypass in DEBUG mode (for development) - - Different throttle scopes (read, write, ai) - -### Test Execution - -```bash -# Run all tests -python manage.py test igny8_core.api.tests --verbosity=2 - -# Run specific test file -python manage.py test igny8_core.api.tests.test_response - -# Run specific test class -python manage.py test igny8_core.api.tests.test_response.ResponseHelpersTestCase - -# Run with coverage -coverage run --source='igny8_core.api' manage.py test igny8_core.api.tests -coverage report -``` - -### Test Results - -All tests pass successfully: -- ✅ Unit tests: 61/61 passing -- ✅ Integration tests: 54/54 passing -- ✅ Total: 115/115 passing - -### Files Created - -- `backend/igny8_core/api/tests/__init__.py` -- `backend/igny8_core/api/tests/test_response.py` -- `backend/igny8_core/api/tests/test_exception_handler.py` -- `backend/igny8_core/api/tests/test_permissions.py` -- `backend/igny8_core/api/tests/test_throttles.py` -- `backend/igny8_core/api/tests/test_integration_base.py` -- `backend/igny8_core/api/tests/test_integration_planner.py` -- `backend/igny8_core/api/tests/test_integration_writer.py` -- `backend/igny8_core/api/tests/test_integration_system.py` -- `backend/igny8_core/api/tests/test_integration_billing.py` -- `backend/igny8_core/api/tests/test_integration_auth.py` -- `backend/igny8_core/api/tests/test_integration_errors.py` -- `backend/igny8_core/api/tests/test_integration_pagination.py` -- `backend/igny8_core/api/tests/test_integration_rate_limiting.py` -- `backend/igny8_core/api/tests/README.md` -- `backend/igny8_core/api/tests/TEST_SUMMARY.md` -- `backend/igny8_core/api/tests/run_tests.py` - ---- - -## Section 2: Documentation ✅ - -### Implementation Summary - -Complete documentation system for IGNY8 API v1.0 including OpenAPI 3.0 schema generation, interactive Swagger UI, and comprehensive documentation files. - -### OpenAPI/Swagger Integration - -#### Package Installation -- ✅ Installed `drf-spectacular>=0.27.0` -- ✅ Added to `INSTALLED_APPS` in `settings.py` -- ✅ Configured `REST_FRAMEWORK['DEFAULT_SCHEMA_CLASS']` - -#### Configuration (`backend/igny8_core/settings.py`) - -```python -SPECTACULAR_SETTINGS = { - 'TITLE': 'IGNY8 API v1.0', - 'DESCRIPTION': 'Comprehensive REST API for content planning, creation, and management...', - 'VERSION': '1.0.0', - 'SCHEMA_PATH_PREFIX': '/api/v1', - 'COMPONENT_SPLIT_REQUEST': True, - 'TAGS': [ - {'name': 'Authentication', 'description': 'User authentication and registration'}, - {'name': 'Planner', 'description': 'Keywords, clusters, and content ideas'}, - {'name': 'Writer', 'description': 'Tasks, content, and images'}, - {'name': 'System', 'description': 'Settings, prompts, and integrations'}, - {'name': 'Billing', 'description': 'Credits, usage, and transactions'}, - ], - 'EXTENSIONS_INFO': { - 'x-code-samples': [ - {'lang': 'Python', 'source': '...'}, - {'lang': 'JavaScript', 'source': '...'} - ] - } -} -``` - -#### Endpoints Created - -- ✅ `/api/schema/` - OpenAPI 3.0 schema (JSON/YAML) -- ✅ `/api/docs/` - Swagger UI (interactive documentation) -- ✅ `/api/redoc/` - ReDoc (alternative documentation UI) - -#### Schema Extensions - -Created `backend/igny8_core/api/schema_extensions.py`: -- ✅ `JWTAuthenticationExtension` - JWT Bearer token authentication -- ✅ `CSRFExemptSessionAuthenticationExtension` - Session authentication -- ✅ Proper OpenAPI security scheme definitions - -#### URL Configuration (`backend/igny8_core/urls.py`) - -```python -from drf_spectacular.views import ( - SpectacularAPIView, - SpectacularRedocView, - SpectacularSwaggerView, -) - -urlpatterns = [ - # ... other URLs ... - path('api/schema/', SpectacularAPIView.as_view(), name='schema'), - path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'), - path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'), -] -``` - -### Documentation Files Created - -#### 1. API-DOCUMENTATION.md -**Purpose**: Complete API reference -**Contents**: -- Quick start guide -- Authentication guide -- Response format details -- Error handling -- Rate limiting -- Pagination -- Endpoint reference -- Code examples (Python, JavaScript, cURL) - -#### 2. AUTHENTICATION-GUIDE.md -**Purpose**: Authentication and authorization -**Contents**: -- JWT Bearer token authentication -- Token management and refresh -- Code examples (Python, JavaScript) -- Security best practices -- Token expiration handling -- Troubleshooting - -#### 3. ERROR-CODES.md -**Purpose**: Complete error code reference -**Contents**: -- HTTP status codes (200, 201, 400, 401, 403, 404, 409, 422, 429, 500) -- Field-specific error messages -- Error handling best practices -- Common error scenarios -- Debugging tips - -#### 4. RATE-LIMITING.md -**Purpose**: Rate limiting and throttling -**Contents**: -- Rate limit scopes and limits -- Handling rate limits (429 responses) -- Best practices -- Code examples with backoff strategies -- Request queuing and caching - -#### 5. MIGRATION-GUIDE.md -**Purpose**: Migration guide for API consumers -**Contents**: -- What changed in v1.0 -- Step-by-step migration instructions -- Code examples (before/after) -- Breaking and non-breaking changes -- Migration checklist - -#### 6. WORDPRESS-PLUGIN-INTEGRATION.md -**Purpose**: WordPress plugin integration -**Contents**: -- Complete PHP API client class -- Authentication implementation -- Error handling -- WordPress admin integration -- Two-way sync (WordPress → IGNY8) -- Site data fetching (posts, taxonomies, products, attributes) -- Semantic mapping and content restructuring -- Best practices -- Testing examples - -#### 7. README.md -**Purpose**: Documentation index -**Contents**: -- Documentation index -- Quick start guide -- Links to all documentation files -- Support information - -### Documentation Statistics - -- **Total Documentation Files**: 7 -- **Total Pages**: ~100+ pages of documentation -- **Code Examples**: Python, JavaScript, PHP, cURL -- **Coverage**: 100% of API features documented - -### Access Points - -#### Interactive Documentation -- **Swagger UI**: `https://api.igny8.com/api/docs/` -- **ReDoc**: `https://api.igny8.com/api/redoc/` -- **OpenAPI Schema**: `https://api.igny8.com/api/schema/` - -#### Documentation Files -- All files in `docs/` directory -- Index: `docs/README.md` - -### Files Created/Modified - -#### Backend Files -- `backend/igny8_core/settings.py` - Added drf-spectacular configuration -- `backend/igny8_core/urls.py` - Added schema/documentation endpoints -- `backend/igny8_core/api/schema_extensions.py` - Custom authentication extensions -- `backend/requirements.txt` - Added drf-spectacular>=0.27.0 - -#### Documentation Files -- `docs/API-DOCUMENTATION.md` -- `docs/AUTHENTICATION-GUIDE.md` -- `docs/ERROR-CODES.md` -- `docs/RATE-LIMITING.md` -- `docs/MIGRATION-GUIDE.md` -- `docs/WORDPRESS-PLUGIN-INTEGRATION.md` -- `docs/README.md` -- `docs/DOCUMENTATION-SUMMARY.md` -- `docs/SECTION-2-COMPLETE.md` - ---- - -## Verification & Status - -### Section 1: Testing ✅ -- ✅ All test files created -- ✅ All tests passing (115/115) -- ✅ 100% coverage of API Standard components -- ✅ Unit tests: 61/61 passing -- ✅ Integration tests: 54/54 passing -- ✅ Test documentation created - -### Section 2: Documentation ✅ -- ✅ drf-spectacular installed and configured -- ✅ Schema generation working (OpenAPI 3.0) -- ✅ Schema endpoint accessible (`/api/schema/`) -- ✅ Swagger UI accessible (`/api/docs/`) -- ✅ ReDoc accessible (`/api/redoc/`) -- ✅ 7 comprehensive documentation files created -- ✅ Code examples included (Python, JavaScript, PHP, cURL) -- ✅ Changelog updated - ---- - -## Deliverables - -### Section 1 Deliverables -1. ✅ Complete test suite (13 test files, 115 test methods) -2. ✅ Test documentation (README.md, TEST_SUMMARY.md) -3. ✅ Test runner script (run_tests.py) -4. ✅ All tests passing - -### Section 2 Deliverables -1. ✅ OpenAPI 3.0 schema generation -2. ✅ Interactive Swagger UI -3. ✅ ReDoc documentation -4. ✅ 7 comprehensive documentation files -5. ✅ Code examples in multiple languages -6. ✅ Integration guides - ---- - -## Next Steps - -### Completed ✅ -- ✅ Section 1: Testing - Complete -- ✅ Section 2: Documentation - Complete - -### Remaining -- Section 3: Frontend Refactoring (if applicable) -- Section 4: Additional Features (if applicable) -- Section 5: Performance Optimization (if applicable) - ---- - -## Summary - -Both **Section 1: Testing** and **Section 2: Documentation** have been successfully implemented and verified: - -- **Testing**: Comprehensive test suite with 115 test methods covering all API Standard components -- **Documentation**: Complete documentation system with OpenAPI schema, Swagger UI, and 7 comprehensive guides - -All deliverables are complete, tested, and ready for use. - ---- - -**Last Updated**: 2025-11-16 -**API Version**: 1.0.0 -**Status**: ✅ Complete - diff --git a/docs/SECTION-2-COMPLETE.md b/docs/SECTION-2-COMPLETE.md deleted file mode 100644 index 204e33ad..00000000 --- a/docs/SECTION-2-COMPLETE.md +++ /dev/null @@ -1,81 +0,0 @@ -# Section 2: Documentation - COMPLETE ✅ - -**Date Completed**: 2025-11-16 -**Status**: All Documentation Implemented, Verified, and Fully Functional - ---- - -## Summary - -Section 2: Documentation has been successfully implemented with: -- ✅ OpenAPI 3.0 schema generation (drf-spectacular v0.29.0) -- ✅ Interactive Swagger UI and ReDoc -- ✅ 7 comprehensive documentation files -- ✅ Code examples in multiple languages -- ✅ Integration guides for all platforms - ---- - -## Deliverables - -### 1. OpenAPI/Swagger Integration ✅ -- **Package**: drf-spectacular v0.29.0 installed -- **Endpoints**: - - `/api/schema/` - OpenAPI 3.0 schema - - `/api/docs/` - Swagger UI - - `/api/redoc/` - ReDoc -- **Configuration**: Comprehensive settings with API description, tags, code samples - -### 2. Documentation Files ✅ -- **API-DOCUMENTATION.md** - Complete API reference -- **AUTHENTICATION-GUIDE.md** - Auth guide with examples -- **ERROR-CODES.md** - Error code reference -- **RATE-LIMITING.md** - Rate limiting guide -- **MIGRATION-GUIDE.md** - Migration instructions -- **WORDPRESS-PLUGIN-INTEGRATION.md** - WordPress integration -- **README.md** - Documentation index - -### 3. Schema Extensions ✅ -- Custom JWT authentication extension -- Session authentication extension -- Proper OpenAPI security schemes - ---- - -## Verification - -✅ **drf-spectacular**: Installed and configured -✅ **Schema Generation**: Working (database created and migrations applied) -✅ **Schema Endpoint**: `/api/schema/` returns 200 OK with OpenAPI 3.0 schema -✅ **Swagger UI**: `/api/docs/` displays full API documentation -✅ **ReDoc**: `/api/redoc/` displays full API documentation -✅ **Documentation Files**: 7 files created -✅ **Changelog**: Updated with documentation section -✅ **Code Examples**: Python, JavaScript, PHP, cURL included - ---- - -## Access - -- **Swagger UI**: `https://api.igny8.com/api/docs/` -- **ReDoc**: `https://api.igny8.com/api/redoc/` -- **OpenAPI Schema**: `https://api.igny8.com/api/schema/` -- **Documentation Files**: `docs/` directory - ---- - -## Status - -**Section 2: Documentation - COMPLETE** ✅ - -All documentation is implemented, verified, and fully functional: -- Database created and migrations applied -- Schema generation working (OpenAPI 3.0) -- Swagger UI displaying full API documentation -- ReDoc displaying full API documentation -- All endpoints accessible and working - ---- - -**Completed**: 2025-11-16 -