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