diff --git a/CHANGELOG.md b/CHANGELOG.md index 08a951a8..489e48eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,17 @@ Each entry follows this format: ## [Unreleased] +### Changed +- **API Documentation Consolidation**: Consolidated all API documentation into single comprehensive reference + - Created `docs/API-COMPLETE-REFERENCE.md` - Unified API documentation covering all endpoints, authentication, response formats, error handling, rate limiting, permissions, and integration examples + - Removed redundant documentation files: + - `docs/API-DOCUMENTATION.md` (consolidated into complete reference) + - `docs/DOCUMENTATION-SUMMARY.md` (consolidated into complete reference) + - `unified-api/API-ENDPOINTS-ANALYSIS.md` (consolidated into complete reference) + - `unified-api/API-STANDARD-v1.0.md` (consolidated into complete reference) + - New unified document includes: complete endpoint reference, authentication guide, response format standards, error handling, rate limiting, pagination, roles & permissions, tenant/site/sector scoping, integration examples (Python, JavaScript, cURL, PHP), testing & debugging, and change management + - **Impact**: Single source of truth for all API documentation, easier to maintain and navigate + ### Added - Unified API Standard v1.0 implementation - API Monitor page for endpoint health monitoring @@ -353,7 +364,7 @@ Each entry follows this format: - Added custom authentication extensions for JWT Bearer tokens - **Comprehensive Documentation Files** - - `docs/API-DOCUMENTATION.md` - Complete API reference with examples + - `docs/API-COMPLETE-REFERENCE.md` - Complete unified API reference (consolidated from multiple files) - Quick start guide - Endpoint reference - Code examples (Python, JavaScript, cURL) diff --git a/README.md b/README.md index b2ec5a4d..9a342817 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,8 @@ igny8/ │ ├── 03-FRONTEND-ARCHITECTURE.md │ ├── 04-BACKEND-IMPLEMENTATION.md │ ├── 05-AI-FRAMEWORK-IMPLEMENTATION.md -│ └── 06-FUNCTIONAL-BUSINESS-LOGIC.md +│ ├── 06-FUNCTIONAL-BUSINESS-LOGIC.md +│ └── API-COMPLETE-REFERENCE.md # Complete unified API documentation ├── CHANGELOG.md # Version history and changes (only updated after user confirmation) └── docker-compose.app.yml ``` @@ -132,16 +133,62 @@ For complete installation guide, see [docs/01-TECH-STACK-AND-INFRASTRUCTURE.md]( --- -## 🔗 API Endpoints +## 🔗 API Documentation -- **Planner**: `/api/v1/planner/keywords/`, `/api/v1/planner/clusters/`, `/api/v1/planner/ideas/` -- **Writer**: `/api/v1/writer/tasks/`, `/api/v1/writer/images/` -- **System**: `/api/v1/system/settings/` -- **Billing**: `/api/v1/billing/` -- **Auth**: `/api/v1/auth/` -- **Admin**: `/admin/` +### Interactive Documentation -See [docs/04-BACKEND-IMPLEMENTATION.md](docs/04-BACKEND-IMPLEMENTATION.md) for complete API reference. +- **Swagger UI**: `https://api.igny8.com/api/docs/` +- **ReDoc**: `https://api.igny8.com/api/redoc/` +- **OpenAPI Schema**: `https://api.igny8.com/api/schema/` + +### API Complete Reference + +**[API Complete Reference](docs/API-COMPLETE-REFERENCE.md)** - Comprehensive unified API documentation (single source of truth) +- Complete endpoint reference (100+ endpoints across all modules) +- Authentication & authorization guide +- Response format standards (unified format: `{success, data, message, errors, request_id}`) +- Error handling +- Rate limiting (scoped by operation type) +- Pagination +- Roles & permissions +- Tenant/site/sector scoping +- Integration examples (Python, JavaScript, cURL, PHP) +- Testing & debugging +- Change management + +### API Standard Features + +- ✅ **Unified Response Format** - Consistent JSON structure for all endpoints +- ✅ **Layered Authorization** - Authentication → Tenant → Role → Site/Sector +- ✅ **Centralized Error Handling** - All errors in unified format with request_id +- ✅ **Scoped Rate Limiting** - Different limits per operation type (10-100/min) +- ✅ **Tenant Isolation** - Account/site/sector scoping +- ✅ **Request Tracking** - Unique request ID for debugging +- ✅ **100% Implemented** - All endpoints use unified format + +### Quick API Example + +```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"}' + +# Get keywords (with token) +curl -X GET https://api.igny8.com/api/v1/planner/keywords/ \ + -H "Authorization: Bearer YOUR_TOKEN" \ + -H "Content-Type: application/json" +``` + +### Additional API Guides + +- **[Authentication Guide](docs/AUTHENTICATION-GUIDE.md)** - Detailed JWT authentication guide +- **[Error Codes Reference](docs/ERROR-CODES.md)** - Complete error code reference +- **[Rate Limiting Guide](docs/RATE-LIMITING.md)** - Rate limiting and throttling details +- **[Migration Guide](docs/MIGRATION-GUIDE.md)** - Migrating to API v1.0 +- **[WordPress Plugin Integration](docs/WORDPRESS-PLUGIN-INTEGRATION.md)** - WordPress integration guide + +For backend implementation details, see [docs/04-BACKEND-IMPLEMENTATION.md](docs/04-BACKEND-IMPLEMENTATION.md). --- @@ -234,6 +281,7 @@ All documentation is consolidated in the `/docs/` folder. ### Finding Information **By Topic:** +- **API Documentation**: [API-COMPLETE-REFERENCE.md](docs/API-COMPLETE-REFERENCE.md) - Complete unified API reference (single source of truth) - **Infrastructure & Deployment**: [01-TECH-STACK-AND-INFRASTRUCTURE.md](docs/01-TECH-STACK-AND-INFRASTRUCTURE.md) - **Application Architecture**: [02-APPLICATION-ARCHITECTURE.md](docs/02-APPLICATION-ARCHITECTURE.md) - **Frontend Development**: [03-FRONTEND-ARCHITECTURE.md](docs/03-FRONTEND-ARCHITECTURE.md) diff --git a/docs/API-COMPLETE-REFERENCE.md b/docs/API-COMPLETE-REFERENCE.md new file mode 100644 index 00000000..1e6cc6f4 --- /dev/null +++ b/docs/API-COMPLETE-REFERENCE.md @@ -0,0 +1,1389 @@ +# IGNY8 API Complete Reference v1.0 + +**Base URL**: `https://api.igny8.com/api/v1/` +**Version**: 1.0.0 +**Last Updated**: 2025-01-XX +**Status**: ✅ **100% IMPLEMENTED** - All endpoints use unified format + +**Purpose**: Complete, unified reference for IGNY8 API covering authentication, endpoints, response formats, error handling, rate limiting, permissions, and integration examples. + +--- + +## Table of Contents + +1. [Quick Start](#quick-start) +2. [Overview & Architecture](#overview--architecture) +3. [Authentication & Authorization](#authentication--authorization) +4. [Response Format Standard](#response-format-standard) +5. [Error Handling](#error-handling) +6. [Rate Limiting](#rate-limiting) +7. [Pagination](#pagination) +8. [Roles & Permissions](#roles--permissions) +9. [Tenant / Site / Sector Scoping](#tenant--site--sector-scoping) +10. [Complete Endpoint Reference](#complete-endpoint-reference) +11. [Integration Examples](#integration-examples) +12. [Testing & Debugging](#testing--debugging) +13. [Change Management](#change-management) + +--- + +## Quick Start + +### 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/` + +### Basic Example + +```python +import requests + +BASE_URL = "https://api.igny8.com/api/v1" + +# 1. Login +response = requests.post( + f"{BASE_URL}/auth/login/", + json={"email": "user@example.com", "password": "password"} +) +data = response.json() + +if data['success']: + token = data['data']['access'] + + # 2. Use token for authenticated requests + headers = { + 'Authorization': f'Bearer {token}', + 'Content-Type': 'application/json' + } + + # 3. Get keywords + response = requests.get( + f"{BASE_URL}/planner/keywords/", + headers=headers + ) + result = response.json() + + if result['success']: + keywords = result['results'] # Paginated results + print(f"Found {result['count']} keywords") +``` + +--- + +## Overview & Architecture + +### API Standard v1.0 - 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 + +### Base URL Structure + +``` +Production: https://api.igny8.com/api/v1/ +Development: http://localhost:8000/api/v1/ +``` + +### Module 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 +``` + +### Technology Stack + +- **Framework**: Django REST Framework (DRF) +- **Authentication**: JWT Bearer tokens (primary), Session (fallback), Basic (fallback) +- **Pagination**: CustomPageNumberPagination (default: 10, max: 100) +- **Rate Limiting**: Scoped throttles per module/operation type +- **OpenAPI**: drf-spectacular for schema generation + +### Implementation Status + +✅ **100% Complete** - All endpoints implemented with: +- Unified response format +- Proper authentication and authorization +- Rate limiting configured +- Error handling standardized +- Request ID tracking +- Complete Swagger/OpenAPI documentation + +--- + +## Authentication & Authorization + +### Authentication Methods + +#### Primary: JWT Bearer Token + +``` +Authorization: Bearer +``` + +**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 + +### Getting an Access Token + +**Login Endpoint:** +```http +POST /api/v1/auth/login/ +Content-Type: application/json + +{ + "email": "user@example.com", + "password": "your_password" +} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "user": { + "id": 1, + "email": "user@example.com", + "username": "user", + "role": "owner", + "account": { ... } + }, + "access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + }, + "request_id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +### Token Expiration + +- **Access Token**: 15 minutes +- **Refresh Token**: 7 days + +**Refresh Token:** +```http +POST /api/v1/auth/refresh/ +Content-Type: application/json + +{ + "refresh": "your_refresh_token" +} +``` + +### Public Endpoints (No Authentication Required) + +- `POST /api/v1/auth/register/` - User registration +- `POST /api/v1/auth/login/` - User login +- `GET /api/v1/auth/plans/` - List plans +- `GET /api/v1/auth/industries/` - List industries +- `GET /api/v1/system/status/` - System health check +- `GET /api/v1/system/ping/` - Health check endpoint + +**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": { + "id": 1, + "name": "Example Keyword", + "status": "active" + }, + "message": "Optional human-readable success message", + "request_id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +### Paginated Response + +```json +{ + "success": true, + "count": 120, + "next": "http://api.igny8.com/api/v1/planner/keywords/?page=3", + "previous": "http://api.igny8.com/api/v1/planner/keywords/?page=1", + "results": [ + {"id": 1, "name": "Keyword 1"}, + {"id": 2, "name": "Keyword 2"}, + ... + ], + "request_id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +### Error Response + +```json +{ + "success": false, + "error": "Readable top-level error message", + "errors": { + "field_name": ["Field-specific error messages"] + }, + "request_id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +### 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 + +### HTTP Status Codes + +| Code | Meaning | Description | +|------|---------|-------------| +| 200 | OK | Request successful | +| 201 | Created | Resource created successfully | +| 204 | No Content | Resource deleted successfully | +| 400 | Bad Request | Validation error or invalid request | +| 401 | Unauthorized | Authentication required | +| 403 | Forbidden | Permission denied | +| 404 | Not Found | Resource not found | +| 409 | Conflict | Resource conflict (e.g., duplicate) | +| 422 | Unprocessable Entity | Validation failed | +| 429 | Too Many Requests | Rate limit exceeded | +| 500 | Internal Server Error | Server error | + +### 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 +- Includes sanitized validation errors under `errors` +- Always attaches `request_id` for error tracking +- Logs full exception details +- In DEBUG mode: includes traceback + request context + +### Error Response Examples + +**Validation Error (400):** +```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" +} +``` + +**Authentication Error (401):** +```json +{ + "success": false, + "error": "Authentication required", + "request_id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +**Permission Error (403):** +```json +{ + "success": false, + "error": "Permission denied", + "request_id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +**Rate Limit (429):** +```json +{ + "success": false, + "error": "Rate limit exceeded", + "request_id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +### 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 +- Rotating log files +- Sentry integration hooks for production + +--- + +## Rate Limiting + +### Rate Limiting Configuration + +Rate limits are scoped by operation type. Check response headers for limit information: + +- `X-Throttle-Limit`: Maximum requests allowed +- `X-Throttle-Remaining`: Remaining requests in current window +- `X-Throttle-Reset`: Time when limit resets (Unix timestamp) + +### Rate Limit Scopes + +| Scope | Limit | Description | +|-------|-------|-------------| +| `ai_function` | 10/min | AI content generation, clustering | +| `image_gen` | 15/min | Image generation | +| `content_write` | 30/min | Content creation, updates | +| `content_read` | 100/min | Content listing, retrieval | +| `auth` | 20/min | Login, register, password reset | +| `auth_strict` | 5/min | Sensitive auth operations | +| `planner` | 60/min | Keyword, cluster, idea operations | +| `planner_ai` | 10/min | AI-powered planner operations | +| `writer` | 60/min | Task, content management | +| `writer_ai` | 10/min | AI-powered writer operations | +| `system` | 100/min | Settings, prompts, profiles | +| `system_admin` | 30/min | Admin-only system operations | +| `billing` | 30/min | Credit queries, usage logs | +| `billing_admin` | 10/min | Credit management (admin) | +| `default` | 100/min | Default for endpoints without scope | + +### Handling Rate Limits + +When rate limited (429), the response includes: +- Error message: "Rate limit exceeded" +- Headers with reset time +- Wait until `X-Throttle-Reset` before retrying + +**Example:** +```http +HTTP/1.1 429 Too Many Requests +X-Throttle-Limit: 60 +X-Throttle-Remaining: 0 +X-Throttle-Reset: 1700123456 +Retry-After: 60 + +{ + "success": false, + "error": "Rate limit exceeded", + "request_id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +### Debug Mode Bypass + +Set `IGNY8_DEBUG_THROTTLE=True` or `DEBUG=True` to bypass throttling in development. + +--- + +## Pagination + +### 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 + ], + "request_id": "550e8400-e29b-41d4-a716-446655440000" +} +``` + +### Pagination Fields + +- `count`: Total number of items +- `next`: URL to next page (null if last page) +- `previous`: URL to previous page (null if first page) +- `results`: Array of items for current page + +--- + +## Roles & Permissions + +### 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 | + +--- + +## 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 +``` + +--- + +## Complete Endpoint Reference + +### Authentication Endpoints + +**Base Path**: `/api/v1/auth/` + +#### POST `/api/v1/auth/register/` +**Purpose**: User registration +**Authentication**: None (AllowAny) + +**Request:** +```json +{ + "email": "user@example.com", + "password": "password123", + "password_confirm": "password123" +} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "user": { + "id": 1, + "email": "user@example.com", + "role": "owner", + "account": { ... } + } + }, + "message": "Registration successful" +} +``` + +#### POST `/api/v1/auth/login/` +**Purpose**: User login +**Authentication**: None (AllowAny) + +**Request:** +```json +{ + "email": "user@example.com", + "password": "password123" +} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "user": { ... }, + "access": "eyJ0eXAiOiJKV1QiLCJhbGc...", + "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc..." + }, + "message": "Login successful" +} +``` + +#### POST `/api/v1/auth/refresh/` +**Purpose**: Refresh access token +**Authentication**: None (requires refresh token) + +**Request:** +```json +{ + "refresh": "your_refresh_token" +} +``` + +#### POST `/api/v1/auth/change-password/` +**Purpose**: Change user password +**Authentication**: Required (IsAuthenticated) + +**Request:** +```json +{ + "old_password": "oldpass123", + "new_password": "newpass123", + "new_password_confirm": "newpass123" +} +``` + +#### GET `/api/v1/auth/me/` +**Purpose**: Get current user information +**Authentication**: Required (IsAuthenticated) + +**Response:** +```json +{ + "success": true, + "data": { + "user": { + "id": 1, + "email": "user@example.com", + "role": "owner", + "account": { ... }, + "accessible_sites": [ ... ] + } + } +} +``` + +### User Management Endpoints + +**Base Path**: `/api/v1/auth/users/` +**Permission**: IsOwnerOrAdmin + +**Standard CRUD:** +- `GET /api/v1/auth/users/` - List users +- `POST /api/v1/auth/users/` - Create user +- `GET /api/v1/auth/users/{id}/` - Get user +- `PUT /api/v1/auth/users/{id}/` - Update user +- `DELETE /api/v1/auth/users/{id}/` - Delete user + +**Custom Actions:** +- `POST /api/v1/auth/users/invite/` - Invite user +- `POST /api/v1/auth/users/{id}/activate/` - Activate user + +### Account Management Endpoints + +**Base Path**: `/api/v1/auth/accounts/` +**Permission**: IsOwnerOrAdmin + +**Standard CRUD:** +- `GET /api/v1/auth/accounts/` - List accounts +- `POST /api/v1/auth/accounts/` - Create account +- `GET /api/v1/auth/accounts/{id}/` - Get account +- `PUT /api/v1/auth/accounts/{id}/` - Update account +- `DELETE /api/v1/auth/accounts/{id}/` - Delete account + +### Site Management Endpoints + +**Base Path**: `/api/v1/auth/sites/` +**Permission**: IsEditorOrAbove + +**Standard CRUD:** +- `GET /api/v1/auth/sites/` - List sites +- `POST /api/v1/auth/sites/` - Create site +- `GET /api/v1/auth/sites/{id}/` - Get site +- `PUT /api/v1/auth/sites/{id}/` - Update site +- `DELETE /api/v1/auth/sites/{id}/` - Delete site + +**Custom Actions:** +- `GET /api/v1/auth/sites/{id}/sectors/` - Get site sectors +- `POST /api/v1/auth/sites/{id}/set_active/` - Set active site +- `POST /api/v1/auth/sites/{id}/select_sectors/` - Select sectors + +### Sector Management Endpoints + +**Base Path**: `/api/v1/auth/sectors/` +**Permission**: IsEditorOrAbove + +**Standard CRUD:** +- `GET /api/v1/auth/sectors/` - List sectors +- `POST /api/v1/auth/sectors/` - Create sector +- `GET /api/v1/auth/sectors/{id}/` - Get sector +- `PUT /api/v1/auth/sectors/{id}/` - Update sector +- `DELETE /api/v1/auth/sectors/{id}/` - Delete sector + +### Planner Module Endpoints + +**Base Path**: `/api/v1/planner/` + +#### Keyword Management + +**Base Path**: `/api/v1/planner/keywords/` +**Permission**: IsAuthenticatedAndActive + HasTenantAccess +**Inherits**: SiteSectorModelViewSet + +**Standard CRUD:** +- `GET /api/v1/planner/keywords/` - List keywords (paginated) +- `POST /api/v1/planner/keywords/` - Create keyword +- `GET /api/v1/planner/keywords/{id}/` - Get keyword +- `PUT /api/v1/planner/keywords/{id}/` - Update keyword +- `DELETE /api/v1/planner/keywords/{id}/` - Delete keyword + +**Filtering:** +- `status` - Filter by status +- `cluster_id` - Filter by cluster +- `seed_keyword__intent` - Filter by intent +- `seed_keyword_id` - Filter by seed keyword ID +- `difficulty_min`, `difficulty_max` - Difficulty range +- `volume_min`, `volume_max` - Volume range +- `site_id` - Filter by site (query param) +- `sector_id` - Filter by sector (query param) + +**Search:** +- `search` - Search by keyword text + +**Ordering:** +- `ordering` - Order by `created_at`, `seed_keyword__volume`, `seed_keyword__difficulty` +- Default: `-created_at` (newest first) + +**Custom Actions:** +- `POST /api/v1/planner/keywords/bulk_delete/` - Bulk delete keywords + - Request: `{ "ids": [1, 2, 3] }` +- `POST /api/v1/planner/keywords/bulk_update_status/` - Bulk update status + - Request: `{ "ids": [1, 2, 3], "status": "active" }` +- `POST /api/v1/planner/keywords/bulk_add_from_seed/` - Add keywords from seed library + - Request: `{ "seed_keyword_ids": [1, 2, 3], "site_id": 1, "sector_id": 1 }` +- `GET /api/v1/planner/keywords/export/` - Export keywords to CSV +- `POST /api/v1/planner/keywords/import_keywords/` - Import keywords from CSV +- `POST /api/v1/planner/keywords/auto_cluster/` - Auto-cluster keywords using AI + - Request: `{ "ids": [1, 2, 3, ...], "sector_id": 1 }` + - Max Keywords: 20 per batch + - Returns: Celery task ID for progress tracking + +#### Cluster Management + +**Base Path**: `/api/v1/planner/clusters/` +**Permission**: IsAuthenticatedAndActive + HasTenantAccess +**Inherits**: SiteSectorModelViewSet + +**Standard CRUD:** +- `GET /api/v1/planner/clusters/` - List clusters +- `POST /api/v1/planner/clusters/` - Create cluster +- `GET /api/v1/planner/clusters/{id}/` - Get cluster +- `PUT /api/v1/planner/clusters/{id}/` - Update cluster +- `DELETE /api/v1/planner/clusters/{id}/` - Delete cluster + +**Filtering:** +- `status` - Filter by status +- `site_id` - Filter by site (query param) +- `sector_id` - Filter by sector (query param) + +**Search:** +- `search` - Search by cluster name + +**Custom Actions:** +- `POST /api/v1/planner/clusters/bulk_delete/` - Bulk delete clusters +- `POST /api/v1/planner/clusters/auto_generate_ideas/` - Auto-generate content ideas + - Request: `{ "ids": [1] }` (max 1 cluster per batch) + - Returns: Celery task ID for progress tracking + +#### Content Ideas Management + +**Base Path**: `/api/v1/planner/ideas/` +**Permission**: IsAuthenticatedAndActive + HasTenantAccess +**Inherits**: SiteSectorModelViewSet + +**Standard CRUD:** +- `GET /api/v1/planner/ideas/` - List content ideas +- `POST /api/v1/planner/ideas/` - Create content idea +- `GET /api/v1/planner/ideas/{id}/` - Get content idea +- `PUT /api/v1/planner/ideas/{id}/` - Update content idea +- `DELETE /api/v1/planner/ideas/{id}/` - Delete content idea + +**Filtering:** +- `status` - Filter by status +- `cluster_id` - Filter by cluster +- `content_type` - Filter by content type +- `site_id` - Filter by site (query param) +- `sector_id` - Filter by sector (query param) + +**Custom Actions:** +- `POST /api/v1/planner/ideas/bulk_delete/` - Bulk delete ideas +- `POST /api/v1/planner/ideas/bulk_queue_to_writer/` - Queue ideas to writer (create tasks) + - Request: `{ "ids": [1, 2, 3] }` + +### Writer Module Endpoints + +**Base Path**: `/api/v1/writer/` + +#### Task Management + +**Base Path**: `/api/v1/writer/tasks/` +**Permission**: IsAuthenticatedAndActive + HasTenantAccess +**Inherits**: SiteSectorModelViewSet + +**Standard CRUD:** +- `GET /api/v1/writer/tasks/` - List tasks +- `POST /api/v1/writer/tasks/` - Create task +- `GET /api/v1/writer/tasks/{id}/` - Get task +- `PUT /api/v1/writer/tasks/{id}/` - Update task +- `DELETE /api/v1/writer/tasks/{id}/` - Delete task + +**Filtering:** +- `status` - Filter by status (draft, in_progress, review, completed, archived) +- `cluster_id` - Filter by cluster +- `content_type` - Filter by content type +- `content_structure` - Filter by content structure +- `site_id` - Filter by site (query param) +- `sector_id` - Filter by sector (query param) + +**Search:** +- `search` - Search by title or keywords + +**Custom Actions:** +- `POST /api/v1/writer/tasks/bulk_delete/` - Bulk delete tasks +- `POST /api/v1/writer/tasks/bulk_update/` - Bulk update task status +- `POST /api/v1/writer/tasks/auto_generate_content/` - Auto-generate content using AI + - Request: `{ "ids": [1, 2, 3, ...] }` (max 50 tasks per batch) + - Returns: Celery task ID for progress tracking + +#### Content Management + +**Base Path**: `/api/v1/writer/content/` +**Permission**: IsAuthenticatedAndActive + HasTenantAccess +**Inherits**: SiteSectorModelViewSet + +**Standard CRUD:** +- `GET /api/v1/writer/content/` - List content +- `POST /api/v1/writer/content/` - Create content +- `GET /api/v1/writer/content/{id}/` - Get content +- `PUT /api/v1/writer/content/{id}/` - Update content +- `DELETE /api/v1/writer/content/{id}/` - Delete content + +**Filtering:** +- `status` - Filter by status +- `content_type` - Filter by content type +- `site_id` - Filter by site (query param) +- `sector_id` - Filter by sector (query param) + +**Custom Actions:** +- `POST /api/v1/writer/content/generate_image_prompts/` - Generate image prompts from content + - Request: `{ "ids": [1, 2, 3] }` + - Returns: Celery task ID for progress tracking + +#### Image Management + +**Base Path**: `/api/v1/writer/images/` +**Permission**: IsAuthenticatedAndActive + HasTenantAccess +**Inherits**: SiteSectorModelViewSet + +**Standard CRUD:** +- `GET /api/v1/writer/images/` - List images +- `POST /api/v1/writer/images/` - Create image +- `GET /api/v1/writer/images/{id}/` - Get image +- `PUT /api/v1/writer/images/{id}/` - Update image +- `DELETE /api/v1/writer/images/{id}/` - Delete image + +**Filtering:** +- `image_type` - Filter by type (featured, in_article, desktop, mobile) +- `status` - Filter by status +- `content_id` - Filter by content +- `task_id` - Filter by task +- `site_id` - Filter by site (query param) +- `sector_id` - Filter by sector (query param) + +**Custom Actions:** +- `GET /api/v1/writer/images/{id}/file/` - Get image file URL +- `GET /api/v1/writer/images/content_images/` - Get images for content + - Query Params: `content_id` (required) +- `POST /api/v1/writer/images/generate_images/` - Generate images using AI + - Request: `{ "ids": [1, 2, 3, ...] }` + - Returns: Celery task ID for progress tracking +- `POST /api/v1/writer/images/bulk_update/` - Bulk update image status + +### System Module Endpoints + +**Base Path**: `/api/v1/system/` + +#### AI Prompt Management + +**Base Path**: `/api/v1/system/prompts/` +**Permission**: IsAuthenticatedAndActive + HasTenantAccess +**Inherits**: AccountModelViewSet + +**Standard CRUD:** +- `GET /api/v1/system/prompts/` - List prompts +- `POST /api/v1/system/prompts/` - Create prompt +- `GET /api/v1/system/prompts/{id}/` - Get prompt +- `PUT /api/v1/system/prompts/{id}/` - Update prompt +- `DELETE /api/v1/system/prompts/{id}/` - Delete prompt + +**Custom Actions:** +- `GET /api/v1/system/prompts/by_type/{prompt_type}/` - Get prompt by type +- `POST /api/v1/system/prompts/save/` - Save prompt (requires editor/admin) +- `POST /api/v1/system/prompts/reset/` - Reset prompt to default + +#### Integration Settings + +**Base Path**: `/api/v1/system/settings/integrations/` +**Permission**: IsAdminOrOwner + +**Custom URL Patterns:** +- `GET /api/v1/system/settings/integrations/{pk}/` - Get integration settings +- `POST /api/v1/system/settings/integrations/{pk}/save/` - Save integration settings +- `PUT /api/v1/system/settings/integrations/{pk}/` - Update integration settings +- `POST /api/v1/system/settings/integrations/{pk}/test/` - Test connection + - Request: `{ "provider": "openai" }` or `{ "provider": "runware" }` +- `POST /api/v1/system/settings/integrations/{pk}/generate/` - Test image generation +- `GET /api/v1/system/settings/task_progress/{task_id}/` - Get Celery task progress +- `GET /api/v1/system/integrations/image_generation/` - Get image generation settings + +#### System Status + +**Base Path**: `/api/v1/system/` + +- `GET /api/v1/system/status/` - System health check (AllowAny) +- `GET /api/v1/system/ping/` - Health check endpoint (AllowAny) +- `GET /api/v1/system/request-metrics/{request_id}/` - Get request metrics for debugging + +### Billing Module Endpoints + +**Base Path**: `/api/v1/billing/` + +#### Credit Balance + +**Base Path**: `/api/v1/billing/credits/balance/` +**Permission**: IsAuthenticatedAndActive + HasTenantAccess + +- `GET /api/v1/billing/credits/balance/balance/` - Get credit balance + +**Response:** +```json +{ + "success": true, + "data": { + "credits": 1000, + "plan_credits_per_month": 500, + "credits_used_this_month": 250, + "credits_remaining": 750 + } +} +``` + +#### Credit Usage + +**Base Path**: `/api/v1/billing/credits/usage/` +**Permission**: IsAuthenticatedAndActive + HasTenantAccess + +**Standard CRUD:** +- `GET /api/v1/billing/credits/usage/` - List usage logs (paginated) +- `GET /api/v1/billing/credits/usage/{id}/` - Get usage log + +**Filtering:** +- `operation_type` - Filter by operation type +- `start_date` - Filter by start date (YYYY-MM-DD) +- `end_date` - Filter by end date (YYYY-MM-DD) + +**Custom Actions:** +- `GET /api/v1/billing/credits/usage/summary/` - Get usage summary +- `GET /api/v1/billing/credits/usage/limits/` - Get usage limits + +#### Credit Transactions + +**Base Path**: `/api/v1/billing/credits/transactions/` +**Permission**: IsAdminOrOwner + +**Standard CRUD:** +- `GET /api/v1/billing/credits/transactions/` - List transactions (paginated) +- `GET /api/v1/billing/credits/transactions/{id}/` - Get transaction + +**Filtering:** +- `transaction_type` - Filter by type +- `start_date` - Filter by start date +- `end_date` - Filter by end date + +--- + +## Integration Examples + +### Python + +```python +import requests + +BASE_URL = "https://api.igny8.com/api/v1" + +# Login +response = requests.post( + f"{BASE_URL}/auth/login/", + json={"email": "user@example.com", "password": "password"} +) +data = response.json() + +if data['success']: + token = data['data']['access'] + + # Use token for authenticated requests + headers = { + 'Authorization': f'Bearer {token}', + 'Content-Type': 'application/json' + } + + # Get keywords + response = requests.get( + f"{BASE_URL}/planner/keywords/?page=1&page_size=25", + headers=headers + ) + result = response.json() + + if result['success']: + keywords = result['results'] + print(f"Found {result['count']} keywords") + else: + print(f"Error: {result['error']}") +``` + +### JavaScript + +```javascript +const BASE_URL = 'https://api.igny8.com/api/v1'; + +// Login +const loginResponse = await fetch(`${BASE_URL}/auth/login/`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email: 'user@example.com', + password: 'password' + }) +}); + +const loginData = await loginResponse.json(); + +if (loginData.success) { + const token = loginData.data.access; + + // Use token for authenticated requests + const headers = { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + }; + + // Get keywords + const keywordsResponse = await fetch( + `${BASE_URL}/planner/keywords/?page=1&page_size=25`, + { headers } + ); + + const keywordsData = await keywordsResponse.json(); + + if (keywordsData.success) { + const keywords = keywordsData.results; + console.log(`Found ${keywordsData.count} keywords`); + } else { + console.error('Error:', keywordsData.error); + } +} +``` + +### 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"}' + +# Get keywords (with token) +curl -X GET https://api.igny8.com/api/v1/planner/keywords/ \ + -H "Authorization: Bearer YOUR_TOKEN" \ + -H "Content-Type: application/json" +``` + +### Frontend Integration (TypeScript) + +```typescript +// Using fetchAPI wrapper (automatically extracts data from unified format) +import { fetchAPI } from './services/api'; + +// List keywords +const response = await fetchAPI('/v1/planner/keywords/?page=1&page_size=25'); +// response is already extracted: { count, next, previous, results } + +// Create keyword +const newKeyword = await fetchAPI('/v1/planner/keywords/', { + method: 'POST', + body: JSON.stringify({ + keyword: 'example keyword', + site_id: 1, + sector_id: 2, + status: 'active' + }) +}); + +// Error handling +try { + const data = await fetchAPI('/v1/planner/keywords/'); +} catch (error) { + // Error is already parsed from unified format + console.error(error.message); + if (error.errors) { + // Handle field-specific errors + Object.keys(error.errors).forEach(field => { + console.error(`${field}: ${error.errors[field].join(', ')}`); + }); + } +} +``` + +### WordPress Plugin Integration (PHP) + +```php +class Igny8API { + private $base_url = 'https://api.igny8.com/api/v1'; + private $token; + + public function login($email, $password) { + $response = wp_remote_post($this->base_url . '/auth/login/', [ + 'headers' => ['Content-Type' => 'application/json'], + 'body' => json_encode(['email' => $email, 'password' => $password]) + ]); + + $data = json_decode(wp_remote_retrieve_body($response), true); + + if ($data['success']) { + $this->token = $data['data']['access']; + return true; + } + + return false; + } + + public function getKeywords($page = 1, $page_size = 25) { + $response = wp_remote_get( + $this->base_url . '/planner/keywords/?page=' . $page . '&page_size=' . $page_size, + [ + 'headers' => [ + 'Authorization' => 'Bearer ' . $this->token, + 'Content-Type' => 'application/json' + ] + ] + ); + + $data = json_decode(wp_remote_retrieve_body($response), true); + + if ($data['success']) { + return $data['results']; + } + + return []; + } +} +``` + +--- + +## Testing & Debugging + +### Request ID Tracking + +Every API request includes a unique `request_id` in the response. Use this ID for: +- Debugging issues +- Log correlation +- Support requests + +The `request_id` is included in: +- All success responses +- All error responses +- Response headers (`X-Request-ID`) + +### Progress Tracking (AI Functions) + +All AI functions return a Celery task ID for progress tracking: + +**Request:** +```json +POST /api/v1/planner/keywords/auto_cluster/ +{ + "ids": [1, 2, 3, 4, 5], + "sector_id": 1 +} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "task_id": "abc123-def456-ghi789" + } +} +``` + +**Poll Progress:** +```json +GET /api/v1/system/settings/task_progress/abc123-def456-ghi789/ +``` + +**Progress Response:** +```json +{ + "state": "PROGRESS", + "meta": { + "phase": "AI_CALL", + "percentage": 50, + "message": "Processing keywords...", + "request_steps": [...], + "response_steps": [...], + "cost": 0.05, + "tokens": 1500 + } +} +``` + +### Error Handling Best Practices + +**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 + +### Rate Limit Monitoring + +```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'); +} +``` + +--- + +## 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 + +### Changelog + +All API changes are documented in `CHANGELOG.md` with: +- Version number +- Date +- Type (Added, Changed, Fixed, Deprecated, Removed, Security) +- Description +- Affected areas +- Migration notes (if applicable) + +--- + +## Summary + +### Implementation Status + +✅ **100% Complete** - All endpoints implemented with: +- Unified response format (`{success, data, message, errors, request_id}`) +- Proper authentication and authorization (JWT Bearer tokens) +- Rate limiting configured (scoped by operation type) +- Error handling standardized (centralized exception handler) +- Request ID tracking (every request has unique ID) +- Complete Swagger/OpenAPI documentation +- Tenant/site/sector scoping (automatic filtering) +- Pagination standardized (default: 10, max: 100) + +### Key Features + +- **100+ endpoints** across 5 modules +- **Unified response format** for all endpoints +- **Scoped rate limiting** (10-100 requests/minute depending on operation) +- **Layered authorization** (Authentication → Tenant → Role → Site/Sector) +- **Complete OpenAPI documentation** (Swagger UI, ReDoc) +- **Request ID tracking** for debugging +- **Progress tracking** for AI functions +- **Comprehensive error handling** with clear messages + +### Access Points + +- **Interactive Documentation**: `https://api.igny8.com/api/docs/` +- **ReDoc**: `https://api.igny8.com/api/redoc/` +- **OpenAPI Schema**: `https://api.igny8.com/api/schema/` + +--- + +**Last Updated**: 2025-01-XX +**API Version**: 1.0.0 +**Status**: ✅ **100% IMPLEMENTED** + diff --git a/docs/API-DOCUMENTATION.md b/docs/API-DOCUMENTATION.md deleted file mode 100644 index 2b724605..00000000 --- a/docs/API-DOCUMENTATION.md +++ /dev/null @@ -1,545 +0,0 @@ -# IGNY8 API Documentation v1.0 - -**Base URL**: `https://api.igny8.com/api/v1/` -**Version**: 1.0.0 -**Last Updated**: 2025-11-16 - -## Quick Links - -- [Interactive API Documentation (Swagger UI)](#swagger-ui) -- [Authentication Guide](#authentication) -- [Response Format](#response-format) -- [Error Handling](#error-handling) -- [Rate Limiting](#rate-limiting) -- [Pagination](#pagination) -- [Endpoint Reference](#endpoint-reference) - ---- - -## Swagger UI - -Interactive API documentation is available at: -- **Swagger UI**: `https://api.igny8.com/api/docs/` -- **ReDoc**: `https://api.igny8.com/api/redoc/` -- **OpenAPI Schema**: `https://api.igny8.com/api/schema/` - -The Swagger UI provides: -- Interactive endpoint testing -- Request/response examples -- Authentication testing -- Schema definitions -- Code samples in multiple languages - ---- - -## Authentication - -### JWT Bearer Token - -All endpoints require JWT Bearer token authentication except: -- `POST /api/v1/auth/login/` - User login -- `POST /api/v1/auth/register/` - User registration - -### Getting an Access Token - -**Login Endpoint:** -```http -POST /api/v1/auth/login/ -Content-Type: application/json - -{ - "email": "user@example.com", - "password": "your_password" -} -``` - -**Response:** -```json -{ - "success": true, - "data": { - "user": { - "id": 1, - "email": "user@example.com", - "username": "user", - "role": "owner" - }, - "access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." - }, - "request_id": "uuid" -} -``` - -### Using the Token - -Include the token in the `Authorization` header: - -```http -GET /api/v1/planner/keywords/ -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... -Content-Type: application/json -``` - -### Token Expiration - -- **Access Token**: 15 minutes -- **Refresh Token**: 7 days - -Use the refresh token to get a new access token: -```http -POST /api/v1/auth/refresh/ -Content-Type: application/json - -{ - "refresh": "your_refresh_token" -} -``` - ---- - -## Response Format - -### Success Response - -All successful responses follow this unified format: - -```json -{ - "success": true, - "data": { - "id": 1, - "name": "Example", - ... - }, - "message": "Optional success message", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -### Paginated Response - -List endpoints return paginated data: - -```json -{ - "success": true, - "count": 100, - "next": "https://api.igny8.com/api/v1/planner/keywords/?page=2", - "previous": null, - "results": [ - {"id": 1, "name": "Keyword 1"}, - {"id": 2, "name": "Keyword 2"}, - ... - ], - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -### Error Response - -All error responses follow this unified format: - -```json -{ - "success": false, - "error": "Validation failed", - "errors": { - "email": ["This field is required"], - "password": ["Password too short"] - }, - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - ---- - -## Error Handling - -### HTTP Status Codes - -| Code | Meaning | Description | -|------|---------|-------------| -| 200 | OK | Request successful | -| 201 | Created | Resource created successfully | -| 204 | No Content | Resource deleted successfully | -| 400 | Bad Request | Validation error or invalid request | -| 401 | Unauthorized | Authentication required | -| 403 | Forbidden | Permission denied | -| 404 | Not Found | Resource not found | -| 409 | Conflict | Resource conflict (e.g., duplicate) | -| 422 | Unprocessable Entity | Validation failed | -| 429 | Too Many Requests | Rate limit exceeded | -| 500 | Internal Server Error | Server error | - -### Error Response Structure - -All errors include: -- `success`: Always `false` -- `error`: Top-level error message -- `errors`: Field-specific errors (for validation errors) -- `request_id`: Unique request ID for debugging - -### Example Error Responses - -**Validation Error (400):** -```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" -} -``` - -**Authentication Error (401):** -```json -{ - "success": false, - "error": "Authentication required", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Permission Error (403):** -```json -{ - "success": false, - "error": "Permission denied", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Not Found (404):** -```json -{ - "success": false, - "error": "Resource not found", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -**Rate Limit (429):** -```json -{ - "success": false, - "error": "Rate limit exceeded", - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - ---- - -## Rate Limiting - -Rate limits are scoped by operation type. Check response headers for limit information: - -- `X-Throttle-Limit`: Maximum requests allowed -- `X-Throttle-Remaining`: Remaining requests in current window -- `X-Throttle-Reset`: Time when limit resets (Unix timestamp) - -### Rate Limit Scopes - -| Scope | Limit | Description | -|-------|-------|-------------| -| `ai_function` | 10/min | AI content generation, clustering | -| `image_gen` | 15/min | Image generation | -| `content_write` | 30/min | Content creation, updates | -| `content_read` | 100/min | Content listing, retrieval | -| `auth` | 20/min | Login, register, password reset | -| `auth_strict` | 5/min | Sensitive auth operations | -| `planner` | 60/min | Keyword, cluster, idea operations | -| `planner_ai` | 10/min | AI-powered planner operations | -| `writer` | 60/min | Task, content management | -| `writer_ai` | 10/min | AI-powered writer operations | -| `system` | 100/min | Settings, prompts, profiles | -| `system_admin` | 30/min | Admin-only system operations | -| `billing` | 30/min | Credit queries, usage logs | -| `billing_admin` | 10/min | Credit management (admin) | -| `default` | 100/min | Default for endpoints without scope | - -### Handling Rate Limits - -When rate limited (429), the response includes: -- Error message: "Rate limit exceeded" -- Headers with reset time -- Wait until `X-Throttle-Reset` before retrying - -**Example:** -```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" -} -``` - ---- - -## Pagination - -List endpoints support pagination with query parameters: - -- `page`: Page number (default: 1) -- `page_size`: Items per page (default: 10, max: 100) - -### Example Request - -```http -GET /api/v1/planner/keywords/?page=2&page_size=20 -``` - -### Paginated Response - -```json -{ - "success": true, - "count": 100, - "next": "https://api.igny8.com/api/v1/planner/keywords/?page=3&page_size=20", - "previous": "https://api.igny8.com/api/v1/planner/keywords/?page=1&page_size=20", - "results": [ - {"id": 21, "name": "Keyword 21"}, - {"id": 22, "name": "Keyword 22"}, - ... - ], - "request_id": "550e8400-e29b-41d4-a716-446655440000" -} -``` - -### Pagination Fields - -- `count`: Total number of items -- `next`: URL to next page (null if last page) -- `previous`: URL to previous page (null if first page) -- `results`: Array of items for current page - ---- - -## Endpoint Reference - -### Authentication Endpoints - -#### Login -```http -POST /api/v1/auth/login/ -``` - -#### Register -```http -POST /api/v1/auth/register/ -``` - -#### Refresh Token -```http -POST /api/v1/auth/refresh/ -``` - -### Planner Endpoints - -#### List Keywords -```http -GET /api/v1/planner/keywords/ -``` - -#### Create Keyword -```http -POST /api/v1/planner/keywords/ -``` - -#### Get Keyword -```http -GET /api/v1/planner/keywords/{id}/ -``` - -#### Update Keyword -```http -PUT /api/v1/planner/keywords/{id}/ -PATCH /api/v1/planner/keywords/{id}/ -``` - -#### Delete Keyword -```http -DELETE /api/v1/planner/keywords/{id}/ -``` - -#### Auto Cluster Keywords -```http -POST /api/v1/planner/keywords/auto_cluster/ -``` - -### Writer Endpoints - -#### List Tasks -```http -GET /api/v1/writer/tasks/ -``` - -#### Create Task -```http -POST /api/v1/writer/tasks/ -``` - -### System Endpoints - -#### System Status -```http -GET /api/v1/system/status/ -``` - -#### List Prompts -```http -GET /api/v1/system/prompts/ -``` - -### Billing Endpoints - -#### Credit Balance -```http -GET /api/v1/billing/credits/balance/balance/ -``` - -#### Usage Summary -```http -GET /api/v1/billing/credits/usage/summary/ -``` - ---- - -## Code Examples - -### Python - -```python -import requests - -BASE_URL = "https://api.igny8.com/api/v1" - -# Login -response = requests.post( - f"{BASE_URL}/auth/login/", - json={"email": "user@example.com", "password": "password"} -) -data = response.json() - -if data['success']: - token = data['data']['access'] - - # Use token for authenticated requests - headers = { - 'Authorization': f'Bearer {token}', - 'Content-Type': 'application/json' - } - - # Get keywords - response = requests.get( - f"{BASE_URL}/planner/keywords/", - headers=headers - ) - keywords_data = response.json() - - if keywords_data['success']: - keywords = keywords_data['results'] - print(f"Found {keywords_data['count']} keywords") - else: - print(f"Error: {keywords_data['error']}") -else: - print(f"Login failed: {data['error']}") -``` - -### JavaScript - -```javascript -const BASE_URL = 'https://api.igny8.com/api/v1'; - -// Login -const loginResponse = await fetch(`${BASE_URL}/auth/login/`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - email: 'user@example.com', - password: 'password' - }) -}); - -const loginData = await loginResponse.json(); - -if (loginData.success) { - const token = loginData.data.access; - - // Use token for authenticated requests - const headers = { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json' - }; - - // Get keywords - const keywordsResponse = await fetch( - `${BASE_URL}/planner/keywords/`, - { headers } - ); - - const keywordsData = await keywordsResponse.json(); - - if (keywordsData.success) { - const keywords = keywordsData.results; - console.log(`Found ${keywordsData.count} keywords`); - } else { - console.error('Error:', keywordsData.error); - } -} else { - console.error('Login failed:', loginData.error); -} -``` - -### 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"}' - -# Get keywords (with token) -curl -X GET https://api.igny8.com/api/v1/planner/keywords/ \ - -H "Authorization: Bearer YOUR_TOKEN" \ - -H "Content-Type: application/json" -``` - ---- - -## Request ID - -Every API request includes a unique `request_id` in the response. Use this ID for: -- Debugging issues -- Log correlation -- Support requests - -The `request_id` is included in: -- All success responses -- All error responses -- Response headers (`X-Request-ID`) - ---- - -## Support - -For API support: -- Check the [Interactive Documentation](https://api.igny8.com/api/docs/) -- Review [Error Codes Reference](ERROR-CODES.md) -- Contact support with your `request_id` - ---- - -**Last Updated**: 2025-11-16 -**API Version**: 1.0.0 - diff --git a/docs/DOCUMENTATION-SUMMARY.md b/docs/DOCUMENTATION-SUMMARY.md deleted file mode 100644 index ac9a2dcb..00000000 --- a/docs/DOCUMENTATION-SUMMARY.md +++ /dev/null @@ -1,210 +0,0 @@ -# Documentation Implementation Summary - -**Section 2: Documentation - COMPLETE** ✅ - -**Date Completed**: 2025-11-16 -**Last Updated**: 2025-01-XX -**Status**: All Documentation Complete and Ready - -**API Standard v1.0**: ✅ **100% COMPLIANT** - All remaining items completed - ---- - -## Implementation Overview - -Complete documentation system for IGNY8 API v1.0 including: -- OpenAPI 3.0 schema generation -- Interactive Swagger UI -- Comprehensive documentation files -- Code examples and integration guides - ---- - -## OpenAPI/Swagger Integration ✅ - -### Configuration -- ✅ Installed `drf-spectacular>=0.27.0` -- ✅ Added to `INSTALLED_APPS` -- ✅ Configured `SPECTACULAR_SETTINGS` with comprehensive description -- ✅ Added URL endpoints for schema and documentation - -### Endpoints Created -- ✅ `/api/schema/` - OpenAPI 3.0 schema (JSON/YAML) -- ✅ `/api/docs/` - Swagger UI (interactive documentation) -- ✅ `/api/redoc/` - ReDoc (alternative documentation UI) - -### Features -- ✅ Comprehensive API description with features overview -- ✅ Authentication documentation (JWT Bearer tokens) -- ✅ Response format examples -- ✅ Rate limiting documentation -- ✅ Pagination documentation -- ✅ Endpoint tags (Authentication, Planner, Writer, System, Billing) -- ✅ Code samples in Python and JavaScript -- ✅ Custom authentication extensions - ---- - -## 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 -- Best practices -- Testing examples - -### 7. README.md -**Purpose**: Documentation index -**Contents**: -- Documentation index -- Quick start guide -- Links to all documentation files -- Support information - ---- - -## Schema Extensions ✅ - -### Custom Authentication Extensions -- ✅ `JWTAuthenticationExtension` - JWT Bearer token authentication -- ✅ `CSRFExemptSessionAuthenticationExtension` - Session authentication -- ✅ Proper OpenAPI security scheme definitions - -**File**: `backend/igny8_core/api/schema_extensions.py` - ---- - -## Verification - -### Schema Generation -```bash -python manage.py spectacular --color -``` -**Status**: ✅ Schema generates successfully - -### Documentation Endpoints -- ✅ `/api/schema/` - OpenAPI schema -- ✅ `/api/docs/` - Swagger UI -- ✅ `/api/redoc/` - ReDoc - -### Documentation Files -- ✅ 7 comprehensive documentation files created -- ✅ All files include code examples -- ✅ All files include best practices -- ✅ All files properly formatted - ---- - -## Documentation Statistics - -- **Total Documentation Files**: 7 -- **Total Pages**: ~100+ pages of documentation -- **Code Examples**: Python, JavaScript, PHP, cURL -- **Coverage**: 100% of API features documented - ---- - -## What's Documented - -### ✅ API Features -- Unified response format -- Authentication and authorization -- Error handling -- Rate limiting -- Pagination -- Request ID tracking - -### ✅ Integration Guides -- Python integration -- JavaScript integration -- WordPress plugin integration -- Migration from legacy format - -### ✅ Reference Materials -- Error codes -- Rate limit scopes -- Endpoint reference -- Code examples - ---- - -## 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` - ---- - -## Next Steps - -1. ✅ Documentation complete -2. ✅ Swagger UI accessible -3. ✅ All guides created -4. ✅ Changelog updated - -**Section 2: Documentation is COMPLETE** ✅ - ---- - -**Last Updated**: 2025-11-16 -**API Version**: 1.0.0 - diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index a07c1379..00000000 --- a/docs/README.md +++ /dev/null @@ -1,113 +0,0 @@ -# IGNY8 API Documentation - -**Version**: 1.0.0 -**Last Updated**: 2025-11-16 - -Complete documentation for the IGNY8 Unified API Standard v1.0. - ---- - -## Documentation Index - -### Getting Started - -1. **[API Documentation](API-DOCUMENTATION.md)** - Complete API reference with examples - - Quick start guide - - Endpoint reference - - Code examples (Python, JavaScript, cURL) - - Response format details - -2. **[Authentication Guide](AUTHENTICATION-GUIDE.md)** - Authentication and authorization - - JWT Bearer token authentication - - Token management - - Code examples - - Security best practices - -3. **[Error Codes Reference](ERROR-CODES.md)** - Complete error code reference - - HTTP status codes - - Field-specific errors - - Error handling best practices - - Common error scenarios - -4. **[Rate Limiting Guide](RATE-LIMITING.md)** - Rate limiting and throttling - - Rate limit scopes - - Handling rate limits - - Best practices - - Code examples - -### Integration Guides - -5. **[Migration Guide](MIGRATION-GUIDE.md)** - Migrating to API v1.0 - - What changed - - Step-by-step migration - - Code examples - - Breaking changes - -6. **[WordPress Plugin Integration](WORDPRESS-PLUGIN-INTEGRATION.md)** - WordPress integration - - PHP API client - - Authentication - - Error handling - - Best practices - -### 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/` - ---- - -## Quick Start - -### 1. Get Access Token - -```bash -curl -X POST https://api.igny8.com/api/v1/auth/login/ \ - -H "Content-Type: application/json" \ - -d '{"email":"user@example.com","password":"password"}' -``` - -### 2. Use Token - -```bash -curl -X GET https://api.igny8.com/api/v1/planner/keywords/ \ - -H "Authorization: Bearer YOUR_TOKEN" \ - -H "Content-Type: application/json" -``` - -### 3. Handle Response - -All responses follow unified format: - -```json -{ - "success": true, - "data": {...}, - "request_id": "uuid" -} -``` - ---- - -## API Standard Features - -- ✅ **Unified Response Format** - Consistent JSON structure -- ✅ **Layered Authorization** - Authentication → Tenant → Role → Site/Sector -- ✅ **Centralized Error Handling** - All errors in unified format -- ✅ **Scoped Rate Limiting** - Different limits per operation type -- ✅ **Tenant Isolation** - Account/site/sector scoping -- ✅ **Request Tracking** - Unique request ID for debugging - ---- - -## Support - -- **Interactive Docs**: [Swagger UI](https://api.igny8.com/api/docs/) -- **Error Reference**: [Error Codes](ERROR-CODES.md) -- **Contact**: Include `request_id` from responses when contacting support - ---- - -**Last Updated**: 2025-11-16 -**API Version**: 1.0.0 - diff --git a/unified-api/API-ENDPOINTS-ANALYSIS.md b/unified-api/API-ENDPOINTS-ANALYSIS.md deleted file mode 100644 index 24f4ad9e..00000000 --- a/unified-api/API-ENDPOINTS-ANALYSIS.md +++ /dev/null @@ -1,1386 +0,0 @@ -# IGNY8 API Endpoints - Complete Analysis - -**Date:** 2025-01-XX -**Purpose:** Comprehensive analysis of all existing API endpoints in the Django deployment, including request/response formats, authentication, rate limiting, usage patterns, and third-party integrations. - ---- - -## Executive Summary - -**Base URL:** `/api/v1/` - -**Total Endpoints:** 100+ endpoints across 5 main modules - -**Authentication:** JWT Bearer tokens (primary), Session authentication (fallback), Basic authentication (fallback) - -**Rate Limiting:** Not currently implemented (planned for future) - -**Response Format:** Standardized JSON with `success`, `data`, `message`, `errors` fields - -**Pagination:** Custom pagination with `page_size` parameter (default: 10, max: 100) - - ---- - -## Table of Contents - -1. [API Architecture Overview](#api-architecture-overview) -2. [Authentication & Authorization](#authentication--authorization) -3. [Response Format Standards](#response-format-standards) -4. [Pagination Format](#pagination-format) -5. [Auth Module Endpoints](#auth-module-endpoints) -6. [Planner Module Endpoints](#planner-module-endpoints) -7. [Writer Module Endpoints](#writer-module-endpoints) -8. [System Module Endpoints](#system-module-endpoints) -9. [Billing Module Endpoints](#billing-module-endpoints) -10. [Frontend API Usage Patterns](#frontend-api-usage-patterns) -11. [Third-Party Integrations](#third-party-integrations) -12. [Dependencies](#dependencies) -13. [Standardization Recommendations](#standardization-recommendations) - ---- - -## API Architecture Overview - -### Base URL Structure - -``` -/api/v1/ -├── auth/ # Authentication and user management -├── planner/ # Keywords, clusters, content ideas -├── writer/ # Tasks, content, images -├── system/ # Settings, integrations, prompts -└── billing/ # Credits, transactions, usage -``` - -### Technology Stack - -- **Framework**: Django REST Framework (DRF) -- **Router**: DefaultRouter (RESTful ViewSets) -- **Authentication**: Custom JWT + Session + Basic -- **Pagination**: CustomPageNumberPagination -- **Filtering**: DjangoFilterBackend, SearchFilter, OrderingFilter -- **Serialization**: DRF Serializers - -### Base Classes - -**AccountModelViewSet:** -- Automatic account filtering -- Admin/Developer override (bypasses account filtering) -- System account users bypass account filtering -- Sets account on create operations - -**SiteSectorModelViewSet:** -- Inherits from AccountModelViewSet -- Additional site/sector filtering -- Site access control (based on user role) -- Sector validation (must belong to site) - ---- - -## Authentication & Authorization - -### Authentication Methods - -**1. JWT Authentication (Primary)** -- **Class**: `igny8_core.api.authentication.JWTAuthentication` -- **Header**: `Authorization: Bearer ` -- **Token Type**: Access token (type: 'access') -- **Expiry**: 15 minutes (configurable via `JWT_ACCESS_TOKEN_EXPIRY`) -- **Token Payload**: Contains `user_id`, `account_id`, `type: 'access'` -- **Account Context**: Sets `request.account` from token - -**2. Session Authentication (Fallback)** -- **Class**: `igny8_core.api.authentication.CSRFExemptSessionAuthentication` -- **Method**: Session cookies (CSRF exempt for API) -- **Use Case**: Admin panel, fallback when JWT fails - -**3. Basic Authentication (Fallback)** -- **Class**: `rest_framework.authentication.BasicAuthentication` -- **Method**: HTTP Basic Auth -- **Use Case**: Fallback authentication - -### Authentication Configuration - -**Location**: `backend/igny8_core/settings.py` - -```python -REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'igny8_core.api.authentication.JWTAuthentication', # Primary - 'igny8_core.api.authentication.CSRFExemptSessionAuthentication', # Fallback - 'rest_framework.authentication.BasicAuthentication', # Fallback - ], - 'DEFAULT_PERMISSION_CLASSES': [ - 'rest_framework.permissions.AllowAny', # Default: AllowAny - ], -} -``` - -### Permission Classes - -**Default**: `AllowAny` (most endpoints) - -**Custom Permission Classes:** -- `IsAuthenticated`: Requires authentication -- `IsOwnerOrAdmin`: Owner or Admin role required -- `IsEditorOrAbove`: Editor, Admin, or Owner role required -- ViewSet-level overrides: Many ViewSets set `permission_classes = []` (AllowAny) - -### Account Context Middleware - -**Class**: `igny8_core.auth.middleware.AccountContextMiddleware` - -**Functionality:** -- Extracts account ID from JWT token -- Loads Account object -- Sets `request.account` for all requests -- Enables automatic account filtering in ViewSets - ---- - -## Response Format Standards - -### Success Response - -```json -{ - "success": true, - "data": { ... }, - "message": "Optional success message" -} -``` - -### Error Response - -```json -{ - "success": false, - "error": "Error message", - "errors": { - "field_name": ["Error detail"] - } -} -``` - -### Pagination Response - -```json -{ - "count": 100, - "next": "http://api.igny8.com/api/v1/endpoint/?page=2", - "previous": null, - "results": [ ... ] -} -``` - -### Standard Response Fields - -- **success**: Boolean indicating success/failure -- **data**: Response data (object or array) -- **message**: Human-readable message (optional) -- **error**: Error message (on failure) -- **errors**: Validation errors object (on failure) - ---- - -## Pagination Format - -### CustomPageNumberPagination - -**Class**: `igny8_core.api.pagination.CustomPageNumberPagination` - -**Configuration:** -- Default page size: 10 -- Max page size: 100 -- Query parameter: `page_size` (optional) -- Page parameter: `page` (default: 1) - -**Example Request:** -``` -GET /api/v1/planner/keywords/?page=2&page_size=25 -``` - -**Response:** -```json -{ - "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": [ ... ] -} -``` - ---- - -## Auth Module Endpoints - -**Base Path**: `/api/v1/auth/` - -### Authentication Endpoints - -#### POST `/api/v1/auth/register/` -**Purpose**: User registration - -**Authentication**: None (AllowAny) - -**Request Body:** -```json -{ - "email": "user@example.com", - "password": "password123", - "password_confirm": "password123" -} -``` - -**Response:** -```json -{ - "success": true, - "message": "Registration successful", - "user": { - "id": 1, - "email": "user@example.com", - "role": "owner", - "account": { ... } - } -} -``` - -**Status Codes**: 201 (Created), 400 (Bad Request) - -#### POST `/api/v1/auth/login/` -**Purpose**: User login - -**Authentication**: None (AllowAny) - -**Request Body:** -```json -{ - "email": "user@example.com", - "password": "password123" -} -``` - -**Response:** -```json -{ - "success": true, - "message": "Login successful", - "user": { ... }, - "tokens": { - "access": "eyJ0eXAiOiJKV1QiLCJhbGc...", - "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...", - "access_expires_at": "2025-01-15T12:30:00Z", - "refresh_expires_at": "2025-01-22T12:00:00Z" - } -} -``` - -**Status Codes**: 200 (OK), 401 (Unauthorized), 400 (Bad Request) - -#### POST `/api/v1/auth/change-password/` -**Purpose**: Change user password - -**Authentication**: Required (IsAuthenticated) - -**Request Body:** -```json -{ - "old_password": "oldpass123", - "new_password": "newpass123", - "new_password_confirm": "newpass123" -} -``` - -**Response:** -```json -{ - "success": true, - "message": "Password changed successfully" -} -``` - -**Status Codes**: 200 (OK), 400 (Bad Request) - -#### GET `/api/v1/auth/me/` -**Purpose**: Get current user information - -**Authentication**: Required (IsAuthenticated) - -**Response:** -```json -{ - "success": true, - "user": { - "id": 1, - "email": "user@example.com", - "role": "owner", - "account": { ... }, - "accessible_sites": [ ... ] - } -} -``` - -**Status Codes**: 200 (OK), 401 (Unauthorized) - -### User Management Endpoints - -#### ViewSet: `UsersViewSet` -**Base Path**: `/api/v1/auth/users/` - -**Permission**: IsOwnerOrAdmin - -**Standard CRUD:** -- `GET /api/v1/auth/users/` - List users -- `POST /api/v1/auth/users/` - Create user -- `GET /api/v1/auth/users/{id}/` - Get user -- `PUT /api/v1/auth/users/{id}/` - Update user -- `DELETE /api/v1/auth/users/{id}/` - Delete user - -**Custom Actions:** -- `POST /api/v1/auth/users/invite/` - Invite user -- `POST /api/v1/auth/users/{id}/activate/` - Activate user - -### Account Management Endpoints - -#### ViewSet: `AccountsViewSet` -**Base Path**: `/api/v1/auth/accounts/` - -**Permission**: IsOwnerOrAdmin - -**Standard CRUD:** -- `GET /api/v1/auth/accounts/` - List accounts -- `POST /api/v1/auth/accounts/` - Create account -- `GET /api/v1/auth/accounts/{id}/` - Get account -- `PUT /api/v1/auth/accounts/{id}/` - Update account -- `DELETE /api/v1/auth/accounts/{id}/` - Delete account - -### Site Management Endpoints - -#### ViewSet: `SiteViewSet` -**Base Path**: `/api/v1/auth/sites/` - -**Permission**: IsEditorOrAbove - -**Standard CRUD:** -- `GET /api/v1/auth/sites/` - List sites -- `POST /api/v1/auth/sites/` - Create site -- `GET /api/v1/auth/sites/{id}/` - Get site -- `PUT /api/v1/auth/sites/{id}/` - Update site -- `DELETE /api/v1/auth/sites/{id}/` - Delete site - -**Custom Actions:** -- `GET /api/v1/auth/sites/{id}/sectors/` - Get site sectors -- `POST /api/v1/auth/sites/{id}/set_active/` - Set active site -- `POST /api/v1/auth/sites/{id}/select_sectors/` - Select sectors - -### Sector Management Endpoints - -#### ViewSet: `SectorViewSet` -**Base Path**: `/api/v1/auth/sectors/` - -**Permission**: IsEditorOrAbove - -**Standard CRUD:** -- `GET /api/v1/auth/sectors/` - List sectors -- `POST /api/v1/auth/sectors/` - Create sector -- `GET /api/v1/auth/sectors/{id}/` - Get sector -- `PUT /api/v1/auth/sectors/{id}/` - Update sector -- `DELETE /api/v1/auth/sectors/{id}/` - Delete sector - -### Plan Management Endpoints - -#### ViewSet: `PlanViewSet` -**Base Path**: `/api/v1/auth/plans/` - -**Permission**: AllowAny (read-only) - -**Endpoints:** -- `GET /api/v1/auth/plans/` - List plans -- `GET /api/v1/auth/plans/{id}/` - Get plan - -### Industry Management Endpoints - -#### ViewSet: `IndustryViewSet` -**Base Path**: `/api/v1/auth/industries/` - -**Permission**: AllowAny (read-only) - -**Endpoints:** -- `GET /api/v1/auth/industries/` - List industries -- `GET /api/v1/auth/industries/{id}/` - Get industry - -### Seed Keyword Endpoints - -#### ViewSet: `SeedKeywordViewSet` -**Base Path**: `/api/v1/auth/seed-keywords/` - -**Permission**: AllowAny (read-only) - -**Endpoints:** -- `GET /api/v1/auth/seed-keywords/` - List seed keywords -- `GET /api/v1/auth/seed-keywords/{id}/` - Get seed keyword - -### Site Access Management Endpoints - -#### ViewSet: `SiteUserAccessViewSet` -**Base Path**: `/api/v1/auth/site-access/` - -**Permission**: IsOwnerOrAdmin - -**Standard CRUD:** -- `GET /api/v1/auth/site-access/` - List site access records -- `POST /api/v1/auth/site-access/` - Grant site access -- `GET /api/v1/auth/site-access/{id}/` - Get site access -- `PUT /api/v1/auth/site-access/{id}/` - Update site access -- `DELETE /api/v1/auth/site-access/{id}/` - Revoke site access - -### Subscription Management Endpoints - -#### ViewSet: `SubscriptionsViewSet` -**Base Path**: `/api/v1/auth/subscriptions/` - -**Permission**: IsOwnerOrAdmin - -**Standard CRUD:** -- `GET /api/v1/auth/subscriptions/` - List subscriptions -- `POST /api/v1/auth/subscriptions/` - Create subscription -- `GET /api/v1/auth/subscriptions/{id}/` - Get subscription -- `PUT /api/v1/auth/subscriptions/{id}/` - Update subscription -- `DELETE /api/v1/auth/subscriptions/{id}/` - Delete subscription - -**Custom Actions:** -- `GET /api/v1/auth/subscriptions/by-account/{account_id}/` - Get subscriptions by account - ---- - -## Planner Module Endpoints - -**Base Path**: `/api/v1/planner/` - -### Keyword Management Endpoints - -#### ViewSet: `KeywordViewSet` -**Base Path**: `/api/v1/planner/keywords/` - -**Permission**: AllowAny (default) - -**Inherits**: SiteSectorModelViewSet (automatic account/site/sector filtering) - -**Standard CRUD:** -- `GET /api/v1/planner/keywords/` - List keywords (paginated) -- `POST /api/v1/planner/keywords/` - Create keyword -- `GET /api/v1/planner/keywords/{id}/` - Get keyword -- `PUT /api/v1/planner/keywords/{id}/` - Update keyword -- `DELETE /api/v1/planner/keywords/{id}/` - Delete keyword - -**Filtering:** -- `status`: Filter by status -- `cluster_id`: Filter by cluster -- `seed_keyword__intent`: Filter by intent -- `seed_keyword_id`: Filter by seed keyword ID -- `difficulty_min`: Minimum difficulty -- `difficulty_max`: Maximum difficulty -- `volume_min`: Minimum volume -- `volume_max`: Maximum volume -- `site_id`: Filter by site (query param) -- `sector_id`: Filter by sector (query param) - -**Search:** -- `search`: Search by keyword text (searches `seed_keyword__keyword` field) - -**Ordering:** -- `ordering`: Order by `created_at`, `seed_keyword__volume`, `seed_keyword__difficulty` -- Default: `-created_at` (newest first) - -**Custom Actions:** -- `POST /api/v1/planner/keywords/bulk_delete/` - Bulk delete keywords - - **Request**: `{ "ids": [1, 2, 3] }` - - **Response**: `{ "deleted_count": 3 }` - -- `POST /api/v1/planner/keywords/bulk_update_status/` - Bulk update status - - **Request**: `{ "ids": [1, 2, 3], "status": "active" }` - - **Response**: `{ "updated_count": 3 }` - -- `POST /api/v1/planner/keywords/bulk_add_from_seed/` - Add keywords from seed library - - **Request**: `{ "seed_keyword_ids": [1, 2, 3], "site_id": 1, "sector_id": 1 }` - - **Response**: `{ "added_count": 3, "keywords": [ ... ] }` - -- `GET /api/v1/planner/keywords/export/` - Export keywords to CSV - - **Query Params**: Same filtering as list endpoint - - **Response**: CSV file download - -- `POST /api/v1/planner/keywords/import_keywords/` - Import keywords from CSV - - **Request**: Multipart form data with CSV file - - **Response**: `{ "imported_count": 10, "errors": [] }` - -- `POST /api/v1/planner/keywords/auto_cluster/` - Auto-cluster keywords using AI - - **Request**: `{ "ids": [1, 2, 3, ...], "sector_id": 1 }` - - **Response**: `{ "success": true, "task_id": "abc123" }` - - **Max Keywords**: 20 per batch - - **Returns**: Celery task ID for progress tracking - -### Cluster Management Endpoints - -#### ViewSet: `ClusterViewSet` -**Base Path**: `/api/v1/planner/clusters/` - -**Permission**: AllowAny (default) - -**Inherits**: SiteSectorModelViewSet - -**Standard CRUD:** -- `GET /api/v1/planner/clusters/` - List clusters -- `POST /api/v1/planner/clusters/` - Create cluster -- `GET /api/v1/planner/clusters/{id}/` - Get cluster -- `PUT /api/v1/planner/clusters/{id}/` - Update cluster -- `DELETE /api/v1/planner/clusters/{id}/` - Delete cluster - -**Filtering:** -- `status`: Filter by status -- `site_id`: Filter by site (query param) -- `sector_id`: Filter by sector (query param) - -**Search:** -- `search`: Search by cluster name - -**Ordering:** -- `ordering`: Order by `keywords_count`, `volume`, `created_at` - -**Custom Actions:** -- `POST /api/v1/planner/clusters/bulk_delete/` - Bulk delete clusters - - **Request**: `{ "ids": [1, 2, 3] }` - - **Response**: `{ "deleted_count": 3 }` - -- `POST /api/v1/planner/clusters/auto_generate_ideas/` - Auto-generate content ideas - - **Request**: `{ "ids": [1] }` (max 1 cluster per batch) - - **Response**: `{ "success": true, "task_id": "abc123" }` - - **Returns**: Celery task ID for progress tracking - -### Content Ideas Endpoints - -#### ViewSet: `ContentIdeasViewSet` -**Base Path**: `/api/v1/planner/ideas/` - -**Permission**: AllowAny (default) - -**Inherits**: SiteSectorModelViewSet - -**Standard CRUD:** -- `GET /api/v1/planner/ideas/` - List content ideas -- `POST /api/v1/planner/ideas/` - Create content idea -- `GET /api/v1/planner/ideas/{id}/` - Get content idea -- `PUT /api/v1/planner/ideas/{id}/` - Update content idea -- `DELETE /api/v1/planner/ideas/{id}/` - Delete content idea - -**Filtering:** -- `status`: Filter by status -- `cluster_id`: Filter by cluster -- `content_type`: Filter by content type -- `site_id`: Filter by site (query param) -- `sector_id`: Filter by sector (query param) - -**Search:** -- `search`: Search by idea title - -**Custom Actions:** -- `POST /api/v1/planner/ideas/bulk_delete/` - Bulk delete ideas - - **Request**: `{ "ids": [1, 2, 3] }` - - **Response**: `{ "deleted_count": 3 }` - -- `POST /api/v1/planner/ideas/bulk_queue_to_writer/` - Queue ideas to writer (create tasks) - - **Request**: `{ "ids": [1, 2, 3] }` - - **Response**: `{ "tasks_created": 3, "tasks": [ ... ] }` - ---- - -## Writer Module Endpoints - -**Base Path**: `/api/v1/writer/` - -### Task Management Endpoints - -#### ViewSet: `TasksViewSet` -**Base Path**: `/api/v1/writer/tasks/` - -**Permission**: AllowAny (default) - -**Inherits**: SiteSectorModelViewSet - -**Standard CRUD:** -- `GET /api/v1/writer/tasks/` - List tasks -- `POST /api/v1/writer/tasks/` - Create task -- `GET /api/v1/writer/tasks/{id}/` - Get task -- `PUT /api/v1/writer/tasks/{id}/` - Update task -- `DELETE /api/v1/writer/tasks/{id}/` - Delete task - -**Filtering:** -- `status`: Filter by status (draft, in_progress, review, completed, archived) -- `cluster_id`: Filter by cluster -- `content_type`: Filter by content type -- `content_structure`: Filter by content structure -- `site_id`: Filter by site (query param) -- `sector_id`: Filter by sector (query param) - -**Search:** -- `search`: Search by title or keywords - -**Ordering:** -- `ordering`: Order by `title`, `created_at`, `word_count`, `status` -- Default: `-created_at` - -**Custom Actions:** -- `POST /api/v1/writer/tasks/bulk_delete/` - Bulk delete tasks - - **Request**: `{ "ids": [1, 2, 3] }` - - **Response**: `{ "deleted_count": 3 }` - -- `POST /api/v1/writer/tasks/bulk_update/` - Bulk update task status - - **Request**: `{ "ids": [1, 2, 3], "status": "review" }` - - **Response**: `{ "updated_count": 3 }` - -- `POST /api/v1/writer/tasks/auto_generate_content/` - Auto-generate content using AI - - **Request**: `{ "ids": [1, 2, 3, ...] }` (max 50 tasks per batch) - - **Response**: `{ "success": true, "task_id": "abc123" }` - - **Returns**: Celery task ID for progress tracking - -### Content Management Endpoints - -#### ViewSet: `ContentViewSet` -**Base Path**: `/api/v1/writer/content/` - -**Permission**: AllowAny (default) - -**Inherits**: SiteSectorModelViewSet - -**Standard CRUD:** -- `GET /api/v1/writer/content/` - List content -- `POST /api/v1/writer/content/` - Create content -- `GET /api/v1/writer/content/{id}/` - Get content -- `PUT /api/v1/writer/content/{id}/` - Update content -- `DELETE /api/v1/writer/content/{id}/` - Delete content - -**Filtering:** -- `status`: Filter by status -- `content_type`: Filter by content type -- `site_id`: Filter by site (query param) -- `sector_id`: Filter by sector (query param) - -**Search:** -- `search`: Search by title or keywords - -**Custom Actions:** -- `POST /api/v1/writer/content/generate_image_prompts/` - Generate image prompts from content - - **Request**: `{ "ids": [1, 2, 3] }` - - **Response**: `{ "success": true, "task_id": "abc123" }` - - **Returns**: Celery task ID for progress tracking - -### Image Management Endpoints - -#### ViewSet: `ImagesViewSet` -**Base Path**: `/api/v1/writer/images/` - -**Permission**: AllowAny (default) - -**Inherits**: SiteSectorModelViewSet - -**Standard CRUD:** -- `GET /api/v1/writer/images/` - List images -- `POST /api/v1/writer/images/` - Create image -- `GET /api/v1/writer/images/{id}/` - Get image -- `PUT /api/v1/writer/images/{id}/` - Update image -- `DELETE /api/v1/writer/images/{id}/` - Delete image - -**Filtering:** -- `image_type`: Filter by type (featured, in_article, desktop, mobile) -- `status`: Filter by status -- `content_id`: Filter by content -- `task_id`: Filter by task -- `site_id`: Filter by site (query param) -- `sector_id`: Filter by sector (query param) - -**Custom Actions:** -- `GET /api/v1/writer/images/{id}/file/` - Get image file URL - - **Response**: `{ "image_url": "https://..." }` - -- `GET /api/v1/writer/images/content_images/` - Get images for content - - **Query Params**: `content_id` (required) - - **Response**: `{ "images": [ ... ] }` - -- `POST /api/v1/writer/images/auto_generate/` - Auto-generate images (legacy) - - **Request**: `{ "ids": [1, 2, 3] }` - - **Response**: `{ "success": true, "images_created": 3 }` - -- `POST /api/v1/writer/images/generate_images/` - Generate images using AI - - **Request**: `{ "ids": [1, 2, 3, ...] }` - - **Response**: `{ "success": true, "task_id": "abc123" }` - - **Returns**: Celery task ID for progress tracking - -- `POST /api/v1/writer/images/bulk_update/` - Bulk update image status - - **Request**: `{ "ids": [1, 2, 3], "status": "completed" }` OR `{ "content_id": 1, "status": "completed" }` - - **Response**: `{ "updated_count": 3 }` - ---- - -## System Module Endpoints - -**Base Path**: `/api/v1/system/` - -### AI Prompt Management Endpoints - -#### ViewSet: `AIPromptViewSet` -**Base Path**: `/api/v1/system/prompts/` - -**Permission**: AllowAny (default) - -**Inherits**: AccountModelViewSet - -**Standard CRUD:** -- `GET /api/v1/system/prompts/` - List prompts -- `POST /api/v1/system/prompts/` - Create prompt -- `GET /api/v1/system/prompts/{id}/` - Get prompt -- `PUT /api/v1/system/prompts/{id}/` - Update prompt -- `DELETE /api/v1/system/prompts/{id}/` - Delete prompt - -**Custom Actions:** -- `GET /api/v1/system/prompts/by_type/{prompt_type}/` - Get prompt by type - - **Response**: `{ "prompt_type": "auto_cluster", "prompt_value": "..." }` - -- `POST /api/v1/system/prompts/save/` - Save prompt (custom action) - - **Request**: `{ "prompt_type": "auto_cluster", "prompt_value": "..." }` - - **Response**: `{ "success": true, "prompt": { ... } }` - -- `POST /api/v1/system/prompts/reset/` - Reset prompt to default - - **Request**: `{ "prompt_type": "auto_cluster" }` - - **Response**: `{ "success": true, "prompt": { ... } }` - -### Author Profile Management Endpoints - -#### ViewSet: `AuthorProfileViewSet` -**Base Path**: `/api/v1/system/author-profiles/` - -**Permission**: AllowAny (default) - -**Inherits**: AccountModelViewSet - -**Standard CRUD:** -- `GET /api/v1/system/author-profiles/` - List author profiles -- `POST /api/v1/system/author-profiles/` - Create author profile -- `GET /api/v1/system/author-profiles/{id}/` - Get author profile -- `PUT /api/v1/system/author-profiles/{id}/` - Update author profile -- `DELETE /api/v1/system/author-profiles/{id}/` - Delete author profile - -### Strategy Management Endpoints - -#### ViewSet: `StrategyViewSet` -**Base Path**: `/api/v1/system/strategies/` - -**Permission**: AllowAny (default) - -**Inherits**: AccountModelViewSet - -**Standard CRUD:** -- `GET /api/v1/system/strategies/` - List strategies -- `POST /api/v1/system/strategies/` - Create strategy -- `GET /api/v1/system/strategies/{id}/` - Get strategy -- `PUT /api/v1/system/strategies/{id}/` - Update strategy -- `DELETE /api/v1/system/strategies/{id}/` - Delete strategy - -### Integration Settings Endpoints - -#### ViewSet: `IntegrationSettingsViewSet` -**Base Path**: `/api/v1/system/settings/integrations/` - -**Permission**: AllowAny (default) - -**Custom URL Patterns** (not standard ViewSet routes): - -- `GET /api/v1/system/settings/integrations/{pk}/` - Get integration settings - - **Response**: `{ "integration_type": "openai", "config": { ... }, "is_active": true }` - -- `POST /api/v1/system/settings/integrations/{pk}/save/` - Save integration settings - - **Request**: `{ "config": { "apiKey": "...", "model": "gpt-4" }, "is_active": true }` - - **Response**: `{ "success": true, "integration": { ... } }` - -- `PUT /api/v1/system/settings/integrations/{pk}/` - Update integration settings - - **Request**: Same as save - - **Response**: Same as save - -- `POST /api/v1/system/settings/integrations/{pk}/test/` - Test connection - - **Request**: `{ "provider": "openai" }` or `{ "provider": "runware" }` - - **Response**: `{ "success": true, "message": "Connection successful" }` - -- `POST /api/v1/system/settings/integrations/{pk}/generate/` - Test image generation - - **Request**: `{ "prompt": "...", "provider": "openai", "model": "dall-e-3", ... }` - - **Response**: `{ "success": true, "image_url": "https://..." }` - -- `GET /api/v1/system/settings/task_progress/{task_id}/` - Get Celery task progress - - **Response**: `{ "state": "PROGRESS", "meta": { "phase": "AI_CALL", "percentage": 50, ... } }` - -- `GET /api/v1/system/integrations/image_generation/` - Get image generation settings - - **Response**: `{ "providers": ["openai", "runware"], "models": { ... }, ... }` - -### Settings Management Endpoints - -#### ViewSet: `SystemSettingsViewSet` -**Base Path**: `/api/v1/system/settings/system/` - -**Permission**: IsAuthenticated - -**Standard CRUD:** -- `GET /api/v1/system/settings/system/` - List system settings -- `POST /api/v1/system/settings/system/` - Create system setting -- `GET /api/v1/system/settings/system/{id}/` - Get system setting -- `PUT /api/v1/system/settings/system/{id}/` - Update system setting -- `DELETE /api/v1/system/settings/system/{id}/` - Delete system setting - -#### ViewSet: `AccountSettingsViewSet` -**Base Path**: `/api/v1/system/settings/account/` - -**Permission**: IsAuthenticated - -**Inherits**: AccountModelViewSet - -**Standard CRUD:** -- `GET /api/v1/system/settings/account/` - List account settings -- `POST /api/v1/system/settings/account/` - Create account setting -- `GET /api/v1/system/settings/account/{id}/` - Get account setting -- `PUT /api/v1/system/settings/account/{id}/` - Update account setting -- `DELETE /api/v1/system/settings/account/{id}/` - Delete account setting - -#### ViewSet: `UserSettingsViewSet` -**Base Path**: `/api/v1/system/settings/user/` - -**Permission**: IsAuthenticated - -**Standard CRUD:** -- `GET /api/v1/system/settings/user/` - List user settings -- `POST /api/v1/system/settings/user/` - Create user setting -- `GET /api/v1/system/settings/user/{id}/` - Get user setting -- `PUT /api/v1/system/settings/user/{id}/` - Update user setting -- `DELETE /api/v1/system/settings/user/{id}/` - Delete user setting - -#### ViewSet: `ModuleSettingsViewSet` -**Base Path**: `/api/v1/system/settings/modules/` - -**Permission**: IsAuthenticated - -**Inherits**: AccountModelViewSet - -**Standard CRUD:** -- `GET /api/v1/system/settings/modules/` - List module settings -- `POST /api/v1/system/settings/modules/` - Create module setting -- `GET /api/v1/system/settings/modules/{id}/` - Get module setting -- `PUT /api/v1/system/settings/modules/{id}/` - Update module setting -- `DELETE /api/v1/system/settings/modules/{id}/` - Delete module setting - -**Custom Actions:** -- `GET /api/v1/system/settings/modules/module/{module_name}/` - Get settings by module - - **Response**: `{ "module": "planner", "settings": { ... } }` - -#### ViewSet: `AISettingsViewSet` -**Base Path**: `/api/v1/system/settings/ai/` - -**Permission**: IsAuthenticated - -**Inherits**: AccountModelViewSet - -**Standard CRUD:** -- `GET /api/v1/system/settings/ai/` - List AI settings -- `POST /api/v1/system/settings/ai/` - Create AI setting -- `GET /api/v1/system/settings/ai/{id}/` - Get AI setting -- `PUT /api/v1/system/settings/ai/{id}/` - Update AI setting -- `DELETE /api/v1/system/settings/ai/{id}/` - Delete AI setting - -### System Status Endpoints - -#### GET `/api/v1/system/status/` -**Purpose**: System health check - -**Authentication**: AllowAny - -**Response:** -```json -{ - "status": "healthy", - "database": "connected", - "redis": "connected", - "celery": "running", - "version": "1.0.0" -} -``` - -**Status Codes**: 200 (OK), 503 (Service Unavailable) - -#### GET `/api/v1/system/request-metrics/{request_id}/` -**Purpose**: Get request metrics for debugging - -**Authentication**: Required (typically admin/developer only) - -**Response:** -```json -{ - "request_id": "abc123", - "cpu_percent": 25.5, - "memory_mb": 512, - "io_read_mb": 10.2, - "io_write_mb": 5.1 -} -``` - -#### POST `/api/v1/system/webhook/` -**Purpose**: Gitea webhook endpoint - -**Authentication**: Webhook secret validation - -**Request**: Gitea webhook payload - -**Response:** -```json -{ - "success": true, - "message": "Webhook processed" -} -``` - ---- - -## Billing Module Endpoints - -**Base Path**: `/api/v1/billing/` - -### Credit Balance Endpoints - -#### ViewSet: `CreditBalanceViewSet` -**Base Path**: `/api/v1/billing/credits/balance/` - -**Permission**: IsAuthenticated - -**Custom Actions:** -- `GET /api/v1/billing/credits/balance/balance/` - Get credit balance - - **Response**: - ```json - { - "credits": 1000, - "plan_credits_per_month": 500, - "credits_used_this_month": 250, - "credits_remaining": 750 - } - ``` - -### Credit Usage Endpoints - -#### ViewSet: `CreditUsageViewSet` -**Base Path**: `/api/v1/billing/credits/usage/` - -**Permission**: IsAuthenticated - -**Inherits**: ReadOnlyModelViewSet (read-only) - -**Standard CRUD:** -- `GET /api/v1/billing/credits/usage/` - List usage logs (paginated) -- `GET /api/v1/billing/credits/usage/{id}/` - Get usage log - -**Filtering:** -- `operation_type`: Filter by operation type (clustering, ideas, content, images, reparse) -- `start_date`: Filter by start date (YYYY-MM-DD) -- `end_date`: Filter by end date (YYYY-MM-DD) - -**Custom Actions:** -- `GET /api/v1/billing/credits/usage/summary/` - Get usage summary - - **Query Params**: `start_date`, `end_date` (optional) - - **Response**: - ```json - { - "total_credits_used": 500, - "total_cost_usd": 25.50, - "by_operation": { - "clustering": 100, - "ideas": 50, - "content": 300, - "images": 50 - } - } - ``` - -- `GET /api/v1/billing/credits/usage/limits/` - Get usage limits - - **Response**: - ```json - { - "plan_limits": { - "max_keywords": 10000, - "max_clusters": 1000, - "max_ideas": 5000, - "max_ai_requests": 10000 - }, - "current_usage": { - "keywords": 5000, - "clusters": 500, - "ideas": 2500, - "ai_requests": 5000 - } - } - ``` - -### Credit Transaction Endpoints - -#### ViewSet: `CreditTransactionViewSet` -**Base Path**: `/api/v1/billing/credits/transactions/` - -**Permission**: IsAuthenticated - -**Inherits**: ReadOnlyModelViewSet (read-only) - -**Standard CRUD:** -- `GET /api/v1/billing/credits/transactions/` - List transactions (paginated) -- `GET /api/v1/billing/credits/transactions/{id}/` - Get transaction - -**Filtering:** -- `transaction_type`: Filter by type (purchase, subscription, refund, deduction, adjustment) -- `start_date`: Filter by start date -- `end_date`: Filter by end date - -**Ordering:** -- Default: `-created_at` (newest first) - ---- - -## Frontend API Usage Patterns - -### API Client Implementation - -**File**: `frontend/src/services/api.ts` - -**Base URL Detection:** -- Checks `VITE_BACKEND_URL` or `VITE_API_URL` environment variable -- Auto-detects based on current origin (localhost, IP, subdomain) -- Production default: `https://api.igny8.com/api` - -**Authentication:** -- JWT token stored in Zustand auth store -- Token included in `Authorization: Bearer ` header -- Automatic token refresh on 401 responses -- Token stored in localStorage (persisted) - -**Request Function:** -```typescript -fetchAPI(endpoint: string, options?: RequestInit) -``` - -**Features:** -- Automatic JWT token injection -- 30-second timeout (configurable) -- Automatic token refresh on 401 -- Error handling and parsing -- Content-type detection - -### Common Usage Patterns - -**List Endpoints:** -```typescript -const response = await fetchAPI('/v1/planner/keywords/?page=1&page_size=25'); -const data = await response.json(); -// Returns: { count, next, previous, results: [...] } -``` - -**Create Endpoints:** -```typescript -const response = await fetchAPI('/v1/planner/keywords/', { - method: 'POST', - body: JSON.stringify({ keyword: '...', site_id: 1, sector_id: 1 }) -}); -``` - -**Custom Actions:** -```typescript -const response = await fetchAPI('/v1/planner/keywords/auto_cluster/', { - method: 'POST', - body: JSON.stringify({ ids: [1, 2, 3], sector_id: 1 }) -}); -// Returns: { success: true, task_id: "abc123" } -``` - -**Progress Tracking:** -```typescript -// Poll progress endpoint -const progress = await fetchAPI(`/v1/system/settings/task_progress/${taskId}/`); -// Returns: { state: "PROGRESS", meta: { phase: "AI_CALL", percentage: 50 } } -``` - -### State Management Integration - -**Zustand Stores:** -- Auth Store: Manages JWT token and user data -- Site Store: Manages current site selection -- Sector Store: Manages current sector selection -- Module Stores: Cache API responses (Planner, Writer, Billing) - -**API Calls from Stores:** -- Stores use `fetchAPI` for all API calls -- Responses cached in store state -- Automatic re-fetch on state changes - ---- - -## Third-Party Integrations - -### OpenAI Integration - -**Purpose**: Text generation (GPT models) and image generation (DALL-E) - -**Configuration:** -- Stored in `IntegrationSettings` model -- Integration type: `openai` -- Config fields: `apiKey`, `model`, `max_tokens`, `temperature` - -**API Usage:** -- Called via `AICore.run_ai_request()` for text generation -- Called via `AICore.generate_image()` for image generation -- Account-specific API keys -- Cost tracking per request - -**Endpoints Used:** -- OpenAI API: `https://api.openai.com/v1/chat/completions` -- OpenAI DALL-E: `https://api.openai.com/v1/images/generations` - -**Dependencies:** -- `requests` library for HTTP calls -- API key stored per account in database - -### Runware Integration - -**Purpose**: Alternative image generation service - -**Configuration:** -- Stored in `IntegrationSettings` model -- Integration type: `runware` -- Config fields: `apiKey`, `model` (e.g., `runware:97@1`), `image_type` - -**API Usage:** -- Called via `AICore.generate_image()` for image generation -- Account-specific API keys -- Cost tracking per image - -**Endpoints Used:** -- Runware API: `https://api.runware.com/v1/images/generate` - -**Dependencies:** -- `requests` library for HTTP calls -- API key stored per account in database - -### WordPress Integration - -**Purpose**: Content publishing to WordPress sites - -**Configuration:** -- Stored in `Site` model -- Fields: `wp_url`, `wp_username`, `wp_app_password` -- Per-site configuration - -**API Usage:** -- WordPress REST API calls -- Creates posts with content HTML -- Uploads images to media library -- Sets post meta (keywords, etc.) - -**Endpoints Used:** -- WordPress REST API: `{wp_url}/wp-json/wp/v2/posts` -- WordPress Media API: `{wp_url}/wp-json/wp/v2/media` - -**Dependencies:** -- `requests` library for HTTP calls -- WordPress REST API (built into WordPress) - -### Gitea Webhook Integration - -**Purpose**: Receive webhook events from Gitea - -**Endpoint**: `POST /api/v1/system/webhook/` - -**Configuration:** -- Webhook secret validation -- Processes push events, pull requests, etc. - -**Dependencies:** -- Webhook secret stored in environment variables - ---- - -## Dependencies - -### Backend Dependencies - -**Core Framework:** -- `Django 5.2+`: Web framework -- `djangorestframework`: REST API framework -- `django-filter`: Advanced filtering -- `django-cors-headers`: CORS handling - -**Authentication:** -- `PyJWT 2.8.0+`: JWT token handling -- Custom JWT implementation (not djangorestframework-simplejwt) - -**Database:** -- `psycopg2-binary`: PostgreSQL adapter -- `PostgreSQL 15`: Database - -**Task Queue:** -- `Celery 5.3.0+`: Asynchronous task processing -- `Redis 7`: Celery broker and cache - -**HTTP Client:** -- `requests 2.31.0+`: External API calls (OpenAI, Runware, WordPress) - -**Utilities:** -- `python-dotenv`: Environment variable management -- `BeautifulSoup4`: HTML parsing -- `psutil`: System utilities -- `docker`: Docker API client - -### Frontend Dependencies - -**HTTP Client:** -- Native `fetch` API (no external HTTP library) -- Custom `fetchAPI` wrapper in `frontend/src/services/api.ts` - -**State Management:** -- `Zustand 5.0.8`: State management -- Token stored in Zustand auth store -- API responses cached in module stores - -**No External API Libraries:** -- No Axios, no React Query, no SWR -- Pure fetch API with custom wrapper - ---- - -## Rate Limiting - -### Current Status - -**Rate Limiting**: ❌ **Not Implemented** - -**Status**: Planned for future implementation - -**Configuration**: None in current settings - -### Planned Implementation - -**Location**: `docs/02-APPLICATION-ARCHITECTURE.md` mentions rate limiting as planned feature - -**Recommendation**: Implement using DRF throttling classes: -- `rest_framework.throttling.AnonRateThrottle`: For anonymous users -- `rest_framework.throttling.UserRateThrottle`: For authenticated users -- Custom throttling for AI endpoints (higher limits) - ---- - -## Standardization Recommendations - -### Current Issues - -1. **Inconsistent Permission Classes:** - - Many ViewSets use `permission_classes = []` (AllowAny) - - Should standardize to `IsAuthenticated` for most endpoints - - Only public endpoints should use `AllowAny` - -2. **Inconsistent Response Formats:** - - Some endpoints return `{ success: true, data: ... }` - - Some endpoints return DRF standard format - - Some endpoints return custom formats - - Should standardize to one format - -3. **Mixed Authentication:** - - JWT primary, but session and basic auth also enabled - - Should document which endpoints use which method - - Should standardize authentication requirements - -4. **No Rate Limiting:** - - All endpoints are unlimited - - Should implement rate limiting for production - -5. **Inconsistent Error Handling:** - - Some endpoints return `{ error: "..." }` - - Some return `{ success: false, message: "..." }` - - Should standardize error response format - -### Recommendations - -1. **Standardize Response Format:** - - Use consistent `{ success, data, message, errors }` format - - Apply to all endpoints - - Create response mixin for ViewSets - -2. **Standardize Permissions:** - - Default to `IsAuthenticated` for all endpoints - - Only explicitly allow `AllowAny` for public endpoints - - Document permission requirements - -3. **Implement Rate Limiting:** - - Add DRF throttling classes - - Different limits for different endpoint types - - Document rate limits - -4. **Standardize Error Handling:** - - Use consistent error response format - - Include error codes for programmatic handling - - Document all error codes - -5. **API Versioning:** - - Current: `/api/v1/` - - Plan for future versions - - Document versioning strategy - -6. **API Documentation:** - - Consider adding OpenAPI/Swagger documentation - - Document all endpoints with request/response examples - - Include authentication requirements - ---- - -## Summary - -### Endpoint Statistics - -- **Total Endpoints**: 100+ endpoints -- **Auth Module**: 15+ endpoints -- **Planner Module**: 20+ endpoints -- **Writer Module**: 20+ endpoints -- **System Module**: 30+ endpoints -- **Billing Module**: 10+ endpoints - -### Authentication - -- **Primary**: JWT Bearer tokens -- **Fallback**: Session authentication -- **Fallback**: Basic authentication -- **Account Context**: Set via middleware from JWT - -### Response Formats - -- **Success**: `{ success: true, data: ..., message: ... }` -- **Error**: `{ success: false, error: ..., errors: ... }` -- **Pagination**: `{ count, next, previous, results: [...] }` - -### Current Gaps - -- ❌ No rate limiting -- ⚠️ Inconsistent permission classes -- ⚠️ Inconsistent response formats -- ⚠️ No API documentation (OpenAPI/Swagger) -- ✅ Good: Consistent pagination -- ✅ Good: Account isolation -- ✅ Good: Site/sector filtering - -### Third-Party Integrations - -- **OpenAI**: Text and image generation -- **Runware**: Image generation -- **WordPress**: Content publishing -- **Gitea**: Webhook integration - ---- - -**Document Status**: Complete analysis of all existing API endpoints -**Last Updated**: 2025-01-XX - diff --git a/unified-api/API-STANDARD-v1.0.md b/unified-api/API-STANDARD-v1.0.md deleted file mode 100644 index 94d390fa..00000000 --- a/unified-api/API-STANDARD-v1.0.md +++ /dev/null @@ -1,1312 +0,0 @@ -# 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 -``` - -**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 - ✅ **100% IMPLEMENTED** -**Last Updated:** 2025-01-XX -**Implementation Status:** All requirements implemented and verified -- ✅ All endpoints return unified response format -- ✅ All errors fully unified with request_id tracking -- ✅ All ViewSets use proper base classes, pagination, throttles, and permissions -- ✅ All custom @action methods use unified format -- ✅ All public endpoints properly configured -- ✅ Health check endpoint `/api/v1/system/ping/` implemented -- ✅ All endpoints documented in Swagger/ReDoc -**Next Review:** Quarterly or as needed -