Files
igny8/docs/plans/final-dev-guides-of-futute-implementation/DocB-Platform-Modules-Dev-Guide.md
2026-03-08 02:36:44 +00:00

69 KiB
Raw Blame History

Doc B — IGNY8 Platform Modules: Development Guide for Claude Code

Version: 1.0 Date: March 2026 For: Claude Code (Opus 4.6) in VSCode on IGNY8 repo Purpose: Step-by-step implementation guide for all IGNY8 platform module enhancements — Content Types Writing, Taxonomy & Term Content, Optimizer, GSC Integration, Rich Schema & SERP Enhancement, Socializer, and Video Creator Rule: Nothing currently working breaks. All new functionality uses the existing pipeline pattern. All new modules use feature flags. Existing Writer/Planner/Automation pages are enhanced, not replaced. Dependency: Doc A (SAG Architecture) provides the blueprint, cluster, and attribute data that several modules here consume. Content Types Writing and Taxonomy & Term Content should ideally complete before Optimizer, but GSC and Rich Schema can run in parallel.


Table of Contents

  1. System Context — Current Pipeline & Module Structure
  2. Implementation Sequence
  3. Module 1: Content Types Writing
  4. Module 2: Taxonomy & Term Content
  5. Module 3: Optimizer Module
  6. Module 4: GSC Integration
  7. Module 5: Rich Schema & SERP Enhancement
  8. Module 6: Socializer
  9. Module 7: Video Creator
  10. Updated Automation Pipeline — All Stages
  11. Updated Navigation & Sidebar
  12. Complete API Endpoint Registry
  13. Complete AI Function Registry
  14. Complete Celery Task Registry
  15. Feature Flag Registry
  16. Credit Cost Summary
  17. Cross-Module Dependencies

1. System Context — Current Pipeline & Module Structure

1.1 Current Content Pipeline (What Exists)

Stage 1: Process New Keywords       → modules/planner/ + business/planning/
Stage 2: AI Cluster Keywords        → ai/functions/auto_cluster.py
Stage 3: Generate Content Ideas     → ai/functions/generate_ideas.py + modules/planner/
Stage 4: Create Writer Tasks        → modules/writer/
Stage 5: Generate Article Content   → ai/functions/generate_content.py + business/content/
Stage 6: Extract Image Prompts      → ai/functions/generate_image_prompts.py
Stage 7: Generate Images            → ai/functions/generate_images.py → Review Queue

All stages execute via Celery tasks defined in tasks/. Automation orchestration lives in business/automation/. Configuration per site is in AutomationConfig.

1.2 Current Content Model Fields (Relevant)

# modules/writer/models.py — Content model (simplified)
class Content(SiteSectorBaseModel):
    task = ForeignKey(Tasks)
    title = CharField()
    slug = SlugField()
    content = TextField()           # Full HTML
    meta_title = CharField()
    meta_description = TextField()
    status = CharField()            # queue, draft, review, published
    content_type = CharField()      # Currently: 'post', 'page'
    word_count = IntegerField()
    # ... images, keywords, publishing fields

1.3 Current Inactive Modules

Module Backend API Frontend Flag
Linker business/linking/ modules/linker/ pages/Linker/, api/linker.api.ts linker_enabled
Optimizer business/optimization/ modules/optimizer/ pages/Optimizer/, api/optimizer.api.ts optimizer_enabled

1.4 Existing Prompt System

Prompts are stored in PromptTemplate model or defaults in code. Templates exist for: auto_cluster, generate_ideas, generate_content, generate_image_prompts, optimize_content (pending). Users customize via Settings → Prompts (Thinker module).

1.5 Existing Integration Architecture

WordPress communication uses:

  • Site.wp_api_key for authentication
  • Webhook endpoints for sync (plugin → IGNY8 and IGNY8 → plugin)
  • business/integration/ for sync services
  • modules/integration/ for API endpoints
  • Plugin file: data/site-collection.php for data gathering

1.6 Existing Credit System

All AI operations deduct credits via CreditService.check_credits() → execute → CreditService.deduct_credits_for_operation(). Costs configured per model in AIModelConfig.


2. Implementation Sequence

MODULE 1 ─── Content Types Writing (FIRST — foundation for all others)
   │         Extends Writer pipeline with new content types and structures.
   │         No new module — enhances existing Planner + Writer + Publisher.
   │
MODULE 2 ─── Taxonomy & Term Content
   │         Depends on Module 1 for content structures.
   │         Requires taxonomy sync restoration.
   │         Enhances Planner + Writer + Publisher + Integration.
   │
MODULE 3 ─── Optimizer (activate existing module)
   │         Depends on Module 1+2 for content type support.
   │         Benefits from SAG cluster mapping (Doc A Phase 5).
   │         Activates optimizer_enabled flag.
   │
MODULE 4 ─── GSC Integration (CAN PARALLEL with 1-3)
   │         Independent of content pipeline changes.
   │         New module entirely: OAuth, URL Inspection, metrics.
   │
MODULE 5 ─── Rich Schema & SERP Enhancement (CAN PARALLEL with 4)
   │         Enhances content pipeline Stage 5 + adds retroactive engine.
   │         Benefits from Module 1 (content type classification).
   │
MODULE 6 ─── Socializer
   │         Depends on published content (any type from Module 1+2).
   │         New module: OAuth, platform connections, scheduling.
   │         New automation Stage 8.
   │
MODULE 7 ─── Video Creator
             Depends on Module 6 infrastructure (OAuth, scheduling, media storage).
             New module: script generation, TTS, video assembly.
             New automation Stage 9.

Parallel tracks:

  • GSC (Module 4) is fully independent — start anytime
  • Rich Schema (Module 5) can start alongside GSC
  • Socializer OAuth/platform connections can start while earlier modules finish

3. Module 1: Content Types Writing

3.1 What This Module Delivers

IGNY8 currently writes blog posts (content_type='post'). This module extends the Writer to produce pages, products (WooCommerce), services, company pages, taxonomy landing pages, and cluster hub pages — all through the same pipeline.

3.2 Backend: Content Type Expansion

Modify: modules/writer/models.py — extend content_type choices on Content model

# Add new choices to Content.content_type:
CONTENT_TYPE_CHOICES = [
    ('post', 'Blog Post'),                    # Existing
    ('page', 'Page'),                          # Existing (limited use)
    ('product', 'Product Page'),               # NEW
    ('service', 'Service Page'),               # NEW
    ('company_page', 'Company Page'),          # NEW
    ('taxonomy_landing', 'Taxonomy Landing'),   # NEW
    ('cluster_hub', 'Cluster Hub Page'),        # NEW
    ('comparison', 'Comparison Page'),          # NEW
    ('brand_page', 'Brand Page'),              # NEW
]

Add new field: content_structure on Content model (or extend existing structure field)

# Add to Content model:
content_structure = models.CharField(
    max_length=30, null=True, blank=True,
    choices=[
        # Blog structures (existing, now explicit)
        ('guide_tutorial', 'Guide/Tutorial'),
        ('comparison', 'Comparison'),
        ('review', 'Review'),
        ('how_to', 'How To'),
        ('question', 'Question/Answer'),
        ('top_listicle', 'Top Listicle'),
        # Page structures (NEW)
        ('landing_page', 'Landing Page'),
        ('about_page', 'About Page'),
        ('contact_page', 'Contact Page'),
        # Product structures (NEW)
        ('product_single', 'Single Product'),
        ('product_collection', 'Product Collection'),
        # Service structures (NEW)
        ('service_single', 'Single Service'),
        ('service_area', 'Service Area Page'),
        # Company structures (NEW)
        ('company_about', 'Company About'),
        ('company_team', 'Company Team'),
        ('company_careers', 'Company Careers'),
        # Taxonomy structures (NEW)
        ('category_archive', 'Category Archive'),
        ('tag_archive', 'Tag Archive'),
        ('attribute_archive', 'Attribute Archive'),
        ('cluster_hub', 'Cluster Hub'),
    ]
)

Modify: modules/planner/models.py — extend ContentIdea model with same fields

# Add to ContentIdea model:
content_type = models.CharField(max_length=30, null=True, blank=True)   # Same choices as Content
content_structure = models.CharField(max_length=30, null=True, blank=True)

