Files
igny8/docs/planning/phases/PHASE-1-SERVICE-LAYER-REFACTORING.md
IGNY8 VPS (Salman) 7f8982a0ab Add scheduled automation task and update URL routing
- 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.
2025-11-16 22:11:05 +00:00

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**