# Database Models Reference **Last Verified:** December 27, 2025 --- ## Data Scoping Overview | Scope | Models | Base Class | Filter By | |-------|--------|------------|-----------| | **Global** | `GlobalIntegrationSettings`, `GlobalAIPrompt`, `GlobalAuthorProfile`, `GlobalStrategy`, `GlobalModuleSettings`, `Industry`, `SeedKeyword` | `models.Model` | None (platform-wide) | | **Account** | `Account`, `User`, `Plan`, `IntegrationSettings`, `ModuleEnableSettings`, `AISettings`, `AIPrompt`, `AuthorProfile`, `CreditBalance` | `AccountBaseModel` | `account` | | **Site+Sector** | `Keywords`, `Clusters`, `ContentIdeas`, `Tasks`, `Content`, `Images`, `AutomationConfig` | `SiteSectorBaseModel` | `site`, `sector` | --- ## Global Models (`igny8_core/modules/system/global_settings_models.py`) **Purpose:** Platform-wide defaults and API keys. Admin-only. NOT account-scoped. ### GlobalIntegrationSettings (Singleton) ```python class GlobalIntegrationSettings(models.Model): # OpenAI (used by ALL accounts) openai_api_key = CharField(max_length=500) openai_model = CharField(default='gpt-4o-mini') openai_temperature = FloatField(default=0.7) openai_max_tokens = IntegerField(default=8192) # DALL-E / Image Generation dalle_api_key = CharField(max_length=500) dalle_model = CharField(default='dall-e-3') dalle_size = CharField(default='1024x1024') # Runware runware_api_key = CharField(max_length=500) ``` **Critical:** Singleton (pk=1). API keys here are used by ALL accounts. ### GlobalAIPrompt ```python class GlobalAIPrompt(models.Model): prompt_type = CharField(max_length=100) # clustering, ideas, content_generation prompt_value = TextField() variables = JSONField(default=list) is_active = BooleanField(default=True) ``` ### GlobalAuthorProfile ```python class GlobalAuthorProfile(models.Model): name = CharField(max_length=255) tone = CharField(max_length=50) # professional, casual, technical language = CharField(max_length=10, default='en') is_active = BooleanField(default=True) ``` --- ## Auth Models (`igny8_core/auth/models/`) ### User ```python class User(AbstractBaseUser, PermissionsMixin): id = UUIDField(primary_key=True) email = EmailField(unique=True) first_name = CharField(max_length=150) last_name = CharField(max_length=150) account = ForeignKey(Account, related_name='users') role = ForeignKey(Group, null=True) is_active = BooleanField(default=True) is_staff = BooleanField(default=False) created_at = DateTimeField(auto_now_add=True) updated_at = DateTimeField(auto_now=True) ``` **Relations:** Account (many-to-one) --- ### Account ```python class Account(models.Model): id = UUIDField(primary_key=True) name = CharField(max_length=255) plan = ForeignKey(Plan, null=True) owner = ForeignKey(User, related_name='owned_accounts') is_active = BooleanField(default=True) created_at = DateTimeField(auto_now_add=True) ``` **Relations:** Plan (many-to-one), Users (one-to-many), Sites (one-to-many) --- ### Site ```python class Site(models.Model): id = UUIDField(primary_key=True) name = CharField(max_length=255) domain = CharField(max_length=255, blank=True) account = ForeignKey(Account, related_name='sites') industry = ForeignKey(Industry, null=True) is_active = BooleanField(default=True) created_at = DateTimeField(auto_now_add=True) ``` **Relations:** Account (many-to-one), Sectors (one-to-many), Industries (many-to-one) --- ### Sector ```python class Sector(models.Model): id = UUIDField(primary_key=True) name = CharField(max_length=255) description = TextField(blank=True) site = ForeignKey(Site, related_name='sectors') is_active = BooleanField(default=True) created_at = DateTimeField(auto_now_add=True) ``` **Relations:** Site (many-to-one) --- ### Industry ```python class Industry(models.Model): id = UUIDField(primary_key=True) name = CharField(max_length=255) description = TextField(blank=True) ``` **Used for:** Default seed keywords, industry-specific prompts --- ## Planner Models (`igny8_core/modules/planner/models.py`) ### Keyword ```python class Keyword(models.Model): id = UUIDField(primary_key=True) keyword = CharField(max_length=255) site = ForeignKey(Site, related_name='keywords') sector = ForeignKey(Sector, null=True, related_name='keywords') cluster = ForeignKey(Cluster, null=True, related_name='keywords') search_volume = IntegerField(null=True) difficulty = IntegerField(null=True) cpc = DecimalField(null=True) status = CharField(choices=KEYWORD_STATUS) # pending, clustered, used, archived created_by = ForeignKey(User) created_at = DateTimeField(auto_now_add=True) ``` **Status Values:** - `pending` - New, awaiting clustering - `clustered` - Assigned to a cluster - `used` - Used in content idea - `archived` - No longer active --- ### Cluster ```python class Cluster(models.Model): id = UUIDField(primary_key=True) name = CharField(max_length=255) description = TextField(blank=True) site = ForeignKey(Site, related_name='clusters') sector = ForeignKey(Sector, null=True, related_name='clusters') created_by = ForeignKey(User) created_at = DateTimeField(auto_now_add=True) ``` **Relations:** Site, Sector, Keywords (one-to-many), ContentIdeas (one-to-many) --- ### ContentIdea ```python class ContentIdea(models.Model): id = UUIDField(primary_key=True) title = CharField(max_length=255) description = TextField(blank=True) site = ForeignKey(Site, related_name='ideas') sector = ForeignKey(Sector, null=True) cluster = ForeignKey(Cluster, related_name='ideas') primary_keyword = ForeignKey(Keyword, related_name='primary_ideas') secondary_keywords = ManyToManyField(Keyword, related_name='secondary_ideas') status = CharField(choices=IDEA_STATUS) # pending, approved, used, archived created_at = DateTimeField(auto_now_add=True) ``` --- ## Writer Models (`igny8_core/modules/writer/models.py`) ### Task ```python class Task(models.Model): id = UUIDField(primary_key=True) title = CharField(max_length=255) brief = TextField(blank=True) site = ForeignKey(Site, related_name='tasks') sector = ForeignKey(Sector, null=True) idea = ForeignKey(ContentIdea, null=True, related_name='tasks') primary_keyword = CharField(max_length=255) secondary_keywords = JSONField(default=list) status = CharField(choices=TASK_STATUS) # pending, in_progress, completed, cancelled priority = CharField(choices=PRIORITY) # low, medium, high assigned_to = ForeignKey(User, null=True) due_date = DateField(null=True) created_by = ForeignKey(User) created_at = DateTimeField(auto_now_add=True) ``` --- ### Content ```python class Content(models.Model): id = UUIDField(primary_key=True) title = CharField(max_length=255) body = TextField() # HTML content excerpt = TextField(blank=True) site = ForeignKey(Site, related_name='content') sector = ForeignKey(Sector, null=True) task = ForeignKey(Task, related_name='content') meta_title = CharField(max_length=255, blank=True) meta_description = TextField(blank=True) status = CharField(choices=CONTENT_STATUS) # draft, review, approved, published word_count = IntegerField(default=0) created_by = ForeignKey(User) created_at = DateTimeField(auto_now_add=True) updated_at = DateTimeField(auto_now=True) ``` **Status Values:** - `draft` - Initial state after generation - `review` - Pending human review - `approved` - Ready for publishing - `published` - Published to WordPress --- ### ContentImage ```python class ContentImage(models.Model): id = UUIDField(primary_key=True) content = ForeignKey(Content, related_name='images') url = URLField() thumbnail_url = URLField(blank=True) alt_text = CharField(max_length=255) caption = TextField(blank=True) is_featured = BooleanField(default=False) position = IntegerField(default=0) # AI generation metadata prompt = TextField(blank=True) provider = CharField(max_length=50) # dalle, runware created_at = DateTimeField(auto_now_add=True) ``` --- ## Integration Models (`igny8_core/modules/integration/models.py`) ### SiteIntegration ```python class SiteIntegration(models.Model): id = UUIDField(primary_key=True) name = CharField(max_length=255) site = ForeignKey(Site, related_name='integrations') integration_type = CharField(max_length=50) # wordpress # Credentials (encrypted) url = URLField() username = CharField(max_length=255) api_key = CharField(max_length=255) # Application password # Cached structure categories = JSONField(default=list) tags = JSONField(default=list) authors = JSONField(default=list) post_types = JSONField(default=list) # Status is_active = BooleanField(default=True) last_sync_at = DateTimeField(null=True) structure_updated_at = DateTimeField(null=True) created_at = DateTimeField(auto_now_add=True) ``` --- ## Billing Models (`igny8_core/modules/billing/models.py`) ### Plan ```python class Plan(models.Model): id = UUIDField(primary_key=True) name = CharField(max_length=100) slug = SlugField(unique=True) idea_credits = IntegerField(default=0) content_credits = IntegerField(default=0) image_credits = IntegerField(default=0) optimization_credits = IntegerField(default=0) max_sites = IntegerField(default=1) max_users = IntegerField(default=1) price_monthly = DecimalField(max_digits=10, decimal_places=2) price_yearly = DecimalField(max_digits=10, decimal_places=2) is_active = BooleanField(default=True) is_internal = BooleanField(default=False) ``` --- ### CreditBalance ```python class CreditBalance(models.Model): account = ForeignKey(Account, related_name='credit_balances') site = ForeignKey(Site, null=True, related_name='credit_balances') idea_credits = IntegerField(default=0) content_credits = IntegerField(default=0) image_credits = IntegerField(default=0) optimization_credits = IntegerField(default=0) period_start = DateField() period_end = DateField() created_at = DateTimeField(auto_now_add=True) updated_at = DateTimeField(auto_now=True) ``` --- ### CreditUsage ```python class CreditUsage(models.Model): account = ForeignKey(Account, related_name='credit_usage') site = ForeignKey(Site, null=True) user = ForeignKey(User) credit_type = CharField(max_length=50) # idea, content, image, optimization amount = IntegerField() operation = CharField(max_length=100) # generate_content, etc. related_content_type = ForeignKey(ContentType, null=True) related_object_id = UUIDField(null=True) created_at = DateTimeField(auto_now_add=True) ``` --- ## System Models (`igny8_core/modules/system/`) ### ModuleEnableSettings ```python class ModuleEnableSettings(models.Model): account = OneToOneField(Account, primary_key=True) planner_enabled = BooleanField(default=True) writer_enabled = BooleanField(default=True) linker_enabled = BooleanField(default=False) optimizer_enabled = BooleanField(default=False) automation_enabled = BooleanField(default=True) integration_enabled = BooleanField(default=True) publisher_enabled = BooleanField(default=True) ``` --- ### AIIntegrationSettings ```python class AIIntegrationSettings(models.Model): account = ForeignKey(Account, related_name='ai_settings') # OpenAI openai_api_key = CharField(max_length=255, blank=True) openai_model = CharField(max_length=50, default='gpt-4') # Image generation image_provider = CharField(max_length=50, default='dalle') # dalle, runware dalle_api_key = CharField(max_length=255, blank=True) runware_api_key = CharField(max_length=255, blank=True) is_validated = BooleanField(default=False) validated_at = DateTimeField(null=True) ``` --- ### PromptTemplate ```python class PromptTemplate(models.Model): account = ForeignKey(Account, null=True) # null = system default prompt_type = CharField(max_length=100) # auto_cluster, generate_ideas, etc. template = TextField() variables = JSONField(default=list) is_active = BooleanField(default=True) created_at = DateTimeField(auto_now_add=True) updated_at = DateTimeField(auto_now=True) ``` --- ## Publisher Models (`igny8_core/modules/publisher/models.py`) ### PublishingRecord ```python class PublishingRecord(models.Model): id = UUIDField(primary_key=True) content = ForeignKey(Content, related_name='publishing_records') integration = ForeignKey(SiteIntegration, related_name='publishing_records') external_id = CharField(max_length=255) # WordPress post ID external_url = URLField(blank=True) status = CharField(max_length=50) # pending, published, failed published_at = DateTimeField(null=True) created_at = DateTimeField(auto_now_add=True) ``` --- ## Automation Models (`igny8_core/modules/automation/models.py`) ### AutomationConfig ```python class AutomationConfig(models.Model): site = ForeignKey(Site, related_name='automation_configs') # Stage limits clustering_limit = IntegerField(default=10) ideas_limit = IntegerField(default=10) content_limit = IntegerField(default=5) image_limit = IntegerField(default=10) publish_limit = IntegerField(default=5) # Timing delay_between_operations = IntegerField(default=5) # seconds max_runtime = IntegerField(default=3600) # 1 hour # Behavior auto_approve = BooleanField(default=False) auto_publish = BooleanField(default=False) stop_on_error = BooleanField(default=True) is_active = BooleanField(default=True) ``` --- ### AutomationRun ```python class AutomationRun(models.Model): id = UUIDField(primary_key=True) site = ForeignKey(Site, related_name='automation_runs') config = ForeignKey(AutomationConfig) status = CharField(max_length=50) # pending, running, paused, completed, failed, cancelled # Progress tracking current_stage = CharField(max_length=50, blank=True) items_processed = IntegerField(default=0) items_total = IntegerField(default=0) # Timing started_at = DateTimeField(null=True) completed_at = DateTimeField(null=True) # Results error_message = TextField(blank=True) started_by = ForeignKey(User) created_at = DateTimeField(auto_now_add=True) ``` --- ## Entity Relationship Overview ``` Account ├── Users (many) ├── Sites (many) │ ├── Sectors (many) │ ├── Keywords (many) │ ├── Clusters (many) │ ├── ContentIdeas (many) │ ├── Tasks (many) │ ├── Content (many) │ │ └── ContentImages (many) │ ├── SiteIntegrations (many) │ │ └── PublishingRecords (many) │ └── AutomationConfigs (many) │ └── AutomationRuns (many) ├── Plan (one) ├── CreditBalances (many) ├── CreditUsage (many) ├── ModuleEnableSettings (one) ├── AIIntegrationSettings (many) └── PromptTemplates (many) ```