Modify: modules/writer/models.py — extend Tasks model

# Add to Tasks model:
content_type = models.CharField(max_length=30, default='post')
content_structure = models.CharField(max_length=30, null=True, blank=True)

3.3 Backend: Type-Specific Prompt Templates

Location: Add to existing PromptTemplate system or as defaults in ai/functions/generate_content.py

Each content_type × content_structure combination gets a distinct prompt. The prompt includes type-specific section requirements:

Content Type Required Sections in Prompt
product Features/benefits, specs table, comparison to alternatives, FAQs, CTA, product schema placeholders
service Service overview, process steps, outcomes/results, FAQs, local SEO sections (if location-based), CTA
company_page Brand mission/values, history, team bios (if team page), FAQ, media/press block
taxonomy_landing Intro + topical definition, key subtopics with internal link placeholders, related items, FAQ section
cluster_hub Comprehensive guide introduction, section per supporting topic, product/service roundup, FAQ, internal linking sections
comparison Head-to-head comparison table, pros/cons per item, winner recommendation, FAQ

Register new prompt templates:

# In PromptTemplate seeding or defaults:
'generate_content_product'          # Product page prompt
'generate_content_service'          # Service page prompt
'generate_content_company'          # Company page prompt
'generate_content_taxonomy_landing' # Taxonomy landing prompt
'generate_content_cluster_hub'      # Cluster hub prompt
'generate_content_comparison'       # Comparison page prompt

3.4 Backend: Type-Specific Idea Generation

Modify: ai/functions/generate_ideas.py — enhance GenerateContentIdeas

When generating ideas, the system now considers content_type:

  • Product ideas: features/specs/benefits angle, "Best X for Y" format
  • Service ideas: process/outcomes angle, "How [Service] Works" format
  • Company page ideas: mission/team/careers angle
  • Taxonomy landing ideas: topical overview, "Complete Guide to [Term]" format

The existing function stays but gets an additional parameter: target_content_type. If provided, idea generation is type-aware. If not provided (legacy), defaults to blog post ideas.

3.5 Backend: Publishing Enhancement

Modify: business/publishing/ — extend publishing to handle content types

# business/publishing/wordpress_publisher.py — extend publish logic:

def publish_content(content):
    if content.content_type == 'post':
        # Existing: publish as WordPress post
        pass
    elif content.content_type == 'page':
        # Publish as WordPress page
        pass
    elif content.content_type == 'product':
        # Publish as WooCommerce product (requires WooCommerce API)
        pass
    elif content.content_type == 'service':
        # Publish as custom post type 'service' (requires theme/plugin CPT)
        pass
    elif content.content_type == 'taxonomy_landing':
        # Publish as term description content (Module 2 handles this)
        pass
    elif content.content_type == 'cluster_hub':
        # Publish as WordPress page with hub template
        pass

Plugin side: The IGNY8 Bridge plugin needs enhanced content receiving:

igny8-plugin/includes/modules/content-sync/
├── class-content-mapper.php     # MODIFY: map IGNY8 content_type to WP post type

Mapping:

IGNY8 content_type WordPress post_type Template
post post Standard
page page Default page
product product (WooCommerce) Product template
service service (CPT from theme) Service template
company_page page Company page template
taxonomy_landing term description Term archive template
cluster_hub page Hub page template
comparison post Standard (with comparison CSS)

3.6 Frontend: Writer UI Enhancement

Location: pages/Writer/ — enhance existing views

Task Creation — Add content type selector:

pages/Writer/
├── components/
│   ├── TaskCreationForm.tsx    # MODIFY: add content_type dropdown + content_structure dropdown
│   └── ContentTypeSelector.tsx # NEW: visual card selector for content type

When creating a new task (manual mode), user sees:

  • Content Type dropdown: Blog Post, Page, Product, Service, Company Page, Taxonomy Landing, Cluster Hub, Comparison
  • Content Structure dropdown: dynamically filtered based on content_type selection
  • Existing fields (title, keywords, cluster, sector) remain unchanged

Content List — Show type badge:

pages/Writer/
├── components/
│   └── ContentListItem.tsx    # MODIFY: add content_type badge next to title

Each content item in Queue/Drafts/Review/Published shows a small badge: "Post", "Product", "Hub", "Service", etc.

Ideas List — Show type:

pages/Planner/
├── components/
│   └── IdeaListItem.tsx       # MODIFY: show content_type and content_structure

3.7 Frontend: No New Pages

Module 1 adds NO new pages to the sidebar. Everything happens within existing Planner and Writer pages. The changes are:

  • Dropdowns added to task creation
  • Badges added to list items
  • Type-specific preview in content review

4. Module 2: Taxonomy & Term Content

4.1 What This Module Delivers

Every taxonomy term (WordPress categories, tags, WooCommerce product categories/attributes, custom taxonomies from SAG) becomes a rich SEO landing page generated through the same pipeline as posts.

4.2 Backend: Restore Taxonomy Sync

Current state: Taxonomy sync was partially implemented then removed ("legacy removed"). ContentTaxonomy model exists. WordPress client knows how to fetch categories/tags/WooCommerce attributes.

Restore and enhance in: business/integration/

# business/integration/taxonomy_sync_service.py    # RESTORE/REWRITE

class TaxonomySyncService:
    def sync_taxonomies(self, site):
        """Fetch all taxonomies + terms from WordPress and sync to ContentTaxonomy."""
        # 1. Fetch via plugin API: categories, tags, WooCommerce product_cat, 
        #    product_tag, all pa_* attributes, custom taxonomies (from SAG)
        # 2. Create/update ContentTaxonomy records
        # 3. Map terms to clusters where possible (using SAG blueprint if active)
        pass
    
    def publish_term_content(self, content_taxonomy, content):
        """Push generated content back to WordPress term description."""
        # 1. Content → term description HTML
        # 2. POST to plugin endpoint: /wp-json/igny8/v1/terms/{term_id}/content
        # 3. Update ContentTaxonomy sync status
        pass

Plugin endpoint needed:

POST /wp-json/igny8/v1/terms/{term_id}/content
Body: {description: "HTML content", meta: {igny8_term_content, igny8_term_faq, ...}}

4.3 Backend: Term-to-Cluster Mapping Service

# business/planning/cluster_mapping_service.py    # NEW

class ClusterMappingService:
    def map_term_to_cluster(self, term_name, term_description, site):
        """Match a taxonomy term to the best SAG cluster."""
        # If SAG blueprint active: match term to cluster by attribute value overlap
        # If no blueprint: use AI semantic similarity to existing clusters
        # Return: cluster_id, confidence_score
        pass
    
    def bulk_map_terms(self, terms, site):
        """Map all terms for a site to clusters."""
        pass

4.4 Backend: Term Content Generation

The key insight: term content generation follows the SAME pipeline as post content. The difference is in content_type and publishing destination.

Idea generation for terms:

# business/planning/ — extend idea generation

def generate_term_ideas(site, terms):
    """For each taxonomy term without content, create a ContentIdea."""
    for term in terms:
        idea = ContentIdea(
            title=f"Complete Guide to {term.name}",
            content_type='taxonomy_landing',
            content_structure='category_archive',  # or tag_archive, attribute_archive
            cluster=term.mapped_cluster,
            idea_source='sag_blueprint' if site.sag_blueprint_id else 'keyword_clustering',
            # ... sector, keywords
        )

Task creation and content generation use the same pipeline as Module 1 — the content_type='taxonomy_landing' selects the appropriate prompt template.

Publishing goes to term description instead of post content (handled by TaxonomySyncService.publish_term_content()).

4.5 Backend: ContentTaxonomy Model Enhancement

Modify: existing ContentTaxonomy model (if it exists) or create:

# modules/planner/models.py or modules/integration/models.py

