1790 lines
75 KiB
Markdown
1790 lines
75 KiB
Markdown
# Doc A — SAG Architecture: 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 SAG architecture features — where every file goes, what models to create or modify, what the frontend shows, how automation works
|
||
**Scope:** SAG Core (3-layer architecture, Site Builder, Existing Site Intelligence), Interlinking (Doc 3 / Linker module), External Backlink Campaigns (Doc 4), Industry/Sector Templates
|
||
**Rule:** Nothing currently working breaks. All new models use nullable fields on existing tables. All new modules use feature flags. All new frontend pages use the existing sidebar/routing pattern.
|
||
|
||
---
|
||
|
||
## Table of Contents
|
||
|
||
1. [System Context — What Exists Today](#1-system-context)
|
||
2. [Implementation Sequence — The Critical Path](#2-implementation-sequence)
|
||
3. [Phase 1: Data Foundation — New Models](#3-phase-1-data-foundation)
|
||
4. [Phase 2: Sector Attribute Templates](#4-phase-2-sector-attribute-templates)
|
||
5. [Phase 3: Cluster Formation & Keyword Generation Engine](#5-phase-3-cluster-formation--keyword-generation)
|
||
6. [Phase 4: Case 2 — SAG Site Builder Wizard](#6-phase-4-sag-site-builder-wizard)
|
||
7. [Phase 5: Blueprint-Aware Content Pipeline](#7-phase-5-blueprint-aware-content-pipeline)
|
||
8. [Phase 6: Taxonomy Creation Flow](#8-phase-6-taxonomy-creation-flow)
|
||
9. [Phase 7: Case 1 — Existing Site Analysis](#9-phase-7-existing-site-analysis)
|
||
10. [Phase 8: Blueprint Health Monitoring](#10-phase-8-blueprint-health-monitoring)
|
||
11. [Phase 9: SAG Interlinking — Linker Module Evolution](#11-phase-9-sag-interlinking)
|
||
12. [Phase 10: External Backlink Campaign Module](#12-phase-10-external-backlink-campaigns)
|
||
13. [Frontend Navigation & UI Map](#13-frontend-navigation--ui-map)
|
||
14. [API Endpoint Registry](#14-api-endpoint-registry)
|
||
15. [AI Function Registry](#15-ai-function-registry)
|
||
16. [Celery Task Registry](#16-celery-task-registry)
|
||
17. [Feature Flag Registry](#17-feature-flag-registry)
|
||
18. [Cross-Reference: What Feeds What](#18-cross-reference)
|
||
|
||
---
|
||
|
||
## 1. System Context — What Exists Today {#1-system-context}
|
||
|
||
Before building anything, understand the current codebase layout that MUST be preserved.
|
||
|
||
### 1.1 Backend File Structure (Django)
|
||
|
||
```
|
||
backend/igny8_core/
|
||
├── auth/ # User, Account, Site, Sector, Plan models + auth views
|
||
│ ├── models.py # Site model lives here — will get sag_blueprint_id field
|
||
│ └── ...
|
||
├── api/ # Base ViewSets, authentication, pagination
|
||
├── ai/ # AI engine — will get new SAG functions
|
||
│ ├── engine.py # AIEngine orchestrator
|
||
│ ├── functions/ # AutoCluster, GenerateIdeas, GenerateContent, etc.
|
||
│ ├── providers/ # OpenAI, Anthropic, Runware, Bria
|
||
│ ├── registry.py # Function registry
|
||
│ └── model_registry.py # ModelRegistry service
|
||
├── modules/ # API layer — ViewSets, serializers, URLs per module
|
||
│ ├── planner/ # Keywords, Clusters, Ideas
|
||
│ ├── writer/ # Tasks, Content, Images
|
||
│ ├── billing/ # Credits, usage
|
||
│ ├── integration/ # WordPress integration
|
||
│ ├── system/ # Settings, prompts, AI config
|
||
│ ├── linker/ # Internal linking (INACTIVE — behind linker_enabled flag)
|
||
│ ├── optimizer/ # Content optimization (INACTIVE)
|
||
│ └── publisher/ # Publishing pipeline
|
||
├── business/ # Service layer — business logic
|
||
│ ├── automation/ # 7-stage automation pipeline
|
||
│ ├── content/ # Content generation orchestration
|
||
│ ├── integration/ # Sync services
|
||
│ ├── linking/ # Link processing (INACTIVE)
|
||
│ ├── optimization/ # Content optimization (INACTIVE)
|
||
│ ├── planning/ # Clustering, idea generation
|
||
│ └── publishing/ # Publishing orchestration
|
||
├── plugins/ # Plugin distribution system
|
||
└── tasks/ # Celery task definitions
|
||
```
|
||
|
||
### 1.2 Frontend File Structure (React/TypeScript)
|
||
|
||
```
|
||
frontend/src/
|
||
├── api/ # API clients (linker.api.ts, optimizer.api.ts, etc.)
|
||
├── services/
|
||
│ └── api.ts # Main API service (2500+ lines)
|
||
├── store/ # Zustand stores (authStore, siteStore, sectorStore, billingStore, moduleStore)
|
||
├── pages/ # Route pages
|
||
│ ├── Dashboard/ # Main dashboard with widgets
|
||
│ ├── Planner/ # Keywords, Clusters, Ideas
|
||
│ ├── Writer/ # Tasks, Content, Images, Review, Published
|
||
│ ├── Automation/ # Pipeline config and monitoring
|
||
│ ├── Linker/ # Internal linking (INACTIVE)
|
||
│ ├── Optimizer/ # Content optimization (INACTIVE)
|
||
│ ├── Settings/ # Site settings, AI models, prompts
|
||
│ ├── Billing/ # Plans, usage, transactions
|
||
│ └── Auth/ # Login, register, password reset
|
||
├── components/
|
||
│ ├── common/ # Shared components
|
||
│ ├── dashboard/ # Dashboard widgets
|
||
│ └── header/ # NotificationDropdown
|
||
├── layout/ # AppLayout, AppHeader, AppSidebar
|
||
└── hooks/ # Custom hooks
|
||
```
|
||
|
||
### 1.3 Current Sidebar Navigation
|
||
|
||
```
|
||
Dashboard
|
||
SETUP
|
||
├── Add Keywords
|
||
├── Content Settings
|
||
├── Sites (if sites_enabled)
|
||
└── Thinker (admin only, if thinker_enabled)
|
||
WORKFLOW
|
||
├── Planner (Keywords → Clusters → Ideas)
|
||
├── Writer (Queue → Drafts → Images → Review → Published)
|
||
├── Automation
|
||
├── Linker (if linker_enabled — currently hidden)
|
||
└── Optimizer (if optimizer_enabled — currently hidden)
|
||
ACCOUNT
|
||
├── Account Settings
|
||
├── Plans & Billing
|
||
├── Usage
|
||
└── AI Models (admin only)
|
||
HELP
|
||
└── Help & Docs
|
||
```
|
||
|
||
### 1.4 Existing Models That Will Be Modified
|
||
|
||
| Model | Location | What Gets Added | Why |
|
||
|-------|----------|----------------|-----|
|
||
| **Site** | `auth/models.py` | `sag_blueprint_id` (FK, nullable) | Link site to its active blueprint |
|
||
| **Cluster** | `modules/planner/models.py` | `sag_cluster_id` (FK, nullable), `cluster_type` (Enum, nullable) | Connect existing clusters to SAG clusters |
|
||
| **Tasks** | `modules/writer/models.py` | `sag_cluster_id` (FK, nullable), `blueprint_context` (JSON, nullable) | Writer gets cluster context for type-specific prompts |
|
||
| **Content** | `modules/writer/models.py` | `sag_cluster_id` (FK, nullable), `outbound_link_count` (Int, nullable), `inbound_link_count` (Int, nullable), `backlink_count` (Int, nullable) | Map content to clusters, track link metrics |
|
||
| **ContentIdea** | `modules/planner/models.py` | `sag_cluster_id` (FK, nullable), `idea_source` (Enum, nullable) | Track whether idea came from keyword clustering or SAG blueprint |
|
||
|
||
**Critical rule:** ALL additions to existing models are nullable. No migrations that alter non-null columns. No breaking changes to existing API serializers — new fields are added as optional with `required=False`.
|
||
|
||
### 1.5 Existing AI Functions
|
||
|
||
```
|
||
ai/functions/
|
||
├── auto_cluster.py # AutoClusterKeywords — Keywords → Clusters
|
||
├── generate_ideas.py # GenerateContentIdeas — Cluster → Ideas
|
||
├── generate_content.py # GenerateContent — Task → Full article
|
||
├── generate_image_prompts.py # GenerateImagePrompts — Content → Image prompts
|
||
├── generate_images.py # GenerateImages — Prompts → Images
|
||
└── optimize_content.py # OptimizeContent — PENDING, not implemented
|
||
```
|
||
|
||
### 1.6 Existing Automation Pipeline (7 stages)
|
||
|
||
```
|
||
Stage 1: Process New Keywords
|
||
Stage 2: AI Cluster Keywords
|
||
Stage 3: Generate Content Ideas
|
||
Stage 4: Create Writer Tasks
|
||
Stage 5: Generate Article Content
|
||
Stage 6: Extract Image Prompts
|
||
Stage 7: Generate Images → Review Queue
|
||
```
|
||
|
||
### 1.7 Multi-Tenant Data Scoping
|
||
|
||
All new models MUST follow the existing pattern:
|
||
- Extend `AccountBaseModel` for account-scoped data (SAGBlueprint, SAGCampaign)
|
||
- Extend `SiteSectorBaseModel` for site+sector-scoped data where applicable
|
||
- ViewSets extend `AccountModelViewSet` or `SiteSectorModelViewSet` for auto-filtering
|
||
- `AccountContextMiddleware` resolves tenant from JWT — no manual filtering needed
|
||
|
||
---
|
||
|
||
## 2. Implementation Sequence — The Critical Path {#2-implementation-sequence}
|
||
|
||
Everything depends on what came before. This sequence cannot be reordered.
|
||
|
||
```
|
||
PHASE 1 ─── Data Foundation (NEW models + modified existing models)
|
||
│ No UI yet. Backend only. Migrations.
|
||
│
|
||
PHASE 2 ─── Sector Attribute Templates (NEW data layer)
|
||
│ Admin interface to manage templates.
|
||
│ AI-assisted template generation.
|
||
│
|
||
PHASE 3 ─── Cluster Formation & Keyword Generation Engine
|
||
│ AI functions that turn attributes → clusters → keywords.
|
||
│ No user-facing UI yet — these are services called by wizard and pipeline.
|
||
│
|
||
PHASE 4 ─── SAG Site Builder Wizard (Case 2)
|
||
│ Frontend: Setup wizard gets Step 3 "Site Structure".
|
||
│ First user-facing SAG feature.
|
||
│
|
||
PHASE 5 ─── Blueprint-Aware Content Pipeline
|
||
│ Existing 7-stage pipeline enhanced with blueprint context.
|
||
│ Idea generation reads blueprint. Writer uses type-specific prompts.
|
||
│
|
||
PHASE 6 ─── Taxonomy Creation Flow
|
||
│ IGNY8 → Plugin: push taxonomy creation payload.
|
||
│ Plugin creates WP taxonomies from blueprint.
|
||
│
|
||
PHASE 7 ─── Existing Site Analysis (Case 1)
|
||
│ Plugin sends site data → IGNY8 AI extracts attributes → gap analysis.
|
||
│
|
||
PHASE 8 ─── Blueprint Health Monitoring
|
||
│ Background Celery tasks. Dashboard widgets.
|
||
│
|
||
PHASE 9 ─── SAG Interlinking (Linker Module Evolution)
|
||
│ Activate linker_enabled. New SAG-aware linking rules.
|
||
│ Depends on: blueprints, clusters, published content.
|
||
│
|
||
PHASE 10 ── External Backlink Campaign Module
|
||
Depends on: blueprints, clusters, interlinking, GSC data.
|
||
New models, new UI, FatGrid/PR integrations.
|
||
```
|
||
|
||
**Parallel tracks possible:**
|
||
- Phase 2 (templates) and Phase 8 (health monitoring) share no dependencies — template creation can continue while monitoring is built.
|
||
- Phase 9 (interlinking) and Phase 10 (backlinks) can overlap: interlinking rules can be finalized while backlink data models are built.
|
||
|
||
---
|
||
|
||
## 3. Phase 1: Data Foundation — New Models {#3-phase-1-data-foundation}
|
||
|
||
### 3.1 New App: `sag`
|
||
|
||
Create a new Django app for all SAG-specific models and business logic. This keeps SAG cleanly separated from existing modules.
|
||
|
||
**Create:**
|
||
```
|
||
backend/igny8_core/
|
||
├── sag/ # NEW Django app
|
||
│ ├── __init__.py
|
||
│ ├── apps.py # SagConfig
|
||
│ ├── models.py # SAGBlueprint, SAGAttribute, SAGCluster,
|
||
│ │ # SectorAttributeTemplate
|
||
│ ├── serializers.py # DRF serializers for all SAG models
|
||
│ ├── views.py # ViewSets (SAGBlueprintViewSet, etc.)
|
||
│ ├── urls.py # /api/v1/sag/*
|
||
│ ├── admin.py # Django admin for SAG models
|
||
│ ├── services/ # Business logic
|
||
│ │ ├── __init__.py
|
||
│ │ ├── blueprint_service.py # Blueprint CRUD, versioning, lifecycle
|
||
│ │ ├── attribute_service.py # Attribute framework loading, merging, validation
|
||
│ │ ├── cluster_service.py # Cluster formation, type classification
|
||
│ │ ├── keyword_service.py # Keyword auto-generation from attribute intersections
|
||
│ │ ├── template_service.py # Sector template loading, AI generation
|
||
│ │ └── health_service.py # Blueprint health score calculation
|
||
│ ├── ai_functions/ # SAG-specific AI functions
|
||
│ │ ├── __init__.py
|
||
│ │ ├── attribute_discovery.py # AI: Industry+Sector → Attribute framework
|
||
│ │ ├── attribute_extraction.py # AI: Site data → Attribute values (Case 1)
|
||
│ │ ├── attribute_population.py # AI: User inputs → Attribute values (Case 2)
|
||
│ │ ├── cluster_formation.py # AI: Populated attributes → Clusters with types
|
||
│ │ ├── keyword_generation.py # AI: Clusters + attribute values → Keywords
|
||
│ │ └── content_planning.py # AI: Clusters + keywords → Content ideas
|
||
│ └── migrations/
|
||
│ └── 0001_initial.py
|
||
```
|
||
|
||
**Register in settings.py:**
|
||
```python
|
||
INSTALLED_APPS = [
|
||
...
|
||
'igny8_core.sag',
|
||
]
|
||
```
|
||
|
||
**Register URLs in root urls.py:**
|
||
```python
|
||
urlpatterns = [
|
||
...
|
||
path('api/v1/sag/', include('igny8_core.sag.urls')),
|
||
]
|
||
```
|
||
|
||
### 3.2 New Models — Complete Definitions
|
||
|
||
**SAGBlueprint** — The master architectural document for a site.
|
||
|
||
```python
|
||
# sag/models.py
|
||
|
||
class SAGBlueprint(AccountBaseModel):
|
||
"""
|
||
The SAG Blueprint is the complete site architecture generated from
|
||
attribute analysis. Both Case 1 (existing site) and Case 2 (new site)
|
||
produce this same model. One active blueprint per site at a time.
|
||
"""
|
||
id = models.UUIDField(primary_key=True, default=uuid4)
|
||
site = models.ForeignKey('auth.Site', on_delete=models.CASCADE, related_name='sag_blueprints')
|
||
version = models.IntegerField(default=1)
|
||
status = models.CharField(
|
||
max_length=20,
|
||
choices=[
|
||
('draft', 'Draft'), # Generated, awaiting user confirmation
|
||
('active', 'Active'), # Confirmed, driving all content operations
|
||
('evolving', 'Evolving'), # New clusters being added as site grows
|
||
('archived', 'Archived'), # Replaced by newer version
|
||
],
|
||
default='draft'
|
||
)
|
||
source = models.CharField(
|
||
max_length=20,
|
||
choices=[
|
||
('site_builder', 'Site Builder (Case 2)'),
|
||
('site_analysis', 'Existing Site Analysis (Case 1)'),
|
||
('manual', 'Manual Creation'),
|
||
]
|
||
)
|
||
# Denormalized JSON for quick reads — authoritative data is in related models
|
||
attributes_json = models.JSONField(default=dict, blank=True)
|
||
clusters_json = models.JSONField(default=dict, blank=True)
|
||
taxonomy_plan = models.JSONField(default=dict, blank=True)
|
||
execution_priority = models.JSONField(default=list, blank=True)
|
||
internal_linking_map = models.JSONField(
|
||
default=dict, blank=True,
|
||
help_text="Placeholder until Doc 3 interlinking spec populates this"
|
||
)
|
||
|
||
# Metrics
|
||
sag_health_score = models.FloatField(default=0.0, help_text="0-100 score")
|
||
total_clusters = models.IntegerField(default=0)
|
||
total_keywords = models.IntegerField(default=0)
|
||
total_content_planned = models.IntegerField(default=0)
|
||
total_content_published = models.IntegerField(default=0)
|
||
|
||
# Timestamps
|
||
confirmed_at = models.DateTimeField(null=True, blank=True)
|
||
last_health_check = models.DateTimeField(null=True, blank=True)
|
||
|
||
class Meta:
|
||
ordering = ['-created_at']
|
||
unique_together = ['site', 'version']
|
||
```
|
||
|
||
**SAGAttribute** — A classification axis within a blueprint.
|
||
|
||
```python
|
||
class SAGAttribute(models.Model):
|
||
"""
|
||
One dimensional axis of the SAG grid. Each attribute becomes a WordPress
|
||
custom taxonomy. Values become taxonomy terms.
|
||
"""
|
||
id = models.UUIDField(primary_key=True, default=uuid4)
|
||
blueprint = models.ForeignKey(SAGBlueprint, on_delete=models.CASCADE, related_name='attributes')
|
||
name = models.CharField(max_length=100) # "Target Area"
|
||
slug = models.SlugField(max_length=100) # "target-area"
|
||
description = models.TextField(blank=True) # "Primary body area the device targets"
|
||
level = models.CharField(
|
||
max_length=20,
|
||
choices=[
|
||
('primary', 'Primary'), # Main navigation axes
|
||
('secondary', 'Secondary'), # Cluster depth axes
|
||
('tertiary', 'Tertiary'), # Filtering/tagging
|
||
]
|
||
)
|
||
values = models.JSONField(
|
||
default=list,
|
||
help_text='Array of {name, slug} objects. E.g. [{"name": "Foot", "slug": "foot"}]'
|
||
)
|
||
# WordPress sync state
|
||
wp_taxonomy_slug = models.CharField(max_length=100, null=True, blank=True)
|
||
wp_sync_status = models.CharField(
|
||
max_length=20,
|
||
choices=[
|
||
('pending', 'Pending'),
|
||
('synced', 'Synced'),
|
||
('failed', 'Failed'),
|
||
],
|
||
default='pending'
|
||
)
|
||
sort_order = models.IntegerField(default=0)
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
||
class Meta:
|
||
ordering = ['sort_order', 'level']
|
||
```
|
||
|
||
**SAGCluster** — A meaningful intersection of 2+ attribute values.
|
||
|
||
```python
|
||
class SAGCluster(AccountBaseModel):
|
||
"""
|
||
A cluster represents a topical ecosystem formed at the intersection of
|
||
2+ attribute values. Each cluster has a hub page and supporting content.
|
||
"""
|
||
id = models.UUIDField(primary_key=True, default=uuid4)
|
||
blueprint = models.ForeignKey(SAGBlueprint, on_delete=models.CASCADE, related_name='clusters')
|
||
site = models.ForeignKey('auth.Site', on_delete=models.CASCADE, related_name='sag_clusters')
|
||
name = models.CharField(max_length=200) # "Foot Massagers for Neuropathy"
|
||
slug = models.SlugField(max_length=200)
|
||
cluster_type = models.CharField(
|
||
max_length=30,
|
||
choices=[
|
||
('product_category', 'Product/Service Category'),
|
||
('condition_problem', 'Condition/Problem'),
|
||
('feature', 'Feature'),
|
||
('brand', 'Brand'),
|
||
('informational', 'Informational'),
|
||
('comparison', 'Comparison'),
|
||
]
|
||
)
|
||
attribute_intersection = models.JSONField(
|
||
help_text='Which attribute values form this cluster. E.g. {"target_area": "Foot", "relief_focus": "Neuropathy"}'
|
||
)
|
||
|
||
# Hub page info
|
||
hub_page_title = models.CharField(max_length=300, blank=True)
|
||
hub_page_type = models.CharField(max_length=30, default='cluster_hub')
|
||
hub_page_structure = models.CharField(max_length=30, default='guide_tutorial')
|
||
hub_page_url_slug = models.CharField(max_length=300, blank=True)
|
||
|
||
# Auto-generated keywords
|
||
auto_generated_keywords = models.JSONField(default=list)
|
||
|
||
# Supporting content plan
|
||
supporting_content_plan = models.JSONField(
|
||
default=list,
|
||
help_text='Array of {title, type, structure, keywords} for planned supporting content'
|
||
)
|
||
|
||
# Linking
|
||
linked_attribute_terms = models.JSONField(
|
||
default=list,
|
||
help_text='Which attribute term slugs this cluster connects to'
|
||
)
|
||
cross_cluster_links = models.JSONField(
|
||
default=list,
|
||
help_text='Slugs of other clusters sharing an attribute value'
|
||
)
|
||
|
||
# Status and metrics
|
||
status = models.CharField(
|
||
max_length=20,
|
||
choices=[
|
||
('planned', 'Planned'),
|
||
('partial', 'Partial'), # Some content published
|
||
('complete', 'Complete'), # Hub + all supporting content published
|
||
],
|
||
default='planned'
|
||
)
|
||
content_count = models.IntegerField(default=0)
|
||
link_coverage_score = models.FloatField(default=0.0, help_text="0-100")
|
||
|
||
# Backlink campaign fields (Phase 10)
|
||
backlink_target_tier = models.CharField(
|
||
max_length=5,
|
||
choices=[('T1','T1'),('T2','T2'),('T3','T3'),('T4','T4'),('T5','T5')],
|
||
null=True, blank=True,
|
||
help_text='Backlink campaign tier assignment — set by Doc 4 campaign generator'
|
||
)
|
||
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
||
class Meta:
|
||
ordering = ['name']
|
||
```
|
||
|
||
**SectorAttributeTemplate** — The NEW data layer: sector-level attribute intelligence.
|
||
|
||
```python
|
||
class SectorAttributeTemplate(models.Model):
|
||
"""
|
||
This is the foundational data layer that does NOT currently exist.
|
||
Each sector gets an attribute framework that defines its dimensional axes
|
||
and suggested values. This is the structural DNA of a sector.
|
||
"""
|
||
id = models.UUIDField(primary_key=True, default=uuid4)
|
||
industry = models.CharField(max_length=200)
|
||
sector = models.CharField(max_length=200)
|
||
site_type = models.CharField(
|
||
max_length=30,
|
||
choices=[
|
||
('e_commerce', 'E-Commerce'),
|
||
('services', 'Services'),
|
||
('saas', 'SaaS'),
|
||
('content', 'Content/Blog'),
|
||
('local_business', 'Local Business'),
|
||
('brand', 'Brand'),
|
||
]
|
||
)
|
||
attribute_framework = models.JSONField(
|
||
help_text='Template attributes with suggested values. Array of {name, description, level, suggested_values[]}'
|
||
)
|
||
keyword_templates = models.JSONField(
|
||
default=dict,
|
||
help_text='Keyword generation templates per cluster type. E.g. {"condition_problem": ["best {target} for {condition}", ...]}'
|
||
)
|
||
source = models.CharField(
|
||
max_length=30,
|
||
choices=[
|
||
('manual', 'Manual'),
|
||
('ai_generated', 'AI Generated'),
|
||
('user_contributed', 'User Contributed'),
|
||
],
|
||
default='manual'
|
||
)
|
||
is_active = models.BooleanField(default=True)
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
updated_at = models.DateTimeField(auto_now=True)
|
||
|
||
class Meta:
|
||
unique_together = ['industry', 'sector']
|
||
ordering = ['industry', 'sector']
|
||
```
|
||
|
||
### 3.3 Migrations for Existing Models
|
||
|
||
**Site model** (`auth/models.py`):
|
||
```python
|
||
# Add to Site model:
|
||
sag_blueprint_id = models.ForeignKey(
|
||
'sag.SAGBlueprint', on_delete=models.SET_NULL,
|
||
null=True, blank=True, related_name='active_for_sites',
|
||
help_text='Currently active SAG blueprint for this site'
|
||
)
|
||
```
|
||
|
||
**Cluster model** (`modules/planner/models.py`):
|
||
```python
|
||
# Add to existing Cluster model:
|
||
sag_cluster_id = models.ForeignKey(
|
||
'sag.SAGCluster', on_delete=models.SET_NULL,
|
||
null=True, blank=True, related_name='legacy_clusters'
|
||
)
|
||
cluster_type = models.CharField(max_length=30, null=True, blank=True)
|
||
```
|
||
|
||
**Tasks model** (`modules/writer/models.py`):
|
||
```python
|
||
# Add to existing Tasks model:
|
||
sag_cluster_id = models.ForeignKey(
|
||
'sag.SAGCluster', on_delete=models.SET_NULL,
|
||
null=True, blank=True
|
||
)
|
||
blueprint_context = models.JSONField(null=True, blank=True)
|
||
```
|
||
|
||
**Content model** (`modules/writer/models.py`):
|
||
```python
|
||
# Add to existing Content model:
|
||
sag_cluster_id = models.ForeignKey(
|
||
'sag.SAGCluster', on_delete=models.SET_NULL,
|
||
null=True, blank=True
|
||
)
|
||
outbound_link_count = models.IntegerField(null=True, blank=True)
|
||
inbound_link_count = models.IntegerField(null=True, blank=True)
|
||
backlink_count = models.IntegerField(null=True, blank=True)
|
||
```
|
||
|
||
**ContentIdea model** (`modules/planner/models.py`):
|
||
```python
|
||
# Add to existing ContentIdea model:
|
||
sag_cluster_id = models.ForeignKey(
|
||
'sag.SAGCluster', on_delete=models.SET_NULL,
|
||
null=True, blank=True
|
||
)
|
||
idea_source = models.CharField(
|
||
max_length=30, null=True, blank=True,
|
||
choices=[
|
||
('keyword_clustering', 'Keyword Clustering'),
|
||
('sag_blueprint', 'SAG Blueprint'),
|
||
('gap_analysis', 'Gap Analysis'),
|
||
]
|
||
)
|
||
```
|
||
|
||
### 3.4 Serializers
|
||
|
||
```
|
||
sag/serializers.py
|
||
```
|
||
|
||
Create DRF serializers for each model. Key considerations:
|
||
- `SAGBlueprintSerializer` — include nested `attributes` and `clusters` on detail view, exclude on list view for performance
|
||
- `SAGBlueprintListSerializer` — lightweight: id, site, version, status, health_score, total_clusters, total_keywords, timestamps
|
||
- `SAGAttributeSerializer` — full attribute with values array
|
||
- `SAGClusterSerializer` — full cluster with keywords, supporting content plan, linking data
|
||
- `SectorAttributeTemplateSerializer` — admin-only, includes full attribute_framework JSON
|
||
|
||
### 3.5 ViewSets and URLs
|
||
|
||
```python
|
||
# sag/views.py
|
||
|
||
class SAGBlueprintViewSet(AccountModelViewSet):
|
||
"""
|
||
CRUD for SAG Blueprints.
|
||
Additional actions: confirm, archive, regenerate, health_check
|
||
"""
|
||
queryset = SAGBlueprint.objects.all()
|
||
serializer_class = SAGBlueprintSerializer
|
||
|
||
@action(detail=True, methods=['post'])
|
||
def confirm(self, request, pk=None):
|
||
"""Move blueprint from draft → active. Sets site.sag_blueprint_id."""
|
||
pass
|
||
|
||
@action(detail=True, methods=['post'])
|
||
def archive(self, request, pk=None):
|
||
"""Move blueprint to archived. Removes from site.sag_blueprint_id."""
|
||
pass
|
||
|
||
@action(detail=True, methods=['post'])
|
||
def regenerate(self, request, pk=None):
|
||
"""Create new version of blueprint from updated attributes."""
|
||
pass
|
||
|
||
@action(detail=True, methods=['get'])
|
||
def health_check(self, request, pk=None):
|
||
"""Run health check and return score + details."""
|
||
pass
|
||
|
||
class SAGAttributeViewSet(AccountModelViewSet):
|
||
"""CRUD for attributes within a blueprint."""
|
||
queryset = SAGAttribute.objects.all()
|
||
serializer_class = SAGAttributeSerializer
|
||
|
||
class SAGClusterViewSet(AccountModelViewSet):
|
||
"""CRUD for clusters within a blueprint."""
|
||
queryset = SAGCluster.objects.all()
|
||
serializer_class = SAGClusterSerializer
|
||
|
||
class SectorAttributeTemplateViewSet(ModelViewSet):
|
||
"""Admin-only: manage sector attribute templates."""
|
||
queryset = SectorAttributeTemplate.objects.all()
|
||
serializer_class = SectorAttributeTemplateSerializer
|
||
permission_classes = [IsAdminUser]
|
||
```
|
||
|
||
```python
|
||
# sag/urls.py
|
||
|
||
router = DefaultRouter()
|
||
router.register(r'blueprints', SAGBlueprintViewSet)
|
||
router.register(r'attributes', SAGAttributeViewSet)
|
||
router.register(r'clusters', SAGClusterViewSet)
|
||
router.register(r'templates', SectorAttributeTemplateViewSet)
|
||
|
||
urlpatterns = [
|
||
path('', include(router.urls)),
|
||
]
|
||
```
|
||
|
||
### 3.6 Django Admin
|
||
|
||
Register all 4 models in Django admin with:
|
||
- SAGBlueprint: list display (site, version, status, health_score, created_at), filters (status, source)
|
||
- SAGAttribute: inline on Blueprint admin, sortable by sort_order
|
||
- SAGCluster: list display (name, cluster_type, status, content_count), filters (cluster_type, status)
|
||
- SectorAttributeTemplate: list display (industry, sector, site_type, source, is_active), filters (industry, site_type, source)
|
||
|
||
### 3.7 Frontend — Phase 1 Has No User-Facing UI
|
||
|
||
Phase 1 is backend-only. The only frontend addition is a read-only blueprint viewer in Site Settings (for development verification):
|
||
|
||
```
|
||
frontend/src/pages/Settings/
|
||
├── SiteSettings.tsx # EXISTING — add a "SAG Blueprint" tab
|
||
└── components/
|
||
└── BlueprintViewer.tsx # NEW — read-only JSON display of active blueprint
|
||
```
|
||
|
||
This is a development aid. The real UI comes in Phase 4 (wizard) and Phase 8 (dashboard).
|
||
|
||
---
|
||
|
||
## 4. Phase 2: Sector Attribute Templates {#4-phase-2-sector-attribute-templates}
|
||
|
||
### 4.1 What This Phase Delivers
|
||
|
||
The SectorAttributeTemplate model from Phase 1 gets populated with actual data. This is the structural DNA that makes everything else work.
|
||
|
||
### 4.2 Backend: Template Service
|
||
|
||
```
|
||
sag/services/template_service.py
|
||
```
|
||
|
||
**Functions:**
|
||
- `get_template(industry, sector)` → returns SectorAttributeTemplate or None
|
||
- `get_or_generate_template(industry, sector)` → returns existing template OR triggers AI generation
|
||
- `merge_templates(sector_list)` → for multi-sector sites: merge attribute frameworks, combine value lists, deduplicate
|
||
- `validate_template(template_data)` → ensure all attributes have names, levels, and at least suggested_values structure
|
||
|
||
### 4.3 Backend: AI Template Generation
|
||
|
||
```
|
||
sag/ai_functions/attribute_discovery.py
|
||
```
|
||
|
||
**New AI function: `DiscoverSectorAttributes`**
|
||
|
||
Registered in AI engine function registry alongside existing functions.
|
||
|
||
```python
|
||
# Register in ai/registry.py:
|
||
'discover_sector_attributes': 'igny8_core.sag.ai_functions.attribute_discovery.DiscoverSectorAttributes'
|
||
```
|
||
|
||
**Input:** industry name, sector name, site_type
|
||
**Output:** attribute_framework JSON matching SectorAttributeTemplate schema
|
||
**Prompt strategy:** "You are an expert in site architecture for {industry}/{sector}. Define the dimensional axes that organize this sector. For each attribute, specify: name, description, level (primary/secondary/tertiary), and 5-10 suggested values."
|
||
|
||
### 4.4 Backend: Manual Template Seeding
|
||
|
||
Priority: Seed templates for sectors with highest existing user base in IGNY8. Use the Healthcare/Medical Excel workbook (SAGIndustry01HealthcareMedical.xlsx) as the reference format for how templates should be structured.
|
||
|
||
**Admin Interface:** Django admin for SectorAttributeTemplate allows manual creation and editing. The `attribute_framework` JSON field should use a structured widget or at minimum raw JSON with validation.
|
||
|
||
### 4.5 Frontend — Admin Template Manager (Admin Only)
|
||
|
||
```
|
||
frontend/src/pages/Settings/
|
||
└── components/
|
||
└── SectorTemplateManager.tsx # NEW — admin-only interface
|
||
```
|
||
|
||
This is a simple CRUD interface visible only to admin users (similar to existing AI Models admin page). Shows list of all templates, allows editing attribute frameworks, and can trigger AI generation for missing sectors.
|
||
|
||
**Not in main sidebar** — accessed via Settings → Admin → Sector Templates (similar to how AI Models is nested under Settings).
|
||
|
||
---
|
||
|
||
## 5. Phase 3: Cluster Formation & Keyword Generation Engine {#5-phase-3-cluster-formation--keyword-generation}
|
||
|
||
### 5.1 What This Phase Delivers
|
||
|
||
The AI intelligence that turns populated attributes into clusters with types, and clusters into 300-500+ keywords. These are backend services — no direct UI yet. They're called by the wizard (Phase 4) and the pipeline (Phase 5).
|
||
|
||
### 5.2 Backend: AI Functions
|
||
|
||
**`sag/ai_functions/cluster_formation.py` — `FormClusters`**
|
||
|
||
Register in AI engine:
|
||
```python
|
||
'form_clusters': 'igny8_core.sag.ai_functions.cluster_formation.FormClusters'
|
||
```
|
||
|
||
**Input:** populated attributes (all values per attribute), sector context, site_type
|
||
**Output:** array of cluster objects with: name, cluster_type, attribute_intersection, hub_page_title, hub_page_structure, supporting_content_plan
|
||
|
||
**Logic:**
|
||
1. Generate all 2-value intersections of primary × primary, primary × secondary
|
||
2. AI evaluates each intersection: is this a real topical ecosystem with search demand?
|
||
3. Valid intersections become clusters
|
||
4. AI classifies each cluster by type (product_category, condition_problem, feature, brand, informational, comparison)
|
||
5. AI generates hub page title and supporting content titles per cluster
|
||
6. Maximum 50 clusters per sector (hard cap from SAG methodology)
|
||
|
||
**`sag/ai_functions/keyword_generation.py` — `GenerateKeywords`**
|
||
|
||
Register in AI engine:
|
||
```python
|
||
'generate_keywords': 'igny8_core.sag.ai_functions.keyword_generation.GenerateKeywords'
|
||
```
|
||
|
||
**Input:** clusters with attribute values, keyword_templates from SectorAttributeTemplate
|
||
**Output:** per-cluster keyword arrays (15-25 keywords per cluster)
|
||
|
||
**Logic:**
|
||
1. Load keyword templates for this sector type
|
||
2. For each cluster, substitute attribute values into templates
|
||
3. Generate long-tail variants with modifiers (best, review, vs, for, how to)
|
||
4. Deduplicate across clusters
|
||
5. Total should be 300-500+ keywords per site
|
||
|
||
### 5.3 Backend: Blueprint Assembly Service
|
||
|
||
```
|
||
sag/services/blueprint_service.py — extend with:
|
||
```
|
||
|
||
**`assemble_blueprint(site, attributes, clusters, keywords)`**
|
||
|
||
Takes all outputs from Phases 2-3 and assembles the complete SAGBlueprint:
|
||
1. Create SAGBlueprint record (status=draft)
|
||
2. Create SAGAttribute records from attributes
|
||
3. Create SAGCluster records from clusters
|
||
4. Populate auto_generated_keywords on each cluster
|
||
5. Generate taxonomy_plan from attributes
|
||
6. Generate execution_priority from cluster types and keyword volumes
|
||
7. Populate denormalized JSON fields on blueprint
|
||
8. Return blueprint ID
|
||
|
||
### 5.4 Backend: Cluster Service
|
||
|
||
```
|
||
sag/services/cluster_service.py
|
||
```
|
||
|
||
**Functions:**
|
||
- `classify_cluster_type(intersection, sector_context)` → Enum
|
||
- `generate_hub_page_info(cluster)` → title, type, structure, url_slug
|
||
- `plan_supporting_content(cluster)` → array of {title, type, structure, keywords}
|
||
- `find_cross_cluster_links(all_clusters)` → for each cluster, find others sharing attribute values
|
||
- `find_linked_attribute_terms(cluster)` → which attribute value slugs this cluster connects to
|
||
|
||
---
|
||
|
||
## 6. Phase 4: SAG Site Builder Wizard (Case 2) {#6-phase-4-sag-site-builder-wizard}
|
||
|
||
### 6.1 What This Phase Delivers
|
||
|
||
The first user-facing SAG feature. The setup wizard gets a new Step 3 "Site Structure" that collects business data and generates a complete blueprint.
|
||
|
||
### 6.2 Backend: Wizard API Endpoints
|
||
|
||
Add to `sag/views.py` or create `sag/wizard_views.py`:
|
||
|
||
```python
|
||
# POST /api/v1/sag/wizard/generate-attributes/
|
||
# Input: {industry, sectors[], site_type}
|
||
# Output: {attributes: [{name, level, suggested_values}]}
|
||
# Calls: template_service.get_or_generate_template() + merge if multi-sector
|
||
|
||
# POST /api/v1/sag/wizard/populate-attributes/
|
||
# Input: {attributes: [{name, level, values}], business_data: {products, services, brands, locations, conditions}}
|
||
# Output: {populated_attributes: [{name, level, values}]} (values now enriched from business data)
|
||
# Calls: ai_functions.attribute_population.PopulateAttributes
|
||
|
||
# POST /api/v1/sag/wizard/generate-blueprint/
|
||
# Input: {site_id, populated_attributes, mode: 'quick'|'detailed'}
|
||
# Output: {blueprint_id, clusters, keywords_count, content_plan_count, taxonomy_count}
|
||
# Calls: cluster_formation → keyword_generation → blueprint_service.assemble_blueprint()
|
||
|
||
# POST /api/v1/sag/wizard/confirm-blueprint/
|
||
# Input: {blueprint_id}
|
||
# Output: {success, blueprint_status: 'active'}
|
||
# Calls: blueprint_service.confirm() — sets site.sag_blueprint_id, triggers taxonomy creation
|
||
```
|
||
|
||
### 6.3 Backend: AI Function for Business Data Population
|
||
|
||
**`sag/ai_functions/attribute_population.py` — `PopulateAttributes`**
|
||
|
||
**Input:** attribute framework + user's business data (products list, services list, brands, locations, conditions)
|
||
**Output:** populated attributes with site-specific values extracted from business data
|
||
|
||
**Logic:**
|
||
1. Parse business data inputs (free text, comma-separated lists, structured inputs)
|
||
2. Map business items to attribute values (e.g., "foot massagers, neck massagers" → Target Area: [Foot, Neck])
|
||
3. Identify values not in suggested_values → add as new values
|
||
4. Apply pruning rules (single-value primary → demote to secondary, etc.)
|
||
5. Assess completeness per attribute → flag any that need user attention
|
||
|
||
### 6.4 Frontend: Setup Wizard Enhancement
|
||
|
||
The existing setup wizard lives at:
|
||
```
|
||
frontend/src/pages/Settings/ # or wherever the Add Site wizard is
|
||
```
|
||
|
||
**Modify the wizard to insert Step 3 between "Add Site" and "Connect WordPress":**
|
||
|
||
```
|
||
frontend/src/pages/Settings/
|
||
├── SetupWizard/ # EXISTING wizard component
|
||
│ ├── WizardStep1Welcome.tsx # No changes
|
||
│ ├── WizardStep2AddSite.tsx # No changes — already collects Industry, Sectors
|
||
│ ├── WizardStep3SiteStructure.tsx # NEW — the Site Builder step
|
||
│ │ ├── ModeSelector.tsx # Quick Mode vs Detailed Mode toggle
|
||
│ │ ├── AttributeReview.tsx # Shows AI-generated attributes, toggle on/off, edit values
|
||
│ │ ├── BusinessDataInput.tsx # Per-site-type input forms (products, services, etc.)
|
||
│ │ ├── BlueprintPreview.tsx # Tree view of clusters, keywords count, content plan
|
||
│ │ └── BlueprintConfirm.tsx # Approve & Build / Adjust Attributes buttons
|
||
│ ├── WizardStep4ConnectWP.tsx # EXISTING — enhanced: auto-creates taxonomies after connect
|
||
│ ├── WizardStep5Keywords.tsx # EXISTING — now shows "optional" messaging + gap analysis
|
||
│ └── WizardStep6Complete.tsx # EXISTING — enhanced: shows blueprint summary
|
||
```
|
||
|
||
### 6.5 Frontend: Step 3 Component Details
|
||
|
||
**ModeSelector.tsx**
|
||
- Two cards: "Quick Mode" (auto-build, skip review) and "Detailed Mode" (full review + business data)
|
||
- Quick mode calls: generate-attributes → generate-blueprint (with defaults) → confirm
|
||
- Detailed mode proceeds through all sub-steps
|
||
|
||
**AttributeReview.tsx**
|
||
- Displays attributes grouped by level (Primary, Secondary, Tertiary)
|
||
- Each attribute: name, toggle switch (on/off), expandable values list
|
||
- Values: chip/tag UI with [+ Add] button, click to remove
|
||
- [+ Add Custom Attribute] button at bottom
|
||
- Loading state while AI generates attributes
|
||
|
||
**BusinessDataInput.tsx**
|
||
- Dynamic form based on site_type from Step 2
|
||
- E-commerce: Products/categories (textarea), Device types (textarea), Problems solved (textarea), Brands (textarea), Features (textarea)
|
||
- Services: Services offered (textarea), Locations (textarea), Property types (textarea), Problems solved (textarea)
|
||
- SaaS: Features (textarea), Use cases (textarea), Integrations (textarea), Competitors (textarea)
|
||
- Content: Topics (textarea), Subtopics (textarea), Audience (textarea)
|
||
- Local Business: Services (textarea), Locations (textarea), Conditions (textarea)
|
||
- Each textarea has helper text: "Enter one per line, or comma-separated"
|
||
|
||
**BlueprintPreview.tsx**
|
||
- Tree/accordion view of clusters grouped by primary attribute value
|
||
- Each cluster shows: name, type badge, hub page title, supporting content count, keyword count
|
||
- Summary bar at top: X clusters, Y keywords, Z content pieces, W taxonomies
|
||
- Expandable per cluster: see all keywords, all planned supporting content titles
|
||
- This is the "Your Site Architecture" preview from the spec document
|
||
|
||
**BlueprintConfirm.tsx**
|
||
- Two buttons: [Approve & Build] and [Adjust Attributes] (goes back to AttributeReview)
|
||
- Approve triggers: POST /wizard/confirm-blueprint/
|
||
- Shows brief loading animation during confirmation
|
||
- On success: proceeds to Step 4 (Connect WordPress)
|
||
|
||
### 6.6 Frontend: Zustand Store
|
||
|
||
```
|
||
frontend/src/store/
|
||
└── sagStore.ts # NEW
|
||
```
|
||
|
||
```typescript
|
||
interface SAGState {
|
||
blueprint: SAGBlueprint | null;
|
||
attributes: SAGAttribute[];
|
||
clusters: SAGCluster[];
|
||
wizardMode: 'quick' | 'detailed';
|
||
wizardStep: number; // Sub-step within Step 3
|
||
isGenerating: boolean;
|
||
error: string | null;
|
||
|
||
// Actions
|
||
setWizardMode: (mode: 'quick' | 'detailed') => void;
|
||
generateAttributes: (industry: string, sectors: string[]) => Promise<void>;
|
||
populateAttributes: (attributes: any[], businessData: any) => Promise<void>;
|
||
generateBlueprint: (siteId: string) => Promise<void>;
|
||
confirmBlueprint: (blueprintId: string) => Promise<void>;
|
||
loadBlueprint: (siteId: string) => Promise<void>;
|
||
}
|
||
```
|
||
|
||
### 6.7 Frontend: API Client
|
||
|
||
```
|
||
frontend/src/api/
|
||
└── sag.api.ts # NEW
|
||
```
|
||
|
||
API client for all `/api/v1/sag/*` endpoints. Follows existing pattern from other API clients (linker.api.ts, optimizer.api.ts).
|
||
|
||
---
|
||
|
||
## 7. Phase 5: Blueprint-Aware Content Pipeline {#7-phase-5-blueprint-aware-content-pipeline}
|
||
|
||
### 7.1 What This Phase Delivers
|
||
|
||
The existing 7-stage automation pipeline becomes SAG-aware. Ideas generate from the blueprint, tasks carry cluster context, writer uses type-specific prompts, and content gets auto-assigned to correct taxonomies.
|
||
|
||
### 7.2 Backend: Modified Automation Stages
|
||
|
||
**Location:** `business/automation/` — modify existing stage handlers
|
||
|
||
**Stage 0 (NEW): Blueprint Check**
|
||
```python
|
||
# business/automation/stages/stage_0_blueprint_check.py (NEW)
|
||
# Before any pipeline run:
|
||
# 1. Check if site has active SAG blueprint (site.sag_blueprint_id is not None)
|
||
# 2. If yes: load blueprint, identify unfulfilled content needs
|
||
# 3. If no: pipeline runs in legacy mode (no changes to current behavior)
|
||
```
|
||
|
||
**Stage 2: AI Cluster Keywords — ENHANCED**
|
||
```python
|
||
# business/automation/stages/ — modify existing Stage 2
|
||
# If blueprint exists:
|
||
# - Skip AI clustering (clusters already defined by blueprint)
|
||
# - Instead: map any new user-added keywords to existing SAG clusters
|
||
# - Flag keywords that don't match any cluster
|
||
# If no blueprint:
|
||
# - Run existing AutoClusterKeywords (unchanged)
|
||
```
|
||
|
||
**Stage 3: Generate Content Ideas — ENHANCED**
|
||
```python
|
||
# business/automation/stages/ — modify existing Stage 3
|
||
# If blueprint exists:
|
||
# - Call sag/ai_functions/content_planning.py instead of generic idea generation
|
||
# - Each idea gets: correct Sector, Structure, Type, Cluster from blueprint
|
||
# - idea_source = 'sag_blueprint'
|
||
# If no blueprint:
|
||
# - Run existing GenerateContentIdeas (unchanged)
|
||
```
|
||
|
||
**Stage 4: Create Writer Tasks — ENHANCED**
|
||
```python
|
||
# business/automation/stages/ — modify existing Stage 4
|
||
# If blueprint exists:
|
||
# - Tasks carry sag_cluster_id and blueprint_context
|
||
# - blueprint_context includes: cluster_type, hub_title, attribute_terms, related_content
|
||
# If no blueprint:
|
||
# - Run existing task creation (unchanged)
|
||
```
|
||
|
||
**Stage 5: Generate Article Content — ENHANCED**
|
||
```python
|
||
# business/automation/stages/ — modify existing Stage 5
|
||
# If task has blueprint_context:
|
||
# - Select prompt template by Structure + Type (instead of generic)
|
||
# - Include SAG context variables: {cluster_name}, {cluster_type}, {hub_title}, {attribute_terms}
|
||
# - Content generation includes type-specific sections
|
||
# If no blueprint_context:
|
||
# - Run existing GenerateContent (unchanged)
|
||
```
|
||
|
||
**Stage 6 (NEW enhancement): Taxonomy Assignment**
|
||
```python
|
||
# After content generation, before image prompts:
|
||
# If blueprint exists:
|
||
# - Auto-assign content to correct custom taxonomies from blueprint
|
||
# - Set sag_cluster_id on Content record
|
||
# - Mark cluster status as 'partial' if first content piece
|
||
```
|
||
|
||
### 7.3 Backend: Enhanced Prompt Templates
|
||
|
||
**Location:** Existing `PromptTemplate` model or defaults in code
|
||
|
||
Add SAG-context prompt variants. These are stored in the same PromptTemplate system but selected based on content type:
|
||
|
||
| Content Type | Structure | Prompt Template Key |
|
||
|-------------|-----------|-------------------|
|
||
| Cluster Hub Page | Guide Tutorial | `sag_hub_guide` |
|
||
| Cluster Hub Page | Top Listicle | `sag_hub_listicle` |
|
||
| Blog Post | Comparison | `sag_blog_comparison` |
|
||
| Blog Post | Review | `sag_blog_review` |
|
||
| Blog Post | How To | `sag_blog_howto` |
|
||
| Blog Post | Question | `sag_blog_question` |
|
||
| Attribute Term Page | Guide Tutorial | `sag_term_page` |
|
||
| Product Page | Review | `sag_product_page` |
|
||
| Service Page | Guide Tutorial | `sag_service_page` |
|
||
|
||
Each prompt includes SAG context variables:
|
||
```
|
||
You are writing a {content_type} for the cluster "{cluster_name}".
|
||
This cluster covers the intersection of {attribute_intersection}.
|
||
The hub page for this cluster is: "{hub_page_title}" at {hub_page_url}.
|
||
Related content in this cluster includes: {related_blogs}.
|
||
This content should naturally reference these taxonomy terms: {attribute_terms}.
|
||
```
|
||
|
||
### 7.4 Frontend: Pipeline UI Shows Blueprint Context
|
||
|
||
**Location:** `pages/Automation/` — existing pipeline monitoring view
|
||
|
||
When a site has an active blueprint, the automation page shows:
|
||
- Blueprint status badge: "SAG Blueprint Active (v1)"
|
||
- Pipeline mode indicator: "Running in SAG Mode" vs "Running in Legacy Mode"
|
||
- Stage 0 (Blueprint Check) appears as the first stage in the progress display
|
||
|
||
**Location:** `pages/Writer/` — existing task and content views
|
||
|
||
When viewing a task or content item that has `sag_cluster_id`:
|
||
- Show cluster badge: "Cluster: Foot Massagers for Neuropathy"
|
||
- Show type badge: "Type: Hub Page" or "Type: Supporting Blog"
|
||
- Show blueprint context panel (collapsible): cluster type, attribute terms, related content links
|
||
|
||
These are display-only enhancements to existing views — no new pages needed.
|
||
|
||
---
|
||
|
||
## 8. Phase 6: Taxonomy Creation Flow {#8-phase-6-taxonomy-creation-flow}
|
||
|
||
### 8.1 What This Phase Delivers
|
||
|
||
When a blueprint is confirmed, IGNY8 pushes taxonomy creation instructions to the WordPress plugin, which creates the actual WordPress custom taxonomies and terms.
|
||
|
||
### 8.2 Backend: Taxonomy Payload Generator
|
||
|
||
```
|
||
sag/services/taxonomy_service.py # NEW
|
||
```
|
||
|
||
**Functions:**
|
||
- `generate_taxonomy_payload(blueprint)` → JSON payload matching plugin's expected format
|
||
- `send_taxonomy_payload(site, payload)` → POST to WordPress plugin endpoint
|
||
- `handle_taxonomy_response(site, response)` → update SAGAttribute wp_sync_status
|
||
- `check_taxonomy_status(site)` → GET current taxonomy state from plugin
|
||
|
||
**Payload format:**
|
||
```json
|
||
{
|
||
"taxonomies": [
|
||
{
|
||
"slug": "target-area",
|
||
"label": "Target Area",
|
||
"description": "Primary body area the device targets",
|
||
"hierarchical": true,
|
||
"post_types": ["product", "post", "page"],
|
||
"terms": [
|
||
{"name": "Foot", "slug": "foot", "description": "Foot massagers and foot therapy devices"},
|
||
{"name": "Neck", "slug": "neck", "description": "Neck massagers and cervical therapy"}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 8.3 Plugin Side: Taxonomy Builder
|
||
|
||
The WordPress plugin already has planned files for this:
|
||
```
|
||
igny8-plugin/includes/modules/sag/
|
||
├── class-taxonomy-builder.php # Create WP taxonomies from payload
|
||
├── class-term-builder.php # Create terms within taxonomies
|
||
```
|
||
|
||
Plugin endpoint: `POST /wp-json/igny8/v1/sag/create-taxonomies`
|
||
- Receives payload from IGNY8 app
|
||
- Registers taxonomies via `register_taxonomy()`
|
||
- Creates terms via `wp_insert_term()`
|
||
- Returns success with term IDs mapped to slugs
|
||
- Stores taxonomy registrations in option for persistence across requests
|
||
|
||
### 8.4 Backend: Integration with Existing Sync Architecture
|
||
|
||
**Location:** `business/integration/` — extend existing sync services
|
||
|
||
The taxonomy creation uses the same `Site.wp_api_key` authentication and webhook architecture that content publishing already uses. No new auth mechanism needed.
|
||
|
||
**Flow:**
|
||
```
|
||
Blueprint confirmed
|
||
→ sag/services/taxonomy_service.generate_taxonomy_payload()
|
||
→ business/integration/sync_service.push_to_wordpress(site, '/sag/create-taxonomies', payload)
|
||
→ Plugin creates taxonomies + terms
|
||
→ Plugin POSTs response back to IGNY8 webhook
|
||
→ sag/services/taxonomy_service.handle_taxonomy_response()
|
||
→ SAGAttribute.wp_sync_status updated to 'synced'
|
||
```
|
||
|
||
### 8.5 Frontend: Taxonomy Sync Status
|
||
|
||
**Location:** `pages/Settings/SiteSettings.tsx` — add SAG tab or extend existing integration tab
|
||
|
||
Show:
|
||
- List of attributes from blueprint
|
||
- Each attribute: name, WP taxonomy slug, sync status (pending/synced/failed)
|
||
- "Sync Taxonomies" button to retry failed syncs
|
||
- This is visible after blueprint is confirmed (Phase 4) and site is connected to WordPress
|
||
|
||
---
|
||
|
||
## 9. Phase 7: Existing Site Analysis (Case 1) {#9-phase-7-existing-site-analysis}
|
||
|
||
### 9.1 What This Phase Delivers
|
||
|
||
For existing WordPress/WooCommerce sites, IGNY8 collects site data, AI extracts attributes from it, generates a gap analysis, and produces a blueprint.
|
||
|
||
### 9.2 Backend: Extended Site Data Collection
|
||
|
||
**Location:** Plugin already has site data collection:
|
||
```
|
||
igny8-plugin/data/site-collection.php # Collects post data, taxonomy data, product data
|
||
igny8-plugin/data/semantic-mapping.php # Maps site content to semantic strategy
|
||
```
|
||
|
||
**Enhance plugin to collect additional data for SAG:**
|
||
- All WooCommerce product attributes + values (pa_color, pa_size, custom attributes)
|
||
- Product titles and descriptions (for AI attribute extraction)
|
||
- Existing custom taxonomies with all terms
|
||
- Navigation menu structure with hierarchy
|
||
- Page templates in use
|
||
|
||
**New plugin endpoint:** `GET /wp-json/igny8/v1/sag/site-analysis`
|
||
Returns comprehensive site data package for AI analysis.
|
||
|
||
### 9.3 Backend: AI Attribute Extraction (Case 1)
|
||
|
||
**`sag/ai_functions/attribute_extraction.py` — `ExtractAttributes`**
|
||
|
||
**Input:** raw site data (product titles, descriptions, categories, existing taxonomies, menu structure)
|
||
**Output:** discovered attributes with values and confidence scores
|
||
|
||
**Logic:**
|
||
1. AI analyzes product/content titles for recurring patterns
|
||
2. Cross-references against sector template (if exists) for validation
|
||
3. Returns discovered attributes with frequency counts per value
|
||
4. Flags low-confidence discoveries for user review
|
||
|
||
### 9.4 Backend: Gap Analysis Service
|
||
|
||
```
|
||
sag/services/gap_analysis_service.py # NEW
|
||
```
|
||
|
||
**Functions:**
|
||
- `analyze_gap(site_data, blueprint)` → comprehensive gap report
|
||
- Gap report includes: missing cluster hubs, missing supporting content, products needing attribute enrichment, taxonomy terms without content, internal links missing
|
||
|
||
### 9.5 Frontend: Case 1 Analysis UI
|
||
|
||
**Location:** Accessed from Site Settings when a site is connected but has no blueprint
|
||
|
||
```
|
||
frontend/src/pages/Settings/
|
||
└── components/
|
||
├── SiteAnalysis.tsx # NEW — trigger and display site analysis
|
||
├── DiscoveredAttributes.tsx # NEW — show AI-discovered attributes, user confirms/edits
|
||
├── GapAnalysisReport.tsx # NEW — show gap analysis results
|
||
└── ProductAutoTagger.tsx # NEW — review and approve AI-generated product tags
|
||
```
|
||
|
||
**Flow:**
|
||
1. User clicks "Analyze Site Structure" in Site Settings
|
||
2. Loading state while plugin collects data and AI processes it
|
||
3. DiscoveredAttributes screen: shows AI findings, user toggles/edits/confirms
|
||
4. After confirmation → blueprint generates (same as Case 2 but with extracted data)
|
||
5. GapAnalysisReport: shows what's missing vs what the blueprint recommends
|
||
6. ProductAutoTagger: for e-commerce sites, review AI-suggested attribute assignments per product
|
||
|
||
---
|
||
|
||
## 10. Phase 8: Blueprint Health Monitoring {#10-phase-8-blueprint-health-monitoring}
|
||
|
||
### 10.1 What This Phase Delivers
|
||
|
||
Background monitoring that tracks blueprint completion, content coverage per cluster, link health, and overall SAG health score. Dashboard widgets surface this data.
|
||
|
||
### 10.2 Backend: Health Service
|
||
|
||
```
|
||
sag/services/health_service.py # Already created in Phase 1, now implement
|
||
```
|
||
|
||
**`calculate_health_score(blueprint)`** returns 0-100 score based on:
|
||
- Content completeness per cluster (hub exists? blogs published?) — 30 points
|
||
- Taxonomy sync status (all taxonomies created?) — 15 points
|
||
- Internal link coverage (from Linker module when active) — 20 points
|
||
- Keyword coverage (keywords have matching content?) — 15 points
|
||
- Unassigned content (pages/products not mapped to clusters) — 10 points
|
||
- Overall structure balance (no cluster with 0 content while others have 5+) — 10 points
|
||
|
||
### 10.3 Backend: Celery Tasks
|
||
|
||
```
|
||
sag/tasks.py # NEW
|
||
```
|
||
|
||
```python
|
||
@shared_task
|
||
def run_blueprint_health_check(site_id):
|
||
"""Weekly health check for a site's active blueprint."""
|
||
site = Site.objects.get(id=site_id)
|
||
if not site.sag_blueprint_id:
|
||
return
|
||
blueprint = site.sag_blueprint
|
||
score = health_service.calculate_health_score(blueprint)
|
||
blueprint.sag_health_score = score
|
||
blueprint.last_health_check = now()
|
||
blueprint.save()
|
||
|
||
@shared_task
|
||
def check_blueprint_evolution_triggers(site_id):
|
||
"""Check if blueprint needs evolution (new products, new keywords, etc.)."""
|
||
pass
|
||
```
|
||
|
||
**Register in Celery Beat schedule** (existing `celery.py` configuration):
|
||
- `run_blueprint_health_check`: weekly for all sites with active blueprints
|
||
- `check_blueprint_evolution_triggers`: weekly, same schedule
|
||
|
||
### 10.4 Frontend: Dashboard Widgets
|
||
|
||
**Location:** `components/dashboard/` — add new widgets alongside existing ones
|
||
|
||
```
|
||
frontend/src/components/dashboard/
|
||
├── SAGHealthWidget.tsx # NEW — health score gauge, cluster completion bars
|
||
├── BlueprintProgressWidget.tsx # NEW — content published vs planned per cluster
|
||
```
|
||
|
||
**SAGHealthWidget:**
|
||
- Circular gauge showing overall health score (0-100)
|
||
- Color: green (80+), yellow (50-79), red (<50)
|
||
- Below gauge: quick stats (clusters complete, content published/planned, taxonomies synced)
|
||
- Click → goes to blueprint detail page
|
||
|
||
**BlueprintProgressWidget:**
|
||
- Horizontal bar chart: each cluster as a row
|
||
- Bar shows: published content / planned content
|
||
- Color coding by cluster status: complete (green), partial (yellow), planned (gray)
|
||
- Sorted by execution priority
|
||
|
||
**Dashboard integration:**
|
||
- Widgets only appear when site has an active blueprint
|
||
- Add to existing dashboard grid alongside WorkflowPipelineWidget, AIOperationsWidget, etc.
|
||
|
||
### 10.5 Frontend: Blueprint Management Page
|
||
|
||
```
|
||
frontend/src/pages/
|
||
└── Blueprint/ # NEW page
|
||
├── BlueprintOverview.tsx # Health score, cluster grid, quick actions
|
||
├── ClusterDetail.tsx # Single cluster view: hub, supporting content, keywords, links
|
||
├── AttributeManager.tsx # View/edit attributes, see taxonomy sync status
|
||
└── ExecutionPlan.tsx # Phase 1-4 execution plan, what to build next
|
||
```
|
||
|
||
**Sidebar addition:**
|
||
```
|
||
WORKFLOW
|
||
├── Planner
|
||
├── Writer
|
||
├── Automation
|
||
├── Blueprint (NEW — if site has active blueprint, always visible)
|
||
├── Linker (if linker_enabled)
|
||
└── Optimizer (if optimizer_enabled)
|
||
```
|
||
|
||
---
|
||
|
||
## 11. Phase 9: SAG Interlinking — Linker Module Evolution {#11-phase-9-sag-interlinking}
|
||
|
||
### 11.1 What This Phase Delivers
|
||
|
||
The existing Linker module (currently INACTIVE behind `linker_enabled` flag) evolves from generic content-similarity linking to SAG-aware deterministic linking. This implements Doc 3 — Interlinking Specification.
|
||
|
||
### 11.2 Backend: New Models for Interlinking
|
||
|
||
Add to `sag/models.py`:
|
||
|
||
```python
|
||
class SAGLink(AccountBaseModel):
|
||
"""Individual internal link tracked by the SAG interlinking system."""
|
||
id = models.UUIDField(primary_key=True, default=uuid4)
|
||
blueprint = models.ForeignKey(SAGBlueprint, on_delete=models.CASCADE, related_name='links')
|
||
source_content = models.ForeignKey('writer.Content', on_delete=models.CASCADE, related_name='outbound_sag_links')
|
||
target_content = models.ForeignKey('writer.Content', on_delete=models.CASCADE, null=True, blank=True, related_name='inbound_sag_links')
|
||
target_url = models.URLField(blank=True, help_text='For term pages or external targets')
|
||
link_type = models.CharField(max_length=30, choices=[
|
||
('hub_upward', 'Supporting → Hub'),
|
||
('hub_downward', 'Hub → Supporting'),
|
||
('sibling', 'Sibling within cluster'),
|
||
('cross_cluster', 'Cross-cluster hub ↔ hub'),
|
||
('taxonomy_contextual', 'Term page → cluster hubs'),
|
||
('breadcrumb', 'Breadcrumb structural'),
|
||
('related_content', 'Related reading cross-cluster'),
|
||
])
|
||
anchor_text = models.CharField(max_length=300)
|
||
placement_zone = models.CharField(max_length=30, choices=[
|
||
('in_body', 'In Body'),
|
||
('related_section', 'Related Section'),
|
||
('breadcrumb', 'Breadcrumb'),
|
||
('guide_contents', 'Guide Contents'),
|
||
])
|
||
status = models.CharField(max_length=20, choices=[
|
||
('planned', 'Planned'),
|
||
('injected', 'Injected into content'),
|
||
('published', 'Published on WordPress'),
|
||
('broken', 'Broken'),
|
||
('removed', 'Removed'),
|
||
], default='planned')
|
||
score = models.FloatField(default=0.0)
|
||
injected_at = models.DateTimeField(null=True, blank=True)
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
||
class SAGLinkAudit(AccountBaseModel):
|
||
"""Periodic link audit snapshot."""
|
||
id = models.UUIDField(primary_key=True, default=uuid4)
|
||
blueprint = models.ForeignKey(SAGBlueprint, on_delete=models.CASCADE)
|
||
audit_date = models.DateTimeField(auto_now_add=True)
|
||
total_links = models.IntegerField(default=0)
|
||
missing_mandatory = models.IntegerField(default=0)
|
||
orphan_pages = models.IntegerField(default=0)
|
||
broken_links = models.IntegerField(default=0)
|
||
over_linked_pages = models.IntegerField(default=0)
|
||
cluster_scores = models.JSONField(default=dict)
|
||
recommendations = models.JSONField(default=list)
|
||
```
|
||
|
||
### 11.3 Backend: Linking Services
|
||
|
||
```
|
||
sag/services/linking_service.py # NEW
|
||
```
|
||
|
||
**Functions:**
|
||
- `generate_links_for_content(content)` → creates SAGLink records for a newly generated content piece
|
||
- `audit_cluster_links(cluster)` → score the cluster's link completeness (0-100)
|
||
- `audit_site_links(blueprint)` → full site link audit
|
||
- `find_missing_mandatory_links(blueprint)` → list of mandatory links that don't exist
|
||
- `suggest_anchor_text(source_content, target_content, link_type)` → AI-generated anchor text variants
|
||
|
||
**Link generation rules (from Doc 3):**
|
||
|
||
| Link Type | Rule | Mandatory? | Max Count |
|
||
|-----------|------|-----------|-----------|
|
||
| hub_upward | Every supporting blog → its cluster hub | YES | 1 per blog |
|
||
| hub_downward | Every hub → all its published supporting content | YES | All |
|
||
| sibling | Supporting ↔ supporting within same cluster | No | 2 per article |
|
||
| cross_cluster | Hub ↔ hub sharing attribute value | No | 2 per hub |
|
||
| taxonomy_contextual | Term page → all hubs using that value | YES | All |
|
||
| breadcrumb | Every page has breadcrumb path | YES | 1 chain |
|
||
| related_content | Supporting → content in other clusters | No | 2-3 |
|
||
|
||
### 11.4 Backend: Pipeline Integration (Stage 8)
|
||
|
||
**Add Stage 8 to automation pipeline:**
|
||
|
||
```python
|
||
# business/automation/stages/stage_8_link_generation.py # NEW
|
||
|
||
# After Stage 7 (images generated):
|
||
# 1. Load blueprint context for this content
|
||
# 2. Generate required SAGLink records per rules
|
||
# 3. Inject link HTML into content body
|
||
# 4. Content enters review queue with links already present
|
||
```
|
||
|
||
Modify `business/automation/pipeline.py` to include Stage 8 when `linker_enabled` AND blueprint exists.
|
||
|
||
### 11.5 Frontend: Linker Page Evolution
|
||
|
||
**Location:** `pages/Linker/` — existing but INACTIVE
|
||
|
||
When `linker_enabled` is activated and blueprint exists, the Linker page shows:
|
||
|
||
```
|
||
frontend/src/pages/Linker/
|
||
├── LinkerOverview.tsx # REPLACE existing — SAG link dashboard
|
||
│ ├── ClusterLinkCoverage.tsx # Table: clusters × link scores
|
||
│ ├── SiteLinkMap.tsx # Visual: clusters as nodes, links as edges
|
||
│ ├── LinkAuditDashboard.tsx # Stats: total links, missing, broken, orphans
|
||
│ └── GapAnalysisExport.tsx # Download link gap report
|
||
├── LinkDetail.tsx # Single link view: source, target, anchor, status
|
||
└── LinkAudit.tsx # Audit history with snapshots
|
||
```
|
||
|
||
### 11.6 Backend: Celery Tasks for Linking
|
||
|
||
```python
|
||
# sag/tasks.py — add:
|
||
|
||
@shared_task
|
||
def generate_links_for_published_content(content_id):
|
||
"""After content publishes, generate/update SAG links."""
|
||
pass
|
||
|
||
@shared_task
|
||
def run_link_audit(blueprint_id):
|
||
"""Weekly link audit for a blueprint."""
|
||
pass
|
||
|
||
@shared_task
|
||
def check_broken_links(blueprint_id):
|
||
"""Check all published SAGLinks for broken targets."""
|
||
pass
|
||
```
|
||
|
||
---
|
||
|
||
## 12. Phase 10: External Backlink Campaign Module {#12-phase-10-external-backlink-campaigns}
|
||
|
||
### 12.1 What This Phase Delivers
|
||
|
||
Automated backlink campaign generation from SAG blueprints. Implements Doc 4 — External Backlink Campaign Specification. New models, new UI, external API integrations (FatGrid, PR distribution).
|
||
|
||
### 12.2 Backend: New Models
|
||
|
||
Add to `sag/models.py`:
|
||
|
||
```python
|
||
class CountryMarketProfile(models.Model):
|
||
"""Country-specific campaign parameters. Admin-editable."""
|
||
country_code = models.CharField(max_length=5, primary_key=True)
|
||
country_name = models.CharField(max_length=100)
|
||
competition_floor = models.CharField(max_length=20)
|
||
profile_data = models.JSONField(help_text='Full country profile: DR targets, budgets, link mix, anchor mix, velocity, quality thresholds, KPI milestones')
|
||
is_active = models.BooleanField(default=True)
|
||
updated_at = models.DateTimeField(auto_now=True)
|
||
|
||
class SAGCampaign(AccountBaseModel):
|
||
"""A backlink campaign generated from a SAG blueprint for a specific market."""
|
||
id = models.UUIDField(primary_key=True, default=uuid4)
|
||
blueprint = models.ForeignKey(SAGBlueprint, on_delete=models.CASCADE, related_name='campaigns')
|
||
site = models.ForeignKey('auth.Site', on_delete=models.CASCADE)
|
||
country_code = models.CharField(max_length=5)
|
||
status = models.CharField(max_length=20, choices=[
|
||
('draft', 'Draft'), ('active', 'Active'),
|
||
('paused', 'Paused'), ('completed', 'Completed'),
|
||
], default='draft')
|
||
tier_assignments = models.JSONField(default=dict, help_text='{content_id: tier}')
|
||
total_links_target = models.IntegerField(default=0)
|
||
total_budget_estimate = models.JSONField(default=dict, help_text='{min: X, max: Y}')
|
||
timeline_months = models.IntegerField(default=0)
|
||
monthly_plan = models.JSONField(default=list)
|
||
anchor_text_plan = models.JSONField(default=dict)
|
||
current_month = models.IntegerField(default=0)
|
||
kpi_data = models.JSONField(default=dict)
|
||
started_at = models.DateTimeField(null=True, blank=True)
|
||
completed_at = models.DateTimeField(null=True, blank=True)
|
||
|
||
class SAGBacklink(AccountBaseModel):
|
||
"""Individual backlink tracked within a campaign."""
|
||
id = models.UUIDField(primary_key=True, default=uuid4)
|
||
blueprint = models.ForeignKey(SAGBlueprint, on_delete=models.CASCADE)
|
||
campaign = models.ForeignKey(SAGCampaign, on_delete=models.CASCADE, related_name='backlinks')
|
||
target_content = models.ForeignKey('writer.Content', on_delete=models.CASCADE, null=True, blank=True)
|
||
target_url = models.URLField()
|
||
target_tier = models.CharField(max_length=5)
|
||
source_url = models.URLField(blank=True)
|
||
source_domain = models.CharField(max_length=200, blank=True)
|
||
source_dr = models.IntegerField(null=True, blank=True)
|
||
source_traffic = models.IntegerField(null=True, blank=True)
|
||
anchor_text = models.CharField(max_length=300, blank=True)
|
||
anchor_type = models.CharField(max_length=30, blank=True)
|
||
link_type = models.CharField(max_length=30, blank=True)
|
||
marketplace = models.CharField(max_length=100, blank=True)
|
||
cost = models.DecimalField(max_digits=10, decimal_places=2, default=0)
|
||
quality_score = models.FloatField(default=0.0)
|
||
country_relevant = models.BooleanField(default=False)
|
||
date_built = models.DateField(null=True, blank=True)
|
||
date_live = models.DateField(null=True, blank=True)
|
||
date_last_checked = models.DateField(null=True, blank=True)
|
||
status = models.CharField(max_length=20, choices=[
|
||
('ordered', 'Ordered'), ('pending', 'Pending'), ('live', 'Live'),
|
||
('dead', 'Dead'), ('removed', 'Removed'), ('replaced', 'Replaced'),
|
||
], default='ordered')
|
||
notes = models.TextField(blank=True)
|
||
|
||
class SAGCampaignSnapshot(models.Model):
|
||
"""Monthly KPI snapshot for a campaign."""
|
||
id = models.UUIDField(primary_key=True, default=uuid4)
|
||
campaign = models.ForeignKey(SAGCampaign, on_delete=models.CASCADE, related_name='snapshots')
|
||
snapshot_date = models.DateField()
|
||
kpi_values = models.JSONField(help_text='All 18+ KPI metrics for this month')
|
||
comparison_to_previous = models.JSONField(default=dict)
|
||
```
|
||
|
||
### 12.3 Backend: Campaign Services
|
||
|
||
```
|
||
sag/services/campaign_service.py # NEW
|
||
```
|
||
|
||
**Functions:**
|
||
- `generate_campaign(blueprint, country_code, budget_override=None)` → creates SAGCampaign with full plan
|
||
- `assign_tiers(blueprint, clusters)` → auto-classify pages into T1-T5
|
||
- `generate_monthly_plan(campaign)` → month-by-month execution plan
|
||
- `generate_anchor_text_plan(campaign)` → pre-generated anchors per target page
|
||
- `calculate_budget(campaign)` → budget estimate from link counts × cost ranges
|
||
- `detect_tipping_point(campaign)` → check if authority tipping point indicators are met
|
||
|
||
### 12.4 Backend: External API Integrations
|
||
|
||
```
|
||
sag/integrations/ # NEW
|
||
├── __init__.py
|
||
├── fatgrid.py # FatGrid API client (publisher discovery, pricing)
|
||
├── pr_distribution.py # PRNews.io / EIN Presswire / Linking News
|
||
└── ahrefs.py # Ahrefs API (DR/DA tracking, lost links)
|
||
```
|
||
|
||
These integrations are optional — campaigns can be generated and tracked without them. The APIs enrich the campaign with real marketplace data and automated monitoring.
|
||
|
||
### 12.5 Frontend: Campaign UI
|
||
|
||
```
|
||
frontend/src/pages/
|
||
└── Campaigns/ # NEW page (or sub-page of Linker)
|
||
├── CampaignOverview.tsx # Campaign dashboard: progress, budget, current month
|
||
├── CampaignGenerator.tsx # Generate new campaign wizard
|
||
├── MonthlyPlan.tsx # This month's targets vs actual
|
||
├── LinkTracker.tsx # Filterable table of all backlinks
|
||
├── TierBreakdown.tsx # T1-T5 progress visualization
|
||
├── KPIDashboard.tsx # Monthly trend charts (DR, traffic, keywords)
|
||
├── TippingPointDetector.tsx # Authority tipping point indicators
|
||
└── LinkOpportunities.tsx # FatGrid publisher search (if integrated)
|
||
```
|
||
|
||
**Sidebar addition:**
|
||
```
|
||
WORKFLOW
|
||
├── Planner
|
||
├── Writer
|
||
├── Automation
|
||
├── Blueprint
|
||
├── Linker (internal links)
|
||
├── Campaigns (NEW — external backlink campaigns, if campaign_enabled)
|
||
└── Optimizer
|
||
```
|
||
|
||
**Feature flag:** `campaign_enabled` — follows same pattern as `linker_enabled` via GlobalModuleSettings.
|
||
|
||
---
|
||
|
||
## 13. Frontend Navigation — Updated Sidebar {#13-frontend-navigation--ui-map}
|
||
|
||
After all SAG phases are complete, the sidebar becomes:
|
||
|
||
```
|
||
Dashboard (with SAG health + blueprint progress widgets)
|
||
SETUP
|
||
├── Add Keywords (now shows "optional" when blueprint active)
|
||
├── Content Settings
|
||
├── Sites (setup wizard now includes Step 3 Site Builder)
|
||
└── Thinker (admin only)
|
||
WORKFLOW
|
||
├── Planner (Keywords → Clusters → Ideas — enhanced with blueprint source)
|
||
├── Writer (Queue → Drafts → Images → Review → Published — shows cluster context)
|
||
├── Automation (7→8 stages when linker active, SAG mode indicator)
|
||
├── Blueprint (NEW — health, clusters, attributes, execution plan)
|
||
├── Linker (SAG-aware internal linking — when linker_enabled)
|
||
├── Campaigns (External backlink campaigns — when campaign_enabled)
|
||
└── Optimizer (when optimizer_enabled)
|
||
ACCOUNT
|
||
├── Account Settings
|
||
├── Plans & Billing
|
||
├── Usage
|
||
└── AI Models (admin only)
|
||
ADMIN (admin only)
|
||
└── Sector Templates (manage attribute templates)
|
||
HELP
|
||
└── Help & Docs
|
||
```
|
||
|
||
---
|
||
|
||
## 14. API Endpoint Registry {#14-api-endpoint-registry}
|
||
|
||
Complete list of new API endpoints introduced across all phases:
|
||
|
||
### SAG Core (Phase 1-3)
|
||
```
|
||
GET /api/v1/sag/blueprints/ # List blueprints for current site
|
||
POST /api/v1/sag/blueprints/ # Create blueprint (admin/internal)
|
||
GET /api/v1/sag/blueprints/{id}/ # Blueprint detail with attributes + clusters
|
||
POST /api/v1/sag/blueprints/{id}/confirm/ # Draft → Active
|
||
POST /api/v1/sag/blueprints/{id}/archive/ # Active → Archived
|
||
POST /api/v1/sag/blueprints/{id}/regenerate/ # Create new version
|
||
GET /api/v1/sag/blueprints/{id}/health_check/ # Run health check
|
||
GET /api/v1/sag/attributes/ # List attributes for current blueprint
|
||
GET /api/v1/sag/clusters/ # List clusters for current blueprint
|
||
GET /api/v1/sag/clusters/{id}/ # Cluster detail with keywords, content, links
|
||
GET /api/v1/sag/templates/ # Admin: list sector templates
|
||
POST /api/v1/sag/templates/ # Admin: create template
|
||
PUT /api/v1/sag/templates/{id}/ # Admin: update template
|
||
```
|
||
|
||
### Site Builder Wizard (Phase 4)
|
||
```
|
||
POST /api/v1/sag/wizard/generate-attributes/ # Industry+Sectors → attribute framework
|
||
POST /api/v1/sag/wizard/populate-attributes/ # Attributes+BusinessData → populated attributes
|
||
POST /api/v1/sag/wizard/generate-blueprint/ # Populated attributes → full blueprint
|
||
POST /api/v1/sag/wizard/confirm-blueprint/ # Blueprint → active, trigger taxonomy creation
|
||
```
|
||
|
||
### Existing Site Analysis (Phase 7)
|
||
```
|
||
POST /api/v1/sag/analysis/extract-attributes/ # Site data → discovered attributes
|
||
POST /api/v1/sag/analysis/generate-gap-report/ # Blueprint + site data → gap report
|
||
POST /api/v1/sag/analysis/auto-tag-products/ # AI product attribute assignment
|
||
```
|
||
|
||
### Interlinking (Phase 9)
|
||
```
|
||
GET /api/v1/sag/links/ # List all SAG links for blueprint
|
||
POST /api/v1/sag/links/generate/ # Generate links for content
|
||
GET /api/v1/sag/links/audit/ # Run link audit
|
||
GET /api/v1/sag/links/audit/history/ # Audit snapshots
|
||
GET /api/v1/sag/links/missing/ # Missing mandatory links
|
||
```
|
||
|
||
### Backlink Campaigns (Phase 10)
|
||
```
|
||
GET /api/v1/sag/campaigns/ # List campaigns
|
||
POST /api/v1/sag/campaigns/generate/ # Generate campaign from blueprint + country
|
||
GET /api/v1/sag/campaigns/{id}/ # Campaign detail
|
||
PATCH /api/v1/sag/campaigns/{id}/ # Update status, adjust plan
|
||
GET /api/v1/sag/campaigns/{id}/monthly/ # Current month plan
|
||
GET /api/v1/sag/campaigns/{id}/kpi/ # KPI dashboard data
|
||
GET /api/v1/sag/campaigns/{id}/tipping-point/ # Tipping point indicators
|
||
GET /api/v1/sag/backlinks/ # List all backlinks for campaign
|
||
POST /api/v1/sag/backlinks/ # Log new backlink
|
||
PATCH /api/v1/sag/backlinks/{id}/ # Update backlink status
|
||
GET /api/v1/sag/countries/ # List country market profiles
|
||
GET /api/v1/sag/fatgrid/search/ # FatGrid publisher search (proxy)
|
||
```
|
||
|
||
---
|
||
|
||
## 15. AI Function Registry {#15-ai-function-registry}
|
||
|
||
New AI functions to register in `ai/registry.py`:
|
||
|
||
| Function Key | Location | Input | Output |
|
||
|-------------|----------|-------|--------|
|
||
| `discover_sector_attributes` | `sag/ai_functions/attribute_discovery.py` | Industry, sector, site_type | Attribute framework JSON |
|
||
| `extract_site_attributes` | `sag/ai_functions/attribute_extraction.py` | Raw site data | Discovered attributes with confidence |
|
||
| `populate_attributes` | `sag/ai_functions/attribute_population.py` | Attributes + business data | Populated attribute values |
|
||
| `form_clusters` | `sag/ai_functions/cluster_formation.py` | Populated attributes, sector | Clusters with types |
|
||
| `generate_keywords` | `sag/ai_functions/keyword_generation.py` | Clusters + templates | Per-cluster keyword arrays |
|
||
| `plan_content` | `sag/ai_functions/content_planning.py` | Clusters + keywords + existing content | Content ideas with Structure + Type |
|
||
| `generate_anchor_text` | `sag/ai_functions/anchor_text.py` | Source, target, link_type, cluster | Anchor text variants |
|
||
|
||
All functions use the existing `AIEngine → Function → Provider` pattern. They're registered the same way as `AutoClusterKeywords` and `GenerateContentIdeas`.
|
||
|
||
---
|
||
|
||
## 16. Celery Task Registry {#16-celery-task-registry}
|
||
|
||
New periodic and on-demand tasks:
|
||
|
||
| Task | Schedule | Trigger | Location |
|
||
|------|----------|---------|----------|
|
||
| `run_blueprint_health_check` | Weekly (Celery Beat) | Also manual from dashboard | `sag/tasks.py` |
|
||
| `check_blueprint_evolution_triggers` | Weekly (Celery Beat) | — | `sag/tasks.py` |
|
||
| `generate_links_for_published_content` | On demand | After content publishes | `sag/tasks.py` |
|
||
| `run_link_audit` | Weekly (Celery Beat) | Also manual from Linker | `sag/tasks.py` |
|
||
| `check_broken_links` | Weekly (Celery Beat) | — | `sag/tasks.py` |
|
||
| `check_backlink_status` | Weekly (Celery Beat) | — | `sag/tasks.py` |
|
||
| `generate_campaign_snapshot` | Monthly (Celery Beat) | — | `sag/tasks.py` |
|
||
| `detect_tipping_point` | Monthly (Celery Beat) | After snapshot | `sag/tasks.py` |
|
||
|
||
---
|
||
|
||
## 17. Feature Flag Registry {#17-feature-flag-registry}
|
||
|
||
| Flag | Controls | Default | Phase |
|
||
|------|---------|---------|-------|
|
||
| `sag_enabled` | Blueprint generation, wizard Step 3, blueprint-aware pipeline | `False` | Phase 1 |
|
||
| `linker_enabled` | Linker module, SAG link generation, link audit | `False` (exists) | Phase 9 |
|
||
| `campaign_enabled` | External backlink campaigns, FatGrid integration | `False` | Phase 10 |
|
||
|
||
All flags follow existing pattern: `GlobalModuleSettings` (platform-wide) + `ModuleEnableSettings` (per-account). Checked in sidebar rendering and API permission classes.
|
||
|
||
When `sag_enabled` is `False`:
|
||
- Setup wizard skips Step 3 (current behavior preserved)
|
||
- Pipeline runs in legacy mode (current behavior preserved)
|
||
- Blueprint page hidden from sidebar
|
||
- All SAG API endpoints return 403
|
||
|
||
---
|
||
|
||
## 18. Cross-Reference: What Feeds What {#18-cross-reference}
|
||
|
||
```
|
||
SectorAttributeTemplate
|
||
└── feeds → Blueprint generation (Layer 1 attributes)
|
||
|
||
SAGBlueprint
|
||
├── feeds → Content pipeline (idea generation, task context, type-specific prompts)
|
||
├── feeds → Taxonomy creation (plugin creates WP taxonomies)
|
||
├── feeds → Linker module (link rules derived from cluster structure)
|
||
├── feeds → Campaign module (tier assignments from cluster types + keyword volumes)
|
||
└── feeds → Health monitoring (completeness tracking)
|
||
|
||
SAGCluster
|
||
├── feeds → Content Ideas (hub + supporting content per cluster)
|
||
├── feeds → Keywords (auto-generated from attribute intersections)
|
||
├── feeds → Internal links (hub↔supporting, cross-cluster, taxonomy contextual)
|
||
└── feeds → Backlink tiers (T1-T5 assignment based on cluster type + volume)
|
||
|
||
SAGLink
|
||
├── feeds → Content HTML (links injected before publish)
|
||
├── feeds → Link audit (health scores, gap analysis)
|
||
└── feeds → Blueprint health score (link coverage component)
|
||
|
||
SAGCampaign
|
||
├── feeds → KPI dashboard (monthly snapshots, trend charts)
|
||
├── feeds → Tipping point detection (compares metrics vs country thresholds)
|
||
└── feeds → Blueprint health score (backlink coverage component)
|
||
|
||
GSC Data (from Consolidated Module Plans — separate implementation)
|
||
├── feeds → Campaign KPI dashboard (organic traffic, keywords, impressions)
|
||
├── feeds → Tipping point detection (pages ranking without backlinks)
|
||
└── feeds → Blueprint health (indexed pages, crawl status)
|
||
```
|
||
|
||
---
|
||
|
||
## Reference Documents
|
||
|
||
This guide draws from and should be used alongside:
|
||
|
||
| Document | Purpose | Location |
|
||
|----------|---------|----------|
|
||
| **SAG-Master-Document.md** | Pure SAG methodology — clustering rules, dimensional philosophy | Project knowledge |
|
||
| **SAG-IGNY8-Implementation.md** | Three-layer architecture, two entry scenarios, data models, pipeline integration | Project knowledge |
|
||
| **SAG-Doc3-Interlinking-Specification-PLAN.md** | Internal linking rules, 7 link types, authority flow, scoring | Project knowledge |
|
||
| **SAG-Doc4-External-Backlink-Campaign-PLAN.md** | Campaign generation, country profiles, FatGrid/PR integration, KPI tracking | Project knowledge |
|
||
| **IGNY8-Current-State.md** | Complete current platform state — all file paths, models, modules, navigation | Project knowledge |
|
||
| **SAG-Niche-Definition-Process.docx** | Cluster formation rules, max 50 clusters, hub + supporting structure | Project knowledge |
|
||
| **IGNY8-Industry-Sector-Master-List.md** | All industries and sectors in IGNY8 | Project knowledge |
|
||
| **SAGIndustry01HealthcareMedical.xlsx** | Reference template format for sector attribute frameworks | Project knowledge |
|
||
|
||
---
|
||
|
||
*End of Doc A — SAG Architecture Development Guide*
|