Files
igny8/docs/90-REFERENCE/MODELS.md
IGNY8 VPS (Salman) f10916bfab VErsion 1.3.2
2026-01-03 09:35:43 +00:00

18 KiB

Database Models Reference

Last Verified: January 3, 2026


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 Site, PublishingSettings, AutomationConfig, SiteIntegration AccountBaseModel account, site
Site+Sector Keywords, Clusters, ContentIdeas, Tasks, Content, Images 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)

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

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

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

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

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

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

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

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

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

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

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

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

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)
    
    # Workflow status
    status = CharField(choices=CONTENT_STATUS)  # draft, review, approved, published
    
    # Publishing status (v1.3.2)
    site_status = CharField(choices=SITE_STATUS)  # not_published, scheduled, publishing, published, failed
    scheduled_publish_at = DateTimeField(null=True)
    site_status_updated_at = DateTimeField(null=True)
    
    # External site reference
    external_id = CharField(max_length=255, blank=True)  # WordPress post ID
    external_url = URLField(blank=True)  # Published URL
    
    word_count = IntegerField(default=0)
    
    created_by = ForeignKey(User)
    created_at = DateTimeField(auto_now_add=True)
    updated_at = DateTimeField(auto_now=True)

Workflow Status Values (status):

  • draft - Initial state after generation
  • review - Pending human review
  • approved - Ready for publishing (v1.3.2: NEW status)
  • published - Published to WordPress

Publishing Status Values (site_status) - v1.3.2:

  • not_published - Not yet scheduled for external site
  • scheduled - Scheduled for future publishing
  • publishing - Currently being published
  • published - Successfully published to external site
  • failed - Publishing failed

ContentImage

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/business/integration/models.py)

SiteIntegration

class SiteIntegration(models.Model):
    id = UUIDField(primary_key=True)
    name = CharField(max_length=255)
    
    site = ForeignKey(Site, related_name='integrations')
    platform = 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)

PublishingSettings (NEW v1.3.2)

class PublishingSettings(AccountBaseModel):
    """Site-level publishing configuration. Controls auto-approval, publishing limits, and scheduling."""
    
    site = OneToOneField(Site, related_name='publishing_settings')
    
    # Auto-approval settings
    auto_approval_enabled = BooleanField(default=True)
    
    # Auto-publish settings
    auto_publish_enabled = BooleanField(default=True)
    
    # Publishing limits
    daily_publish_limit = PositiveIntegerField(default=3)
    weekly_publish_limit = PositiveIntegerField(default=15)
    monthly_publish_limit = PositiveIntegerField(default=50)
    
    # Publishing schedule
    publish_days = JSONField(default=['mon', 'tue', 'wed', 'thu', 'fri'])
    publish_time_slots = JSONField(default=['09:00', '14:00', '18:00'])
    
    created_at = DateTimeField(auto_now_add=True)
    updated_at = DateTimeField(auto_now=True)

Default Values:

  • auto_approval_enabled: True (auto-approve after review)
  • auto_publish_enabled: True (auto-publish approved content)
  • daily_publish_limit: 3 articles per day
  • weekly_publish_limit: 15 articles per week
  • monthly_publish_limit: 50 articles per month
  • publish_days: Monday through Friday
  • publish_time_slots: 9:00 AM, 2:00 PM, 6:00 PM

Usage:

# Get or create with defaults
settings, created = PublishingSettings.get_or_create_for_site(site)

Billing Models (igny8_core/business/billing/models.py)

Plan

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

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

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

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

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

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

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

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

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)