# IGNY8 Backend Documentation

**Version:** 1.0  
**Last Updated:** 2025-01-XX  
**Purpose:** Complete backend documentation covering models, views, APIs, modules, serializers, tasks, and structure.

---

## Table of Contents

1. [Backend Overview](#backend-overview)
2. [Tech Stack](#tech-stack)
3. [Project Structure](#project-structure)
4. [Models](#models)
5. [ViewSets](#viewsets)
6. [Serializers](#serializers)
7. [Celery Tasks](#celery-tasks)
8. [API Endpoints](#api-endpoints)
9. [Base Classes](#base-classes)
10. [Middleware](#middleware)
11. [Utilities](#utilities)
12. [Modules](#modules)

---

## Backend Overview

The IGNY8 backend is a Django 5.2+ application using Django REST Framework (DRF) for API endpoints. The backend follows a modular architecture with clear separation of concerns, automatic account isolation, and support for asynchronous task processing via Celery.

### Key Features

- **Multi-Tenancy**: Complete account isolation with automatic filtering
- **RESTful API**: DRF ViewSets with consistent response format
- **Celery Integration**: Asynchronous task processing for long-running operations
- **Account/Site/Sector Hierarchy**: Hierarchical data organization
- **AI Integration**: Unified AIProcessor for all AI operations
- **Progress Tracking**: Real-time progress updates for Celery tasks

---

## Tech Stack

### Core Technologies

- **Django 5.2+**: Web framework
- **Django REST Framework**: API framework
- **PostgreSQL**: Database
- **Celery**: Asynchronous task queue
- **Redis**: Celery broker and caching

### Key Libraries

- **django-filter**: Advanced filtering
- **djangorestframework-simplejwt**: JWT authentication
- **requests**: HTTP client for external APIs
- **python-dotenv**: Environment variable management

---

## Project Structure

```
backend/igny8_core/
├── auth/                     # Multi-tenancy and authentication
│   ├── models.py             # Account, User, Plan, Site, Sector, Industry models
│   ├── views.py              # Account, User, Site, Sector ViewSets
│   ├── serializers.py        # Account, User, Plan serializers
│   └── urls.py               # Auth module URLs
├── modules/                  # Feature modules
│   ├── planner/              # Keywords, Clusters, Ideas
│   │   ├── models.py         # Keywords, Clusters, ContentIdeas models
│   │   ├── views.py          # KeywordViewSet, ClusterViewSet, ContentIdeasViewSet
│   │   ├── tasks.py          # Celery tasks for AI operations
│   │   ├── serializers.py    # Model serializers
│   │   └── urls.py           # Planner module URLs
│   ├── writer/               # Tasks, Content, Images
│   │   ├── models.py         # Tasks, Content, Images models
│   │   ├── views.py          # TasksViewSet
│   │   ├── tasks.py          # Celery tasks for content/image generation
│   │   └── urls.py           # Writer module URLs
│   ├── system/               # Settings, Prompts, Integration
│   │   ├── models.py         # AIPrompt, IntegrationSettings, AuthorProfile, Strategy
│   │   ├── views.py          # AIPromptViewSet, AuthorProfileViewSet
│   │   ├── integration_views.py  # IntegrationSettingsViewSet, task_progress
│   │   ├── utils.py          # Default prompts, prompt loading
│   │   └── urls.py           # System module URLs
│   └── billing/              # Credits, Transactions, Usage
│       ├── models.py         # CreditTransaction, UsageLog models
│       ├── views.py          # Billing ViewSets
│       └── services.py       # CreditService
├── api/                      # API base classes
│   ├── base.py               # AccountModelViewSet, SiteSectorModelViewSet
│   └── pagination.py         # CustomPageNumberPagination
├── utils/                    # Shared utilities
│   ├── ai_processor.py       # Unified AI interface
│   └── content_normalizer.py # Content processing utilities
├── middleware/               # Custom middleware
│   ├── account.py            # AccountContextMiddleware (sets request.account)
│   └── resource_tracker.py   # ResourceTrackerMiddleware (API metrics)
├── settings.py               # Django settings
├── urls.py                   # Root URL configuration
└── celery.py                 # Celery configuration
```

---

## Models

### Base Models

#### AccountBaseModel
**File**: `auth/models.py`

**Purpose**: Base model for all account-isolated models.

**Fields**:
- `account`: ForeignKey to Account
- `created_at`: DateTimeField (auto_now_add)
- `updated_at`: DateTimeField (auto_now)

**Usage**: All models that need account isolation inherit from this.


#### SiteSectorBaseModel
**File**: `auth/models.py`

**Purpose**: Base model for models that belong to Site and Sector.

**Fields**:
- Inherits from `AccountBaseModel`
- `site`: ForeignKey to Site
- `sector`: ForeignKey to Sector

**Methods**:
- `save()`: Automatically sets `account` from `site.account` and validates sector belongs to site

**Usage**: Models like Keywords, Clusters, ContentIdeas, Tasks inherit from this.

### Auth Models

#### Account
**File**: `auth/models.py`

**Table**: `igny8_accounts`

**Fields**:
- `name`: CharField
- `slug`: SlugField (unique)
- `owner`: ForeignKey to User
- `stripe_customer_id`: CharField (optional)
- `plan`: ForeignKey to Plan
- `credits`: IntegerField (default: 0)
- `status`: CharField (choices: active, suspended, trial, cancelled)

**Methods**:
- `is_system_account()`: Returns True if account is system account (aws-admin, default-account, default)

#### User
**File**: `auth/models.py`

**Table**: `igny8_users`

**Fields**:
- Inherits from `AbstractUser`
- `email`: EmailField (unique, USERNAME_FIELD)
- `account`: ForeignKey to Account
- `role`: CharField (choices: developer, owner, admin, editor, viewer, system_bot)

**Methods**:
- `has_role(*roles)`: Check if user has any of the specified roles
- `is_owner_or_admin()`: Returns True if role is owner or admin
- `is_developer()`: Returns True if role is developer or is_superuser
- `is_admin_or_developer()`: Returns True if role is admin or developer
- `is_system_account_user()`: Returns True if user belongs to system account
- `get_accessible_sites()`: Returns QuerySet of sites user can access

#### Plan
**File**: `auth/models.py`

**Table**: `igny8_plans`

**Fields**:
- `name`: CharField
- `slug`: SlugField (unique)
- `price`: DecimalField
- `billing_cycle`: CharField (choices: monthly, annual)
- `features`: JSONField (array of feature strings)
- `max_users`: IntegerField
- `max_sites`: IntegerField
- `max_keywords`: IntegerField
- `max_clusters`: IntegerField
- `max_content_ideas`: IntegerField
- `daily_cluster_limit`: IntegerField
- `monthly_cluster_ai_credits`: IntegerField
- `daily_content_tasks`: IntegerField
- `daily_ai_requests`: IntegerField
- `monthly_word_count_limit`: IntegerField
- `monthly_content_ai_credits`: IntegerField
- `monthly_image_count`: IntegerField
- `daily_image_generation_limit`: IntegerField
- `monthly_image_ai_credits`: IntegerField
- `max_images_per_task`: IntegerField
- `image_model_choices`: JSONField
- `included_credits`: IntegerField
- `extra_credit_price`: DecimalField
- And more...

**Methods**:
- `clean()`: Validates plan limits
- `get_effective_credits_per_month()`: Returns included_credits or credits_per_month

#### Site
**File**: `auth/models.py`

**Table**: `igny8_sites`

**Fields**:
- Inherits from `AccountBaseModel`
- `name`: CharField
- `slug`: SlugField (unique per account)
- `domain`: URLField (optional)
- `industry`: ForeignKey to Industry (optional)
- `is_active`: BooleanField
- `status`: CharField (choices: active, inactive, suspended)
- `wp_url`: URLField (optional, WordPress integration)
- `wp_username`: CharField (optional)
- `wp_app_password`: CharField (optional)

**Methods**:
- `get_active_sectors_count()`: Get count of active sectors
- `can_add_sector()`: Check if site can add another sector (max 5)

#### Sector
**File**: `auth/models.py`

**Table**: `igny8_sectors`

**Fields**:
- Inherits from `AccountBaseModel`
- `site`: ForeignKey to Site
- `industry_sector`: ForeignKey to IndustrySector (optional, template reference)
- `name`: CharField
- `slug`: SlugField (unique per site)
- `is_active`: BooleanField
- `status`: CharField (choices: active, inactive)

### Planner Models

#### Keywords
**File**: `modules/planner/models.py`

**Table**: `igny8_keywords`

**Fields**:
- Inherits from `SiteSectorBaseModel`
- `keyword`: CharField
- `volume`: IntegerField
- `difficulty`: IntegerField
- `intent`: CharField (choices: informational, navigational, commercial, transactional)
- `cluster`: ForeignKey to Clusters (optional)
- `status`: CharField (choices: active, pending, archived)

#### Clusters
**File**: `modules/planner/models.py`

**Table**: `igny8_clusters`

**Fields**:
- Inherits from `SiteSectorBaseModel`
- `name`: CharField (unique)
- `description`: TextField
- `keywords_count`: IntegerField
- `volume`: IntegerField
- `mapped_pages`: IntegerField
- `status`: CharField

#### ContentIdeas
**File**: `modules/planner/models.py`

**Table**: `igny8_content_ideas`

**Fields**:
- Inherits from `SiteSectorBaseModel`
- `idea_title`: CharField
- `description`: TextField
- `content_structure`: CharField (choices: cluster_hub, landing_page, pillar_page, supporting_page)
- `content_type`: CharField (choices: blog_post, article, guide, tutorial)
- `target_keywords`: CharField (comma-separated, legacy)
- `keyword_objects`: ManyToManyField to Keywords
- `keyword_cluster`: ForeignKey to Clusters
- `status`: CharField (choices: new, scheduled, published)
- `estimated_word_count`: IntegerField

### Writer Models

#### Tasks
**File**: `modules/writer/models.py`

**Table**: `igny8_tasks`

**Fields**:
- Inherits from `SiteSectorBaseModel`
- `title`: CharField
- `description`: TextField
- `keywords`: CharField (comma-separated, legacy)
- `keyword_objects`: ManyToManyField to Keywords
- `cluster`: ForeignKey to Clusters
- `idea`: ForeignKey to ContentIdeas
- `content_structure`: CharField
- `content_type`: CharField
- `status`: CharField (choices: queued, in_progress, draft, review, published, completed)
- `content`: TextField (generated content)
- `word_count`: IntegerField
- `meta_title`: CharField
- `meta_description`: TextField
- `assigned_post_id`: IntegerField (WordPress post ID)
- `post_url`: URLField

#### Content
**File**: `modules/writer/models.py`

**Table**: `igny8_content`

**Fields**:
- Inherits from `SiteSectorBaseModel`
- `task`: OneToOneField to Tasks
- `html_content`: TextField
- `word_count`: IntegerField
- `metadata`: JSONField

**Methods**:
- `save()`: Automatically sets account, site, sector from task

#### Images
**File**: `modules/writer/models.py`

**Table**: `igny8_images`

**Fields**:
- Inherits from `SiteSectorBaseModel`
- `task`: ForeignKey to Tasks
- `image_type`: CharField (choices: featured, desktop, mobile, in_article)
- `image_url`: URLField
- `image_path`: CharField (local path)
- `prompt`: TextField
- `status`: CharField
- `position`: IntegerField

**Methods**:
- `save()`: Automatically sets account, site, sector from task

### System Models

#### AIPrompt
**File**: `modules/system/models.py`

**Table**: `igny8_ai_prompts`

**Fields**:
- Inherits from `AccountBaseModel`
- `prompt_type`: CharField (choices: clustering, ideas, content_generation, image_prompt_extraction, image_prompt_template, negative_prompt)
- `prompt_value`: TextField
- `default_prompt`: TextField
- `is_active`: BooleanField

**Unique Constraint**: `(account, prompt_type)`

#### IntegrationSettings
**File**: `modules/system/models.py`

**Table**: `igny8_integration_settings`

**Fields**:
- Inherits from `AccountBaseModel`
- `integration_type`: CharField (choices: openai, runware, gsc, image_generation)
- `config`: JSONField (API keys, settings, etc.)
- `is_active`: BooleanField

**Unique Constraint**: `(account, integration_type)`

#### AuthorProfile
**File**: `modules/system/models.py`

**Table**: `igny8_author_profiles`

**Fields**:
- Inherits from `AccountBaseModel`
- `name`: CharField
- `description`: TextField
- `tone`: CharField
- `language`: CharField
- `structure_template`: JSONField
- `is_active`: BooleanField

#### Strategy
**File**: `modules/system/models.py`

**Table**: `igny8_strategies`

**Fields**:
- Inherits from `AccountBaseModel`
- `name`: CharField
- `description`: TextField
- `sector`: ForeignKey to Sector (optional)
- `prompt_types`: JSONField
- `section_logic`: JSONField
- `is_active`: BooleanField

---

## ViewSets

### Base ViewSets

#### AccountModelViewSet
**File**: `api/base.py`

**Purpose**: Base ViewSet with automatic account filtering.

**Methods**:
- `get_queryset()`: Filters queryset by `request.account` (with admin/developer override)
- `perform_create()`: Sets account on created objects
- `get_serializer_context()`: Adds account to serializer context

**Access Control**:
- Admin/Developer users: Bypass account filtering
- System account users: Bypass account filtering
- Regular users: Only see data from their account

#### SiteSectorModelViewSet
**File**: `api/base.py`

**Purpose**: Base ViewSet with site/sector filtering and access control.

**Inherits**: `AccountModelViewSet`

**Methods**:
- `get_queryset()`: Filters by account, accessible sites, and optional site_id/sector_id
- `perform_create()`: Validates site access and sector-site relationship
- `get_serializer_context()`: Adds accessible sites and sectors to context

**Access Control**:
- Developers: All active sites
- System account users: All active sites
- Owners/Admins: All sites in their account
- Editors/Viewers: Only sites granted via `SiteUserAccess`

### Planner ViewSets

#### KeywordViewSet
**File**: `modules/planner/views.py`

**Inherits**: `SiteSectorModelViewSet`

**Actions**:
- `list()`: List keywords with filtering
- `create()`: Create keyword
- `retrieve()`: Get keyword details
- `update()`: Update keyword
- `destroy()`: Delete keyword
- `auto_cluster()`: Auto-cluster keywords using AI
- `bulk_delete()`: Bulk delete keywords
- `bulk_update_status()`: Bulk update keyword status
- `export_csv()`: Export keywords to CSV
- `import_csv()`: Import keywords from CSV

**Filtering**:
- Search: `keyword` field
- Filters: `status`, `cluster_id`, `intent`
- Custom: `difficulty_min`, `difficulty_max`, `volume_min`, `volume_max`
- Ordering: `created_at`, `volume`, `difficulty`

#### ClusterViewSet
**File**: `modules/planner/views.py`

**Inherits**: `SiteSectorModelViewSet`

**Actions**:
- `list()`: List clusters
- `create()`: Create cluster
- `retrieve()`: Get cluster details
- `update()`: Update cluster
- `destroy()`: Delete cluster
- `auto_generate_ideas()`: Auto-generate content ideas for clusters

#### ContentIdeasViewSet
**File**: `modules/planner/views.py`

**Inherits**: `SiteSectorModelViewSet`

**Actions**:
- `list()`: List content ideas
- `create()`: Create content idea
- `retrieve()`: Get content idea details
- `update()`: Update content idea
- `destroy()`: Delete content idea

### Writer ViewSets

#### TasksViewSet
**File**: `modules/writer/views.py`

**Inherits**: `SiteSectorModelViewSet`

**Actions**:
- `list()`: List tasks
- `create()`: Create task
- `retrieve()`: Get task details
- `update()`: Update task
- `destroy()`: Delete task
- `auto_generate_content()`: Auto-generate content for tasks
- `auto_generate_images()`: Auto-generate images for tasks
- `bulk_delete()`: Bulk delete tasks
- `bulk_update()`: Bulk update task status

**Filtering**:
- Search: `title`, `keywords`
- Filters: `status`, `cluster_id`, `content_type`, `content_structure`
- Ordering: `title`, `created_at`, `word_count`, `status`

### System ViewSets

#### IntegrationSettingsViewSet
**File**: `modules/system/integration_views.py`

**Inherits**: `viewsets.ViewSet`

**Actions**:
- `list()`: List integrations
- `retrieve()`: Get integration settings
- `update()`: Save integration settings
- `save_post()`: Save integration settings (POST)
- `test_connection()`: Test API connection
- `test_openai()`: Test OpenAI connection
- `test_runware()`: Test Runware connection
- `generate_image()`: Test image generation
- `task_progress()`: Get Celery task progress

#### AIPromptViewSet
**File**: `modules/system/views.py`

**Inherits**: `AccountModelViewSet`

**Actions**:
- `list()`: List prompts
- `create()`: Create prompt
- `retrieve()`: Get prompt details
- `update()`: Update prompt
- `destroy()`: Delete prompt
- `reset_to_default()`: Reset prompt to default value

#### AuthorProfileViewSet
**File**: `modules/system/views.py`

**Inherits**: `AccountModelViewSet`

**Actions**:
- `list()`: List author profiles
- `create()`: Create author profile
- `retrieve()`: Get author profile details
- `update()`: Update author profile
- `destroy()`: Delete author profile

---

## Serializers

### Planner Serializers

#### KeywordSerializer
**File**: `modules/planner/serializers.py`

**Fields**: All Keyword model fields

**Validation**: Validates keyword uniqueness, cluster belongs to same sector

#### ClusterSerializer
**File**: `modules/planner/cluster_serializers.py`

**Fields**: All Cluster model fields

**Read-Only Fields**: `keywords_count`, `volume` (calculated)

#### ContentIdeasSerializer
**File**: `modules/planner/serializers.py`

**Fields**: All ContentIdeas model fields

### Writer Serializers

#### TasksSerializer
**File**: `modules/writer/serializers.py`

**Fields**: All Tasks model fields

#### ContentSerializer
**File**: `modules/writer/serializers.py`

**Fields**: All Content model fields

#### ImagesSerializer
**File**: `modules/writer/serializers.py`

**Fields**: All Images model fields

### System Serializers

#### AIPromptSerializer
**File**: `modules/system/serializers.py`

**Fields**: All AIPrompt model fields

#### IntegrationSettingsSerializer
**File**: `modules/system/serializers.py`

**Fields**: All IntegrationSettings model fields

---

## Celery Tasks

### Planner Tasks

#### auto_cluster_keywords_task
**File**: `modules/planner/tasks.py`

**Purpose**: Auto-cluster keywords using AI.

**Parameters**:
- `keyword_ids`: List of keyword IDs
- `account_id`: Account ID
- `site_id`: Site ID
- `sector_id`: Sector ID

**Progress Tracking**: Updates progress with request_steps and response_steps

**Calls**: `_auto_cluster_keywords_core()`

#### auto_generate_ideas_task
**File**: `modules/planner/tasks.py`

**Purpose**: Auto-generate content ideas for clusters.

**Parameters**:
- `cluster_ids`: List of cluster IDs
- `account_id`: Account ID

**Progress Tracking**: Updates progress for each cluster

**Calls**: `_generate_single_idea_core()` for each cluster

### Writer Tasks

#### auto_generate_content_task
**File**: `modules/writer/tasks.py`

**Purpose**: Auto-generate content for tasks.

**Parameters**:
- `task_ids`: List of task IDs
- `account_id`: Account ID

**Progress Tracking**: Updates progress for each task

**Calls**: `AIProcessor.generate_content()`

#### auto_generate_images_task
**File**: `modules/writer/tasks.py`

**Purpose**: Auto-generate images for tasks.

**Parameters**:
- `task_ids`: List of task IDs
- `account_id`: Account ID

**Progress Tracking**: Updates progress for each task

**Calls**: `AIProcessor.extract_image_prompts()` and `AIProcessor.generate_image()`

---

## API Endpoints

### Base URL

`/api/v1/`

### Planner Endpoints

- `GET /api/v1/planner/keywords/` - List keywords
- `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
- `POST /api/v1/planner/keywords/auto_cluster/` - Auto-cluster keywords
- `POST /api/v1/planner/keywords/bulk_delete/` - Bulk delete keywords
- `POST /api/v1/planner/keywords/bulk_update_status/` - Bulk update status
- `GET /api/v1/planner/keywords/export_csv/` - Export keywords
- `POST /api/v1/planner/keywords/import_csv/` - Import keywords
- `GET /api/v1/planner/clusters/` - List clusters
- `POST /api/v1/planner/clusters/auto_generate_ideas/` - Auto-generate ideas
- `GET /api/v1/planner/ideas/` - List content ideas

### Writer Endpoints

- `GET /api/v1/writer/tasks/` - List tasks
- `POST /api/v1/writer/tasks/auto_generate_content/` - Auto-generate content
- `POST /api/v1/writer/tasks/auto_generate_images/` - Auto-generate images

### System Endpoints

- `GET /api/v1/system/settings/integrations/{pk}/` - Get integration settings
- `PUT /api/v1/system/settings/integrations/{pk}/` - Save integration settings
- `POST /api/v1/system/settings/integrations/{pk}/test_openai/` - Test OpenAI
- `POST /api/v1/system/settings/integrations/{pk}/test_runware/` - Test Runware
- `POST /api/v1/system/settings/integrations/{pk}/generate_image/` - Test image generation
- `GET /api/v1/system/settings/task_progress/{task_id}/` - Get task progress

---

## Base Classes

### AccountModelViewSet

**File**: `api/base.py`

**Purpose**: Base ViewSet with automatic account filtering.

**Features**:
- Automatic account filtering
- Admin/Developer override
- Account context in serializers

### SiteSectorModelViewSet

**File**: `api/base.py`

**Purpose**: Base ViewSet with site/sector filtering.

**Features**:
- Account filtering (inherited)
- Site access control
- Sector validation
- Accessible sites/sectors in serializer context

---

## Middleware

### AccountContextMiddleware

**File**: `middleware/account.py`

**Purpose**: Sets `request.account` from JWT token.

**Functionality**:
- Extracts account ID from JWT token
- Loads Account object
- Sets `request.account`

### ResourceTrackerMiddleware

**File**: `middleware/resource_tracker.py`

**Purpose**: Tracks API request metrics.

**Functionality**:
- Tracks CPU, memory, I/O usage
- Stores metrics in cache
- Provides metrics endpoint

---

## Utilities

### AIProcessor

**File**: `utils/ai_processor.py`

**Purpose**: Unified AI interface for all AI operations.

**Methods**:
- `cluster_keywords()`: Cluster keywords using AI
- `generate_ideas()`: Generate content ideas
- `generate_content()`: Generate text content
- `extract_image_prompts()`: Extract image prompts from content
- `generate_image()`: Generate images using OpenAI DALL-E or Runware

**See**: AI Functions documentation for complete details

### Content Normalizer

**File**: `utils/content_normalizer.py`

**Purpose**: Content processing utilities.

**Functions**:
- `_extract_body_content()`: Extract body content from HTML

---

## Modules

### Planner Module

**Purpose**: Keyword management and content planning.

**Models**: Keywords, Clusters, ContentIdeas

**ViewSets**: KeywordViewSet, ClusterViewSet, ContentIdeasViewSet

**Tasks**: auto_cluster_keywords_task, auto_generate_ideas_task

### Writer Module

**Purpose**: Content generation and management.

**Models**: Tasks, Content, Images

**ViewSets**: TasksViewSet

**Tasks**: auto_generate_content_task, auto_generate_images_task

### System Module

**Purpose**: System settings, prompts, and integrations.

**Models**: AIPrompt, IntegrationSettings, AuthorProfile, Strategy

**ViewSets**: AIPromptViewSet, AuthorProfileViewSet, IntegrationSettingsViewSet

**Utilities**: Default prompts, prompt loading

### Billing Module

**Purpose**: Credits, transactions, and usage tracking.

**Models**: CreditTransaction, UsageLog

**ViewSets**: CreditTransactionViewSet, UsageLogViewSet

**Services**: CreditService

---

## Summary

The IGNY8 backend is built on:

1. **Django + DRF**: Robust web framework with RESTful API
2. **Multi-Tenancy**: Complete account isolation with automatic filtering
3. **Modular Architecture**: Clear module boundaries with shared utilities
4. **Celery Integration**: Asynchronous task processing for long-running operations
5. **Base ViewSets**: Consistent access control and filtering
6. **AI Integration**: Unified AIProcessor for all AI operations
7. **Progress Tracking**: Real-time progress updates for Celery tasks
8. **Account/Site/Sector Hierarchy**: Hierarchical data organization

This architecture ensures scalability, maintainability, and extensibility while providing a robust API for the frontend.

