Update site builder configurations and enhance migration dependencies

- Added `OptimizationConfig` to `INSTALLED_APPS` in `settings.py`.
- Updated migration dependencies in `0001_initial.py` to include `writer` for content source fields.
- Modified the `account` ForeignKey in `PageBlueprint` and `SiteBlueprint` models to use `tenant_id` for better clarity.
- Deleted obsolete implementation plan documents for phases 0-4 to streamline project documentation.
- Improved overall project structure by removing outdated files and enhancing migration clarity.
This commit is contained in:
IGNY8 VPS (Salman)
2025-11-17 20:22:29 +00:00
parent f7115190dc
commit b6b1aecdce
13 changed files with 1246 additions and 4032 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,524 +0,0 @@
# PHASE 0: FOUNDATION & CREDIT SYSTEM
**Detailed Implementation Plan**
**Goal**: Migrate to credit-only model while preserving all existing functionality.
**Timeline**: 1-2 weeks
**Priority**: HIGH
**Dependencies**: None
---
## TABLE OF CONTENTS
1. [Overview](#overview)
2. [Module Settings System](#module-settings-system)
3. [Credit System Updates](#credit-system-updates)
4. [Operational Limits](#operational-limits)
5. [Database Migrations](#database-migrations)
6. [Testing & Validation](#testing--validation)
7. [Implementation Checklist](#implementation-checklist)
---
## OVERVIEW
### Objectives
- ✅ Migrate from plan-based limits to credit-only system
- ✅ Implement module enable/disable functionality
- ✅ Add credit cost tracking for all operations
- ✅ Preserve all existing functionality
- ✅ Update frontend to show credits instead of limits
### Key Principles
- **Backward Compatibility**: All existing APIs continue working
- **No Breaking Changes**: Frontend continues working without changes
- **Gradual Migration**: Add credit checks without removing existing code initially
- **Credit-Only Model**: Remove all plan limit fields, keep only credits
---
## MODULE SETTINGS SYSTEM
### 0.0 Module Settings System (Enable/Disable Modules)
**Purpose**: Allow accounts to enable/disable modules per account.
#### Backend Implementation
| Task | File | Current State | Implementation |
|------|------|---------------|----------------|
| **Extend ModuleSettings Model** | `business/system/models.py` | EXISTING (ModuleSettings) | Add `enabled` boolean field per module |
| **Module Settings API** | `modules/system/views.py` | EXISTING | Extend ViewSet to handle enable/disable |
| **Module Settings Serializer** | `modules/system/serializers.py` | EXISTING | Add enabled field to serializer |
**ModuleSettings Model Extension**:
```python
# business/system/models.py (or core/system/models.py if exists)
class ModuleSettings(AccountBaseModel):
# Existing fields...
# NEW: Module enable/disable flags
planner_enabled = models.BooleanField(default=True)
writer_enabled = models.BooleanField(default=True)
thinker_enabled = models.BooleanField(default=True)
automation_enabled = models.BooleanField(default=True)
site_builder_enabled = models.BooleanField(default=True)
linker_enabled = models.BooleanField(default=True)
optimizer_enabled = models.BooleanField(default=True)
publisher_enabled = models.BooleanField(default=True)
```
**Modules to Control**:
- Planner
- Writer
- Thinker
- Automation
- Site Builder (NEW)
- Linker (NEW)
- Optimizer (NEW)
- Publisher (NEW)
#### Frontend Implementation
| Task | File | Current State | Implementation |
|------|------|---------------|----------------|
| **Module Settings UI** | `frontend/src/pages/Settings/Modules.tsx` | EXISTING (placeholder) | Implement toggle UI for each module |
| **Frontend Module Loader** | `frontend/src/config/modules.config.ts` | NEW | Define module config with enabled checks |
| **Route Guard** | `frontend/src/components/common/ModuleGuard.tsx` | NEW | Component to check module status before rendering |
| **Sidebar Filter** | `frontend/src/layout/AppSidebar.tsx` | EXISTING | Filter out disabled modules from sidebar |
**Module Enable/Disable Logic**:
- Each module has `enabled` flag in ModuleSettings
- Frontend checks module status before loading routes
- Disabled modules don't appear in sidebar
- Disabled modules don't load code (lazy loading check)
**Module Config Example**:
```typescript
// frontend/src/config/modules.config.ts
export const MODULES = {
planner: {
name: 'Planner',
route: '/planner',
enabled: true, // Checked from API
},
writer: {
name: 'Writer',
route: '/writer',
enabled: true,
},
// ... other modules
};
```
**Route Guard Example**:
```typescript
// frontend/src/components/common/ModuleGuard.tsx
const ModuleGuard = ({ module, children }) => {
const { moduleSettings } = useSettingsStore();
const isEnabled = moduleSettings[module]?.enabled ?? true;
if (!isEnabled) {
return <Navigate to="/settings/modules" />;
}
return children;
};
```
---
## CREDIT SYSTEM UPDATES
### 0.1 Credit System Updates
**Purpose**: Migrate from plan-based limits to credit-only system.
#### Plan Model Updates
| Task | File | Current State | Implementation |
|------|------|---------------|----------------|
| **Remove Plan Limit Fields** | `core/auth/models.py` | EXISTING | Remove all limit fields, add migration |
| **Update Plan Model** | `core/auth/models.py` | EXISTING | Keep only `monthly_credits`, `support_level`, `billing_cycle`, `price` |
**Plan Model (Simplified)**:
```python
# core/auth/models.py
class Plan(models.Model):
name = models.CharField(max_length=255)
monthly_credits = models.IntegerField(default=0) # KEEP
support_level = models.CharField(max_length=50) # KEEP
billing_cycle = models.CharField(max_length=20) # KEEP
price = models.DecimalField(max_digits=10, decimal_places=2) # KEEP
features = models.JSONField(default=dict) # KEEP (for future use)
# REMOVE: All limit fields
# - max_keywords
# - max_clusters
# - max_content_ideas
# - daily_content_tasks
# - monthly_word_count_limit
# - daily_image_generation_limit
# - monthly_image_count
# - etc.
```
**Migration Strategy**:
1. Create migration to add defaults for removed fields (if needed)
2. Create migration to remove limit fields
3. Ensure existing accounts have credit balances set
#### Credit Cost Constants
| Task | File | Current State | Implementation |
|------|------|---------------|----------------|
| **Add Credit Costs** | `business/billing/constants.py` | NEW | Define credit costs per operation |
**Credit Cost Constants**:
```python
# business/billing/constants.py
CREDIT_COSTS = {
'clustering': 10, # Per clustering request
'idea_generation': 15, # Per cluster → ideas request
'content_generation': 1, # Per 100 words
'image_prompt_extraction': 2, # Per content piece
'image_generation': 5, # Per image
'linking': 8, # Per content piece (NEW)
'optimization': 1, # Per 200 words (NEW)
'site_structure_generation': 50, # Per site blueprint (NEW)
'site_page_generation': 20, # Per page (NEW)
}
```
#### CreditService Updates
| Task | File | Current State | Implementation |
|------|------|---------------|----------------|
| **Update CreditService** | `business/billing/services/credit_service.py` | EXISTING | Add credit cost constants, update methods |
**CreditService Methods**:
```python
# business/billing/services/credit_service.py
class CreditService:
def check_credits(self, account, operation_type, amount=None):
"""Check if account has sufficient credits"""
required = self.get_credit_cost(operation_type, amount)
if account.credits < required:
raise InsufficientCreditsError(f"Need {required} credits, have {account.credits}")
return True
def deduct_credits(self, account, operation_type, amount=None):
"""Deduct credits after operation"""
cost = self.get_credit_cost(operation_type, amount)
account.credits -= cost
account.save()
# Log usage
CreditUsageLog.objects.create(...)
def get_credit_cost(self, operation_type, amount=None):
"""Get credit cost for operation"""
base_cost = CREDIT_COSTS.get(operation_type, 0)
if operation_type == 'content_generation' and amount:
return base_cost * (amount / 100) # Per 100 words
if operation_type == 'optimization' and amount:
return base_cost * (amount / 200) # Per 200 words
return base_cost
```
#### AI Engine Updates
| Task | File | Current State | Implementation |
|------|------|---------------|----------------|
| **Update AI Engine** | `infrastructure/ai/engine.py` | EXISTING | Check credits before AI calls |
**AI Engine Credit Check**:
```python
# infrastructure/ai/engine.py
class AIEngine:
def execute(self, function, payload, account):
# Check credits BEFORE AI call
operation_type = function.get_operation_type()
estimated_cost = function.get_estimated_cost(payload)
credit_service.check_credits(account, operation_type, estimated_cost)
# Execute AI function
result = function.execute(payload)
# Deduct credits AFTER successful execution
credit_service.deduct_credits(account, operation_type, actual_cost)
return result
```
#### Content Generation Updates
| Task | File | Current State | Implementation |
|------|------|---------------|----------------|
| **Update Content Generation** | `business/content/services/content_generation_service.py` | NEW (Phase 1) | Check credits before generation |
**Content Generation Credit Check**:
```python
# business/content/services/content_generation_service.py
class ContentGenerationService:
def generate_content(self, task, account):
# Check credits before generation
estimated_words = task.estimated_word_count or 1000
credit_service.check_credits(account, 'content_generation', estimated_words)
# Generate content
content = self._generate(task)
# Deduct credits after generation
actual_words = content.word_count
credit_service.deduct_credits(account, 'content_generation', actual_words)
return content
```
#### Image Generation Updates
| Task | File | Current State | Implementation |
|------|------|---------------|----------------|
| **Update Image Generation** | `infrastructure/ai/functions/generate_images.py` | EXISTING | Check credits before generation |
**Image Generation Credit Check**:
```python
# infrastructure/ai/functions/generate_images.py
class GenerateImagesFunction(BaseAIFunction):
def execute(self, payload, account):
image_ids = payload['image_ids']
# Check credits before generation
credit_service.check_credits(account, 'image_generation', len(image_ids))
# Generate images
results = self._generate_images(image_ids)
# Deduct credits after generation
credit_service.deduct_credits(account, 'image_generation', len(results))
return results
```
#### Remove Limit Checks
| Task | File | Current State | Implementation |
|------|------|---------------|----------------|
| **Remove Limit Checks** | All services | EXISTING | Remove all plan limit validations |
**Files to Update**:
- `modules/planner/views.py` - Remove keyword/cluster limit checks
- `modules/writer/views.py` - Remove task/content limit checks
- `infrastructure/ai/engine.py` - Remove plan limit checks
- All ViewSets - Remove limit validation
**Before (Remove)**:
```python
# OLD: Check plan limits
if account.plan.max_keywords and keywords_count > account.plan.max_keywords:
raise ValidationError("Exceeds plan limit")
```
**After (Credit Only)**:
```python
# NEW: Check credits only
credit_service.check_credits(account, 'clustering', keyword_count)
```
#### Usage Logging Updates
| Task | File | Current State | Implementation |
|------|------|---------------|----------------|
| **Update Usage Logging** | `business/billing/models.py` | EXISTING | Ensure all operations log credits |
**CreditUsageLog Model**:
```python
# business/billing/models.py
class CreditUsageLog(AccountBaseModel):
account = models.ForeignKey(Account, on_delete=models.CASCADE)
operation_type = models.CharField(max_length=50)
credits_used = models.IntegerField()
related_object_type = models.CharField(max_length=50, blank=True)
related_object_id = models.IntegerField(null=True, blank=True)
metadata = models.JSONField(default=dict)
created_at = models.DateTimeField(auto_now_add=True)
```
#### Frontend Updates
| Task | File | Current State | Implementation |
|------|------|---------------|----------------|
| **Update Frontend Limits UI** | `frontend/src/pages/Billing/` | EXISTING | Replace limits display with credit display |
**Frontend Changes**:
- Remove plan limit displays
- Show credit balance prominently
- Show credit costs per operation
- Show usage history by operation type
---
## OPERATIONAL LIMITS
### 0.2 Operational Limits (Keep)
**Purpose**: Technical constraints, not business limits.
| Limit | Value | Location | Implementation | Reason |
|-------|-------|----------|----------------|--------|
| **Keywords per request** | 50 | `modules/planner/views.py` | Request validation | API payload size, processing time |
| **Images per request** | 6 | `modules/writer/views.py` | Request validation | Queue management (user sees as batch) |
| **Images per AI call** | 1 | `infrastructure/ai/functions/generate_images.py` | Internal | Image API limitation |
**Note**: These are **NOT** business limits - they're technical constraints for request processing.
---
## DATABASE MIGRATIONS
### 0.3 Database Migrations
| Migration | Purpose | Risk | Implementation |
|-----------|---------|------|----------------|
| **Remove limit fields from Plan** | Clean up unused fields | LOW - Add defaults first | Create migration to remove fields |
| **Add credit cost tracking** | Enhance CreditUsageLog | LOW - Additive only | Add fields to CreditUsageLog |
| **Monthly credit replenishment** | Celery Beat task | LOW - New feature | Add scheduled task |
**Migration 1: Remove Plan Limit Fields**:
```python
# core/auth/migrations/XXXX_remove_plan_limits.py
class Migration(migrations.Migration):
operations = [
migrations.RemoveField(model_name='plan', name='max_keywords'),
migrations.RemoveField(model_name='plan', name='max_clusters'),
# ... remove all limit fields
]
```
**Migration 2: Add Credit Cost Tracking**:
```python
# business/billing/migrations/XXXX_add_credit_tracking.py
class Migration(migrations.Migration):
operations = [
migrations.AddField(
model_name='creditusagelog',
name='related_object_type',
field=models.CharField(max_length=50, blank=True),
),
migrations.AddField(
model_name='creditusagelog',
name='related_object_id',
field=models.IntegerField(null=True, blank=True),
),
migrations.AddField(
model_name='creditusagelog',
name='metadata',
field=models.JSONField(default=dict),
),
]
```
**Migration 3: Monthly Credit Replenishment**:
- Add Celery Beat task (see Automation section)
---
## TESTING & VALIDATION
### 0.4 Testing
**Test Cases**:
1. **Credit System Tests**:
- ✅ All existing features work with credit checks
- ✅ Credit deduction happens correctly
- ✅ Insufficient credits show clear error
- ✅ Usage logging tracks all operations
- ✅ Frontend shows credit balance, not limits
2. **Module Settings Tests**:
- ✅ Disabled modules don't appear in sidebar
- ✅ Disabled modules don't load routes
- ✅ Disabled modules return 403/404 appropriately
- ✅ Module settings persist correctly
3. **Backward Compatibility Tests**:
- ✅ All existing API endpoints work
- ✅ All existing workflows function
- ✅ Frontend continues working
- ✅ No data loss during migration
**Test Files to Create**:
- `backend/tests/test_credit_system.py`
- `backend/tests/test_module_settings.py`
- `frontend/src/__tests__/ModuleGuard.test.tsx`
---
## IMPLEMENTATION CHECKLIST
### Backend Tasks
- [ ] Create `business/billing/constants.py` with credit costs
- [ ] Update `CreditService` with credit cost methods
- [ ] Update `Plan` model - remove limit fields
- [ ] Create migration to remove plan limit fields
- [ ] Update `AIEngine` to check credits before AI calls
- [ ] Update content generation to check credits
- [ ] Update image generation to check credits
- [ ] Remove all plan limit checks from ViewSets
- [ ] Update `CreditUsageLog` model with tracking fields
- [ ] Create migration for credit tracking
- [ ] Extend `ModuleSettings` model with enabled flags
- [ ] Update module settings API
- [ ] Add monthly credit replenishment Celery Beat task
### Frontend Tasks
- [ ] Implement `frontend/src/pages/Settings/Modules.tsx`
- [ ] Create `frontend/src/config/modules.config.ts`
- [ ] Create `frontend/src/components/common/ModuleGuard.tsx`
- [ ] Update `frontend/src/App.tsx` with conditional route loading
- [ ] Update `frontend/src/layout/AppSidebar.tsx` to filter disabled modules
- [ ] Update `frontend/src/pages/Billing/` to show credits instead of limits
- [ ] Update billing UI to show credit costs per operation
### Testing Tasks
- [ ] Test credit deduction for all operations
- [ ] Test insufficient credits error handling
- [ ] Test module enable/disable functionality
- [ ] Test disabled modules don't load
- [ ] Test backward compatibility
- [ ] Test migration safety
---
## RISK ASSESSMENT
| Risk | Level | Mitigation |
|------|-------|------------|
| **Breaking existing functionality** | MEDIUM | Extensive testing, gradual rollout |
| **Credit calculation errors** | MEDIUM | Unit tests for credit calculations |
| **Migration data loss** | LOW | Backup before migration, test on staging |
| **Frontend breaking changes** | LOW | Backward compatible API changes |
---
## SUCCESS CRITERIA
- ✅ All existing features work with credit checks
- ✅ Credit deduction happens correctly for all operations
- ✅ Insufficient credits show clear error messages
- ✅ Usage logging tracks all operations
- ✅ Frontend shows credit balance, not limits
- ✅ Module settings enable/disable modules correctly
- ✅ Disabled modules don't appear in UI
- ✅ No breaking changes for existing users
---
**END OF PHASE 0 DOCUMENT**

View File

@@ -1,434 +0,0 @@
# PHASE 1: SERVICE LAYER REFACTORING
**Detailed Implementation Plan**
**Goal**: Extract business logic from ViewSets into services, preserving all existing functionality.
**Timeline**: 2-3 weeks
**Priority**: HIGH
**Dependencies**: Phase 0
---
## TABLE OF CONTENTS
1. [Overview](#overview)
2. [Create Business Structure](#create-business-structure)
3. [Move Models to Business](#move-models-to-business)
4. [Create Services](#create-services)
5. [Refactor ViewSets](#refactor-viewsets)
6. [Testing & Validation](#testing--validation)
7. [Implementation Checklist](#implementation-checklist)
---
## OVERVIEW
### Objectives
- ✅ Create `business/` folder structure
- ✅ Move models from `modules/` to `business/`
- ✅ Extract business logic from ViewSets to services
- ✅ Keep ViewSets as thin wrappers
- ✅ Preserve all existing API functionality
### Key Principles
- **Service Layer Pattern**: Business logic in services, not ViewSets
- **Testable Services**: Services can be tested independently
- **Clean Architecture**: Clear separation between API layer (modules/) and business logic (business/)
---
## CREATE BUSINESS STRUCTURE
### 1.1 Create Business Structure
**Purpose**: Organize code by business logic, not technical layers.
#### Folder Structure
```
backend/igny8_core/
├── business/ # NEW: Business logic layer
│ ├── content/ # Content business logic
│ │ ├── __init__.py
│ │ ├── models.py # Content, Tasks, Images
│ │ ├── services/
│ │ │ ├── __init__.py
│ │ │ ├── content_generation_service.py
│ │ │ ├── content_pipeline_service.py
│ │ │ └── content_versioning_service.py
│ │ └── migrations/
│ │
│ ├── planning/ # Planning business logic
│ │ ├── __init__.py
│ │ ├── models.py # Keywords, Clusters, Ideas
│ │ ├── services/
│ │ │ ├── __init__.py
│ │ │ ├── clustering_service.py
│ │ │ └── ideas_service.py
│ │ └── migrations/
│ │
│ ├── billing/ # Billing business logic (already exists)
│ │ ├── models.py # Credits, Transactions
│ │ └── services/
│ │ └── credit_service.py # Already exists
│ │
│ └── automation/ # Automation business logic (Phase 2)
│ ├── models.py
│ └── services/
```
#### Implementation Tasks
| Task | File | Current Location | New Location | Risk |
|------|------|------------------|--------------|------|
| **Create business/ folder** | `backend/igny8_core/business/` | N/A | NEW | LOW |
| **Create content business** | `business/content/` | N/A | NEW | LOW |
| **Create planning business** | `business/planning/` | N/A | NEW | LOW |
| **Create billing business** | `business/billing/` | `modules/billing/` | MOVE | LOW |
| **Create automation business** | `business/automation/` | N/A | NEW (Phase 2) | LOW |
---
## MOVE MODELS TO BUSINESS
### 1.2 Move Models to Business
**Purpose**: Move models from `modules/` to `business/` to separate business logic from API layer.
#### Content Models Migration
| Model | Current Location | New Location | Changes Needed |
|------|------------------|--------------|----------------|
| `Content` | `modules/writer/models.py` | `business/content/models.py` | Move, update imports |
| `Tasks` | `modules/writer/models.py` | `business/content/models.py` | Move, update imports |
| `Images` | `modules/writer/models.py` | `business/content/models.py` | Move, update imports |
**Migration Steps**:
1. Create `business/content/models.py`
2. Copy models from `modules/writer/models.py`
3. Update imports in `modules/writer/views.py`
4. Create migration to ensure no data loss
5. Update all references to models
#### Planning Models Migration
| Model | Current Location | New Location | Changes Needed |
|------|------------------|--------------|----------------|
| `Keywords` | `modules/planner/models.py` | `business/planning/models.py` | Move, update imports |
| `Clusters` | `modules/planner/models.py` | `business/planning/models.py` | Move, update imports |
| `ContentIdeas` | `modules/planner/models.py` | `business/planning/models.py` | Move, update imports |
**Migration Steps**:
1. Create `business/planning/models.py`
2. Copy models from `modules/planner/models.py`
3. Update imports in `modules/planner/views.py`
4. Create migration to ensure no data loss
5. Update all references to models
#### Billing Models Migration
| Model | Current Location | New Location | Changes Needed |
|------|------------------|--------------|----------------|
| `CreditTransaction` | `modules/billing/models.py` | `business/billing/models.py` | Move, update imports |
| `CreditUsageLog` | `modules/billing/models.py` | `business/billing/models.py` | Move, update imports |
**Migration Steps**:
1. Create `business/billing/models.py`
2. Copy models from `modules/billing/models.py`
3. Move `CreditService` to `business/billing/services/credit_service.py`
4. Update imports in `modules/billing/views.py`
5. Create migration to ensure no data loss
---
## CREATE SERVICES
### 1.3 Create Services
**Purpose**: Extract business logic from ViewSets into reusable services.
#### ContentService
| Task | File | Purpose | Dependencies |
|------|------|---------|--------------|
| **Create ContentService** | `business/content/services/content_generation_service.py` | Unified content generation | Existing Writer logic, CreditService |
**ContentService Methods**:
```python
# business/content/services/content_generation_service.py
class ContentGenerationService:
def __init__(self):
self.credit_service = CreditService()
def generate_content(self, task, account):
"""Generate content for a task"""
# Check credits
self.credit_service.check_credits(account, 'content_generation', task.estimated_word_count)
# Generate content (existing logic from Writer ViewSet)
content = self._generate(task)
# Deduct credits
self.credit_service.deduct_credits(account, 'content_generation', content.word_count)
return content
def _generate(self, task):
"""Internal content generation logic"""
# Move logic from Writer ViewSet here
pass
```
#### PlanningService
| Task | File | Purpose | Dependencies |
|------|------|---------|--------------|
| **Create PlanningService** | `business/planning/services/clustering_service.py` | Keyword clustering | Existing Planner logic, CreditService |
**PlanningService Methods**:
```python
# business/planning/services/clustering_service.py
class ClusteringService:
def __init__(self):
self.credit_service = CreditService()
def cluster_keywords(self, keyword_ids, account):
"""Cluster keywords using AI"""
# Check credits
self.credit_service.check_credits(account, 'clustering', len(keyword_ids))
# Cluster keywords (existing logic from Planner ViewSet)
clusters = self._cluster(keyword_ids)
# Deduct credits
self.credit_service.deduct_credits(account, 'clustering', len(keyword_ids))
return clusters
```
#### IdeasService
| Task | File | Purpose | Dependencies |
|------|------|---------|--------------|
| **Create IdeasService** | `business/planning/services/ideas_service.py` | Generate content ideas | Existing Planner logic, CreditService |
**IdeasService Methods**:
```python
# business/planning/services/ideas_service.py
class IdeasService:
def __init__(self):
self.credit_service = CreditService()
def generate_ideas(self, cluster_ids, account):
"""Generate content ideas from clusters"""
# Check credits
self.credit_service.check_credits(account, 'idea_generation', len(cluster_ids))
# Generate ideas (existing logic from Planner ViewSet)
ideas = self._generate_ideas(cluster_ids)
# Deduct credits
self.credit_service.deduct_credits(account, 'idea_generation', len(ideas))
return ideas
```
---
## REFACTOR VIEWSETS
### 1.4 Refactor ViewSets (Keep APIs Working)
**Purpose**: Make ViewSets thin wrappers that delegate to services.
#### Planner ViewSets Refactoring
| ViewSet | Current | New | Risk |
|---------|---------|-----|------|
| **KeywordViewSet** | Business logic in views | Delegate to services | LOW |
| **ClusterViewSet** | Business logic in views | Delegate to services | LOW |
| **ContentIdeasViewSet** | Business logic in views | Delegate to services | LOW |
**Before (Business Logic in ViewSet)**:
```python
# modules/planner/views.py
class ClusterViewSet(SiteSectorModelViewSet):
@action(detail=False, methods=['post'])
def auto_generate_ideas(self, request):
cluster_ids = request.data.get('cluster_ids')
# Business logic here (50+ lines)
clusters = Cluster.objects.filter(id__in=cluster_ids)
# AI call logic
# Idea creation logic
# etc.
return Response(...)
```
**After (Delegate to Service)**:
```python
# modules/planner/views.py
class ClusterViewSet(SiteSectorModelViewSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.ideas_service = IdeasService()
@action(detail=False, methods=['post'])
def auto_generate_ideas(self, request):
cluster_ids = request.data.get('cluster_ids')
account = request.account
# Delegate to service
ideas = self.ideas_service.generate_ideas(cluster_ids, account)
# Serialize and return
serializer = ContentIdeasSerializer(ideas, many=True)
return Response(serializer.data)
```
#### Writer ViewSets Refactoring
| ViewSet | Current | New | Risk |
|---------|---------|-----|------|
| **TasksViewSet** | Business logic in views | Delegate to services | LOW |
| **ImagesViewSet** | Business logic in views | Delegate to services | LOW |
**Before (Business Logic in ViewSet)**:
```python
# modules/writer/views.py
class TasksViewSet(SiteSectorModelViewSet):
@action(detail=False, methods=['post'])
def auto_generate_content(self, request):
task_ids = request.data.get('task_ids')
# Business logic here (100+ lines)
tasks = Task.objects.filter(id__in=task_ids)
# AI call logic
# Content creation logic
# etc.
return Response(...)
```
**After (Delegate to Service)**:
```python
# modules/writer/views.py
class TasksViewSet(SiteSectorModelViewSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.content_service = ContentGenerationService()
@action(detail=False, methods=['post'])
def auto_generate_content(self, request):
task_ids = request.data.get('task_ids')
account = request.account
# Delegate to service
contents = []
for task_id in task_ids:
task = Task.objects.get(id=task_id)
content = self.content_service.generate_content(task, account)
contents.append(content)
# Serialize and return
serializer = ContentSerializer(contents, many=True)
return Response(serializer.data)
```
#### Billing ViewSets
| ViewSet | Current | New | Risk |
|---------|---------|-----|------|
| **CreditTransactionViewSet** | Already uses CreditService | Keep as-is | NONE |
| **CreditUsageLogViewSet** | Already uses CreditService | Keep as-is | NONE |
**Note**: Billing ViewSets already use CreditService, so no changes needed.
---
## TESTING & VALIDATION
### 1.5 Testing
**Test Cases**:
1. **Service Tests**:
- ✅ Services can be tested independently
- ✅ Services handle errors correctly
- ✅ Services check credits before operations
- ✅ Services deduct credits after operations
2. **API Compatibility Tests**:
- ✅ All existing API endpoints work identically
- ✅ Response formats unchanged
- ✅ No breaking changes for frontend
- ✅ All ViewSet actions work correctly
3. **Model Migration Tests**:
- ✅ Models work after migration
- ✅ All relationships preserved
- ✅ No data loss during migration
- ✅ All queries work correctly
**Test Files to Create**:
- `backend/tests/test_content_service.py`
- `backend/tests/test_planning_service.py`
- `backend/tests/test_ideas_service.py`
- `backend/tests/test_viewset_refactoring.py`
---
## IMPLEMENTATION CHECKLIST
### Backend Tasks
- [ ] Create `business/` folder structure
- [ ] Create `business/content/` folder
- [ ] Create `business/planning/` folder
- [ ] Create `business/billing/` folder (move existing)
- [ ] Move Content models to `business/content/models.py`
- [ ] Move Planning models to `business/planning/models.py`
- [ ] Move Billing models to `business/billing/models.py`
- [ ] Create migrations for model moves
- [ ] Create `ContentGenerationService`
- [ ] Create `ClusteringService`
- [ ] Create `IdeasService`
- [ ] Refactor `KeywordViewSet` to use services
- [ ] Refactor `ClusterViewSet` to use services
- [ ] Refactor `ContentIdeasViewSet` to use services
- [ ] Refactor `TasksViewSet` to use services
- [ ] Refactor `ImagesViewSet` to use services
- [ ] Update all imports
- [ ] Test all API endpoints
### Testing Tasks
- [ ] Test all existing API endpoints work
- [ ] Test response formats unchanged
- [ ] Test services independently
- [ ] Test model migrations
- [ ] Test backward compatibility
---
## RISK ASSESSMENT
| Risk | Level | Mitigation |
|------|-------|------------|
| **Import errors** | MEDIUM | Update all imports systematically |
| **Data loss during migration** | LOW | Backup before migration, test on staging |
| **Service logic errors** | MEDIUM | Unit tests for all services |
| **Model migration complexity** | MEDIUM | Use Django migrations, test thoroughly |
---
## SUCCESS CRITERIA
- ✅ Services are testable independently
- ✅ Business logic extracted from ViewSets
- ✅ ViewSets are thin wrappers that delegate to services
- ✅ All models moved to business layer
- ✅ All imports updated correctly
- ✅ Services handle credit checks and business rules
---
**END OF PHASE 1 DOCUMENT**

View File

@@ -1,594 +0,0 @@
# PHASE 2: AUTOMATION SYSTEM
**Detailed Implementation Plan**
**Goal**: Implement automation rules and scheduled tasks.
**Timeline**: 2-3 weeks
**Priority**: HIGH
**Dependencies**: Phase 1
---
## TABLE OF CONTENTS
1. [Overview](#overview)
2. [Automation Models](#automation-models)
3. [Automation Service](#automation-service)
4. [Celery Beat Tasks](#celery-beat-tasks)
5. [Automation API](#automation-api)
6. [Automation UI](#automation-ui)
7. [Testing & Validation](#testing--validation)
8. [Implementation Checklist](#implementation-checklist)
---
## OVERVIEW
### Objectives
- ✅ Create AutomationRule and ScheduledTask models
- ✅ Build AutomationService with rule execution engine
- ✅ Implement Celery Beat scheduled tasks
- ✅ Create automation API endpoints
- ✅ Build automation UI (Dashboard, Rules, History)
### Key Principles
- **Rule-Based**: Users create rules with triggers, conditions, actions
- **Scheduled Execution**: Rules can run on schedule or event triggers
- **Credit-Aware**: Automation respects credit limits
- **Audit Trail**: All automation executions logged
---
## AUTOMATION MODELS
### 2.1 Automation Models
**Purpose**: Store automation rules and scheduled task records.
#### AutomationRule Model
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **AutomationRule Model** | `business/automation/models.py` | Phase 1 | Create model with trigger, conditions, actions, schedule |
**AutomationRule Model**:
```python
# business/automation/models.py
class AutomationRule(SiteSectorBaseModel):
name = models.CharField(max_length=255)
description = models.TextField(blank=True)
# Trigger configuration
trigger = models.CharField(
max_length=50,
choices=[
('schedule', 'Scheduled'),
('keyword_added', 'Keyword Added'),
('cluster_created', 'Cluster Created'),
('idea_created', 'Idea Created'),
('content_generated', 'Content Generated'),
('task_created', 'Task Created'),
]
)
# Condition evaluation
conditions = models.JSONField(default=dict)
# Example: {'field': 'status', 'operator': 'eq', 'value': 'draft'}
# Actions to execute
actions = models.JSONField(default=list)
# Example: [{'type': 'generate_ideas', 'params': {'cluster_ids': [1, 2]}}]
# Schedule configuration (for scheduled triggers)
schedule = models.JSONField(default=dict)
# Example: {'cron': '0 9 * * *', 'timezone': 'UTC'}
# Execution limits
is_active = models.BooleanField(default=True)
max_executions_per_day = models.IntegerField(default=10)
credit_limit_per_execution = models.IntegerField(default=100)
# Tracking
last_executed_at = models.DateTimeField(null=True, blank=True)
execution_count_today = models.IntegerField(default=0)
last_reset_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_at']
```
#### ScheduledTask Model
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **ScheduledTask Model** | `business/automation/models.py` | Phase 1 | Create model to track scheduled executions |
**ScheduledTask Model**:
```python
# business/automation/models.py
class ScheduledTask(SiteSectorBaseModel):
automation_rule = models.ForeignKey(AutomationRule, on_delete=models.CASCADE)
scheduled_at = models.DateTimeField()
executed_at = models.DateTimeField(null=True, blank=True)
status = models.CharField(
max_length=20,
choices=[
('pending', 'Pending'),
('running', 'Running'),
('completed', 'Completed'),
('failed', 'Failed'),
('skipped', 'Skipped'),
],
default='pending'
)
result = models.JSONField(default=dict, blank=True)
error_message = models.TextField(blank=True)
credits_used = models.IntegerField(default=0)
class Meta:
ordering = ['-scheduled_at']
```
#### Automation Migrations
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Automation Migrations** | `business/automation/migrations/` | Phase 1 | Create initial migrations |
---
## AUTOMATION SERVICE
### 2.2 Automation Service
**Purpose**: Execute automation rules with condition evaluation and action execution.
#### AutomationService
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **AutomationService** | `business/automation/services/automation_service.py` | Phase 1 services | Main service for rule execution |
**AutomationService Methods**:
```python
# business/automation/services/automation_service.py
class AutomationService:
def __init__(self):
self.rule_engine = RuleEngine()
self.condition_evaluator = ConditionEvaluator()
self.action_executor = ActionExecutor()
self.credit_service = CreditService()
def execute_rule(self, rule, context=None):
"""Execute an automation rule"""
# Check if rule is active
if not rule.is_active:
return {'status': 'skipped', 'reason': 'Rule is inactive'}
# Check execution limits
if not self._check_execution_limits(rule):
return {'status': 'skipped', 'reason': 'Execution limit reached'}
# Check credits
if not self.credit_service.check_credits(rule.account, 'automation', rule.credit_limit_per_execution):
return {'status': 'skipped', 'reason': 'Insufficient credits'}
# Evaluate conditions
if not self.condition_evaluator.evaluate(rule.conditions, context):
return {'status': 'skipped', 'reason': 'Conditions not met'}
# Execute actions
results = self.action_executor.execute(rule.actions, context)
# Update rule tracking
rule.last_executed_at = timezone.now()
rule.execution_count_today += 1
rule.save()
return {'status': 'completed', 'results': results}
def _check_execution_limits(self, rule):
"""Check if rule can execute (daily limit)"""
# Reset counter if new day
if rule.last_reset_at.date() < timezone.now().date():
rule.execution_count_today = 0
rule.last_reset_at = timezone.now()
rule.save()
return rule.execution_count_today < rule.max_executions_per_day
```
#### Rule Execution Engine
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Rule Execution Engine** | `business/automation/services/rule_engine.py` | Phase 1 services | Orchestrates rule execution |
**RuleEngine Methods**:
```python
# business/automation/services/rule_engine.py
class RuleEngine:
def execute_rule(self, rule, context):
"""Orchestrate rule execution"""
# Validate rule
# Check conditions
# Execute actions
# Handle errors
pass
```
#### Condition Evaluator
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Condition Evaluator** | `business/automation/services/condition_evaluator.py` | None | Evaluates rule conditions |
**ConditionEvaluator Methods**:
```python
# business/automation/services/condition_evaluator.py
class ConditionEvaluator:
def evaluate(self, conditions, context):
"""Evaluate rule conditions"""
# Support operators: eq, ne, gt, gte, lt, lte, in, contains
# Example: {'field': 'status', 'operator': 'eq', 'value': 'draft'}
pass
```
#### Action Executor
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Action Executor** | `business/automation/services/action_executor.py` | Phase 1 services | Executes rule actions |
**ActionExecutor Methods**:
```python
# business/automation/services/action_executor.py
class ActionExecutor:
def __init__(self):
self.clustering_service = ClusteringService()
self.ideas_service = IdeasService()
self.content_service = ContentGenerationService()
def execute(self, actions, context):
"""Execute rule actions"""
results = []
for action in actions:
action_type = action['type']
params = action.get('params', {})
if action_type == 'generate_ideas':
result = self.ideas_service.generate_ideas(params['cluster_ids'], context['account'])
elif action_type == 'generate_content':
result = self.content_service.generate_content(params['task_id'], context['account'])
# ... other action types
results.append(result)
return results
```
---
## CELERY BEAT TASKS
### 2.3 Celery Beat Tasks
**Purpose**: Schedule automation rules and monthly credit replenishment.
#### Scheduled Automation Task
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Scheduled Automation Task** | `infrastructure/messaging/automation_tasks.py` | AutomationService | Periodic task to execute scheduled rules |
**Scheduled Automation Task**:
```python
# infrastructure/messaging/automation_tasks.py
from celery import shared_task
from celery.schedules import crontab
@shared_task
def execute_scheduled_automation_rules():
"""Execute all scheduled automation rules"""
from business.automation.services.automation_service import AutomationService
service = AutomationService()
rules = AutomationRule.objects.filter(
trigger='schedule',
is_active=True
)
for rule in rules:
# Check if rule should execute based on schedule
if should_execute_now(rule.schedule):
service.execute_rule(rule)
```
#### Monthly Credit Replenishment
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Monthly Credit Replenishment** | `infrastructure/messaging/automation_tasks.py` | CreditService | Add credits monthly to accounts |
**Monthly Credit Replenishment Task**:
```python
# infrastructure/messaging/automation_tasks.py
@shared_task
def replenish_monthly_credits():
"""Replenish monthly credits for all active accounts"""
from business.billing.services.credit_service import CreditService
service = CreditService()
accounts = Account.objects.filter(status='active')
for account in accounts:
if account.plan:
monthly_credits = account.plan.monthly_credits
if monthly_credits > 0:
service.add_credits(account, monthly_credits, 'monthly_replenishment')
```
#### Celery Beat Configuration
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Celery Beat Configuration** | `backend/igny8_core/celery.py` | None | Configure periodic tasks |
**Celery Beat Configuration**:
```python
# backend/igny8_core/celery.py
from celery.schedules import crontab
app.conf.beat_schedule = {
'execute-scheduled-automation-rules': {
'task': 'infrastructure.messaging.automation_tasks.execute_scheduled_automation_rules',
'schedule': crontab(minute='*/15'), # Every 15 minutes
},
'replenish-monthly-credits': {
'task': 'infrastructure.messaging.automation_tasks.replenish_monthly_credits',
'schedule': crontab(hour=0, minute=0, day_of_month=1), # First day of month
},
}
```
---
## AUTOMATION API
### 2.4 Automation API
**Purpose**: CRUD API for automation rules and scheduled tasks.
#### AutomationRule ViewSet
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **AutomationRule ViewSet** | `modules/automation/views.py` | AutomationService | CRUD operations for rules |
**AutomationRule ViewSet**:
```python
# modules/automation/views.py
class AutomationRuleViewSet(AccountModelViewSet):
queryset = AutomationRule.objects.all()
serializer_class = AutomationRuleSerializer
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.automation_service = AutomationService()
@action(detail=True, methods=['post'])
def execute(self, request, pk=None):
"""Manually execute a rule"""
rule = self.get_object()
result = self.automation_service.execute_rule(rule, {'account': request.account})
return Response(result)
@action(detail=True, methods=['post'])
def test(self, request, pk=None):
"""Test rule conditions without executing"""
rule = self.get_object()
# Test condition evaluation
pass
```
#### ScheduledTask ViewSet
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **ScheduledTask ViewSet** | `modules/automation/views.py` | AutomationService | View scheduled task history |
**ScheduledTask ViewSet**:
```python
# modules/automation/views.py
class ScheduledTaskViewSet(AccountModelViewSet):
queryset = ScheduledTask.objects.all()
serializer_class = ScheduledTaskSerializer
filterset_fields = ['status', 'automation_rule']
ordering = ['-scheduled_at']
```
#### Automation URLs
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Automation URLs** | `modules/automation/urls.py` | None | Register automation routes |
**Automation URLs**:
```python
# modules/automation/urls.py
from rest_framework.routers import DefaultRouter
from .views import AutomationRuleViewSet, ScheduledTaskViewSet
router = DefaultRouter()
router.register(r'rules', AutomationRuleViewSet, basename='automation-rule')
router.register(r'scheduled-tasks', ScheduledTaskViewSet, basename='scheduled-task')
urlpatterns = router.urls
```
---
## AUTOMATION UI
### 2.5 Automation UI
**Purpose**: User interface for managing automation rules and viewing history.
#### Automation Dashboard
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Automation Dashboard** | `frontend/src/pages/Automation/Dashboard.tsx` | EXISTING (placeholder) | Overview of automation status |
**Dashboard Features**:
- Active rules count
- Recent executions
- Success/failure rates
- Credit usage from automation
- Quick actions (create rule, view history)
#### Rules Management
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Rules Management** | `frontend/src/pages/Automation/Rules.tsx` | NEW | CRUD interface for rules |
**Rules Management Features**:
- List all rules
- Create new rule (wizard)
- Edit existing rule
- Enable/disable rule
- Delete rule
- Test rule
- Manual execution
#### Schedules (Part of Automation Menu)
**Note**: Schedules functionality will be integrated into the Automation menu group, not as a separate page.
**Schedules Features** (within Automation Dashboard):
- List scheduled tasks
- Filter by status, rule, date
- View execution results
- View error messages
- Retry failed tasks
#### Automation API Client
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Automation API Client** | `frontend/src/services/automation.api.ts` | NEW | API client for automation endpoints |
**Automation API Client**:
```typescript
// frontend/src/services/automation.api.ts
export const automationApi = {
getRules: () => fetchAPI('/automation/rules/'),
createRule: (data) => fetchAPI('/automation/rules/', { method: 'POST', body: data }),
updateRule: (id, data) => fetchAPI(`/automation/rules/${id}/`, { method: 'PUT', body: data }),
deleteRule: (id) => fetchAPI(`/automation/rules/${id}/`, { method: 'DELETE' }),
executeRule: (id) => fetchAPI(`/automation/rules/${id}/execute/`, { method: 'POST' }),
getScheduledTasks: (filters) => fetchAPI('/automation/scheduled-tasks/', { params: filters }),
};
```
---
## TESTING & VALIDATION
### 2.6 Testing
**Test Cases**:
1. **Automation Service Tests**:
- ✅ Rules execute correctly
- ✅ Conditions evaluate correctly
- ✅ Actions execute correctly
- ✅ Execution limits enforced
- ✅ Credit checks work
2. **Scheduled Tasks Tests**:
- ✅ Scheduled tasks run on time
- ✅ Credit replenishment works monthly
- ✅ Task status tracking works
3. **API Tests**:
- ✅ CRUD operations work
- ✅ Rule execution endpoint works
- ✅ Scheduled task history works
4. **UI Tests**:
- ✅ Dashboard displays correctly
- ✅ Rules management works
- ✅ Schedule history displays correctly
---
## IMPLEMENTATION CHECKLIST
### Backend Tasks
- [ ] Create `business/automation/models.py`
- [ ] Create AutomationRule model
- [ ] Create ScheduledTask model
- [ ] Create automation migrations
- [ ] Create `business/automation/services/automation_service.py`
- [ ] Create `business/automation/services/rule_engine.py`
- [ ] Create `business/automation/services/condition_evaluator.py`
- [ ] Create `business/automation/services/action_executor.py`
- [ ] Create `infrastructure/messaging/automation_tasks.py`
- [ ] Add scheduled automation task
- [ ] Add monthly credit replenishment task
- [ ] Configure Celery Beat
- [ ] Create `modules/automation/views.py`
- [ ] Create AutomationRule ViewSet
- [ ] Create ScheduledTask ViewSet
- [ ] Create `modules/automation/serializers.py`
- [ ] Create `modules/automation/urls.py`
- [ ] Register automation URLs in main urls.py
### Frontend Tasks
- [ ] Implement `frontend/src/pages/Automation/Dashboard.tsx`
- [ ] Create `frontend/src/pages/Automation/Rules.tsx`
- [ ] Integrate schedules functionality into Automation Dashboard (not as separate page)
- [ ] Create `frontend/src/services/automation.api.ts`
- [ ] Create rule creation wizard
- [ ] Create rule editor
- [ ] Create schedule history table (within Automation Dashboard)
### Testing Tasks
- [ ] Test automation rule execution
- [ ] Test scheduled tasks
- [ ] Test credit replenishment
- [ ] Test API endpoints
- [ ] Test UI components
---
## RISK ASSESSMENT
| Risk | Level | Mitigation |
|------|-------|------------|
| **Rule execution errors** | MEDIUM | Comprehensive error handling, logging |
| **Credit limit violations** | MEDIUM | Credit checks before execution |
| **Scheduled task failures** | MEDIUM | Retry mechanism, error logging |
| **Performance issues** | LOW | Background processing, rate limiting |
---
## SUCCESS CRITERIA
- ✅ Automation rules execute correctly
- ✅ Scheduled tasks run on time
- ✅ Credit replenishment works monthly
- ✅ UI shows automation status
- ✅ Rules can be created, edited, deleted
- ✅ Execution history is tracked
- ✅ All automation respects credit limits
---
**END OF PHASE 2 DOCUMENT**

View File

@@ -1,642 +0,0 @@
# PHASE 3: SITE BUILDER
**Detailed Implementation Plan**
**Goal**: Build Site Builder for creating sites via wizard.
**Timeline**: 3-4 weeks
**Priority**: HIGH
**Dependencies**: Phase 1, Phase 2
---
## TABLE OF CONTENTS
1. [Overview](#overview)
2. [Sites Folder Access & File Management](#sites-folder-access--file-management)
3. [Site Builder Models](#site-builder-models)
4. [Site Structure Generation](#site-structure-generation)
5. [Site Builder API](#site-builder-api)
6. [Site Builder Frontend](#site-builder-frontend)
7. [Global Component Library](#global-component-library)
8. [Page Generation](#page-generation)
9. [Testing & Validation](#testing--validation)
10. [Implementation Checklist](#implementation-checklist)
---
## OVERVIEW
### Objectives
- ✅ Create Site Builder wizard for site creation
- ✅ Generate site structure using AI
- ✅ Build preview canvas for site editing
- ✅ Create shared component library
- ✅ Support multiple layouts and templates
- ✅ Enable file management for site assets
### Key Principles
- **Wizard-Based**: Step-by-step site creation process
- **AI-Powered**: AI generates site structure from business brief
- **Component Reuse**: Shared components across Site Builder, Sites Renderer, Main App
- **User-Friendly**: "Website Builder" or "Site Creator" in UI
---
## SITES FOLDER ACCESS & FILE MANAGEMENT
### 3.0 Sites Folder Access & File Management
**Purpose**: Manage site files and assets with proper access control.
#### Sites Folder Structure
```
/data/app/sites-data/
└── clients/
└── {site_id}/
└── v{version}/
├── site.json # Site definition
├── pages/ # Page definitions
│ ├── home.json
│ ├── about.json
│ └── ...
└── assets/ # User-managed files
├── images/
├── documents/
└── media/
```
#### User Access Rules
- **Owner/Admin**: Full access to all account sites
- **Editor**: Access to granted sites (via SiteUserAccess)
- **Viewer**: Read-only access to granted sites
- **File operations**: Scoped to user's accessible sites only
#### Site File Management Service
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Site File Management Service** | `business/site_building/services/file_management_service.py` | Phase 1 | File upload, delete, organize |
**FileManagementService**:
```python
# business/site_building/services/file_management_service.py
class SiteBuilderFileService:
def get_user_accessible_sites(self, user):
"""Get sites user can access for file management"""
if user.is_owner_or_admin():
return Site.objects.filter(account=user.account)
return user.get_accessible_sites()
def get_site_files_path(self, site_id, version=1):
"""Get site's files directory"""
return f"/data/app/sites-data/clients/{site_id}/v{version}/assets/"
def check_file_access(self, user, site_id):
"""Check if user can access site's files"""
accessible_sites = self.get_user_accessible_sites(user)
return any(site.id == site_id for site in accessible_sites)
def upload_file(self, user, site_id, file, folder='images'):
"""Upload file to site's assets folder"""
if not self.check_file_access(user, site_id):
raise PermissionDenied("No access to this site")
# Check storage quota
if not self.check_storage_quota(site_id, file.size):
raise ValidationError("Storage quota exceeded")
# Upload file
file_path = self._save_file(site_id, file, folder)
return file_path
```
#### File Upload API
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **File Upload API** | `modules/site_builder/views.py` | File Management Service | Handle file uploads |
#### File Browser UI
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **File Browser UI** | `site-builder/src/components/files/FileBrowser.tsx` | NEW | File browser component |
#### Storage Quota Check
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Storage Quota Check** | `infrastructure/storage/file_storage.py` | Phase 1 | Check site storage quota |
---
## SITE BUILDER MODELS
### 3.1 Site Builder Models
**Purpose**: Store site blueprints and page definitions.
#### SiteBlueprint Model
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **SiteBlueprint Model** | `business/site_building/models.py` | Phase 1 | Store site structure |
**SiteBlueprint Model**:
```python
# business/site_building/models.py
class SiteBlueprint(SiteSectorBaseModel):
name = models.CharField(max_length=255)
description = models.TextField(blank=True)
# Site configuration
config_json = models.JSONField(default=dict)
# Example: {'business_type': 'ecommerce', 'style': 'modern'}
# Generated structure
structure_json = models.JSONField(default=dict)
# Example: {'pages': [...], 'layout': 'default', 'theme': {...}}
# Status tracking
status = models.CharField(
max_length=20,
choices=[
('draft', 'Draft'),
('generating', 'Generating'),
('ready', 'Ready'),
('deployed', 'Deployed'),
],
default='draft'
)
# Hosting configuration
hosting_type = models.CharField(
max_length=50,
choices=[
('igny8_sites', 'IGNY8 Sites'),
('wordpress', 'WordPress'),
('shopify', 'Shopify'),
('multi', 'Multiple Destinations'),
],
default='igny8_sites'
)
# Version tracking
version = models.IntegerField(default=1)
deployed_version = models.IntegerField(null=True, blank=True)
class Meta:
ordering = ['-created_at']
```
#### PageBlueprint Model
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **PageBlueprint Model** | `business/site_building/models.py` | Phase 1 | Store page definitions |
**PageBlueprint Model**:
```python
# business/site_building/models.py
class PageBlueprint(SiteSectorBaseModel):
site_blueprint = models.ForeignKey(SiteBlueprint, on_delete=models.CASCADE, related_name='pages')
slug = models.SlugField(max_length=255)
title = models.CharField(max_length=255)
# Page type
type = models.CharField(
max_length=50,
choices=[
('home', 'Home'),
('about', 'About'),
('services', 'Services'),
('products', 'Products'),
('blog', 'Blog'),
('contact', 'Contact'),
('custom', 'Custom'),
]
)
# Page content (blocks)
blocks_json = models.JSONField(default=list)
# Example: [{'type': 'hero', 'data': {...}}, {'type': 'features', 'data': {...}}]
# Status
status = models.CharField(
max_length=20,
choices=[
('draft', 'Draft'),
('generating', 'Generating'),
('ready', 'Ready'),
],
default='draft'
)
# Order
order = models.IntegerField(default=0)
class Meta:
ordering = ['order', 'created_at']
unique_together = [['site_blueprint', 'slug']]
```
#### Site Builder Migrations
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Site Builder Migrations** | `business/site_building/migrations/` | Phase 1 | Create initial migrations |
---
## SITE STRUCTURE GENERATION
### 3.2 Site Structure Generation
**Purpose**: Use AI to generate site structure from business brief.
#### Structure Generation AI Function
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Structure Generation AI Function** | `infrastructure/ai/functions/generate_site_structure.py` | Existing AI framework | AI function for structure generation |
**GenerateSiteStructureFunction**:
```python
# infrastructure/ai/functions/generate_site_structure.py
class GenerateSiteStructureFunction(BaseAIFunction):
def get_operation_type(self):
return 'site_structure_generation'
def get_estimated_cost(self, payload):
return CREDIT_COSTS['site_structure_generation']
def execute(self, payload, account):
"""Generate site structure from business brief"""
business_brief = payload['business_brief']
objectives = payload.get('objectives', [])
style_preferences = payload.get('style', {})
# Build prompt
prompt = self._build_prompt(business_brief, objectives, style_preferences)
# Call AI
response = self.ai_core.generate(prompt, model='gpt-4')
# Parse response to structure JSON
structure = self._parse_structure(response)
return structure
```
#### Structure Generation Service
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Structure Generation Service** | `business/site_building/services/structure_generation_service.py` | Phase 1, AI framework | Service to generate site structure |
**StructureGenerationService**:
```python
# business/site_building/services/structure_generation_service.py
class StructureGenerationService:
def __init__(self):
self.ai_function = GenerateSiteStructureFunction()
self.credit_service = CreditService()
def generate_structure(self, site_blueprint, business_brief, objectives, style):
"""Generate site structure for blueprint"""
account = site_blueprint.account
# Check credits
self.credit_service.check_credits(account, 'site_structure_generation')
# Update status
site_blueprint.status = 'generating'
site_blueprint.save()
# Generate structure
payload = {
'business_brief': business_brief,
'objectives': objectives,
'style': style,
}
structure = self.ai_function.execute(payload, account)
# Deduct credits
self.credit_service.deduct_credits(account, 'site_structure_generation')
# Update blueprint
site_blueprint.structure_json = structure
site_blueprint.status = 'ready'
site_blueprint.save()
# Create page blueprints
self._create_page_blueprints(site_blueprint, structure)
return site_blueprint
```
#### Site Structure Prompts
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Site Structure Prompts** | `infrastructure/ai/prompts.py` | Existing prompt system | Add site structure prompts |
---
## SITE BUILDER API
### 3.3 Site Builder API
**Purpose**: API endpoints for site builder operations.
#### Site Builder ViewSet
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Site Builder ViewSet** | `modules/site_builder/views.py` | Structure Generation Service | CRUD operations for site blueprints |
**SiteBuilderViewSet**:
```python
# modules/site_builder/views.py
class SiteBuilderViewSet(AccountModelViewSet):
queryset = SiteBlueprint.objects.all()
serializer_class = SiteBlueprintSerializer
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.structure_service = StructureGenerationService()
@action(detail=True, methods=['post'])
def generate_structure(self, request, pk=None):
"""Generate site structure"""
blueprint = self.get_object()
business_brief = request.data.get('business_brief')
objectives = request.data.get('objectives', [])
style = request.data.get('style', {})
blueprint = self.structure_service.generate_structure(
blueprint, business_brief, objectives, style
)
serializer = self.get_serializer(blueprint)
return Response(serializer.data)
```
#### Site Builder URLs
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Site Builder URLs** | `modules/site_builder/urls.py` | None | Register site builder routes |
#### Site Builder Serializers
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Site Builder Serializers** | `modules/site_builder/serializers.py` | None | Serializers for SiteBlueprint and PageBlueprint |
---
## SITE BUILDER FRONTEND
### 3.4 Site Builder Frontend (New Container)
**User-Friendly Name**: "Website Builder" or "Site Creator"
#### Create Site Builder Container
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Create Site Builder Container** | `docker-compose.app.yml` | None | Add new container for site builder |
**Docker Compose Configuration**:
```yaml
# docker-compose.app.yml
igny8_site_builder:
build: ./site-builder
ports:
- "8022:5175"
volumes:
- /data/app/igny8/site-builder:/app
environment:
- VITE_API_URL=http://igny8_backend:8010
```
#### Wizard Steps
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Wizard Steps** | `site-builder/src/pages/wizard/` | NEW | Step-by-step wizard components |
**Wizard Steps**:
- Step 1: Type Selection (Business type, industry)
- Step 2: Business Brief (Description, goals)
- Step 3: Objectives (What pages needed)
- Step 4: Style Preferences (Colors, fonts, layout)
#### Preview Canvas
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Preview Canvas** | `site-builder/src/pages/preview/` | NEW | Live preview of site |
#### Site Builder State
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Site Builder State** | `site-builder/src/state/builderStore.ts` | NEW | Zustand store for builder state |
#### Site Builder API Client
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Site Builder API Client** | `site-builder/src/api/builder.api.ts` | NEW | API client for site builder |
#### Layout Selection
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Layout Selection** | `site-builder/src/components/layouts/` | NEW | Layout selector component |
#### Template Library
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Template Library** | `site-builder/src/components/templates/` | NEW | Template selector component |
#### Block Components
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Block Components** | `site-builder/src/components/blocks/` | NEW | Block components (imports from shared) |
---
## GLOBAL COMPONENT LIBRARY
### 3.7 Global Component Library
**Purpose**: Shared components across Site Builder, Sites Renderer, and Main App.
#### Create Shared Component Library
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Create Shared Component Library** | `frontend/src/components/shared/` | None | Create shared component structure |
**Component Library Structure**:
```
frontend/src/components/shared/
├── blocks/
│ ├── Hero.tsx
│ ├── Features.tsx
│ ├── Services.tsx
│ ├── Products.tsx
│ ├── Testimonials.tsx
│ ├── ContactForm.tsx
│ └── ...
├── layouts/
│ ├── DefaultLayout.tsx
│ ├── MinimalLayout.tsx
│ ├── MagazineLayout.tsx
│ ├── EcommerceLayout.tsx
│ ├── PortfolioLayout.tsx
│ ├── BlogLayout.tsx
│ └── CorporateLayout.tsx
└── templates/
├── BlogTemplate.tsx
├── BusinessTemplate.tsx
├── PortfolioTemplate.tsx
└── ...
```
**Usage**: Site Builder, Sites Renderer, and Main App all use same components (no duplicates)
#### Component Documentation
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Component Documentation** | `frontend/src/components/shared/README.md` | None | Document all shared components |
---
## PAGE GENERATION
### 3.5 Page Generation (Reuse Content Service)
**Purpose**: Generate page content using existing ContentService.
#### Extend ContentService
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Extend ContentService** | `business/content/services/content_generation_service.py` | Phase 1 | Add site page generation method |
#### Add Site Page Type
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Add Site Page Type** | `business/content/models.py` | Phase 1 | Add site page content type |
#### Page Generation Prompts
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Page Generation Prompts** | `infrastructure/ai/prompts.py` | Existing prompt system | Add page generation prompts |
---
## TESTING & VALIDATION
### 3.6 Testing
**Test Cases**:
1. **Site Builder Tests**:
- ✅ Site Builder wizard works end-to-end
- ✅ Structure generation creates valid blueprints
- ✅ Preview renders correctly
- ✅ Page generation reuses existing content service
2. **File Management Tests**:
- ✅ File upload works
- ✅ File access control works
- ✅ Storage quota enforced
3. **Component Library Tests**:
- ✅ Components render correctly
- ✅ Components work in Site Builder
- ✅ Components work in Sites Renderer
---
## IMPLEMENTATION CHECKLIST
### Backend Tasks
- [ ] Create `business/site_building/models.py`
- [ ] Create SiteBlueprint model
- [ ] Create PageBlueprint model
- [ ] Create site builder migrations
- [ ] Create `business/site_building/services/file_management_service.py`
- [ ] Create `business/site_building/services/structure_generation_service.py`
- [ ] Create `infrastructure/ai/functions/generate_site_structure.py`
- [ ] Add site structure prompts
- [ ] Create `modules/site_builder/views.py`
- [ ] Create SiteBuilder ViewSet
- [ ] Create `modules/site_builder/serializers.py`
- [ ] Create `modules/site_builder/urls.py`
- [ ] Extend ContentService for page generation
### Frontend Tasks
- [ ] Create `site-builder/` folder structure
- [ ] Create Site Builder container in docker-compose
- [ ] Create wizard steps
- [ ] Create preview canvas
- [ ] Create builder state store
- [ ] Create API client
- [ ] Create layout selector
- [ ] Create template library
- [ ] Create `frontend/src/components/shared/` structure
- [ ] Create block components
- [ ] Create layout components
- [ ] Create template components
- [ ] Create component documentation
### Testing Tasks
- [ ] Test site builder wizard
- [ ] Test structure generation
- [ ] Test file management
- [ ] Test component library
- [ ] Test page generation
---
## RISK ASSESSMENT
| Risk | Level | Mitigation |
|------|-------|------------|
| **AI structure generation quality** | MEDIUM | Prompt engineering, validation |
| **Component compatibility** | MEDIUM | Shared component library, testing |
| **File management security** | MEDIUM | Access control, validation |
| **Performance with large sites** | LOW | Optimization, caching |
---
## SUCCESS CRITERIA
- ✅ Site Builder wizard works end-to-end
- ✅ Structure generation creates valid blueprints
- ✅ Preview renders correctly
- ✅ Page generation reuses existing content service
- ✅ File management works correctly
- ✅ Shared components work across all apps
- ✅ Multiple layouts supported
---
**END OF PHASE 3 DOCUMENT**

View File

@@ -1,391 +0,0 @@
# PHASE 4: LINKER & OPTIMIZER
**Detailed Implementation Plan**
**Goal**: Add linking and optimization as post-processing stages with multiple entry points.
**Timeline**: 4-5 weeks
**Priority**: MEDIUM
**Dependencies**: Phase 1
---
## TABLE OF CONTENTS
1. [Overview](#overview)
2. [Content Workflow & Entry Points](#content-workflow--entry-points)
3. [Content Model Extensions](#content-model-extensions)
4. [Linker Implementation](#linker-implementation)
5. [Optimizer Implementation](#optimizer-implementation)
6. [Content Pipeline Service](#content-pipeline-service)
7. [Linker & Optimizer APIs](#linker--optimizer-apis)
8. [Linker & Optimizer UI](#linker--optimizer-ui)
9. [Testing & Validation](#testing--validation)
10. [Implementation Checklist](#implementation-checklist)
---
## OVERVIEW
### Objectives
- ✅ Add internal linking to content
- ✅ Add content optimization
- ✅ Support multiple entry points (Writer, WordPress Sync, 3rd Party, Manual)
- ✅ Create content pipeline service
- ✅ Build UI for linker and optimizer
### Key Principles
- **Multiple Entry Points**: Optimizer works from any content source
- **Unified Content Model**: All content stored in same model with source tracking
- **Pipeline Orchestration**: Linker → Optimizer → Publish workflow
- **Source Agnostic**: Optimizer works on any content regardless of source
---
## CONTENT WORKFLOW & ENTRY POINTS
### 4.0 Content Workflow & Entry Points
**Content Sources**:
1. **IGNY8 Generated** - Content created via Writer module
2. **WordPress Synced** - Content synced from WordPress via plugin
3. **3rd Party Synced** - Content synced from external sources (Shopify, custom APIs)
**Workflow Entry Points**:
```
Entry Point 1: Writer → Linker → Optimizer → Publish
Entry Point 2: WordPress Sync → Optimizer → Publish
Entry Point 3: 3rd Party Sync → Optimizer → Publish
Entry Point 4: Manual Selection → Linker/Optimizer
```
**Content Storage Strategy**:
- All content stored in unified `Content` model
- `source` field: `'igny8'`, `'wordpress'`, `'shopify'`, `'custom'`
- `sync_status` field: `'native'`, `'imported'`, `'synced'`
---
## CONTENT MODEL EXTENSIONS
### 4.1 Content Model Extensions
**Purpose**: Add fields to track content source and sync status.
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Add source field** | `business/content/models.py` | Phase 1 | Track content source |
| **Add sync_status field** | `business/content/models.py` | Phase 1 | Track sync status |
| **Add external_id field** | `business/content/models.py` | Phase 1 | Store external platform ID |
| **Add sync_metadata field** | `business/content/models.py` | Phase 1 | Store platform-specific metadata |
**Content Model Extensions**:
```python
# business/content/models.py
class Content(SiteSectorBaseModel):
# Existing fields...
# NEW: Source tracking
source = models.CharField(
max_length=50,
choices=[
('igny8', 'IGNY8 Generated'),
('wordpress', 'WordPress Synced'),
('shopify', 'Shopify Synced'),
('custom', 'Custom API Synced'),
],
default='igny8'
)
# NEW: Sync status
sync_status = models.CharField(
max_length=50,
choices=[
('native', 'Native IGNY8 Content'),
('imported', 'Imported from External'),
('synced', 'Synced from External'),
],
default='native'
)
# NEW: External reference
external_id = models.CharField(max_length=255, blank=True, null=True)
external_url = models.URLField(blank=True, null=True)
sync_metadata = models.JSONField(default=dict)
# NEW: Linking fields
internal_links = models.JSONField(default=list)
linker_version = models.IntegerField(default=0)
# NEW: Optimization fields
optimizer_version = models.IntegerField(default=0)
optimization_scores = models.JSONField(default=dict)
```
---
## LINKER IMPLEMENTATION
### 4.2 Linker Models
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **InternalLink Model** | `business/linking/models.py` | Phase 1 | Store link relationships |
| **LinkGraph Model** | `business/linking/models.py` | Phase 1 | Store link graph |
### 4.3 Linker Service
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **LinkerService** | `business/linking/services/linker_service.py` | Phase 1, ContentService | Main linking service |
| **Link Candidate Engine** | `business/linking/services/candidate_engine.py` | Phase 1 | Find link candidates |
| **Link Injection Engine** | `business/linking/services/injection_engine.py` | Phase 1 | Inject links into content |
**LinkerService**:
```python
# business/linking/services/linker_service.py
class LinkerService:
def process(self, content_id):
"""Process content for linking"""
content = Content.objects.get(id=content_id)
# Check credits
credit_service.check_credits(content.account, 'linking')
# Find link candidates
candidates = self.candidate_engine.find_candidates(content)
# Inject links
linked_content = self.injection_engine.inject_links(content, candidates)
# Update content
content.internal_links = linked_content['links']
content.linker_version += 1
content.save()
# Deduct credits
credit_service.deduct_credits(content.account, 'linking')
return content
```
---
## OPTIMIZER IMPLEMENTATION
### 4.5 Optimizer Models
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **OptimizationTask Model** | `business/optimization/models.py` | Phase 1 | Store optimization results |
| **OptimizationScores Model** | `business/optimization/models.py` | Phase 1 | Store optimization scores |
### 4.6 Optimizer Service (Multiple Entry Points)
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **OptimizerService** | `business/optimization/services/optimizer_service.py` | Phase 1, ContentService | Main optimization service |
| **Content Analyzer** | `business/optimization/services/analyzer.py` | Phase 1 | Analyze content quality |
| **Optimization AI Function** | `infrastructure/ai/functions/optimize_content.py` | Existing AI framework | AI optimization function |
**OptimizerService**:
```python
# business/optimization/services/optimizer_service.py
class OptimizerService:
def optimize_from_writer(self, content_id):
"""Entry Point 1: Writer → Optimizer"""
content = Content.objects.get(id=content_id, source='igny8')
return self.optimize(content)
def optimize_from_wordpress_sync(self, content_id):
"""Entry Point 2: WordPress Sync → Optimizer"""
content = Content.objects.get(id=content_id, source='wordpress')
return self.optimize(content)
def optimize_from_external_sync(self, content_id):
"""Entry Point 3: External Sync → Optimizer"""
content = Content.objects.get(id=content_id, source__in=['shopify', 'custom'])
return self.optimize(content)
def optimize_manual(self, content_id):
"""Entry Point 4: Manual Selection → Optimizer"""
content = Content.objects.get(id=content_id)
return self.optimize(content)
def optimize(self, content):
"""Unified optimization logic"""
# Check credits
credit_service.check_credits(content.account, 'optimization', content.word_count)
# Analyze content
scores_before = self.analyzer.analyze(content)
# Optimize content
optimized = self.ai_function.optimize(content)
# Analyze optimized content
scores_after = self.analyzer.analyze(optimized)
# Store optimization task
OptimizationTask.objects.create(
content=content,
scores_before=scores_before,
scores_after=scores_after,
html_before=content.html_content,
html_after=optimized['html_content'],
)
# Update content
content.optimizer_version += 1
content.optimization_scores = scores_after
content.save()
# Deduct credits
credit_service.deduct_credits(content.account, 'optimization', content.word_count)
return content
```
---
## CONTENT PIPELINE SERVICE
### 4.7 Content Pipeline Service
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **ContentPipelineService** | `business/content/services/content_pipeline_service.py` | LinkerService, OptimizerService | Orchestrate content pipeline |
**Pipeline Workflow States**:
```
Content States:
- 'draft' → Generated, not processed
- 'linked' → Links added, ready for optimization
- 'optimized' → Optimized, ready for review
- 'review' → Ready for publishing
- 'published' → Published to destination(s)
```
**ContentPipelineService**:
```python
# business/content/services/content_pipeline_service.py
class ContentPipelineService:
def process_writer_content(self, content_id, stages=['linking', 'optimization']):
"""Writer → Linker → Optimizer pipeline"""
content = Content.objects.get(id=content_id, source='igny8')
if 'linking' in stages:
content = linker_service.process(content.id)
if 'optimization' in stages:
content = optimizer_service.optimize_from_writer(content.id)
return content
def process_synced_content(self, content_id, stages=['optimization']):
"""Synced Content → Optimizer (skip linking if needed)"""
content = Content.objects.get(id=content_id)
if 'optimization' in stages:
content = optimizer_service.optimize_manual(content.id)
return content
```
---
## LINKER & OPTIMIZER APIs
### 4.8 Linker & Optimizer APIs
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Linker ViewSet** | `modules/linker/views.py` | LinkerService | API for linker operations |
| **Optimizer ViewSet** | `modules/optimizer/views.py` | OptimizerService | API for optimizer operations |
---
## LINKER & OPTIMIZER UI
### 4.9 Linker & Optimizer UI
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Linker Dashboard** | `frontend/src/pages/Linker/Dashboard.tsx` | NEW | Linker overview |
| **Optimizer Dashboard** | `frontend/src/pages/Optimizer/Dashboard.tsx` | NEW | Optimizer overview |
| **Content Selection UI** | `frontend/src/components/optimizer/ContentSelector.tsx` | NEW | Select content for optimization |
| **Source Badge Component** | `frontend/src/components/content/SourceBadge.tsx` | NEW | Show content source |
**Optimizer UI Features**:
- Show content source (IGNY8, WordPress, Shopify badge)
- Show sync status (Native, Synced, Imported badge)
- Entry point selection (from Writer, from Sync, Manual)
- Content list with source filters
- "Send to Optimizer" button (works for any source)
### 4.10 Content Filtering & Display
| Task | File | Dependencies | Implementation |
|------|------|--------------|----------------|
| **Content Filter Component** | `frontend/src/components/content/ContentFilter.tsx` | NEW | Filter content by source |
| **Source Filter** | `frontend/src/components/content/SourceFilter.tsx` | NEW | Filter by source |
| **Sync Status Filter** | `frontend/src/components/content/SyncStatusFilter.tsx` | NEW | Filter by sync status |
---
## TESTING & VALIDATION
### 4.11 Testing
**Test Cases**:
- ✅ Writer → Linker handover works
- ✅ Linker finds appropriate link candidates
- ✅ Links inject correctly into content
- ✅ Optimizer works from Writer entry point
- ✅ Optimizer works from WordPress sync entry point
- ✅ Optimizer works from 3rd party sync entry point
- ✅ Optimizer works from manual selection
- ✅ Synced content stored correctly with source flags
- ✅ Content filtering works (by source, sync_status)
- ✅ Pipeline orchestrates correctly
- ✅ All entry points use same optimization logic
---
## IMPLEMENTATION CHECKLIST
### Backend Tasks
- [ ] Extend Content model with source/sync fields
- [ ] Create `business/linking/models.py`
- [ ] Create LinkerService
- [ ] Create `business/optimization/models.py`
- [ ] Create OptimizerService
- [ ] Create optimization AI function
- [ ] Create ContentPipelineService
- [ ] Create Linker ViewSet
- [ ] Create Optimizer ViewSet
- [ ] Create content sync service (for Phase 6)
### Frontend Tasks
- [ ] Create Linker Dashboard
- [ ] Create Optimizer Dashboard
- [ ] Create content selection UI
- [ ] Create source badge component
- [ ] Create content filters
- [ ] Update content list with filters
---
## SUCCESS CRITERIA
- ✅ Writer → Linker handover works
- ✅ Optimizer works from all entry points
- ✅ Content source tracking works
- ✅ Pipeline orchestrates correctly
- ✅ UI shows content sources and filters
---
**END OF PHASE 4 DOCUMENT**