class ContentTaxonomy(SiteSectorBaseModel):
    # Existing fields...
    external_taxonomy = models.CharField(max_length=100)  # 'category', 'post_tag', 'pa_color', etc.
    external_term_id = models.IntegerField()
    name = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200)
    description = models.TextField(blank=True)
    parent_term_id = models.IntegerField(null=True, blank=True)
    post_count = models.IntegerField(default=0)
    
    # NEW fields:
    mapped_cluster_id = models.ForeignKey('sag.SAGCluster', null=True, blank=True, on_delete=models.SET_NULL)
    has_generated_content = models.BooleanField(default=False)
    generated_content_id = models.ForeignKey('writer.Content', null=True, blank=True, on_delete=models.SET_NULL)
    content_sync_status = models.CharField(max_length=20, default='pending',
        choices=[('pending','Pending'),('synced','Synced'),('failed','Failed')])
    last_synced_at = models.DateTimeField(null=True, blank=True)

4.6 Frontend: Taxonomy Management UI

Location: Add to Planner section

frontend/src/pages/Planner/
├── Taxonomies.tsx              # NEW — list all synced taxonomies + terms
├── components/
│   ├── TaxonomyList.tsx        # Taxonomy groups with term counts
│   ├── TermList.tsx            # Terms within a taxonomy with content status
│   ├── TermClusterMapper.tsx   # Assign/reassign cluster per term
│   └── TermContentStatus.tsx   # Content generated? Published? Sync status?

Sidebar integration: Add "Taxonomies" as a sub-item under Planner:

WORKFLOW
  ├── Planner
  │   ├── Keywords
  │   ├── Clusters
  │   ├── Ideas
  │   └── Taxonomies (NEW)
  ├── Writer
  ...

Taxonomy List view:

  • Shows all synced taxonomies grouped: WordPress Default (categories, tags), WooCommerce (product_cat, product_tag, pa_*), Custom/SAG (from blueprint)
  • Per taxonomy: term count, terms with content, terms without content
  • "Sync Taxonomies" button to trigger fresh sync from WordPress
  • "Generate All Term Content" button to batch-create ideas for all unmapped terms

Term Detail view:

  • Term name, slug, description, post count
  • Cluster mapping: current cluster (or "Unmapped"), dropdown to change
  • Content status: Not generated / Draft / Review / Published
  • "Generate Content" button for individual term
  • Preview of generated content

4.7 Frontend: Automation Integration

When automation runs with taxonomy content enabled:

  • Stage 3 (Idea Generation) includes term ideas alongside post ideas
  • Ideas list in Planner shows term ideas with "Taxonomy Landing" badge
  • Writer Queue/Drafts show term content alongside post content
  • Publishing routes term content to term description instead of creating a new post

5. Module 3: Optimizer Module

5.1 What This Module Delivers

Activates the existing optimizer_enabled module. Analyzes and optimizes existing published content: maps to clusters, rewrites structure for intent alignment, refreshes SEO metadata, generates schema markup.

5.2 Backend: Implement OptimizeContent AI Function

Location: ai/functions/optimize_content.py — currently PENDING, implement it

class OptimizeContent:
    """
    Takes existing content and produces an optimized version:
    - Maps to best-matching cluster
    - Rewrites structure for intent alignment
    - Refreshes meta title/description
    - Adds missing sections (FAQs, comparisons, etc.)
    - Generates schema JSON-LD
    """
    
    def execute(self, content, cluster=None, optimization_config=None):
        # 1. If no cluster provided, call ClusterMappingService to find best match
        # 2. Analyze current content: heading structure, keyword density, missing sections
        # 3. Generate optimized version with SAG context
        # 4. Generate before/after scores
        # 5. Return: optimized_content, meta, schema, scores, diff_summary
        pass

5.3 Backend: Optimizer Service

# business/optimization/optimizer_service.py    # IMPLEMENT (file exists, logic pending)

class OptimizerService:
    def analyze_content(self, content):
        """Score content against its cluster targets. Return analysis report."""
        # Keyword coverage score
        # Heading structure score
        # Content length assessment
        # Missing sections detection
        # Internal link opportunities
        # Schema coverage
        pass
    
    def optimize_content(self, content, apply_mode='manual'):
        """Generate optimized version. apply_mode: 'manual' (review first) or 'auto'."""
        pass
    
    def batch_optimize(self, site, content_ids):
        """Queue batch optimization as Celery tasks."""
        pass
    
    def generate_schema(self, content):
        """Generate appropriate JSON-LD schema based on content_type."""
        pass

5.4 Backend: Optimizer Models

Modify/create in: modules/optimizer/models.py

