# Planner Module

**Last Verified:** December 25, 2025  
**Status:** ✅ Active  
**Backend Path:** `backend/igny8_core/modules/planner/`  
**Frontend Path:** `frontend/src/pages/Planner/`

---

## Quick Reference

| What | File | Key Items |
|------|------|-----------|
| Models | `modules/planner/models.py` | `Keywords`, `Clusters`, `ContentIdeas` |
| Views | `modules/planner/views.py` | `KeywordViewSet`, `ClusterViewSet`, `ContentIdeaViewSet` |
| Serializers | `modules/planner/serializers.py` | Keyword/Cluster/Idea serializers |
| AI Functions | `ai/functions/clustering.py` | `AutoClusterFunction` |
| AI Functions | `ai/functions/ideas.py` | `GenerateIdeasFunction` |
| Frontend Pages | `pages/Planner/Keywords.tsx` | Keyword management |
| Frontend Pages | `pages/Planner/Clusters.tsx` | Cluster management |
| Frontend Pages | `pages/Planner/Ideas.tsx` | Content ideas |

---

## Purpose

The Planner module manages the SEO content planning pipeline:

```
SeedKeywords (Global) → Keywords (Site/Sector) → Clusters → ContentIdeas → Tasks
```

---

## Data Models

### Keywords

| Field | Type | Purpose |
|-------|------|---------|
| account | FK | Owner account |
| site | FK | Parent site |
| sector | FK | Parent sector |
| seed_keyword | FK | Reference to global SeedKeyword |
| keyword | CharField | Keyword text |
| search_volume | Integer | Monthly search volume |
| difficulty | Integer | SEO difficulty (0-100) |
| cpc | Decimal | Cost per click |
| search_intent | CharField | informational/commercial/transactional/navigational |
| status | CharField | new/mapped/used |
| cluster | FK | Assigned cluster (nullable) |
| created_at | DateTime | Creation date |

### Clusters

| Field | Type | Purpose |
|-------|------|---------|
| account | FK | Owner account |
| site | FK | Parent site |
| sector | FK | Parent sector |
| name | CharField | Cluster name |
| description | TextField | Cluster description |
| primary_keyword | FK | Main keyword |
| status | CharField | draft/active/complete |
| keyword_count | Integer | Number of keywords |
| created_at | DateTime | Creation date |

### ContentIdeas

| Field | Type | Purpose |
|-------|------|---------|
| account | FK | Owner account |
| site | FK | Parent site |
| sector | FK | Parent sector |
| cluster | FK | Source cluster |
| title | CharField | Content title |
| description | TextField | Content brief |
| target_keywords | JSON | Keywords to target |
| content_type | CharField | blog_post/guide/comparison/etc. |
| word_count_target | Integer | Target word count |
| status | CharField | draft/queued/used |
| priority | Integer | Priority score |
| created_at | DateTime | Creation date |

---

## API Endpoints

### Keywords

| Method | Path | Handler | Purpose |
|--------|------|---------|---------|
| GET | `/api/v1/planner/keywords/` | `KeywordViewSet.list` | List keywords with filtering |
| POST | `/api/v1/planner/keywords/` | `KeywordViewSet.create` | Create single keyword |
| GET | `/api/v1/planner/keywords/{id}/` | `KeywordViewSet.retrieve` | Get keyword detail |
| PUT | `/api/v1/planner/keywords/{id}/` | `KeywordViewSet.update` | Update keyword |
| DELETE | `/api/v1/planner/keywords/{id}/` | `KeywordViewSet.destroy` | Soft delete keyword |
| POST | `/api/v1/planner/keywords/bulk_delete/` | `KeywordViewSet.bulk_delete` | Hard delete multiple |
| POST | `/api/v1/planner/keywords/bulk_status/` | `KeywordViewSet.bulk_status` | Update status for multiple |
| POST | `/api/v1/planner/keywords/add_to_workflow/` | `KeywordViewSet.add_to_workflow` | Add SeedKeywords to workflow |

**Filters:** `?site_id=`, `?sector_id=`, `?status=`, `?cluster_id=`, `?difficulty_min=`, `?difficulty_max=`, `?volume_min=`, `?volume_max=`

### Clusters

