- Introduced a new scheduled task for executing automation rules every 5 minutes in the Celery beat schedule. - Updated URL routing to include a new endpoint for automation-related functionalities. - Refactored imports in various modules to align with the new business layer structure, ensuring backward compatibility for billing models, exceptions, and services.
435 lines
14 KiB
Markdown
435 lines
14 KiB
Markdown
# 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**
|
|
|