class OptimizationJob(SiteSectorBaseModel):
    """Tracks a single optimization operation."""
    content = models.ForeignKey('writer.Content', on_delete=models.CASCADE)
    status = models.CharField(max_length=20, choices=[
        ('pending', 'Pending'),
        ('analyzing', 'Analyzing'),
        ('optimized', 'Optimized'),
        ('applied', 'Applied'),
        ('rejected', 'Rejected'),
    ], default='pending')
    original_score = models.FloatField(null=True, blank=True)
    optimized_score = models.FloatField(null=True, blank=True)
    cluster_match = models.ForeignKey('sag.SAGCluster', null=True, blank=True, on_delete=models.SET_NULL)
    cluster_confidence = models.FloatField(null=True, blank=True)
    optimized_content = models.TextField(blank=True)
    optimized_meta_title = models.CharField(max_length=300, blank=True)
    optimized_meta_description = models.TextField(blank=True)
    generated_schema = models.JSONField(default=dict, blank=True)
    diff_summary = models.JSONField(default=dict, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    applied_at = models.DateTimeField(null=True, blank=True)

5.5 Backend: Optimizer API

Enhance: modules/optimizer/views.py

# POST /api/v1/optimizer/analyze/
# Input: {content_id}
# Output: {score, cluster_match, recommendations}

# POST /api/v1/optimizer/optimize/
# Input: {content_id, cluster_id (optional override)}
# Output: {job_id, optimized_preview}

# POST /api/v1/optimizer/apply/{job_id}/
# Input: {job_id}
# Output: {success, updated_content}

# POST /api/v1/optimizer/batch/
# Input: {content_ids: [...]}
# Output: {jobs: [{content_id, job_id}]}

# GET /api/v1/optimizer/jobs/
# List all optimization jobs with status

5.6 Frontend: Optimizer Page

Location: pages/Optimizer/ — existing but INACTIVE, implement UI

frontend/src/pages/Optimizer/
├── OptimizerDashboard.tsx      # IMPLEMENT — overview of optimization opportunities
│   ├── ContentScoreList.tsx    # All content sorted by optimization score (lowest first)
│   ├── ClusterCoverage.tsx     # Which clusters have optimized vs unoptimized content
│   └── OptimizationQueue.tsx   # Active/pending optimization jobs
├── OptimizeContent.tsx         # IMPLEMENT — single content optimization view
│   ├── BeforeAfterView.tsx     # Side-by-side original vs optimized
│   ├── ScoreComparison.tsx     # Score breakdown: before vs after
│   ├── ClusterMatcher.tsx      # Show matched cluster, allow override
│   ├── SchemaPreview.tsx       # Preview generated JSON-LD
│   └── ApplyRejectButtons.tsx  # Apply optimization or reject
└── BatchOptimize.tsx           # IMPLEMENT — select multiple, batch optimize

Sidebar: Optimizer appears under WORKFLOW when optimizer_enabled = True (existing behavior, now with actual UI).

5.7 Settings Integration

Location: pages/Settings/ — add Optimizer settings tab

Settings for Optimizer module:

  • Enable/disable Optimizer
  • Default schema type per content type (Article, Product, FAQ, etc.)
  • Keyword density targets (percentage range)
  • Content length guidelines (min/max per content type)
  • Auto-apply vs manual review toggle
  • Exclude content from optimization (by ID or date range)

6. Module 4: GSC Integration

6.1 What This Module Delivers

Google Search Console integration: OAuth connection, URL Inspection API, auto-indexing pipeline, search metrics dashboard, plugin status sync.

6.2 Backend: New Django App

backend/igny8_core/
├── gsc/                              # NEW Django app
│   ├── __init__.py
│   ├── apps.py
│   ├── models.py                     # GSCConnection, URLTrackingRecord, SearchMetric
│   ├── serializers.py
│   ├── views.py                      # OAuth flow, inspection, metrics endpoints
│   ├── urls.py                       # /api/v1/gsc/*
│   ├── admin.py
│   ├── services/
│   │   ├── __init__.py
│   │   ├── oauth_service.py          # Google OAuth token management
│   │   ├── site_mapping_service.py   # Map IGNY8 sites to GSC properties
│   │   ├── inspection_service.py     # URL Inspection API calls
│   │   ├── indexing_service.py       # Auto-indexing queue + pipeline
│   │   ├── metrics_service.py        # Search Analytics API data fetch
│   │   └── quota_service.py          # Daily quota tracking (2,000/day)
│   ├── tasks.py                      # Celery tasks for queue processing
│   └── migrations/

6.3 Backend: Models

# gsc/models.py

class GSCConnection(AccountBaseModel):
    """One Google OAuth connection per account. Manages all sites."""
    google_email = models.EmailField()
    access_token = models.TextField()
    refresh_token = models.TextField()
    token_expiry = models.DateTimeField()
    scopes = models.JSONField(default=list)
    is_active = models.BooleanField(default=True)
    connected_at = models.DateTimeField(auto_now_add=True)
    last_refreshed = models.DateTimeField(null=True, blank=True)

class GSCSiteMapping(models.Model):
    """Maps an IGNY8 site to a GSC property."""
    site = models.OneToOneField('auth.Site', on_delete=models.CASCADE, related_name='gsc_mapping')
    gsc_property = models.CharField(max_length=300, help_text='e.g., sc-domain:example.com')
    property_type = models.CharField(max_length=20, choices=[
        ('domain', 'Domain Property'),
        ('url_prefix', 'URL Prefix'),
    ])
    status = models.CharField(max_length=20, choices=[
        ('matched', 'Auto-Matched'),
        ('manual', 'Manually Mapped'),
        ('not_found', 'Not Found in GSC'),
    ])
    verified = models.BooleanField(default=False)
    mapped_at = models.DateTimeField(auto_now_add=True)

class URLTrackingRecord(SiteSectorBaseModel):
    """Tracks indexing status for each URL."""
    url = models.URLField()
    content = models.ForeignKey('writer.Content', null=True, blank=True, on_delete=models.SET_NULL)
    is_igny8_content = models.BooleanField(default=True)
    
    # Inspection results
    index_status = models.CharField(max_length=30, choices=[
        ('unknown', 'Unknown'),
        ('indexed', 'Indexed'),
        ('not_indexed', 'Not Indexed'),
        ('indexing_requested', 'Indexing Requested'),
        ('error', 'Error'),
        ('noindex', 'Noindex Detected'),
    ], default='unknown')
    coverage_state = models.CharField(max_length=100, blank=True)
    last_crawl_time = models.DateTimeField(null=True, blank=True)
    crawl_status = models.CharField(max_length=50, blank=True)
    
    # Queue management
    queue_priority = models.IntegerField(default=50)
    next_check_at = models.DateTimeField(null=True, blank=True)
    check_count = models.IntegerField(default=0)
    max_checks = models.IntegerField(default=4)
    
    last_inspected_at = models.DateTimeField(null=True, blank=True)
    indexing_requested_at = models.DateTimeField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

class SearchMetricSnapshot(SiteSectorBaseModel):
    """Daily/weekly search metrics from GSC Search Analytics API."""
    date = models.DateField()
    dimension = models.CharField(max_length=20, choices=[
        ('page', 'Page'), ('query', 'Query'),
        ('country', 'Country'), ('device', 'Device'),
    ])
    dimension_value = models.CharField(max_length=500)
    clicks = models.IntegerField(default=0)
    impressions = models.IntegerField(default=0)
    ctr = models.FloatField(default=0.0)
    position = models.FloatField(default=0.0)
    is_igny8_content = models.BooleanField(default=False)

6.4 Backend: Queue Processing

# gsc/tasks.py

@shared_task
def process_indexing_queue():
    """Process URL inspection/indexing queue. Runs every 5 minutes."""
    # 1. Check daily quota (2,000 inspections, resets midnight PT)
    # 2. Pick next item from queue by priority
    # 3. Call URL Inspection API
    # 4. Parse response: indexed? → done. Not indexed? → request indexing
    # 5. Schedule re-inspection (24h, 3d, 6d, 13d)
    # 6. Wait 3 seconds between calls
    # 7. Sync status to WordPress plugin
    pass

@shared_task
def fetch_search_metrics(site_id):
    """Fetch search analytics data from GSC. Runs daily."""
    pass

@shared_task
def auto_index_published_content(content_id):
    """Triggered when content is published to WordPress. Adds to indexing queue."""
    pass

@shared_task
def sync_index_status_to_plugin(site_id):
    """Batch sync index statuses to WordPress plugin. Runs every 5 min."""
    pass

6.5 Backend: API Endpoints

# gsc/urls.py

# OAuth
POST   /api/v1/gsc/connect/              # Initiate OAuth flow
GET    /api/v1/gsc/callback/             # OAuth callback
DELETE /api/v1/gsc/disconnect/           # Revoke connection
GET    /api/v1/gsc/status/               # Connection status

# Site mapping
GET    /api/v1/gsc/sites/                # List GSC properties + mapping status
POST   /api/v1/gsc/sites/map/            # Manually map IGNY8 site to GSC property
POST   /api/v1/gsc/sites/auto-map/       # Auto-detect and map

# URL Inspection
GET    /api/v1/gsc/urls/                 # List tracked URLs with index status
POST   /api/v1/gsc/urls/inspect/         # Manual inspect a URL
POST   /api/v1/gsc/urls/request-index/   # Manual request indexing
GET    /api/v1/gsc/urls/queue/           # Queue status (pending, quota remaining)

# Search Metrics
GET    /api/v1/gsc/metrics/              # Search metrics with date range + dimensions
GET    /api/v1/gsc/metrics/top-pages/    # Top pages by clicks
GET    /api/v1/gsc/metrics/top-queries/  # Top queries
GET    /api/v1/gsc/metrics/igny8-only/   # IGNY8-published content metrics only

6.6 Frontend: GSC Pages

frontend/src/pages/
└── SearchConsole/                     # NEW page
    ├── GSCConnect.tsx                 # OAuth connection flow + welcome screen
    ├── SiteMapping.tsx                # Map IGNY8 sites to GSC properties
    ├── IndexingDashboard.tsx          # URL list, index status, queue status
    │   ├── IndexStatusTable.tsx       # Filterable URL table
    │   ├── QueueStatus.tsx            # Quota remaining, items in queue
    │   └── ManualInspect.tsx          # Inspect any URL manually
    ├── PerformanceMetrics.tsx         # Search analytics dashboard
    │   ├── MetricsSummary.tsx         # Clicks, impressions, CTR, position cards
    │   ├── TopPages.tsx               # Top pages table with IGNY8 star markers
    │   ├── TopQueries.tsx             # Top queries table
    │   └── DateRangePicker.tsx        # Date range selector
    └── components/
        └── IndexStatusBadge.tsx       # Reusable status badge component

Sidebar addition:

WORKFLOW
  ├── Planner
  ├── Writer
  ├── Automation
  ├── Blueprint (if SAG active)
  ├── Linker (if linker_enabled)
  ├── Campaigns (if campaign_enabled)
  ├── Search Console (NEW — if gsc_enabled)
  └── Optimizer (if optimizer_enabled)

Feature flag: gsc_enabled

6.7 Plugin Side Enhancement

igny8-plugin/includes/modules/gsc/
├── class-gsc-module.php           # Module entry
├── class-gsc-status-display.php   # Index status column in WP admin content list
├── class-gsc-metabox.php          # Edit screen metabox showing index status
└── views/
    └── gsc-metabox.php            # Metabox template

Plugin receives index status updates from IGNY8 app via:

POST /wp-json/igny8/v1/gsc/status-sync
Body: {urls: [{url, index_status, last_inspected, coverage_state}]}

7. Module 5: Rich Schema & SERP Enhancement

7.1 What This Module Delivers

Automated JSON-LD schema injection and on-page SERP elements (TL;DR boxes, TOC, definition blocks, comparison tables, PAA subheadings) into content — both during generation and retroactively for existing pages.

7.2 Backend: Schema Service

backend/igny8_core/
├── schema/                           # NEW (or extend within modules/writer/)
│   ├── __init__.py
│   ├── services/
│   │   ├── schema_generator.py       # Core: content → schema JSON-LD
│   │   ├── content_classifier.py     # Classify content type for schema mapping
│   │   ├── faq_generator.py          # AI: extract/generate FAQ pairs
│   │   ├── howto_extractor.py        # AI: detect procedural content → HowTo
│   │   ├── review_analyzer.py        # AI: sentiment analysis → Review schema
│   │   ├── proscons_generator.py     # AI: generate pros/cons from content
│   │   ├── toc_generator.py          # Parse H2/H3 → TOC with jump links
│   │   ├── tldr_generator.py         # AI: generate TL;DR summary
│   │   ├── definition_extractor.py   # AI: extract key terms → definition blocks
│   │   ├── paa_integrator.py         # AI: generate PAA-style subheadings
│   │   └── validator.py              # JSON-LD structural validation
│   └── ai_functions/
│       ├── generate_schema_elements.py  # Combined AI function for all schema/SERP elements
│       └── retroactive_analyzer.py      # AI: analyze existing page → what's missing

7.3 Backend: Content Type → Schema Mapping

This is the core decision engine. For each content classification, determine which schemas and elements apply:

# schema/services/schema_generator.py

SCHEMA_MAP = {
    'blog_article': {
        'schemas': ['faq', 'article', 'author_person', 'breadcrumb'],
        'elements': ['tldr', 'toc', 'definition_blocks', 'paa_subheadings'],
    },
    'tutorial_guide': {
        'schemas': ['faq', 'howto', 'article', 'author_person', 'breadcrumb'],
        'elements': ['tldr', 'toc', 'definition_blocks', 'paa_subheadings'],
    },
    'product_review': {
        'schemas': ['faq', 'review_rating', 'pros_cons', 'article', 'author_person', 'breadcrumb'],
        'elements': ['tldr', 'toc', 'paa_subheadings'],
    },
    'service_page': {
        'schemas': ['faq', 'breadcrumb', 'service'],
        'elements': ['definition_blocks'],
    },
    'comparison_post': {
        'schemas': ['faq', 'review_rating', 'pros_cons', 'article', 'author_person', 'breadcrumb'],
        'elements': ['tldr', 'toc', 'comparison_table', 'paa_subheadings'],
    },
    'product_page': {
        'schemas': ['faq', 'product', 'review_rating', 'breadcrumb'],
        'elements': [],
    },
}

7.4 Backend: Pipeline Integration

Enhance Stage 5 (Content Generation):

After AI generates content body, a post-processing step generates schema and on-page elements:

# business/content/ — extend content generation flow

def post_process_content(content):
    """After content body is generated, add schema and SERP elements."""
    # 1. Classify content type
    content_class = content_classifier.classify(content)
    
    # 2. Get applicable schemas and elements from SCHEMA_MAP
    applicable = SCHEMA_MAP.get(content_class, {})
    
    # 3. Generate each applicable schema
    schemas = {}
    if 'faq' in applicable['schemas']:
        schemas['faq'] = faq_generator.generate(content)
    if 'howto' in applicable['schemas']:
        schemas['howto'] = howto_extractor.extract(content)
    # ... etc
    
    # 4. Generate on-page elements
    elements = {}
    if 'tldr' in applicable['elements']:
        elements['tldr'] = tldr_generator.generate(content)
    if 'toc' in applicable['elements']:
        elements['toc'] = toc_generator.generate(content)
    # ... etc
    
    # 5. Store on Content model
    content.schema_data = schemas       # NEW JSON field
    content.serp_elements = elements    # NEW JSON field
    content.save()

New fields on Content model:

# Add to modules/writer/models.py — Content model:
schema_data = models.JSONField(null=True, blank=True, help_text='Generated JSON-LD schemas')
serp_elements = models.JSONField(null=True, blank=True, help_text='Generated SERP elements (TL;DR, TOC, etc.)')

7.5 Backend: Retroactive Enhancement Engine

# schema/services/retroactive_engine.py

class RetroactiveEngine:
    def scan_site(self, site):
        """Fetch all published pages via plugin, classify, identify missing schemas."""
        # 1. GET site inventory from plugin
        # 2. For each page: classify content type, check existing schema
        # 3. Return: [{url, content_type, missing_schemas, missing_elements}]
        pass
    
    def generate_enhancements(self, site, pages):
        """For each page with missing schemas, generate them."""
        # AI analyzes page content → generates applicable schemas + elements
        # Returns review-ready enhancement set
        pass
    
    def push_enhancements(self, site, approved_enhancements):
        """Push approved schemas to WordPress via plugin bulk endpoint."""
        # POST /wp-json/igny8/v1/schema/bulk-update
        pass

7.6 Backend: Validation Pipeline

# schema/services/validator.py

class SchemaValidator:
    def validate_structural(self, schema_json):
        """Check JSON-LD syntax and schema.org conformance."""
        pass
    
    def validate_rich_results(self, url, schema_json):
        """Check against Google Rich Results Test API."""
        pass

7.7 Frontend: Schema Module UI

frontend/src/pages/
└── Schema/                           # NEW page (or sub-section of Optimizer)
    ├── SchemaOverview.tsx             # Site-wide schema coverage dashboard
    │   ├── SchemaCoverage.tsx         # % of pages with each schema type
    │   ├── MissingSchemaList.tsx      # Pages missing applicable schemas
    │   └── ValidationStatus.tsx       # Schema validation results
    ├── RetroactiveEnhancer.tsx        # Scan existing site, review/approve enhancements
    │   ├── SiteScanResults.tsx        # Classified pages with enhancement recommendations
    │   ├── EnhancementPreview.tsx     # Preview schema + elements per page
    │   └── BulkApprove.tsx            # Approve all / select and approve
    └── SchemaSettings.tsx             # Per-content-type schema defaults

Sidebar: Can be a sub-page under Optimizer or a standalone item if schema_enabled flag is set.

7.8 Plugin Side Enhancement

igny8-plugin/includes/modules/schema/    # Already planned in Plugin Build Plan
├── class-schema-module.php
├── class-schema-generator.php           # JSON-LD output in <head>
├── class-schema-renderer.php            # On-page element renderer (shortcodes/blocks)

Plugin stores schemas in post meta (igny8_schema_faq, igny8_schema_howto, etc.) and renders them in wp_head hook.

On-page elements (FAQ section, TOC, TL;DR box) rendered via shortcodes or automatic injection based on content type.

Bulk update endpoint:

POST /wp-json/igny8/v1/schema/bulk-update
Body: {pages: [{post_id, schemas: {faq: {...}, article: {...}}, elements: {tldr: "...", toc: [...]}}]}

8. Module 6: Socializer

8.1 What This Module Delivers

Adapts published content into social posts and schedules across 5 platforms: LinkedIn, Twitter/X, Facebook, Instagram, TikTok.

8.2 Backend: New Django App

backend/igny8_core/
├── socializer/                        # NEW Django app
│   ├── __init__.py
│   ├── apps.py
│   ├── models.py                      # SocialAccount, SocialPost, SocialSchedule
│   ├── serializers.py
│   ├── views.py
│   ├── urls.py                        # /api/v1/socializer/*
│   ├── admin.py
│   ├── services/
│   │   ├── __init__.py
│   │   ├── oauth_service.py           # OAuth2 flows per platform
│   │   ├── content_adapter.py         # AI: adapt content for each platform
│   │   ├── image_resizer.py           # Resize/crop per platform specs
│   │   ├── publisher.py               # Publish to platform APIs
│   │   ├── scheduler.py               # Schedule management, best-time slots
│   │   └── metrics_service.py         # Fetch engagement metrics
│   ├── platforms/                      # Platform-specific API clients
│   │   ├── __init__.py
│   │   ├── linkedin.py
│   │   ├── twitter.py
│   │   ├── facebook.py
│   │   ├── instagram.py
│   │   └── tiktok.py
│   ├── ai_functions/
│   │   ├── adapt_for_social.py        # AI: content → platform-specific post
│   │   └── generate_hashtags.py       # AI: generate relevant hashtags
│   ├── tasks.py                       # Celery tasks for scheduled posting + metrics
│   └── migrations/

8.3 Backend: Models

# socializer/models.py

class SocialAccount(AccountBaseModel):
    """Connected social media account/page."""
    platform = models.CharField(max_length=20, choices=[
        ('linkedin', 'LinkedIn'), ('twitter', 'Twitter/X'),
        ('facebook', 'Facebook'), ('instagram', 'Instagram'),
        ('tiktok', 'TikTok'),
    ])
    account_name = models.CharField(max_length=200)
    account_id = models.CharField(max_length=200)
    access_token = models.TextField()
    refresh_token = models.TextField(blank=True)
    token_expiry = models.DateTimeField(null=True, blank=True)
    page_id = models.CharField(max_length=200, blank=True, help_text='For Facebook Pages, LinkedIn Company Pages')
    is_active = models.BooleanField(default=True)
    connected_at = models.DateTimeField(auto_now_add=True)

class SocialPost(SiteSectorBaseModel):
    """A social post generated from IGNY8 content."""
    source_content = models.ForeignKey('writer.Content', on_delete=models.CASCADE, related_name='social_posts')
    platform = models.CharField(max_length=20)
    social_account = models.ForeignKey(SocialAccount, on_delete=models.CASCADE)
    post_type = models.CharField(max_length=30, choices=[
        ('announcement', 'Announcement'),
        ('highlight', 'Key Highlights'),
        ('quote_card', 'Quote Card'),
        ('faq_snippet', 'FAQ Snippet'),
        ('thread', 'Thread (Twitter)'),
    ])
    text_content = models.TextField()
    hashtags = models.JSONField(default=list)
    image_url = models.URLField(blank=True)
    link_url = models.URLField(blank=True)
    
    # Scheduling
    status = models.CharField(max_length=20, choices=[
        ('draft', 'Draft'), ('scheduled', 'Scheduled'),
        ('published', 'Published'), ('failed', 'Failed'),
    ], default='draft')
    scheduled_at = models.DateTimeField(null=True, blank=True)
    published_at = models.DateTimeField(null=True, blank=True)
    platform_post_id = models.CharField(max_length=200, blank=True)
    
    # Metrics
    clicks = models.IntegerField(default=0)
    likes = models.IntegerField(default=0)
    shares = models.IntegerField(default=0)
    comments = models.IntegerField(default=0)
    impressions = models.IntegerField(default=0)
    metrics_updated_at = models.DateTimeField(null=True, blank=True)
    
    created_at = models.DateTimeField(auto_now_add=True)

8.4 Backend: Automation Pipeline Stage 8

# business/automation/stages/stage_8_socializer.py    # NEW

# After content is published to WordPress (Stage 7 + publish):
# 1. Check if socializer_enabled for this site
# 2. Load connected social accounts
# 3. For each active platform:
#    a. AI adapts content for platform (tone, length, format)
#    b. Resize image for platform specs
#    c. Generate hashtags
#    d. Create SocialPost (status=scheduled)
#    e. Queue for scheduled publishing

Add to AutomationConfig choices:

# Stage 8: Socializer (if socializer_enabled)

8.5 Backend: Celery Tasks

# socializer/tasks.py

@shared_task
def publish_scheduled_posts():
    """Every 5 min: check for posts due for publishing, publish them."""
    pass

@shared_task
def fetch_engagement_metrics():
    """Every 6 hours: fetch metrics for recently published posts."""
    pass

@shared_task
def refresh_social_tokens():
    """Daily: refresh OAuth tokens approaching expiry."""
    pass

8.6 Frontend: Socializer Pages

frontend/src/pages/
└── Socializer/                        # NEW page
    ├── SocialAccounts.tsx             # Connected accounts management
    │   ├── ConnectAccount.tsx         # OAuth connect flow per platform
    │   └── AccountList.tsx            # List connected accounts with status
    ├── SocialPosts.tsx                # All social posts with status
    │   ├── PostList.tsx               # Filterable by platform, status, date
    │   ├── PostPreview.tsx            # Platform-specific preview card
    │   └── PostEditor.tsx             # Edit text/image before scheduling
    ├── SocialCalendar.tsx             # Calendar view of scheduled posts
    └── SocialAnalytics.tsx            # Engagement metrics per platform/post

Sidebar addition:

WORKFLOW
  ├── ...
  ├── Socializer (NEW — if socializer_enabled)
  └── ...

Feature flag: socializer_enabled


9. Module 7: Video Creator

9.1 What This Module Delivers

Converts published articles into video content and publishes to YouTube, Instagram Reels, TikTok, YouTube Shorts.

9.2 Backend: New Django App

backend/igny8_core/
├── video/                             # NEW Django app
│   ├── __init__.py
│   ├── apps.py
│   ├── models.py                      # VideoProject, VideoScript, VideoAsset, VideoRender
│   ├── serializers.py
│   ├── views.py
│   ├── urls.py                        # /api/v1/video/*
│   ├── admin.py
│   ├── services/
│   │   ├── __init__.py
│   │   ├── script_service.py          # AI script generation from content
│   │   ├── tts_service.py             # Text-to-speech (OpenAI, ElevenLabs, self-hosted)
│   │   ├── asset_service.py           # Stock footage/image fetching (Pexels, Pixabay)
│   │   ├── composer_service.py        # FFmpeg + MoviePy video assembly
│   │   ├── subtitle_service.py        # SRT caption generation
│   │   ├── thumbnail_service.py       # AI thumbnail generation
│   │   ├── seo_service.py             # Video titles, descriptions, tags per platform
│   │   └── publisher_service.py       # Publish to YouTube, Instagram, TikTok
│   ├── platforms/
│   │   ├── youtube.py                 # YouTube Data API v3
│   │   ├── instagram.py               # Instagram Graph API (Reels)
│   │   └── tiktok.py                  # TikTok Content Posting API
│   ├── ai_functions/
│   │   ├── generate_script.py         # AI: content → VideoScript
│   │   ├── generate_video_seo.py      # AI: script → platform-specific SEO
│   │   └── generate_thumbnail.py      # AI: content → thumbnail image
│   ├── tasks.py                       # Celery tasks (separate queue for rendering)
│   └── migrations/

9.3 Backend: Models

# video/models.py

class VideoProject(SiteSectorBaseModel):
    """A video project generated from IGNY8 content."""
    source_content = models.ForeignKey('writer.Content', on_delete=models.CASCADE, related_name='video_projects')
    video_type = models.CharField(max_length=20, choices=[
        ('short', 'Short Form (30-90s)'),
        ('medium', 'Medium (60-180s)'),
        ('long', 'Long Form (5-15 min)'),
    ])
    status = models.CharField(max_length=20, choices=[
        ('script_draft', 'Script Draft'),
        ('script_approved', 'Script Approved'),
        ('rendering', 'Rendering'),
        ('rendered', 'Rendered'),
        ('published', 'Published'),
        ('failed', 'Failed'),
    ], default='script_draft')
    target_platforms = models.JSONField(default=list, help_text='["youtube", "instagram", "tiktok"]')
    render_preset = models.CharField(max_length=30, choices=[
        ('youtube_long', '1920×1080 3-15min'),
        ('youtube_short', '1080×1920 30-60s'),
        ('instagram_reel', '1080×1920 30-90s'),
        ('tiktok', '1080×1920 30-180s'),
    ])
    created_at = models.DateTimeField(auto_now_add=True)

class VideoScript(models.Model):
    """AI-generated narration script for a video project."""
    project = models.OneToOneField(VideoProject, on_delete=models.CASCADE, related_name='script')
    sections = models.JSONField(help_text='[{type: "hook"|"intro"|"point"|"cta", text, visual_cue, duration_seconds}]')
    total_duration_seconds = models.IntegerField(default=0)
    voice_id = models.CharField(max_length=100, blank=True)
    voice_provider = models.CharField(max_length=30, blank=True)
    seo_title = models.JSONField(default=dict, help_text='{youtube: "...", instagram: "...", tiktok: "..."}')
    seo_description = models.JSONField(default=dict)
    seo_tags = models.JSONField(default=list)
    chapter_markers = models.JSONField(default=list, help_text='For YouTube chapters')
    created_at = models.DateTimeField(auto_now_add=True)

class VideoRender(models.Model):
    """A rendered video file for a specific platform."""
    project = models.ForeignKey(VideoProject, on_delete=models.CASCADE, related_name='renders')
    platform = models.CharField(max_length=20)
    file_url = models.URLField(blank=True, help_text='S3/storage URL')
    file_size_bytes = models.BigIntegerField(default=0)
    duration_seconds = models.IntegerField(default=0)
    resolution = models.CharField(max_length=20)
    thumbnail_url = models.URLField(blank=True)
    subtitle_url = models.URLField(blank=True, help_text='SRT file URL')
    status = models.CharField(max_length=20, choices=[
        ('queued', 'Queued'), ('rendering', 'Rendering'),
        ('complete', 'Complete'), ('failed', 'Failed'),
    ], default='queued')
    platform_video_id = models.CharField(max_length=200, blank=True)
    published_at = models.DateTimeField(null=True, blank=True)
    render_started_at = models.DateTimeField(null=True, blank=True)
    render_completed_at = models.DateTimeField(null=True, blank=True)

9.4 Backend: Celery Tasks (Separate Queue)

Video rendering is CPU/memory intensive — use a separate Celery queue.

# video/tasks.py

@shared_task(queue='video_render')
def render_video(project_id, platform):
    """Heavy task: assemble and render video. Runs on dedicated worker."""
    # 1. Load script + assets
    # 2. TTS: generate voiceover audio
    # 3. Fetch stock footage/images for visual cues
    # 4. Compose video with FFmpeg/MoviePy
    # 5. Add subtitles
    # 6. Upload to S3/storage
    # 7. Update VideoRender record
    pass

@shared_task
def publish_video(render_id):
    """Publish rendered video to platform."""
    pass

@shared_task
def generate_video_thumbnail(project_id):
    """AI-generate thumbnail from content."""
    pass

Celery config addition:

# celery.py — add video_render queue
CELERY_TASK_ROUTES = {
    'igny8_core.video.tasks.render_video': {'queue': 'video_render'},
}

9.5 Backend: Automation Pipeline Stage 9

# business/automation/stages/stage_9_video.py    # NEW

# After socializer (Stage 8) or after publish:
# 1. Check if video_enabled for this site
# 2. If auto-video enabled: generate script → queue for rendering
# 3. If manual: create project in script_draft status for user review

9.6 Frontend: Video Creator Pages

frontend/src/pages/
└── VideoCreator/                      # NEW page
    ├── VideoProjects.tsx              # List all video projects with status
    ├── ScriptEditor.tsx               # View/edit AI-generated script
    │   ├── ScriptSections.tsx         # Section-by-section editor
    │   ├── VoiceSelector.tsx          # Choose TTS voice + preview
    │   └── VisualCueEditor.tsx        # Edit visual cues per section
    ├── VideoPreview.tsx               # Preview rendered video
    ├── VideoPublisher.tsx             # Select platforms + publish
    └── VideoAnalytics.tsx             # View/engagement metrics per video

Sidebar addition:

WORKFLOW
  ├── ...
  ├── Socializer (if socializer_enabled)
  ├── Video Creator (NEW — if video_enabled)
  └── ...

Feature flag: video_enabled


10. Updated Automation Pipeline — All Stages

After all modules are implemented, the full pipeline becomes:

Stage 0:  Blueprint Check (if SAG active — from Doc A)
Stage 1:  Process New Keywords
Stage 2:  AI Cluster Keywords (or SAG cluster mapping)
Stage 3:  Generate Content Ideas (type-aware, blueprint-guided)
Stage 4:  Create Writer Tasks (with content_type + content_structure)
Stage 5:  Generate Article Content (type-specific prompts + schema/SERP post-processing)
Stage 6:  Extract Image Prompts
Stage 7:  Generate Images → Review Queue
--- After publish to WordPress ---
Stage 7.5: Auto-Index via GSC (if gsc_enabled)
Stage 8:  Linker — Generate SAG links (if linker_enabled — from Doc A)
Stage 9:  Socializer — Generate social posts (if socializer_enabled)
Stage 10: Video Creator — Generate video project (if video_enabled)

Each stage beyond 7 is independently enabled/disabled. The pipeline gracefully skips disabled stages.

AutomationConfig model extends to include stage enable/disable per site:

# Add to AutomationConfig or AutomationSettings:
gsc_auto_index = models.BooleanField(default=True)
auto_generate_links = models.BooleanField(default=True)
auto_generate_social = models.BooleanField(default=False)
auto_generate_video = models.BooleanField(default=False)

11. Updated Navigation & Sidebar

After all modules implemented:

Dashboard (with GSC indexing widget, social metrics widget, video status widget)
SETUP
  ├── Add Keywords (optional when SAG active)
  ├── Content Settings
  ├── Sites
  └── Thinker (admin only)
WORKFLOW
  ├── Planner
  │   ├── Keywords
  │   ├── Clusters
  │   ├── Ideas
  │   └── Taxonomies (if taxonomy sync active — Module 2)
  ├── Writer (Queue → Drafts → Images → Review → Published, all content types)
  ├── Automation (Stages 1-10 visualization, per-stage toggle)
  ├── Blueprint (if SAG active — from Doc A)
  ├── Linker (if linker_enabled — from Doc A)
  ├── Campaigns (if campaign_enabled — from Doc A)
  ├── Search Console (if gsc_enabled — Module 4)
  ├── Optimizer (if optimizer_enabled — Module 3)
  ├── Schema (if schema_enabled — Module 5, or nested under Optimizer)
  ├── Socializer (if socializer_enabled — Module 6)
  └── Video Creator (if video_enabled — Module 7)
ACCOUNT
  ├── Account Settings
  ├── Plans & Billing
  ├── Usage
  └── AI Models (admin only)
ADMIN (admin only)
  └── Sector Templates
HELP
  └── Help & Docs

12. Complete API Endpoint Registry

Content Types Writing (Module 1 — no new endpoints, enhances existing)

Existing writer/tasks/ and writer/content/ endpoints — now accept content_type and content_structure fields

Taxonomy & Term Content (Module 2)

GET    /api/v1/planner/taxonomies/                    # List synced taxonomies
POST   /api/v1/planner/taxonomies/sync/               # Trigger taxonomy sync from WordPress
GET    /api/v1/planner/taxonomies/{id}/terms/          # List terms within taxonomy
POST   /api/v1/planner/taxonomies/terms/{id}/map/      # Map term to cluster
POST   /api/v1/planner/taxonomies/terms/{id}/generate/ # Generate content for term
POST   /api/v1/planner/taxonomies/bulk-generate/       # Batch generate term content

Optimizer (Module 3)

POST   /api/v1/optimizer/analyze/                     # Analyze content
POST   /api/v1/optimizer/optimize/                    # Generate optimized version
POST   /api/v1/optimizer/apply/{job_id}/              # Apply optimization
POST   /api/v1/optimizer/reject/{job_id}/             # Reject optimization
POST   /api/v1/optimizer/batch/                       # Batch optimize
GET    /api/v1/optimizer/jobs/                        # List optimization jobs
GET    /api/v1/optimizer/settings/                    # Module settings
PUT    /api/v1/optimizer/settings/                    # Update settings

GSC Integration (Module 4)

POST   /api/v1/gsc/connect/                          # OAuth initiate
GET    /api/v1/gsc/callback/                          # OAuth callback
DELETE /api/v1/gsc/disconnect/                        # Revoke
GET    /api/v1/gsc/status/                            # Connection status
GET    /api/v1/gsc/sites/                             # GSC properties
POST   /api/v1/gsc/sites/map/                         # Manual mapping
POST   /api/v1/gsc/sites/auto-map/                    # Auto-detect
GET    /api/v1/gsc/urls/                              # Tracked URLs
POST   /api/v1/gsc/urls/inspect/                      # Manual inspect
POST   /api/v1/gsc/urls/request-index/                # Manual index request
GET    /api/v1/gsc/urls/queue/                        # Queue status
GET    /api/v1/gsc/metrics/                           # Search metrics
GET    /api/v1/gsc/metrics/top-pages/                 # Top pages
GET    /api/v1/gsc/metrics/top-queries/               # Top queries
GET    /api/v1/gsc/metrics/igny8-only/                # IGNY8 content only

Rich Schema (Module 5)

GET    /api/v1/schema/coverage/                       # Site-wide schema coverage stats
POST   /api/v1/schema/generate/{content_id}/          # Generate schema for content
POST   /api/v1/schema/scan-site/                      # Retroactive: scan site
POST   /api/v1/schema/generate-bulk/                  # Retroactive: generate for multiple pages
POST   /api/v1/schema/push-bulk/                      # Push approved schemas to WordPress
POST   /api/v1/schema/validate/{content_id}/          # Validate schema
GET    /api/v1/schema/settings/                       # Schema settings
PUT    /api/v1/schema/settings/                       # Update settings

Socializer (Module 6)

GET    /api/v1/socializer/accounts/                   # List connected accounts
POST   /api/v1/socializer/accounts/connect/{platform}/ # OAuth initiate
DELETE /api/v1/socializer/accounts/{id}/               # Disconnect
GET    /api/v1/socializer/posts/                      # List social posts
POST   /api/v1/socializer/posts/generate/             # Generate posts from content
PATCH  /api/v1/socializer/posts/{id}/                 # Edit post text/schedule
POST   /api/v1/socializer/posts/{id}/publish/         # Publish now
DELETE /api/v1/socializer/posts/{id}/                 # Delete draft
GET    /api/v1/socializer/calendar/                   # Calendar view data
GET    /api/v1/socializer/analytics/                  # Engagement metrics
GET    /api/v1/socializer/settings/                   # Scheduling rules, defaults
PUT    /api/v1/socializer/settings/                   # Update settings

Video Creator (Module 7)

GET    /api/v1/video/projects/                        # List video projects
POST   /api/v1/video/projects/create/                 # Create project from content
GET    /api/v1/video/projects/{id}/                   # Project detail
PATCH  /api/v1/video/projects/{id}/script/            # Edit script
POST   /api/v1/video/projects/{id}/approve-script/    # Approve script, start render
POST   /api/v1/video/projects/{id}/render/            # Queue rendering
GET    /api/v1/video/projects/{id}/renders/           # List renders per platform
POST   /api/v1/video/projects/{id}/publish/           # Publish to platforms
GET    /api/v1/video/analytics/                       # Video metrics
GET    /api/v1/video/voices/                          # Available TTS voices

13. Complete AI Function Registry

Function Key Module Location Input Output
generate_content_product 1 ai/functions/generate_content.py (extend) Task + product context Product page HTML
generate_content_service 1 same Task + service context Service page HTML
generate_content_taxonomy 1 same Task + term context Term landing HTML
generate_content_hub 1 same Task + cluster context Hub page HTML
optimize_content 3 ai/functions/optimize_content.py (implement) Content + cluster Optimized content + schema
generate_faq_pairs 5 schema/ai_functions/ Content body FAQ Q&A pairs
extract_howto_steps 5 schema/ai_functions/ Content body HowTo steps
generate_pros_cons 5 schema/ai_functions/ Content body Pros and cons lists
generate_tldr 5 schema/ai_functions/ Content body TL;DR summary
adapt_for_social 6 socializer/ai_functions/adapt_for_social.py Content + platform Platform-adapted text
generate_hashtags 6 socializer/ai_functions/generate_hashtags.py Content + platform Hashtag list
generate_video_script 7 video/ai_functions/generate_script.py Content + video_type VideoScript sections
generate_video_seo 7 video/ai_functions/generate_video_seo.py Script + platform SEO title/desc/tags
generate_thumbnail 7 video/ai_functions/generate_thumbnail.py Content Thumbnail image prompt

14. Complete Celery Task Registry

Task Module Schedule Queue
process_indexing_queue GSC Every 5 min default
fetch_search_metrics GSC Daily default
auto_index_published_content GSC On demand (after publish) default
sync_index_status_to_plugin GSC Every 5 min default
refresh_gsc_token GSC Daily default
publish_scheduled_posts Socializer Every 5 min default
fetch_engagement_metrics Socializer Every 6 hours default
refresh_social_tokens Socializer Daily default
render_video Video On demand video_render (separate)
publish_video Video On demand default
generate_video_thumbnail Video On demand default

15. Feature Flag Registry

Flag Module Controls Default
optimizer_enabled Optimizer Optimizer page, optimization API, automation integration False (exists)
gsc_enabled GSC Search Console page, OAuth, auto-indexing False
schema_enabled Rich Schema Schema generation in pipeline, retroactive engine False
socializer_enabled Socializer Socializer page, OAuth, social posting, Stage 9 False
video_enabled Video Creator Video Creator page, rendering, Stage 10 False

Content Types Writing and Taxonomy & Term Content have no feature flags — they extend existing pipeline capabilities and are always available once deployed.


16. Credit Cost Summary

Operation Module Credits
Generate product/service/hub content Content Types Same as articles (5 per 100 words)
Generate taxonomy landing content Taxonomy Same as articles
Analyze content for optimization Optimizer 2
Optimize content (rewrite) Optimizer 5 per 100 words
Generate schema elements Rich Schema 2 per page
Retroactive scan + generate Rich Schema 1 per page scanned + 2 per page enhanced
Adapt content for 1 platform Socializer 1
Generate hashtags Socializer 0.5
Generate Twitter thread Socializer 2
Generate social image Socializer 3-10
Full social suite (5 platforms) Socializer 15-25 per content item
Generate video script Video 5
TTS voiceover Video 10/min (standard), 20/min (HD), 2/min (self-hosted)
Visual assets per video Video 15-50
Thumbnail generation Video 3-10
Video composition (render) Video 5 per render
Video SEO metadata Video 1 per platform
Full short-form video Video ~40-80 total
Full long-form video Video ~100-250 total

17. Cross-Module Dependencies

Content Types Writing (Module 1)
  └── feeds → Taxonomy & Term Content (content structures for term pages)
  └── feeds → Optimizer (supports all content types)
  └── feeds → Rich Schema (content type classification drives schema mapping)
  └── feeds → Socializer (any content type can be socialized)
  └── feeds → Video Creator (any content type can become a video)

Taxonomy & Term Content (Module 2)
  └── feeds → Optimizer (term pages can be optimized)
  └── feeds → Rich Schema (term pages get schema)
  └── depends on → Content Types Writing (Module 1)
  └── depends on → SAG Blueprint (Doc A) for cluster mapping

Optimizer (Module 3)
  └── feeds → Rich Schema (schema generation is part of optimization)
  └── depends on → Content Types Writing (Module 1)
  └── depends on → SAG clusters (Doc A) for cluster matching

GSC Integration (Module 4)
  └── feeds → SAG Backlink Campaigns (Doc A Phase 10) for KPI data
  └── feeds → Blueprint Health (Doc A Phase 8) for indexed page tracking
  └── INDEPENDENT — no dependencies on other modules

Rich Schema (Module 5)
  └── feeds → WordPress plugin (schema storage + rendering)
  └── depends on → Content Types Writing (Module 1) for type classification
  └── benefits from → GSC (Module 4) for schema error monitoring

Socializer (Module 6)
  └── depends on → Published content (any module)
  └── shares OAuth patterns with → Video Creator (Module 7)

Video Creator (Module 7)
  └── depends on → Published content (any module)
  └── depends on → Socializer (Module 6) for shared infrastructure
  └── requires → S3/media storage, FFmpeg, separate Celery queue

Reference Documents

Document Purpose
IGNY8-Consolidated-Module-Plans.md Strategic plans for all modules — source for this guide
IGNY8-Rich-Schema-SERP-Enhancement-Module.docx Detailed schema types, mapping matrix, rollout plan
IGNY8-Current-State.md Current platform state — all file paths, models, modules
Doc A — SAG Architecture Dev Guide SAG models, blueprint, clusters — consumed by Modules 2, 3, 5

End of Doc B — IGNY8 Platform Modules Development Guide