69 KiB
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
- System Context — Current Pipeline & Module Structure
- Implementation Sequence
- Module 1: Content Types Writing
- Module 2: Taxonomy & Term Content
- Module 3: Optimizer Module
- Module 4: GSC Integration
- Module 5: Rich Schema & SERP Enhancement
- Module 6: Socializer
- Module 7: Video Creator
- Updated Automation Pipeline — All Stages
- Updated Navigation & Sidebar
- Complete API Endpoint Registry
- Complete AI Function Registry
- Complete Celery Task Registry
- Feature Flag Registry
- Credit Cost Summary
- 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_keyfor authentication- Webhook endpoints for sync (plugin → IGNY8 and IGNY8 → plugin)
business/integration/for sync servicesmodules/integration/for API endpoints- Plugin file:
data/site-collection.phpfor 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