From 04d5004cdfd7d0591a4322a0106002dd638e702d Mon Sep 17 00:00:00 2001 From: "IGNY8 VPS (Salman)" Date: Fri, 14 Nov 2025 13:13:39 +0000 Subject: [PATCH] api --- docs/API-ENDPOINTS-ANALYSIS.md | 1386 ++++++++++++++++++++++++++++++++ 1 file changed, 1386 insertions(+) create mode 100644 docs/API-ENDPOINTS-ANALYSIS.md diff --git a/docs/API-ENDPOINTS-ANALYSIS.md b/docs/API-ENDPOINTS-ANALYSIS.md new file mode 100644 index 00000000..24f4ad9e --- /dev/null +++ b/docs/API-ENDPOINTS-ANALYSIS.md @@ -0,0 +1,1386 @@ +# 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 +