| Method | Path | Handler | Purpose |
|--------|------|---------|---------|
| GET | `/api/v1/planner/clusters/` | `ClusterViewSet.list` | List clusters |
| POST | `/api/v1/planner/clusters/` | `ClusterViewSet.create` | Create cluster manually |
| POST | `/api/v1/planner/clusters/auto_cluster/` | `ClusterViewSet.auto_cluster` | AI-powered clustering |
| POST | `/api/v1/planner/clusters/generate_ideas/` | `ClusterViewSet.generate_ideas` | Generate ideas from clusters |

### Content Ideas

| Method | Path | Handler | Purpose |
|--------|------|---------|---------|
| GET | `/api/v1/planner/ideas/` | `ContentIdeaViewSet.list` | List ideas |
| POST | `/api/v1/planner/ideas/` | `ContentIdeaViewSet.create` | Create idea manually |
| POST | `/api/v1/planner/ideas/create_tasks/` | `ContentIdeaViewSet.create_tasks` | Convert ideas to tasks |

---

## Business Logic

### Auto Clustering (AI)

**Trigger:** User clicks "Auto Cluster" button  
**AI Function:** `AutoClusterFunction`  
**Credit Cost:** Per batch (configurable)

**Flow:**
1. User selects keywords (or all unclustered)
2. Frontend calls `POST /clusters/auto_cluster/`
3. Backend validates minimum 5 keywords
4. AIEngine executes `AutoClusterFunction`:
   - Sends keywords to GPT-4
   - AI groups by semantic similarity
   - Returns cluster assignments
5. Creates/updates `Clusters` records
6. Assigns keywords to clusters
7. Returns created clusters

### Generate Ideas (AI)

**Trigger:** User clicks "Generate Ideas" on cluster(s)  
**AI Function:** `GenerateIdeasFunction`  
**Credit Cost:** Per idea generated

**Flow:**
1. User selects clusters
2. Frontend calls `POST /clusters/generate_ideas/`
3. Backend validates clusters have keywords
4. AIEngine executes `GenerateIdeasFunction`:
   - Analyzes cluster keywords
   - Generates content titles + briefs
   - Suggests word counts and content types
5. Creates `ContentIdeas` records
6. Returns created ideas

### Add Keywords to Workflow

**Trigger:** User selects SeedKeywords in setup  
**Credit Cost:** None

**Flow:**
1. User browses global SeedKeywords
2. Selects keywords to add to their sector
3. Frontend calls `POST /keywords/add_to_workflow/`
4. Backend creates `Keywords` records linked to SeedKeywords
5. Keywords appear in Planner for clustering

---

## Frontend Pages

### Keywords Page (`/planner/keywords`)

- Table of all keywords with filtering
- Bulk actions: delete, update status
- Add keywords from SeedKeyword library
- Import keywords from CSV
- Assign to clusters manually

### Clusters Page (`/planner/clusters`)

- Grid/list of clusters
- Auto-cluster action (AI)
- Generate ideas action (AI)
- View keywords in cluster
- Cluster status management

### Ideas Page (`/planner/ideas`)

- Table of content ideas
- Convert to tasks action
- Edit idea details
- Priority management

---

## Integration Points

| From | To | Trigger |
|------|----|---------| 
| SeedKeywords | Keywords | Add to workflow |
| Keywords | Clusters | Auto clustering |
| Clusters | ContentIdeas | Generate ideas |
| ContentIdeas | Tasks | Create tasks |
| Automation Stage 1 | Clusters | Automated clustering |
| Automation Stage 2 | ContentIdeas | Automated idea generation |

---

## Common Issues

| Issue | Cause | Fix |
|-------|-------|-----|
| Clustering fails | Less than 5 keywords | Ensure minimum keywords |
| Ideas not generating | Cluster has no keywords | Assign keywords to cluster |
| Keywords not showing | Wrong site/sector filter | Check active site/sector |
| Duplicate keywords | Same keyword added twice | Check seed_keyword reference |

---

## Planned Changes

| Feature | Status | Description |
|---------|--------|-------------|
| Keyword import improvements | 🔜 Planned | Better CSV parsing and validation |
| Cluster merging | 🔜 Planned | Merge similar clusters |
| Idea prioritization | 🔜 Planned | AI-based priority scoring |
