Files
igny8/docs/90-REFERENCE/MODELS.md
IGNY8 VPS (Salman) c777e5ccb2 dos updates
2026-01-20 14:45:21 +00:00

26 KiB
Raw Blame History

Database Models Reference

Last Verified: January 20, 2026
Version: 1.8.4
Total Models: 52+


Data Scoping Overview

Scope Models Base Class Filter By
Global IntegrationProvider, AIModelConfig, SystemAISettings, GlobalAIPrompt, GlobalAuthorProfile, GlobalStrategy, GlobalModuleSettings, Industry, IndustrySector, SeedKeyword models.Model None (platform-wide)
Account Account, User, Plan, Subscription, AccountSettings, ModuleEnableSettings, AISettings, AIPrompt, AuthorProfile, CreditBalance, PasswordResetToken AccountBaseModel account
Site Site, PublishingSettings, AutomationConfig, DefaultAutomationConfig, AutomationRun, SiteIntegration, SiteUserAccess AccountBaseModel account, site
Site+Sector Keywords, Clusters, ContentIdeas, Tasks, Content, Images, ContentTaxonomyRelation SiteSectorBaseModel site, sector
Billing CreditCostConfig, BillingConfiguration, CreditPackage, PaymentMethodConfig, WebhookEvent models.Model varies
System SystemSettings, UserSettings, EmailSettings, EmailTemplate, EmailLog models.Model varies
Plugins Plugin, PluginVersion, PluginInstallation, PluginDownload models.Model varies

Model Count by Location

Location Count Models
auth/models.py 10 Account, User, Plan, Subscription, Industry, IndustrySector, SeedKeyword, Site, SiteUserAccess, PasswordResetToken
modules/system/ 10 IntegrationProvider, SystemAISettings, SystemSettings, UserSettings, EmailSettings, EmailTemplate, EmailLog, GlobalAIPrompt, GlobalAuthorProfile, GlobalStrategy
business/automation/ 3 DefaultAutomationConfig, AutomationConfig, AutomationRun
business/billing/ 6 CreditCostConfig, BillingConfiguration, CreditPackage, PaymentMethodConfig, AIModelConfig, WebhookEvent
business/content/ 1 ContentTaxonomyRelation
plugins/ 4 Plugin, PluginVersion, PluginInstallation, PluginDownload
modules/planner/ 3 Keywords, Clusters, ContentIdeas
modules/writer/ 3 Tasks, Content, Images

System Models (v1.4.0+) (igny8_core/modules/system/)

Purpose: Centralized AI configuration, provider API keys, and system-wide defaults.

IntegrationProvider (NEW v1.4.0)

Centralized storage for ALL external service API keys. Admin-only.

class IntegrationProvider(models.Model):
    """Per final-model-schemas.md - Centralized API key storage"""
    provider_id = CharField(max_length=50, primary_key=True)  # openai, runware, stripe, etc.
    display_name = CharField(max_length=100)
    provider_type = CharField(max_length=20)  # ai, payment, email, storage
    
    # Authentication
    api_key = CharField(max_length=500, blank=True)
    api_secret = CharField(max_length=500, blank=True)
    webhook_secret = CharField(max_length=500, blank=True)
    api_endpoint = URLField(blank=True)
    
    # Configuration
    config = JSONField(default=dict)
    is_active = BooleanField(default=True)
    is_sandbox = BooleanField(default=False)
    
    # Audit
    updated_by = ForeignKey(User, null=True)
    created_at = DateTimeField(auto_now_add=True)
    updated_at = DateTimeField(auto_now=True)

Seeded Providers:

  • openai - AI (text + DALL-E)
  • runware - AI (images)
  • anthropic - AI (future)
  • stripe - Payment
  • paypal - Payment
  • resend - Email

Helper Methods:

  • IntegrationProvider.get_provider(provider_id) - Get active provider
  • IntegrationProvider.get_api_key(provider_id) - Get API key for provider
  • IntegrationProvider.get_providers_by_type(type) - List providers by type

AIModelConfig (NEW v1.4.0)

Single Source of Truth for all AI models with pricing and credit configuration.

class AIModelConfig(models.Model):
    """Per final-model-schemas.md - Model definitions + pricing"""
    model_name = CharField(max_length=100, unique=True)  # gpt-4o-mini, dall-e-3, runware:97@1
    model_type = CharField(max_length=20)  # text, image
    provider = CharField(max_length=50)  # Links to IntegrationProvider
    display_name = CharField(max_length=200)
    
    is_default = BooleanField(default=False)  # One default per type
    is_active = BooleanField(default=True)
    
    # Text Model Pricing (per 1K tokens)
    cost_per_1k_input = DecimalField(max_digits=10, decimal_places=6, null=True)
    cost_per_1k_output = DecimalField(max_digits=10, decimal_places=6, null=True)
    tokens_per_credit = IntegerField(null=True)  # e.g., 1000, 10000
    
    # Image Model Pricing
    credits_per_image = IntegerField(null=True)  # e.g., 1, 5, 15
    quality_tier = CharField(max_length=20, null=True)  # basic, quality, premium
    
    # Model Limits
    max_tokens = IntegerField(null=True)
    context_window = IntegerField(null=True)
    capabilities = JSONField(default=dict)  # vision, function_calling, etc.
    
    created_at = DateTimeField(auto_now_add=True)
    updated_at = DateTimeField(auto_now=True)

Credit Configuration Examples:

