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:
File diff suppressed because it is too large
Load Diff
1180
docs/planning/phases/PHASE-0-4-FOUNDATION-TO-LINKER-OPTIMIZER.md
Normal file
1180
docs/planning/phases/PHASE-0-4-FOUNDATION-TO-LINKER-OPTIMIZER.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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**
|
||||
|
||||
@@ -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**
|
||||
|
||||
@@ -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**
|
||||
|
||||
@@ -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**
|
||||
|
||||
@@ -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**
|
||||
|
||||
Reference in New Issue
Block a user