Model Type tokens_per_credit credits_per_image quality_tier
gpt-4o text 1000 - -
gpt-4o-mini text 10000 - -
runware:97@1 image - 1 basic
dall-e-3 image - 5 quality
google:4@2 image - 15 premium

Image Model Reference (v1.5.0 Planned):

Model AIR ID Tier Supported Dimensions
Hi Dream Full runware:97@1 Basic 1024×1024, 1280×768
Bria 3.2 bria:10@1 Quality 1024×1024, 1344×768
Nano Banana google:4@2 Premium 1024×1024, 1376×768

Helper Methods:

  • AIModelConfig.get_default_text_model() - Get default text model
  • AIModelConfig.get_default_image_model() - Get default image model
  • AIModelConfig.get_image_models_by_tier() - List image models by quality tier

SystemAISettings (NEW v1.4.0)

System-wide AI defaults. Singleton (pk=1).

class SystemAISettings(models.Model):
    """Per final-model-schemas.md - Renamed from GlobalIntegrationSettings"""
    # AI Parameters
    temperature = FloatField(default=0.7)  # 0.0-2.0
    max_tokens = IntegerField(default=8192)
    
    # Image Generation Settings
    image_style = CharField(max_length=30, default='photorealistic')
    image_quality = CharField(max_length=20, default='standard')  # standard, hd
    max_images_per_article = IntegerField(default=4)  # 1-8
    image_size = CharField(max_length=20, default='1024x1024')
    
    # Audit
    updated_by = ForeignKey(User, null=True)
    updated_at = DateTimeField(auto_now=True)

Image Style Choices:

  • photorealistic - Ultra realistic photography
  • illustration - Digital illustration
  • 3d_render - Computer generated 3D
  • minimal_flat - Minimal / Flat Design
  • artistic - Artistic / Painterly
  • cartoon - Cartoon / Stylized

Image Size Choices:

  • 1024x1024 - Square
  • 1792x1024 - Landscape
  • 1024x1792 - Portrait

Helper Methods:

  • SystemAISettings.get_instance() - Get singleton instance
  • SystemAISettings.get_effective_temperature(account) - Get with account override
  • SystemAISettings.get_effective_image_style(account) - Get with account override

AccountSettings (Per-Account Overrides)

Generic key-value store for account-specific settings.

class AccountSettings(AccountBaseModel):
    """Per final-model-schemas.md - Account overrides"""
    key = CharField(max_length=100)  # Setting key
    value = JSONField(default=dict)  # Setting value
    
    created_at = DateTimeField(auto_now_add=True)
    updated_at = DateTimeField(auto_now=True)

AI-Related Keys (override SystemAISettings defaults):

Key Type Example Notes
ai.temperature float 0.8 Override system default
ai.max_tokens int 8192 Override system default
ai.image_style string "illustration" Override system default
ai.image_quality string "hd" Override system default
ai.max_images int 6 Override system default
ai.image_quality_tier string "premium" User's preferred tier

CreditCostConfig (Operation-Level Pricing)

Fixed credit costs per operation type.

class CreditCostConfig(models.Model):
    """Per final-model-schemas.md - Operation pricing"""
    operation_type = CharField(max_length=50, primary_key=True)  # Unique operation ID
    display_name = CharField(max_length=100)
    base_credits = IntegerField(default=1)  # Fixed credits per operation
    is_active = BooleanField(default=True)
    description = TextField(blank=True)

Note: tokens_per_credit moved to AIModelConfig as of v1.4.0.


DEPRECATED Models

GlobalIntegrationSettings (DEPRECATED in v1.4.0)

Replaced by: IntegrationProvider (API keys) + AIModelConfig (model configs) + SystemAISettings (defaults)

# DEPRECATED - Do not use
class GlobalIntegrationSettings(models.Model):
    # API keys now in IntegrationProvider
    openai_api_key = CharField(max_length=500)  # → IntegrationProvider.get_api_key('openai')
    runware_api_key = CharField(max_length=500)  # → IntegrationProvider.get_api_key('runware')
    
    # Models now in AIModelConfig
    openai_model = CharField(default='gpt-4o-mini')  # → AIModelConfig.is_default
    
    # Settings now in SystemAISettings
    openai_temperature = FloatField(default=0.7)  # → SystemAISettings.temperature
    openai_max_tokens = IntegerField(default=8192)  # → SystemAISettings.max_tokens

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)  # new, mapped
    
    created_by = ForeignKey(User)
    created_at = DateTimeField(auto_now_add=True)

Status Values:

  • new - Ready for clustering
  • mapped - Assigned to a cluster

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)  # queued, completed
    
    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

⚠️ Note: For WordPress, Site.wp_api_key is the SINGLE source of truth for API authentication. SiteIntegration is used for sync tracking and future multi-platform support.

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, shopify (future)
    
    # Configuration
    external_site_url = URLField()
    config_json = JSONField(default=dict)       # Platform-specific settings
    credentials_json = JSONField(default=dict)  # Reserved for future platforms (NOT for WordPress)
    
    # Sync Tracking
    sync_enabled = BooleanField(default=True)
    sync_status = CharField(max_length=50)  # pending/syncing/completed/error
    last_sync_at = DateTimeField(null=True)
    sync_error = TextField(null=True)
    
    # Connection
    connection_status = CharField(max_length=50)  # connected/error
    is_active = BooleanField(default=True)
    
    # Cached WordPress structure (from initial sync)
    categories = JSONField(default=list)
    tags = JSONField(default=list)
    authors = JSONField(default=list)
    post_types = JSONField(default=list)
    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)