docs & ux improvmeents
This commit is contained in:
290
docs/10-MODULES/AUTOMATION.md
Normal file
290
docs/10-MODULES/AUTOMATION.md
Normal file
@@ -0,0 +1,290 @@
|
||||
# Automation Module
|
||||
|
||||
**Last Verified:** December 25, 2025
|
||||
**Status:** ✅ Active
|
||||
**Backend Path:** `backend/igny8_core/business/automation/`
|
||||
**Frontend Path:** `frontend/src/pages/Automation/`
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| What | File | Key Items |
|
||||
|------|------|-----------|
|
||||
| Models | `business/automation/models.py` | `AutomationConfig`, `AutomationRun` |
|
||||
| Service | `business/automation/services/automation_service.py` | `AutomationService` |
|
||||
| Logger | `business/automation/services/automation_logger.py` | `AutomationLogger` |
|
||||
| Celery Tasks | `business/automation/tasks.py` | `run_automation_task`, `check_scheduled_automations` |
|
||||
| Frontend | `pages/Automation/AutomationPage.tsx` | Main automation UI |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
The Automation module runs the complete 7-stage content pipeline automatically:
|
||||
|
||||
```
|
||||
Keywords → Clusters → Ideas → Tasks → Content → Image Prompts → Images → Review
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7-Stage Pipeline
|
||||
|
||||
| Stage | Name | AI Function | Credit Cost |
|
||||
|-------|------|-------------|-------------|
|
||||
| 1 | Keywords → Clusters | `AutoClusterFunction` | Per batch |
|
||||
| 2 | Clusters → Ideas | `GenerateIdeasFunction` | Per idea |
|
||||
| 3 | Ideas → Tasks | None (local) | None |
|
||||
| 4 | Tasks → Content | `GenerateContentFunction` | Per 100 words |
|
||||
| 5 | Content → Image Prompts | `GenerateImagePromptsFunction` | Per prompt |
|
||||
| 6 | Image Prompts → Images | `process_image_generation_queue` | Per image |
|
||||
| 7 | Manual Review Gate | None | None |
|
||||
|
||||
---
|
||||
|
||||
## Data Models
|
||||
|
||||
### AutomationConfig
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| site | FK | Target site |
|
||||
| enabled | Boolean | Enable/disable automation |
|
||||
| frequency | CharField | daily/weekly/monthly |
|
||||
| scheduled_time | TimeField | Time to run |
|
||||
| stage_1_batch_size | Integer | Keywords per batch |
|
||||
| stage_2_batch_size | Integer | Clusters per batch |
|
||||
| stage_3_batch_size | Integer | Ideas per batch |
|
||||
| stage_4_batch_size | Integer | Tasks per batch |
|
||||
| stage_5_batch_size | Integer | Content per batch |
|
||||
| stage_6_batch_size | Integer | Images per batch |
|
||||
| within_stage_delay | Integer | Seconds between batches |
|
||||
| between_stage_delay | Integer | Seconds between stages |
|
||||
| last_run_at | DateTime | Last execution |
|
||||
| next_run_at | DateTime | Next scheduled run |
|
||||
|
||||
### AutomationRun
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| config | FK | Parent config |
|
||||
| trigger_type | CharField | manual/scheduled |
|
||||
| status | CharField | running/paused/cancelled/completed/failed |
|
||||
| current_stage | Integer | Current stage (1-7) |
|
||||
| started_at | DateTime | Start time |
|
||||
| paused_at | DateTime | Pause time (nullable) |
|
||||
| resumed_at | DateTime | Resume time (nullable) |
|
||||
| cancelled_at | DateTime | Cancel time (nullable) |
|
||||
| completed_at | DateTime | Completion time (nullable) |
|
||||
| total_credits_used | Decimal | Total credits consumed |
|
||||
| stage_1_result | JSON | Stage 1 results |
|
||||
| stage_2_result | JSON | Stage 2 results |
|
||||
| stage_3_result | JSON | Stage 3 results |
|
||||
| stage_4_result | JSON | Stage 4 results |
|
||||
| stage_5_result | JSON | Stage 5 results |
|
||||
| stage_6_result | JSON | Stage 6 results |
|
||||
| stage_7_result | JSON | Stage 7 results |
|
||||
| error_message | TextField | Error details (nullable) |
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| GET | `/api/v1/automation/config/` | Get/create config | Get automation config |
|
||||
| PUT | `/api/v1/automation/update_config/` | Update config | Update settings |
|
||||
| POST | `/api/v1/automation/run_now/` | Start manual run | Start automation |
|
||||
| GET | `/api/v1/automation/current_run/` | Get current run | Run status/progress |
|
||||
| GET | `/api/v1/automation/pipeline_overview/` | Get pipeline | Stage status counts |
|
||||
| GET | `/api/v1/automation/current_processing/` | Get processing | Live processing status |
|
||||
| POST | `/api/v1/automation/pause/` | Pause run | Pause after current item |
|
||||
| POST | `/api/v1/automation/resume/` | Resume run | Resume from saved stage |
|
||||
| POST | `/api/v1/automation/cancel/` | Cancel run | Cancel after current item |
|
||||
| GET | `/api/v1/automation/history/` | Get history | Last 20 runs |
|
||||
| GET | `/api/v1/automation/logs/` | Get logs | Activity log for run |
|
||||
| GET | `/api/v1/automation/estimate/` | Get estimate | Credit estimate |
|
||||
|
||||
**Query Parameters:** All require `?site_id=`, run-specific require `?run_id=`
|
||||
|
||||
---
|
||||
|
||||
## Execution Flow
|
||||
|
||||
### Manual Run
|
||||
|
||||
1. User clicks "Run Now" on frontend
|
||||
2. Frontend calls `POST /automation/run_now/?site_id=X`
|
||||
3. Backend acquires cache lock `automation_lock_{site_id}`
|
||||
4. Estimates credits required (1.2x buffer)
|
||||
5. Validates balance >= estimate
|
||||
6. Creates `AutomationRun` record
|
||||
7. Enqueues `run_automation_task` Celery task
|
||||
8. Returns run ID immediately
|
||||
|
||||
### Stage Execution
|
||||
|
||||
For each stage (1-7):
|
||||
|
||||
1. Check `_check_should_stop()` (paused/cancelled?)
|
||||
2. Load items for processing
|
||||
3. Process in batches (respecting batch_size)
|
||||
4. For AI stages: Call AIEngine function
|
||||
5. Wait `within_stage_delay` between batches
|
||||
6. Save stage result JSON
|
||||
7. Wait `between_stage_delay` before next stage
|
||||
|
||||
### Stage Result Fields
|
||||
|
||||
**Stage 1 (Clustering):**
|
||||
```json
|
||||
{
|
||||
"keywords_processed": 150,
|
||||
"clusters_created": 12,
|
||||
"batches_run": 3,
|
||||
"credits_used": 45,
|
||||
"time_elapsed": 120,
|
||||
"skipped": false,
|
||||
"partial": false
|
||||
}
|
||||
```
|
||||
|
||||
**Stage 2 (Ideas):**
|
||||
```json
|
||||
{
|
||||
"clusters_processed": 12,
|
||||
"ideas_created": 36,
|
||||
"batches_run": 2,
|
||||
"credits_used": 72
|
||||
}
|
||||
```
|
||||
|
||||
**Stage 3 (Tasks):**
|
||||
```json
|
||||
{
|
||||
"ideas_processed": 36,
|
||||
"tasks_created": 36,
|
||||
"batches_run": 4
|
||||
}
|
||||
```
|
||||
|
||||
**Stage 4 (Content):**
|
||||
```json
|
||||
{
|
||||
"tasks_processed": 36,
|
||||
"content_created": 36,
|
||||
"total_words": 54000,
|
||||
"batches_run": 6,
|
||||
"credits_used": 540
|
||||
}
|
||||
```
|
||||
|
||||
**Stage 5 (Image Prompts):**
|
||||
```json
|
||||
{
|
||||
"content_processed": 36,
|
||||
"prompts_created": 180,
|
||||
"batches_run": 4,
|
||||
"credits_used": 36
|
||||
}
|
||||
```
|
||||
|
||||
**Stage 6 (Images):**
|
||||
```json
|
||||
{
|
||||
"images_processed": 180,
|
||||
"images_generated": 180,
|
||||
"batches_run": 18
|
||||
}
|
||||
```
|
||||
|
||||
**Stage 7 (Review):**
|
||||
```json
|
||||
{
|
||||
"ready_for_review": 36
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scheduling
|
||||
|
||||
**Celery Beat Task:** `check_scheduled_automations`
|
||||
**Frequency:** Hourly
|
||||
|
||||
**Logic:**
|
||||
1. Find configs where `enabled=True`
|
||||
2. Check if `next_run_at <= now`
|
||||
3. Check if no active run exists
|
||||
4. Start `run_automation_task` for eligible configs
|
||||
5. Update `next_run_at` based on frequency
|
||||
|
||||
---
|
||||
|
||||
## Lock Mechanism
|
||||
|
||||
**Purpose:** Prevent concurrent runs for same site
|
||||
|
||||
**Key:** `automation_lock_{site_id}`
|
||||
**Storage:** Redis cache
|
||||
**Acquired:** On run start
|
||||
**Released:** On completion/failure/cancel
|
||||
|
||||
---
|
||||
|
||||
## Credit Validation
|
||||
|
||||
Before starting:
|
||||
1. Calculate estimated credits for all stages
|
||||
2. Apply 1.2x safety buffer
|
||||
3. Compare with account balance
|
||||
4. Reject if balance < estimate
|
||||
|
||||
During execution:
|
||||
- Each AI stage checks credits before processing
|
||||
- Deductions happen after successful AI calls
|
||||
- `total_credits_used` accumulates across stages
|
||||
|
||||
---
|
||||
|
||||
## Frontend Integration
|
||||
|
||||
### AutomationPage Components
|
||||
|
||||
- **Config Panel:** Enable/disable, schedule settings
|
||||
- **Pipeline Cards:** Stage-by-stage status with pending counts
|
||||
- **Processing Card:** Live processing status during run
|
||||
- **Control Buttons:** Run Now, Pause, Resume, Cancel
|
||||
- **Activity Log:** Real-time log streaming
|
||||
- **History Table:** Past 20 runs with status
|
||||
|
||||
### Polling
|
||||
|
||||
- Every ~5s while run is running/paused
|
||||
- Fetches: `current_run`, `pipeline_overview`, `current_processing`
|
||||
- Lighter polling when idle
|
||||
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| "Already running" error | Lock exists from previous run | Wait or check if stuck |
|
||||
| Insufficient credits | Balance < 1.2x estimate | Add credits |
|
||||
| Stage skipped | No items to process | Check previous stages |
|
||||
| Run stuck | Worker crashed | Clear lock, restart |
|
||||
| Images not generating | Stage 5 didn't create prompts | Check stage 5 result |
|
||||
|
||||
---
|
||||
|
||||
## Planned Changes
|
||||
|
||||
| Feature | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| Progress bar accuracy | 🐛 Bug | Fix progress calculation based on actual stage |
|
||||
| Completed count display | 🐛 Bug | Fix count display in UI |
|
||||
| Stage skip configuration | 🔜 Planned | Allow skipping certain stages |
|
||||
| Notification on complete | 🔜 Planned | Email/webhook when done |
|
||||
254
docs/10-MODULES/BILLING.md
Normal file
254
docs/10-MODULES/BILLING.md
Normal file
@@ -0,0 +1,254 @@
|
||||
# Billing Module
|
||||
|
||||
**Last Verified:** December 25, 2025
|
||||
**Status:** ✅ Active
|
||||
**Backend Path:** `backend/igny8_core/modules/billing/` + `backend/igny8_core/business/billing/`
|
||||
**Frontend Path:** `frontend/src/pages/Billing/` + `frontend/src/pages/Account/`
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| What | File | Key Items |
|
||||
|------|------|-----------|
|
||||
| Models | `business/billing/models.py` | `CreditTransaction`, `CreditUsageLog`, `CreditCostConfig` |
|
||||
| Service | `business/billing/services/credit_service.py` | `CreditService` |
|
||||
| Views | `modules/billing/views.py` | `CreditBalanceViewSet`, `CreditUsageViewSet` |
|
||||
| Frontend | `pages/Account/PlansAndBillingPage.tsx` | Plans, credits, billing history |
|
||||
| Store | `store/billingStore.ts` | `useBillingStore` |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
The Billing module manages:
|
||||
- Credit balance and transactions
|
||||
- Usage tracking and limits
|
||||
- Plan enforcement
|
||||
- Payment processing
|
||||
|
||||
---
|
||||
|
||||
## Data Models
|
||||
|
||||
### CreditTransaction (Ledger)
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| transaction_type | CharField | purchase/subscription/refund/deduction/adjustment |
|
||||
| amount | Decimal | Positive (add) or negative (deduct) |
|
||||
| balance_after | Decimal | Balance after transaction |
|
||||
| description | CharField | Transaction description |
|
||||
| metadata | JSON | Additional data |
|
||||
| reference_id | CharField | External reference |
|
||||
| created_at | DateTime | Transaction time |
|
||||
|
||||
### CreditUsageLog (Analytics)
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| operation_type | CharField | clustering/idea_generation/content_generation/image_generation |
|
||||
| credits_used | Decimal | Credits consumed |
|
||||
| cost_usd | Decimal | USD cost |
|
||||
| model_used | CharField | AI model used |
|
||||
| tokens_in | Integer | Input tokens |
|
||||
| tokens_out | Integer | Output tokens |
|
||||
| content_type | FK | Related content type |
|
||||
| object_id | Integer | Related object ID |
|
||||
| metadata | JSON | Additional data |
|
||||
| created_at | DateTime | Usage time |
|
||||
|
||||
### CreditCostConfig
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| operation_type | CharField | Operation name |
|
||||
| credits_cost | Decimal | Credits per unit |
|
||||
| unit | CharField | per_request/per_100_words/per_200_words/per_item/per_image |
|
||||
| display_name | CharField | UI display name |
|
||||
| description | TextField | Description |
|
||||
| is_active | Boolean | Enable/disable |
|
||||
| previous_cost | Decimal | Previous cost (audit) |
|
||||
| updated_by | FK | Last updater |
|
||||
|
||||
---
|
||||
|
||||
## Credit Calculation Methods
|
||||
|
||||
### Method 1: Token-Based (Text Models)
|
||||
|
||||
Used for: Clustering, Ideas, Content Generation, Optimization
|
||||
|
||||
**Flow:**
|
||||
1. AI call completes
|
||||
2. OpenAI returns actual token usage
|
||||
3. Calculate: `total_tokens = input_tokens + output_tokens`
|
||||
4. Look up `CreditCostConfig` for operation
|
||||
5. Apply formula based on unit:
|
||||
- `per_100_words`: `credits = ceil(words / 100) * cost`
|
||||
- `per_item`: `credits = items * cost`
|
||||
6. Apply minimum credits
|
||||
7. Deduct from balance
|
||||
|
||||
### Method 2: Fixed Cost (Image Models)
|
||||
|
||||
Used for: Image Generation
|
||||
|
||||
**Flow:**
|
||||
1. Before AI call
|
||||
2. Calculate: `credits = num_images * cost_per_image`
|
||||
3. Check balance sufficient
|
||||
4. Deduct credits
|
||||
5. Then make AI call
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| GET | `/api/v1/billing/balance/` | `CreditBalanceViewSet.list` | Current balance + monthly usage |
|
||||
| GET | `/api/v1/billing/usage/` | `CreditUsageViewSet.list` | Usage log (paginated) |
|
||||
| GET | `/api/v1/billing/usage/summary/` | `CreditUsageViewSet.summary` | Aggregated by operation |
|
||||
| GET | `/api/v1/billing/usage/limits/` | `CreditUsageViewSet.limits` | Plan limits + current usage |
|
||||
| GET | `/api/v1/billing/transactions/` | `TransactionViewSet.list` | Transaction history |
|
||||
|
||||
---
|
||||
|
||||
## Credit Service API
|
||||
|
||||
### Check Credits
|
||||
|
||||
```python
|
||||
CreditService.check_credits(account, required_credits)
|
||||
# Raises InsufficientCreditsError if balance < required
|
||||
```
|
||||
|
||||
### Deduct Credits
|
||||
|
||||
```python
|
||||
CreditService.deduct_credits_for_operation(
|
||||
account=account,
|
||||
operation_type='content_generation',
|
||||
amount=word_count, # For per_word operations
|
||||
model='gpt-4o-mini',
|
||||
tokens_in=2500,
|
||||
tokens_out=1500,
|
||||
metadata={'content_id': 123}
|
||||
)
|
||||
```
|
||||
|
||||
### Add Credits
|
||||
|
||||
```python
|
||||
CreditService.add_credits(
|
||||
account=account,
|
||||
amount=1000,
|
||||
transaction_type='purchase',
|
||||
description='Credit package purchase'
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Plan Limits
|
||||
|
||||
### Hard Limits (Never Reset)
|
||||
|
||||
| Limit | Field | Description |
|
||||
|-------|-------|-------------|
|
||||
| Sites | `max_sites` | Maximum sites per account |
|
||||
| Users | `max_users` | Maximum team members |
|
||||
| Keywords | `max_keywords` | Total keywords allowed |
|
||||
| Clusters | `max_clusters` | Total clusters allowed |
|
||||
|
||||
### Monthly Limits (Reset on Billing Cycle)
|
||||
|
||||
| Limit | Field | Description |
|
||||
|-------|-------|-------------|
|
||||
| Content Ideas | `max_content_ideas` | Ideas per month |
|
||||
| Content Words | `max_content_words` | Words generated per month |
|
||||
| Basic Images | `max_images_basic` | Basic AI images per month |
|
||||
| Premium Images | `max_images_premium` | Premium AI images per month |
|
||||
| Image Prompts | `max_image_prompts` | Prompts per month |
|
||||
|
||||
---
|
||||
|
||||
## Usage Limits Panel
|
||||
|
||||
**Component:** `UsageLimitsPanel.tsx`
|
||||
|
||||
Displays:
|
||||
- Progress bars for each limit
|
||||
- Color coding: blue (safe), yellow (warning), red (critical)
|
||||
- Days until reset for monthly limits
|
||||
- Upgrade CTA when approaching limits
|
||||
|
||||
---
|
||||
|
||||
## Credit Costs Reference
|
||||
|
||||
Current costs (from `CreditCostConfig`):
|
||||
|
||||
| Operation | Unit | Default Cost |
|
||||
|-----------|------|--------------|
|
||||
| Clustering | per_request | 10 credits |
|
||||
| Idea Generation | per_item | 2 credits |
|
||||
| Content Generation | per_100_words | 5 credits |
|
||||
| Image Generation (Basic) | per_image | 3 credits |
|
||||
| Image Generation (Premium) | per_image | 5 credits |
|
||||
| Content Optimization | per_200_words | 3 credits |
|
||||
|
||||
---
|
||||
|
||||
## Frontend Pages
|
||||
|
||||
### Plans & Billing (`/account/plans`)
|
||||
|
||||
**Tabs:**
|
||||
1. **Current Plan** - Active plan, upgrade options
|
||||
2. **Credits Overview** - Balance, usage chart, cost breakdown
|
||||
3. **Purchase Credits** - Credit packages
|
||||
4. **Billing History** - Invoices and transactions
|
||||
|
||||
### Usage Analytics (`/account/usage`)
|
||||
|
||||
**Tabs:**
|
||||
1. **Limits & Usage** - Plan limits with progress bars
|
||||
2. **Activity** - Credit transaction history
|
||||
3. **API Usage** - API call statistics
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
| From | To | Trigger |
|
||||
|------|----|---------|
|
||||
| AIEngine | CreditService | Pre-check and post-deduct |
|
||||
| Automation | CreditService | Per-stage credit tracking |
|
||||
| Subscription | Account | Credit allocation |
|
||||
| Admin | CreditCostConfig | Price adjustments |
|
||||
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| 402 error | Insufficient credits | Add credits or reduce operation |
|
||||
| Usage not showing | Log not created | Check CreditService called |
|
||||
| Limits wrong | Cache stale | Clear cache, reload |
|
||||
| Monthly usage high | Automation running | Pause automation |
|
||||
|
||||
---
|
||||
|
||||
## Planned Changes
|
||||
|
||||
| Feature | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| AI Model Config database | 🔜 Planned | Move model pricing to database |
|
||||
| Budget alerts | 🔜 Planned | Email when approaching limits |
|
||||
| Usage forecasting | 🔜 Planned | Predict credit usage |
|
||||
| Overage billing | 🔜 Planned | Charge for overages instead of blocking |
|
||||
286
docs/10-MODULES/INTEGRATIONS.md
Normal file
286
docs/10-MODULES/INTEGRATIONS.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# Integrations Module
|
||||
|
||||
**Last Verified:** December 25, 2025
|
||||
**Status:** ✅ Active
|
||||
**Backend Path:** `backend/igny8_core/modules/integration/` + `backend/igny8_core/business/integration/`
|
||||
**Frontend Path:** `frontend/src/pages/Settings/IntegrationSettings.tsx`
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| What | File | Key Items |
|
||||
|------|------|-----------|
|
||||
| Models | `business/integration/models.py` | `SiteIntegration`, `SyncEvent` |
|
||||
| Views | `modules/integration/views.py` | `SiteIntegrationViewSet` |
|
||||
| Webhooks | `modules/integration/webhooks.py` | `wordpress_webhook` |
|
||||
| Services | `business/integration/services/*.py` | Sync services |
|
||||
| Frontend | `pages/Settings/IntegrationSettings.tsx` | Integration UI |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
The Integrations module manages:
|
||||
- WordPress site connections
|
||||
- Two-way content synchronization
|
||||
- Webhook handling
|
||||
- External platform integrations
|
||||
|
||||
---
|
||||
|
||||
## Data Models
|
||||
|
||||
### SiteIntegration
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| site | FK | IGNY8 site |
|
||||
| platform | CharField | wordpress/shopify |
|
||||
| site_url | URLField | External site URL |
|
||||
| api_key | CharField | WordPress Application Password |
|
||||
| username | CharField | WordPress username |
|
||||
| is_active | Boolean | Enable/disable |
|
||||
| sync_enabled | Boolean | Enable auto-sync |
|
||||
| last_sync_at | DateTime | Last sync time |
|
||||
| sync_status | CharField | idle/syncing/error |
|
||||
| metadata | JSON | Platform-specific data |
|
||||
| created_at | DateTime | Creation date |
|
||||
|
||||
### SyncEvent
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| integration | FK | Parent integration |
|
||||
| event_type | CharField | content_push/content_pull/webhook |
|
||||
| direction | CharField | igny8_to_wp/wp_to_igny8 |
|
||||
| content_type | CharField | post/page/product |
|
||||
| content_id | Integer | IGNY8 content ID |
|
||||
| external_id | Integer | WordPress post ID |
|
||||
| status | CharField | pending/success/failed |
|
||||
| error_message | TextField | Error details |
|
||||
| metadata | JSON | Additional data |
|
||||
| created_at | DateTime | Event time |
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| GET | `/api/v1/integration/` | `SiteIntegrationViewSet.list` | List integrations |
|
||||
| POST | `/api/v1/integration/` | `SiteIntegrationViewSet.create` | Create integration |
|
||||
| PUT | `/api/v1/integration/{id}/` | `SiteIntegrationViewSet.update` | Update integration |
|
||||
| DELETE | `/api/v1/integration/{id}/` | `SiteIntegrationViewSet.destroy` | Remove integration |
|
||||
| POST | `/api/v1/integration/{id}/test_connection/` | Test connection | Verify credentials |
|
||||
| POST | `/api/v1/integration/{id}/test_collection_connection/` | Test per-collection | Test specific content type |
|
||||
| POST | `/api/v1/integration/{id}/sync/` | Trigger sync | Start synchronization |
|
||||
| GET | `/api/v1/integration/{id}/sync_status/` | Get sync status | Current sync progress |
|
||||
| POST | `/api/v1/integration/{id}/update_structure/` | Update structure | Refresh site structure |
|
||||
| GET | `/api/v1/integration/{id}/content_types/` | Get content types | Available types + counts |
|
||||
| GET | `/api/v1/integration/{id}/sync_health/` | Get sync health | Sync statistics |
|
||||
| POST | `/api/v1/integration/site_sync/` | Site-level sync | Sync by site ID |
|
||||
|
||||
### Webhooks
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| POST | `/api/v1/integration/webhook/wordpress/` | `wordpress_webhook` | Receive WP updates |
|
||||
|
||||
---
|
||||
|
||||
## WordPress Integration
|
||||
|
||||
### Setup Flow
|
||||
|
||||
1. User enters WordPress site URL
|
||||
2. User creates Application Password in WordPress
|
||||
3. User enters credentials in IGNY8
|
||||
4. IGNY8 tests connection via WordPress REST API
|
||||
5. If successful, saves `SiteIntegration` record
|
||||
|
||||
### Required WordPress Setup
|
||||
|
||||
- WordPress 5.6+ (REST API enabled)
|
||||
- Application Passwords enabled
|
||||
- Pretty permalinks enabled
|
||||
- REST API accessible (no blocking plugins)
|
||||
|
||||
### Test Connection
|
||||
|
||||
**Endpoint:** `POST /integration/{id}/test_connection/`
|
||||
|
||||
**Flow:**
|
||||
1. Call WordPress `/wp-json/wp/v2/users/me`
|
||||
2. Verify authentication works
|
||||
3. Return user info and site capabilities
|
||||
|
||||
---
|
||||
|
||||
## Content Synchronization
|
||||
|
||||
### IGNY8 → WordPress (Push)
|
||||
|
||||
**Trigger:** User clicks "Publish to WordPress"
|
||||
|
||||
**Flow:**
|
||||
1. Content is in `approved` status
|
||||
2. Get `SiteIntegration` for content's site
|
||||
3. Build WordPress post payload:
|
||||
- title, content, excerpt, slug
|
||||
- status: `publish` or `draft`
|
||||
- categories, tags (mapped)
|
||||
- featured media (if image exists)
|
||||
4. Call WordPress REST API:
|
||||
- `POST /wp-json/wp/v2/posts` (new)
|
||||
- `PUT /wp-json/wp/v2/posts/{id}` (update)
|
||||
5. Store `wordpress_id` on Content
|
||||
6. Create `SyncEvent` record
|
||||
7. Update Content status to `published`
|
||||
|
||||
### WordPress → IGNY8 (Pull)
|
||||
|
||||
**Trigger:** Manual sync or webhook
|
||||
|
||||
**Flow:**
|
||||
1. Call WordPress `/wp-json/wp/v2/posts`
|
||||
2. For each post:
|
||||
- Check if exists in IGNY8 by `wordpress_id`
|
||||
- If exists: Update if modified
|
||||
- If new: Create Content record
|
||||
3. Sync taxonomies (categories, tags)
|
||||
4. Create `SyncEvent` records
|
||||
|
||||
### Webhook Handling
|
||||
|
||||
**WordPress Plugin** sends webhooks to IGNY8 when:
|
||||
- Post created/updated/deleted
|
||||
- Post status changed (draft → published)
|
||||
|
||||
**Webhook Payload:**
|
||||
```json
|
||||
{
|
||||
"action": "post_updated",
|
||||
"post_id": 123,
|
||||
"post_type": "post",
|
||||
"site_url": "https://example.com"
|
||||
}
|
||||
```
|
||||
|
||||
**IGNY8 Processing:**
|
||||
1. Validate webhook signature (optional)
|
||||
2. Find matching `SiteIntegration`
|
||||
3. Fetch full post from WordPress
|
||||
4. Update/create Content in IGNY8
|
||||
5. Create `SyncEvent` record
|
||||
|
||||
---
|
||||
|
||||
## Image Sync
|
||||
|
||||
### Push (IGNY8 → WordPress)
|
||||
|
||||
1. Image record has `image_url`
|
||||
2. Download image from URL
|
||||
3. Upload to WordPress Media Library
|
||||
4. Get WordPress attachment ID
|
||||
5. Set as featured image on post
|
||||
|
||||
### Pull (WordPress → IGNY8)
|
||||
|
||||
1. Get featured media ID from post
|
||||
2. Fetch media URL from WordPress
|
||||
3. Store URL in IGNY8 Images record
|
||||
|
||||
---
|
||||
|
||||
## Taxonomy Sync
|
||||
|
||||
### Categories
|
||||
|
||||
1. Get WordPress categories via `/wp-json/wp/v2/categories`
|
||||
2. Create `ContentTaxonomy` records (type=category)
|
||||
3. Store `wordpress_id` for mapping
|
||||
|
||||
### Tags
|
||||
|
||||
1. Get WordPress tags via `/wp-json/wp/v2/tags`
|
||||
2. Create `ContentTaxonomy` records (type=tag)
|
||||
3. Store `wordpress_id` for mapping
|
||||
|
||||
---
|
||||
|
||||
## Sync Status Tracking
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| idle | No sync in progress |
|
||||
| syncing | Sync currently running |
|
||||
| error | Last sync failed |
|
||||
|
||||
**Sync Health Metrics:**
|
||||
- Total synced posts
|
||||
- Last successful sync
|
||||
- Failed sync count
|
||||
- Pending items
|
||||
|
||||
---
|
||||
|
||||
## Frontend Pages
|
||||
|
||||
### Integration Settings (`/settings/integration`)
|
||||
|
||||
- Add new integration button
|
||||
- List of configured integrations
|
||||
- Status indicators (connected/error)
|
||||
- Test connection button
|
||||
- Sync now button
|
||||
- Sync status and history
|
||||
|
||||
### WordPress Sync Dashboard (`/sites/{id}/sync`)
|
||||
|
||||
- Detailed sync status
|
||||
- Content sync queue
|
||||
- Error log
|
||||
- Manual sync triggers
|
||||
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| Connection failed | Invalid credentials | Verify Application Password |
|
||||
| 401 Unauthorized | Password expired | Regenerate Application Password |
|
||||
| 403 Forbidden | REST API blocked | Check security plugins |
|
||||
| Images not syncing | CORS/URL issues | Verify image URLs accessible |
|
||||
| Categories missing | Not synced | Run sync_structure first |
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
### Credential Storage
|
||||
|
||||
- API keys encrypted at rest
|
||||
- Never exposed in API responses
|
||||
- Application Passwords rotatable
|
||||
|
||||
### Webhook Security
|
||||
|
||||
- Optional signature verification
|
||||
- Site URL validation
|
||||
- Rate limiting on webhook endpoint
|
||||
|
||||
---
|
||||
|
||||
## Planned Changes
|
||||
|
||||
| Feature | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| Shopify integration | 🔜 Planned | E-commerce platform support |
|
||||
| Ghost integration | 🔜 Planned | Ghost CMS support |
|
||||
| Webflow integration | 🔜 Planned | Webflow CMS support |
|
||||
| Scheduled sync | 🔜 Planned | Automatic periodic sync |
|
||||
| Conflict resolution | 🔜 Planned | Handle edit conflicts |
|
||||
183
docs/10-MODULES/LINKER.md
Normal file
183
docs/10-MODULES/LINKER.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# Linker Module
|
||||
|
||||
**Last Verified:** December 25, 2025
|
||||
**Status:** ⏸️ Inactive (Disabled by Default)
|
||||
**Backend Path:** `backend/igny8_core/modules/linker/`
|
||||
**Frontend Path:** `frontend/src/pages/Linker/`
|
||||
|
||||
---
|
||||
|
||||
## Module Status
|
||||
|
||||
| Aspect | Current State | Notes |
|
||||
|--------|---------------|-------|
|
||||
| Backend API | ✅ Implemented | Endpoints functional |
|
||||
| Frontend Pages | ✅ Implemented | UI exists |
|
||||
| Sidebar Nav | ⚠️ Conditional | Hidden when disabled |
|
||||
| Route Protection | ❌ Not Protected | Direct URL access still works |
|
||||
| Dashboard References | ❌ Not Hidden | May show in dashboard |
|
||||
| Default State | Disabled | `linker_enabled = True` in model, but typically disabled |
|
||||
|
||||
**⚠️ Pending Implementation:** Extend module disable to route-level protection and all page references.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| What | File | Key Items |
|
||||
|------|------|-----------|
|
||||
| Views | `modules/linker/views.py` | `LinkerViewSet` |
|
||||
| API | `modules/linker/urls.py` | Linker endpoints |
|
||||
| Frontend Pages | `pages/Linker/index.tsx` | Linker overview |
|
||||
| Frontend Pages | `pages/Linker/LinkerContent.tsx` | Content for linking |
|
||||
| API Client | `api/linker.api.ts` | `linkerApi` |
|
||||
| Module Control | `modules/system/settings_models.py` | `ModuleEnableSettings.linker_enabled` |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
The Linker module provides internal linking automation:
|
||||
- Identify link opportunities in content
|
||||
- Suggest relevant internal links
|
||||
- Auto-inject links into content body
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| POST | `/api/v1/linker/process/` | `LinkerViewSet.process` | Process single content for linking |
|
||||
| POST | `/api/v1/linker/batch_process/` | `LinkerViewSet.batch_process` | Process multiple content items |
|
||||
|
||||
### Process Request
|
||||
|
||||
```json
|
||||
{
|
||||
"content_id": 123,
|
||||
"max_links": 5,
|
||||
"anchor_strategy": "exact_match"
|
||||
}
|
||||
```
|
||||
|
||||
### Process Response
|
||||
|
||||
```json
|
||||
{
|
||||
"content_id": 123,
|
||||
"links_added": 3,
|
||||
"link_opportunities": [
|
||||
{
|
||||
"anchor_text": "SEO optimization",
|
||||
"target_url": "/blog/seo-guide/",
|
||||
"target_content_id": 456,
|
||||
"position": 234,
|
||||
"confidence": 0.85
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Business Logic
|
||||
|
||||
### Link Candidate Discovery
|
||||
|
||||
**Trigger:** User initiates linking process
|
||||
**Flow:**
|
||||
1. Load source content body
|
||||
2. Extract potential anchor phrases
|
||||
3. Find matching content by:
|
||||
- Keyword overlap
|
||||
- Title similarity
|
||||
- Same sector/industry
|
||||
4. Score candidates by relevance
|
||||
5. Filter to avoid over-linking
|
||||
|
||||
### Link Injection
|
||||
|
||||
**Trigger:** User approves link suggestions
|
||||
**Flow:**
|
||||
1. Locate anchor text in content
|
||||
2. Wrap in `<a>` tag with target URL
|
||||
3. Ensure no nested links
|
||||
4. Save updated content body
|
||||
|
||||
---
|
||||
|
||||
## Module Enable Control
|
||||
|
||||
### Backend Model
|
||||
|
||||
```python
|
||||
# modules/system/settings_models.py
|
||||
class ModuleEnableSettings(AccountBaseModel):
|
||||
linker_enabled = models.BooleanField(default=True)
|
||||
```
|
||||
|
||||
### Frontend Check
|
||||
|
||||
```typescript
|
||||
// layout/AppSidebar.tsx
|
||||
if (isModuleEnabled('linker')) {
|
||||
workflowItems.push({
|
||||
name: "Linker",
|
||||
path: "/linker/content",
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Current Limitation
|
||||
|
||||
Direct URL access to `/linker/*` routes still works even when module is disabled.
|
||||
|
||||
---
|
||||
|
||||
## Frontend Pages
|
||||
|
||||
### Linker Overview (`/linker`)
|
||||
|
||||
- Module overview
|
||||
- Quick stats
|
||||
- Start linking action
|
||||
|
||||
### Content for Linking (`/linker/content`)
|
||||
|
||||
- List of content available for linking
|
||||
- Link status indicators
|
||||
- Process button per content
|
||||
- Batch processing action
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
| From | To | Trigger |
|
||||
|------|----|---------|
|
||||
| Content | Linker | Manual process |
|
||||
| Linker | Content | Link injection |
|
||||
| Automation | Linker | Automated linking (future) |
|
||||
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| Module visible when disabled | Only sidebar hidden | Pending: route protection |
|
||||
| No link candidates | No matching content | Create more related content |
|
||||
| Links broken | Target content deleted | Validate target exists |
|
||||
|
||||
---
|
||||
|
||||
## Planned Changes
|
||||
|
||||
| Feature | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| Route-level protection | 🔜 Pending | Block access when module disabled |
|
||||
| Dashboard card hiding | 🔜 Pending | Hide from dashboard when disabled |
|
||||
| Automation integration | 🔜 Planned | Add to automation pipeline |
|
||||
| Link density control | 🔜 Planned | Prevent over-linking |
|
||||
| External link support | 🔜 Planned | Add outbound links |
|
||||
262
docs/10-MODULES/OPTIMIZER.md
Normal file
262
docs/10-MODULES/OPTIMIZER.md
Normal file
@@ -0,0 +1,262 @@
|
||||
# Optimizer Module
|
||||
|
||||
**Last Verified:** December 25, 2025
|
||||
**Status:** ⏸️ Inactive (Disabled by Default)
|
||||
**Backend Path:** `backend/igny8_core/modules/optimizer/` + `backend/igny8_core/business/optimization/`
|
||||
**Frontend Path:** `frontend/src/pages/Optimizer/`
|
||||
|
||||
---
|
||||
|
||||
## Module Status
|
||||
|
||||
| Aspect | Current State | Notes |
|
||||
|--------|---------------|-------|
|
||||
| Backend API | ✅ Implemented | Endpoints functional |
|
||||
| Business Logic | ✅ Implemented | Optimization service exists |
|
||||
| Frontend Pages | ✅ Implemented | UI exists |
|
||||
| Sidebar Nav | ⚠️ Conditional | Hidden when disabled |
|
||||
| Route Protection | ❌ Not Protected | Direct URL access still works |
|
||||
| Dashboard References | ❌ Not Hidden | May show in dashboard |
|
||||
| Default State | Disabled | `optimizer_enabled = True` in model, but typically disabled |
|
||||
|
||||
**⚠️ Pending Implementation:** Extend module disable to route-level protection and all page references.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| What | File | Key Items |
|
||||
|------|------|-----------|
|
||||
| Views | `modules/optimizer/views.py` | `OptimizerViewSet` |
|
||||
| Models | `business/optimization/models.py` | `OptimizationTask` |
|
||||
| Services | `business/optimization/services/*.py` | Optimization logic |
|
||||
| AI Function | `ai/functions/optimize.py` | `OptimizeContentFunction` |
|
||||
| Frontend Pages | `pages/Optimizer/index.tsx` | Optimizer overview |
|
||||
| Frontend Pages | `pages/Optimizer/OptimizerContent.tsx` | Select content |
|
||||
| Frontend Pages | `pages/Optimizer/OptimizerPreview.tsx` | Analysis preview |
|
||||
| API Client | `api/optimizer.api.ts` | `optimizerApi` |
|
||||
| Module Control | `modules/system/settings_models.py` | `ModuleEnableSettings.optimizer_enabled` |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
The Optimizer module provides AI-powered content optimization:
|
||||
- Analyze existing content for SEO improvements
|
||||
- Suggest and apply optimizations
|
||||
- Track before/after scores
|
||||
|
||||
---
|
||||
|
||||
## Data Models
|
||||
|
||||
### OptimizationTask
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| site | FK | Parent site |
|
||||
| sector | FK | Parent sector |
|
||||
| content | FK | Target content |
|
||||
| entry_point | CharField | auto/igny8/wordpress/external/manual |
|
||||
| status | CharField | pending/analyzing/optimizing/completed/failed |
|
||||
| original_score | Integer | Score before optimization |
|
||||
| optimized_score | Integer | Score after optimization |
|
||||
| original_content | TextField | Content before changes |
|
||||
| optimized_content | TextField | Content after changes |
|
||||
| suggestions | JSON | Optimization suggestions |
|
||||
| applied_changes | JSON | Changes that were applied |
|
||||
| credits_used | Decimal | Credits consumed |
|
||||
| created_at | DateTime | Creation date |
|
||||
| completed_at | DateTime | Completion date |
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| POST | `/api/v1/optimizer/optimize/` | `OptimizerViewSet.optimize` | Optimize single content |
|
||||
| POST | `/api/v1/optimizer/batch_optimize/` | `OptimizerViewSet.batch_optimize` | Optimize multiple items |
|
||||
| POST | `/api/v1/optimizer/analyze/` | `OptimizerViewSet.analyze` | Analyze without applying |
|
||||
|
||||
### Entry Points
|
||||
|
||||
| Entry Point | Description |
|
||||
|-------------|-------------|
|
||||
| `auto` | Auto-detect based on content source |
|
||||
| `igny8` | IGNY8-generated content |
|
||||
| `wordpress` | WordPress-synced content |
|
||||
| `external` | External platform content |
|
||||
| `manual` | Manual optimization trigger |
|
||||
|
||||
### Optimize Request
|
||||
|
||||
```json
|
||||
{
|
||||
"content_id": 123,
|
||||
"entry_point": "igny8",
|
||||
"optimization_goals": ["seo", "readability", "keyword_density"]
|
||||
}
|
||||
```
|
||||
|
||||
### Optimize Response
|
||||
|
||||
```json
|
||||
{
|
||||
"task_id": 456,
|
||||
"content_id": 123,
|
||||
"original_score": 65,
|
||||
"optimized_score": 85,
|
||||
"suggestions": [
|
||||
{
|
||||
"type": "keyword_density",
|
||||
"description": "Increase keyword 'SEO' usage",
|
||||
"applied": true
|
||||
},
|
||||
{
|
||||
"type": "meta_description",
|
||||
"description": "Meta description too short",
|
||||
"applied": true
|
||||
}
|
||||
],
|
||||
"credits_used": 15
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Business Logic
|
||||
|
||||
### Content Analysis
|
||||
|
||||
**Trigger:** User clicks "Analyze"
|
||||
**Credit Cost:** None (analysis only)
|
||||
|
||||
**Checks:**
|
||||
- Keyword density and distribution
|
||||
- Meta title and description optimization
|
||||
- Heading structure (H1, H2, H3)
|
||||
- Readability score
|
||||
- Content length
|
||||
- Internal/external link count
|
||||
- Image alt text presence
|
||||
|
||||
### Content Optimization (AI)
|
||||
|
||||
**Trigger:** User clicks "Optimize"
|
||||
**AI Function:** `OptimizeContentFunction`
|
||||
**Credit Cost:** Per 200 words
|
||||
|
||||
**Flow:**
|
||||
1. Load content with metadata
|
||||
2. Analyze current state
|
||||
3. AIEngine executes `OptimizeContentFunction`:
|
||||
- Reviews content against SEO best practices
|
||||
- Suggests improvements
|
||||
- Rewrites sections if needed
|
||||
4. Create `OptimizationTask` record
|
||||
5. Save original and optimized versions
|
||||
6. Return comparison view
|
||||
|
||||
---
|
||||
|
||||
## Module Enable Control
|
||||
|
||||
### Backend Model
|
||||
|
||||
```python
|
||||
# modules/system/settings_models.py
|
||||
class ModuleEnableSettings(AccountBaseModel):
|
||||
optimizer_enabled = models.BooleanField(default=True)
|
||||
```
|
||||
|
||||
### Frontend Check
|
||||
|
||||
```typescript
|
||||
// layout/AppSidebar.tsx
|
||||
if (isModuleEnabled('optimizer')) {
|
||||
workflowItems.push({
|
||||
name: "Optimizer",
|
||||
path: "/optimizer/content",
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Current Limitation
|
||||
|
||||
Direct URL access to `/optimizer/*` routes still works even when module is disabled.
|
||||
|
||||
---
|
||||
|
||||
## Frontend Pages
|
||||
|
||||
### Optimizer Overview (`/optimizer`)
|
||||
|
||||
- Module overview
|
||||
- Quick stats
|
||||
- Recent optimizations
|
||||
|
||||
### Select Content (`/optimizer/content`)
|
||||
|
||||
- List of content available for optimization
|
||||
- Filter by score, status
|
||||
- Start analysis button
|
||||
- Batch optimize action
|
||||
|
||||
### Analysis Preview (`/optimizer/preview`)
|
||||
|
||||
- Side-by-side comparison
|
||||
- Suggestion list
|
||||
- Accept/reject changes
|
||||
- Apply optimization button
|
||||
|
||||
---
|
||||
|
||||
## Optimization Scoring
|
||||
|
||||
| Metric | Weight | Description |
|
||||
|--------|--------|-------------|
|
||||
| Keyword Density | 20% | Target 1-3% density |
|
||||
| Meta Quality | 15% | Title 50-60 chars, desc 150-160 chars |
|
||||
| Heading Structure | 15% | Proper H1-H6 hierarchy |
|
||||
| Readability | 15% | Flesch-Kincaid score |
|
||||
| Content Length | 10% | Meets word count target |
|
||||
| Internal Links | 10% | 2-5 internal links |
|
||||
| Image Optimization | 10% | Alt text, sizing |
|
||||
| Mobile Friendly | 5% | No wide elements |
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
| From | To | Trigger |
|
||||
|------|----|---------|
|
||||
| Content | Optimizer | Manual analysis/optimize |
|
||||
| WordPress | Optimizer | Synced content optimization |
|
||||
| Optimizer | Content | Apply changes |
|
||||
| Automation | Optimizer | Automated optimization (future) |
|
||||
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| Module visible when disabled | Only sidebar hidden | Pending: route protection |
|
||||
| Optimization not improving | Content already good | Check original score |
|
||||
| High credit usage | Large content | Optimize sections |
|
||||
| Changes not saving | Apply not clicked | Click "Apply Changes" |
|
||||
|
||||
---
|
||||
|
||||
## Planned Changes
|
||||
|
||||
| Feature | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| Route-level protection | 🔜 Pending | Block access when module disabled |
|
||||
| Dashboard card hiding | 🔜 Pending | Hide from dashboard when disabled |
|
||||
| Automation integration | 🔜 Planned | Add to automation pipeline |
|
||||
| Partial optimization | 🔜 Planned | Optimize specific sections only |
|
||||
| Competitor analysis | 🔜 Planned | Compare against top-ranking content |
|
||||
| A/B testing | 🔜 Planned | Track performance of optimizations |
|
||||
231
docs/10-MODULES/PLANNER.md
Normal file
231
docs/10-MODULES/PLANNER.md
Normal file
@@ -0,0 +1,231 @@
|
||||
# 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 |
|
||||
184
docs/10-MODULES/PUBLISHER.md
Normal file
184
docs/10-MODULES/PUBLISHER.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# Publisher Module
|
||||
|
||||
**Last Verified:** December 25, 2025
|
||||
**Status:** ✅ Active
|
||||
**Backend Path:** `backend/igny8_core/modules/publisher/` + `backend/igny8_core/business/publishing/`
|
||||
**Frontend Path:** N/A (API-only module)
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| What | File | Key Items |
|
||||
|------|------|-----------|
|
||||
| Views | `modules/publisher/views.py` | `PublishingRecordViewSet`, `DeploymentViewSet`, `PublishContentViewSet` |
|
||||
| Models | `business/publishing/models.py` | `PublishingRecord`, `DeploymentRecord` |
|
||||
| Services | `business/publishing/services/*.py` | Publishing orchestration |
|
||||
| URLs | `modules/publisher/urls.py` | Publisher endpoints |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
The Publisher module manages:
|
||||
- Content publishing pipeline
|
||||
- Publishing record tracking
|
||||
- Deployment management
|
||||
- Multi-destination publishing
|
||||
|
||||
---
|
||||
|
||||
## Data Models
|
||||
|
||||
### PublishingRecord
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| site | FK | Parent site |
|
||||
| content | FK | Source content |
|
||||
| destination | CharField | wordpress/ghost/webflow |
|
||||
| external_id | CharField | ID on destination platform |
|
||||
| external_url | URLField | Published URL |
|
||||
| status | CharField | pending/published/failed/retracted |
|
||||
| published_at | DateTime | Publication time |
|
||||
| metadata | JSON | Additional data |
|
||||
| created_at | DateTime | Record creation |
|
||||
|
||||
### DeploymentRecord
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| site | FK | Target site |
|
||||
| deployment_type | CharField | full/incremental |
|
||||
| status | CharField | pending/deploying/completed/failed |
|
||||
| items_deployed | Integer | Number of items |
|
||||
| started_at | DateTime | Start time |
|
||||
| completed_at | DateTime | Completion time |
|
||||
| error_log | TextField | Errors encountered |
|
||||
| metadata | JSON | Deployment details |
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| GET | `/api/v1/publisher/records/` | `PublishingRecordViewSet.list` | List publishing records |
|
||||
| POST | `/api/v1/publisher/records/` | `PublishingRecordViewSet.create` | Create record |
|
||||
| GET | `/api/v1/publisher/deployments/` | `DeploymentViewSet.list` | List deployments |
|
||||
| POST | `/api/v1/publisher/publish/` | `PublishContentViewSet.publish` | Publish content |
|
||||
| GET | `/api/v1/publisher/publish/status/` | `PublishContentViewSet.status` | Get publishing status |
|
||||
| GET | `/api/v1/publisher/site-definition/` | `SiteDefinitionViewSet.list` | Public site definitions |
|
||||
|
||||
---
|
||||
|
||||
## Publishing Flow
|
||||
|
||||
### Single Content Publish
|
||||
|
||||
**Trigger:** User clicks "Publish" or API call
|
||||
**Flow:**
|
||||
1. Validate content is in publishable state
|
||||
2. Get site integration credentials
|
||||
3. Transform content for destination:
|
||||
- Format HTML for platform
|
||||
- Process images
|
||||
- Map taxonomies
|
||||
4. Push to destination API
|
||||
5. Create `PublishingRecord` with external ID
|
||||
6. Update Content status to `published`
|
||||
|
||||
### Batch Deployment
|
||||
|
||||
**Trigger:** Deployment action
|
||||
**Flow:**
|
||||
1. Create `DeploymentRecord`
|
||||
2. Gather all pending content
|
||||
3. Process each item:
|
||||
- Publish to destination
|
||||
- Create publishing record
|
||||
- Update content status
|
||||
4. Update deployment status
|
||||
5. Log any errors
|
||||
|
||||
---
|
||||
|
||||
## Destination Adapters
|
||||
|
||||
### WordPress Adapter
|
||||
|
||||
- Uses WordPress REST API
|
||||
- Supports posts, pages, custom post types
|
||||
- Handles media upload
|
||||
- Maps categories/tags
|
||||
|
||||
### Ghost Adapter (Planned)
|
||||
|
||||
- Ghost Admin API integration
|
||||
- Post publishing
|
||||
- Image handling
|
||||
|
||||
### Webflow Adapter (Planned)
|
||||
|
||||
- Webflow CMS API
|
||||
- Collection item publishing
|
||||
- Asset management
|
||||
|
||||
---
|
||||
|
||||
## Publishing States
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| pending | Ready to publish |
|
||||
| published | Successfully published |
|
||||
| failed | Publishing failed |
|
||||
| retracted | Unpublished/removed |
|
||||
|
||||
---
|
||||
|
||||
## Site Definition Endpoint
|
||||
|
||||
**Purpose:** Public endpoint for headless CMS use cases
|
||||
|
||||
Returns site structure for external consumption:
|
||||
- Site metadata
|
||||
- Available taxonomies
|
||||
- Content types
|
||||
- URL structure
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
| From | To | Trigger |
|
||||
|------|----|---------|
|
||||
| Writer | Publisher | Publish action |
|
||||
| Automation Stage 7 | Publisher | Auto-publish (future) |
|
||||
| Publisher | Integrations | Destination APIs |
|
||||
| Publisher | Content | Status updates |
|
||||
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| Publish failed | Invalid credentials | Check integration settings |
|
||||
| Duplicate posts | Published twice | Check existing publishing record |
|
||||
| Images missing | Upload failed | Check media library access |
|
||||
| Wrong category | Mapping issue | Verify taxonomy sync |
|
||||
|
||||
---
|
||||
|
||||
## Planned Changes
|
||||
|
||||
| Feature | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| Ghost integration | 🔜 Planned | Ghost CMS publishing |
|
||||
| Webflow integration | 🔜 Planned | Webflow publishing |
|
||||
| Scheduled publishing | 🔜 Planned | Future-date publishing |
|
||||
| Republish detection | 🔜 Planned | Detect and handle updates |
|
||||
| Publishing queue | 🔜 Planned | Batch publishing with queue |
|
||||
286
docs/10-MODULES/SYSTEM-SETTINGS.md
Normal file
286
docs/10-MODULES/SYSTEM-SETTINGS.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# System Settings Module
|
||||
|
||||
**Last Verified:** December 25, 2025
|
||||
**Status:** ✅ Active
|
||||
**Backend Path:** `backend/igny8_core/modules/system/`
|
||||
**Frontend Path:** `frontend/src/pages/Settings/`
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| What | File | Key Items |
|
||||
|------|------|-----------|
|
||||
| Global Models | `modules/system/global_settings_models.py` | `GlobalIntegrationSettings`, `GlobalAIPrompt`, `GlobalAuthorProfile` |
|
||||
| Account Models | `modules/system/settings_models.py` | `ModuleEnableSettings`, `IntegrationSettings`, `AISettings` |
|
||||
| Views | `modules/system/settings_views.py` | Settings ViewSets |
|
||||
| Integration Views | `modules/system/integration_views.py` | AI integration settings |
|
||||
| Frontend | `pages/Settings/*.tsx` | Settings pages |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
The System Settings module manages:
|
||||
- Platform-wide global settings (API keys, defaults)
|
||||
- Per-account settings overrides
|
||||
- AI prompts and configurations
|
||||
- Module enable/disable
|
||||
- Author profiles and content strategies
|
||||
|
||||
---
|
||||
|
||||
## Settings Hierarchy
|
||||
|
||||
```
|
||||
Global Settings (Platform-wide)
|
||||
↓
|
||||
Account Settings (Per-account overrides)
|
||||
↓
|
||||
User Settings (Per-user preferences)
|
||||
```
|
||||
|
||||
**Priority:** User > Account > Global
|
||||
|
||||
---
|
||||
|
||||
## Global Settings Models
|
||||
|
||||
### GlobalIntegrationSettings (Singleton)
|
||||
|
||||
**Admin:** `/admin/system/globalintegrationsettings/`
|
||||
**Purpose:** Platform-wide API keys and defaults
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| openai_api_key | CharField | OpenAI API key (all accounts) |
|
||||
| openai_model | CharField | Default model (gpt-4o-mini) |
|
||||
| openai_temperature | Float | Default temperature (0.7) |
|
||||
| openai_max_tokens | Integer | Default max tokens (8192) |
|
||||
| dalle_api_key | CharField | DALL-E API key |
|
||||
| dalle_model | CharField | Default model (dall-e-3) |
|
||||
| dalle_size | CharField | Default size (1024x1024) |
|
||||
| dalle_quality | CharField | Default quality (standard) |
|
||||
| dalle_style | CharField | Default style (vivid) |
|
||||
| anthropic_api_key | CharField | Anthropic API key |
|
||||
| runware_api_key | CharField | Runware API key |
|
||||
|
||||
**Critical:** This is a singleton (only 1 record, pk=1). All accounts use these API keys.
|
||||
|
||||
### GlobalAIPrompt
|
||||
|
||||
**Admin:** `/admin/system/globalaiprompt/`
|
||||
**Purpose:** Default AI prompt templates
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| prompt_type | CharField | clustering/ideas/content_generation/etc. |
|
||||
| prompt_value | TextField | The actual prompt text |
|
||||
| description | TextField | What this prompt does |
|
||||
| variables | JSON | Available variables ({keyword}, {industry}) |
|
||||
| version | Integer | Prompt version |
|
||||
| is_active | Boolean | Enable/disable |
|
||||
|
||||
### GlobalAuthorProfile
|
||||
|
||||
**Admin:** `/admin/system/globalauthorprofile/`
|
||||
**Purpose:** Default author persona templates
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| name | CharField | Profile name |
|
||||
| description | TextField | Description |
|
||||
| tone | CharField | professional/casual/technical |
|
||||
| language | CharField | en/es/fr |
|
||||
| structure_template | JSON | Content structure config |
|
||||
| category | CharField | saas/ecommerce/blog/technical |
|
||||
| is_active | Boolean | Enable/disable |
|
||||
|
||||
---
|
||||
|
||||
## Account Settings Models
|
||||
|
||||
### IntegrationSettings
|
||||
|
||||
**Purpose:** Per-account AI model overrides (NOT API keys)
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| integration_type | CharField | openai/runware/image_generation |
|
||||
| config | JSON | Model, temperature, max_tokens overrides |
|
||||
| is_active | Boolean | Enable/disable |
|
||||
|
||||
**Important:**
|
||||
- Free plan cannot create overrides
|
||||
- Starter/Growth/Scale can override model/settings
|
||||
- API keys ALWAYS come from GlobalIntegrationSettings
|
||||
|
||||
### ModuleEnableSettings
|
||||
|
||||
**Purpose:** Enable/disable modules per account
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| planner_enabled | Boolean | Enable Planner |
|
||||
| writer_enabled | Boolean | Enable Writer |
|
||||
| thinker_enabled | Boolean | Enable Thinker (AI settings) |
|
||||
| automation_enabled | Boolean | Enable Automation |
|
||||
| site_builder_enabled | Boolean | Enable Site Builder |
|
||||
| linker_enabled | Boolean | Enable Linker |
|
||||
| optimizer_enabled | Boolean | Enable Optimizer |
|
||||
| publisher_enabled | Boolean | Enable Publisher |
|
||||
|
||||
**Current Implementation:**
|
||||
- Controls sidebar navigation visibility
|
||||
- ⚠️ **Pending:** Extend to other pages and references
|
||||
|
||||
### AIPrompt (Account-Level)
|
||||
|
||||
**Purpose:** Per-account prompt customizations
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| prompt_type | CharField | Prompt type |
|
||||
| prompt_value | TextField | Current prompt (custom or default) |
|
||||
| default_prompt | TextField | Original default (for reset) |
|
||||
| is_customized | Boolean | True if user modified |
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Integration Settings
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| GET | `/api/v1/system/settings/integrations/openai/` | Get OpenAI settings | Get current model/params |
|
||||
| PUT | `/api/v1/system/settings/integrations/openai/` | Save OpenAI settings | Save overrides |
|
||||
| GET | `/api/v1/system/settings/integrations/image_generation/` | Get image settings | Get DALL-E/Runware settings |
|
||||
| PUT | `/api/v1/system/settings/integrations/image_generation/` | Save image settings | Save overrides |
|
||||
| POST | `/api/v1/system/settings/integrations/test/` | Test connection | Test API connectivity |
|
||||
|
||||
### Prompts
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| GET | `/api/v1/system/prompts/` | List prompts | Get all prompts |
|
||||
| GET | `/api/v1/system/prompts/{type}/` | Get prompt | Get specific prompt |
|
||||
| PUT | `/api/v1/system/prompts/{type}/` | Save prompt | Save customization |
|
||||
| POST | `/api/v1/system/prompts/{type}/reset/` | Reset prompt | Reset to default |
|
||||
|
||||
### Module Settings
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| GET | `/api/v1/system/modules/` | Get module settings | Get enable/disable state |
|
||||
| PUT | `/api/v1/system/modules/` | Save module settings | Update enabled modules |
|
||||
|
||||
---
|
||||
|
||||
## Settings Flow (Frontend → Backend)
|
||||
|
||||
### Getting OpenAI Settings
|
||||
|
||||
1. Frontend requests: `GET /system/settings/integrations/openai/`
|
||||
2. Backend checks account's `IntegrationSettings`
|
||||
3. Gets global defaults from `GlobalIntegrationSettings`
|
||||
4. Merges: account overrides > global defaults
|
||||
5. Returns (NEVER includes API keys):
|
||||
```json
|
||||
{
|
||||
"model": "gpt-4o-mini",
|
||||
"temperature": 0.7,
|
||||
"max_tokens": 8192,
|
||||
"using_global": true
|
||||
}
|
||||
```
|
||||
|
||||
### Saving OpenAI Settings
|
||||
|
||||
1. Frontend sends: `PUT /system/settings/integrations/openai/`
|
||||
2. Backend STRIPS any API key fields (security)
|
||||
3. Validates account plan allows overrides
|
||||
4. Saves to `IntegrationSettings.config`
|
||||
5. Returns updated settings
|
||||
|
||||
---
|
||||
|
||||
## Module Enable/Disable
|
||||
|
||||
### How It Works (Current)
|
||||
|
||||
1. On app load, frontend fetches module settings
|
||||
2. `useModuleStore.isModuleEnabled(name)` checks state
|
||||
3. `AppSidebar.tsx` conditionally renders menu items:
|
||||
|
||||
```typescript
|
||||
if (isModuleEnabled('linker')) {
|
||||
workflowItems.push({
|
||||
name: "Linker",
|
||||
path: "/linker/content",
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Current Limitations (⚠️ Pending Implementation)
|
||||
|
||||
- Only hides sidebar menu items
|
||||
- Direct URL access still works
|
||||
- Other page references still show module links
|
||||
- Dashboard cards may still show disabled modules
|
||||
|
||||
### Required Extension
|
||||
|
||||
Need to add `ModuleGuard` component to:
|
||||
- Route-level protection
|
||||
- Dashboard cards/widgets
|
||||
- Cross-module references
|
||||
- Settings page links
|
||||
|
||||
---
|
||||
|
||||
## Frontend Pages
|
||||
|
||||
### AI Settings (`/settings/ai`)
|
||||
|
||||
- OpenAI model selection
|
||||
- Temperature and max tokens
|
||||
- Image generation settings
|
||||
- Test connection button
|
||||
|
||||
### Prompts (`/thinker/prompts`)
|
||||
|
||||
- List all prompt types
|
||||
- Edit prompt text
|
||||
- Reset to default
|
||||
- Variable reference
|
||||
|
||||
### Module Settings (Admin Only)
|
||||
|
||||
- Enable/disable modules
|
||||
- Per-account configuration
|
||||
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| Settings not saving | Plan restriction | Upgrade plan |
|
||||
| API key exposed | Security flaw | Should never happen - check code |
|
||||
| Module still visible | Cache stale | Clear cache, reload |
|
||||
| Prompt reset not working | default_prompt missing | Re-run migration |
|
||||
|
||||
---
|
||||
|
||||
## Planned Changes
|
||||
|
||||
| Feature | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| Module guard extension | 🔜 Pending | Extend disable to all pages, not just sidebar |
|
||||
| AIModelConfig database | 🔜 Planned | Move model pricing to database |
|
||||
| Strategy templates | 🔜 Planned | Global strategy library |
|
||||
| Per-user preferences | 🔜 Planned | User-level setting overrides |
|
||||
293
docs/10-MODULES/WRITER.md
Normal file
293
docs/10-MODULES/WRITER.md
Normal file
@@ -0,0 +1,293 @@
|
||||
# Writer Module
|
||||
|
||||
**Last Verified:** December 25, 2025
|
||||
**Status:** ✅ Active
|
||||
**Backend Path:** `backend/igny8_core/modules/writer/`
|
||||
**Frontend Path:** `frontend/src/pages/Writer/`
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| What | File | Key Items |
|
||||
|------|------|-----------|
|
||||
| Models | `modules/writer/models.py` | `Tasks`, `Content`, `Images`, `ContentTaxonomy` |
|
||||
| Views | `modules/writer/views.py` | `TaskViewSet`, `ContentViewSet`, `ImageViewSet` |
|
||||
| AI Functions | `ai/functions/content.py` | `GenerateContentFunction` |
|
||||
| AI Functions | `ai/functions/images.py` | `GenerateImagesFunction`, `GenerateImagePromptsFunction` |
|
||||
| Frontend Pages | `pages/Writer/Tasks.tsx` | Task management |
|
||||
| Frontend Pages | `pages/Writer/Content.tsx` | Content listing |
|
||||
| Frontend Pages | `pages/Writer/ContentViewer.tsx` | Content preview/edit |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
The Writer module manages the content creation pipeline:
|
||||
|
||||
```
|
||||
ContentIdeas → Tasks → Content → Images → Review → Publish
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Models
|
||||
|
||||
### Tasks
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| site | FK | Parent site |
|
||||
| sector | FK | Parent sector |
|
||||
| content_idea | FK | Source idea (nullable) |
|
||||
| title | CharField | Task/content title |
|
||||
| description | TextField | Task brief |
|
||||
| target_keywords | JSON | Keywords to target |
|
||||
| content_type | CharField | blog_post/guide/comparison/etc. |
|
||||
| word_count_target | Integer | Target word count |
|
||||
| status | CharField | pending/in_progress/completed/cancelled |
|
||||
| assigned_to | FK | Assigned user (nullable) |
|
||||
| due_date | DateTime | Due date (nullable) |
|
||||
| priority | Integer | Priority level |
|
||||
| created_at | DateTime | Creation date |
|
||||
|
||||
### Content
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| site | FK | Parent site |
|
||||
| sector | FK | Parent sector |
|
||||
| task | FK | Source task (nullable) |
|
||||
| title | CharField | Content title |
|
||||
| slug | SlugField | URL slug |
|
||||
| content_body | TextField | HTML content |
|
||||
| excerpt | TextField | Short summary |
|
||||
| meta_title | CharField | SEO meta title |
|
||||
| meta_description | CharField | SEO meta description |
|
||||
| word_count | Integer | Actual word count |
|
||||
| status | CharField | draft/review/approved/published |
|
||||
| content_type | CharField | post/page/product |
|
||||
| content_structure | CharField | article/guide/comparison/review/listicle |
|
||||
| source | CharField | igny8/wordpress/manual |
|
||||
| wordpress_id | Integer | WP post ID (if synced) |
|
||||
| published_at | DateTime | Publication date |
|
||||
| created_at | DateTime | Creation date |
|
||||
|
||||
### Images
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| site | FK | Parent site |
|
||||
| sector | FK | Parent sector |
|
||||
| content | FK | Parent content |
|
||||
| image_type | CharField | featured/desktop/mobile/in_article |
|
||||
| prompt | TextField | Generation prompt |
|
||||
| image_url | URLField | Image URL |
|
||||
| alt_text | CharField | Alt text for SEO |
|
||||
| status | CharField | pending/generating/completed/failed |
|
||||
| position | Integer | Order for in-article images |
|
||||
| provider | CharField | dalle/runware |
|
||||
| model | CharField | dall-e-3/runware:97@1 |
|
||||
| created_at | DateTime | Creation date |
|
||||
|
||||
### ContentTaxonomy
|
||||
|
||||
| Field | Type | Purpose |
|
||||
|-------|------|---------|
|
||||
| account | FK | Owner account |
|
||||
| site | FK | Parent site |
|
||||
| name | CharField | Category/tag name |
|
||||
| slug | SlugField | URL slug |
|
||||
| taxonomy_type | CharField | category/tag |
|
||||
| parent | FK | Parent taxonomy (for hierarchy) |
|
||||
| description | TextField | Description |
|
||||
| wordpress_id | Integer | WP term ID (if synced) |
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Tasks
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| GET | `/api/v1/writer/tasks/` | `TaskViewSet.list` | List tasks |
|
||||
| POST | `/api/v1/writer/tasks/` | `TaskViewSet.create` | Create task |
|
||||
| POST | `/api/v1/writer/tasks/bulk_create/` | `TaskViewSet.bulk_create` | Create multiple tasks |
|
||||
| POST | `/api/v1/writer/tasks/{id}/generate_content/` | `TaskViewSet.generate_content` | AI content generation |
|
||||
|
||||
### Content
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| GET | `/api/v1/writer/content/` | `ContentViewSet.list` | List content |
|
||||
| POST | `/api/v1/writer/content/` | `ContentViewSet.create` | Create content manually |
|
||||
| PUT | `/api/v1/writer/content/{id}/` | `ContentViewSet.update` | Update content |
|
||||
| POST | `/api/v1/writer/content/{id}/update_content/` | `ContentViewSet.update_content` | Update with validation |
|
||||
| POST | `/api/v1/writer/content/{id}/generate_images/` | `ContentViewSet.generate_images` | Generate images |
|
||||
| POST | `/api/v1/writer/content/{id}/publish_to_wordpress/` | `ContentViewSet.publish_to_wordpress` | Publish to WP |
|
||||
|
||||
### Images
|
||||
|
||||
| Method | Path | Handler | Purpose |
|
||||
|--------|------|---------|---------|
|
||||
| GET | `/api/v1/writer/images/` | `ImageViewSet.list` | List images |
|
||||
| POST | `/api/v1/writer/images/generate_for_content/` | `ImageViewSet.generate_for_content` | Generate images |
|
||||
| POST | `/api/v1/writer/images/regenerate/` | `ImageViewSet.regenerate` | Regenerate image |
|
||||
|
||||
---
|
||||
|
||||
## Business Logic
|
||||
|
||||
### Content Generation (AI)
|
||||
|
||||
**Trigger:** User clicks "Generate" on task
|
||||
**AI Function:** `GenerateContentFunction`
|
||||
**Credit Cost:** Per 100 words generated
|
||||
|
||||
**Flow:**
|
||||
1. User has task with title, keywords, word count target
|
||||
2. Frontend calls `POST /tasks/{id}/generate_content/`
|
||||
3. Backend validates task and credits
|
||||
4. AIEngine executes `GenerateContentFunction`:
|
||||
- Loads account's AI prompts and strategy
|
||||
- Sends to GPT-4 with structured output
|
||||
- Receives HTML content with proper structure
|
||||
5. Creates `Content` record linked to task
|
||||
6. Updates task status to `completed`
|
||||
7. Returns content for review
|
||||
|
||||
### Image Prompt Generation (AI)
|
||||
|
||||
**Trigger:** Part of content generation or explicit
|
||||
**AI Function:** `GenerateImagePromptsFunction`
|
||||
**Credit Cost:** Per prompt
|
||||
|
||||
**Flow:**
|
||||
1. Content exists with body
|
||||
2. AI analyzes content sections
|
||||
3. Generates prompts for:
|
||||
- Featured image (1)
|
||||
- In-article images (configurable count)
|
||||
4. Creates `Images` records with prompts, status=pending
|
||||
|
||||
### Image Generation (AI)
|
||||
|
||||
**Trigger:** User clicks "Generate Images" or automation
|
||||
**AI Function:** `GenerateImagesFunction`
|
||||
**Credit Cost:** Per image
|
||||
|
||||
**Flow:**
|
||||
1. Image record exists with prompt, status=pending
|
||||
2. Backend calls DALL-E or Runware API
|
||||
3. Receives image URL
|
||||
4. Updates `Images` record with URL, status=completed
|
||||
|
||||
### WordPress Publishing
|
||||
|
||||
**Trigger:** User clicks "Publish to WordPress"
|
||||
**Credit Cost:** None
|
||||
|
||||
**Flow:**
|
||||
1. Content is in `approved` status
|
||||
2. Site has WordPress integration configured
|
||||
3. Backend calls WordPress REST API:
|
||||
- Creates/updates post
|
||||
- Uploads featured image
|
||||
- Sets categories/tags
|
||||
4. Updates Content with `wordpress_id`
|
||||
5. Sets status to `published`
|
||||
|
||||
---
|
||||
|
||||
## Content Structures
|
||||
|
||||
| Structure | Purpose | Typical Sections |
|
||||
|-----------|---------|------------------|
|
||||
| article | General blog post | Intro, Body, Conclusion |
|
||||
| guide | How-to content | Steps, Tips, Summary |
|
||||
| comparison | Product comparison | Features, Pros/Cons, Verdict |
|
||||
| review | Product review | Overview, Features, Rating |
|
||||
| listicle | List-based content | Numbered items with details |
|
||||
| pillar | Long-form authority | Multiple sections with depth |
|
||||
|
||||
---
|
||||
|
||||
## Frontend Pages
|
||||
|
||||
### Tasks Page (`/writer/tasks`)
|
||||
|
||||
- Table of all tasks
|
||||
- Filter by status, assigned user
|
||||
- Generate content action
|
||||
- Bulk actions
|
||||
|
||||
### Content Page (`/writer/content`)
|
||||
|
||||
- Table of all content
|
||||
- Filter by status, content type
|
||||
- Quick preview
|
||||
- Publish actions
|
||||
|
||||
### Content Viewer (`/writer/content/{id}`)
|
||||
|
||||
- Full content preview
|
||||
- Edit mode
|
||||
- Image management
|
||||
- Publish to WordPress
|
||||
- Status management
|
||||
|
||||
### Draft/Review/Published Tabs
|
||||
|
||||
- Filtered views by status
|
||||
- Different actions per status
|
||||
|
||||
---
|
||||
|
||||
## Content Status Flow
|
||||
|
||||
```
|
||||
draft → review → approved → published
|
||||
↓
|
||||
(rejected) → draft (revision)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
| From | To | Trigger |
|
||||
|------|----|---------|
|
||||
| ContentIdeas | Tasks | Create tasks |
|
||||
| Tasks | Content | Generate content |
|
||||
| Content | Images | Generate images |
|
||||
| Content | WordPress | Publish |
|
||||
| WordPress | Content | Sync imports |
|
||||
| Automation Stage 4 | Content | Automated generation |
|
||||
| Automation Stage 5-6 | Images | Automated image generation |
|
||||
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| Content too short | Low word count target | Increase target in task |
|
||||
| Images not generating | No prompts created | Run image prompt generation first |
|
||||
| WordPress publish fails | Invalid credentials | Check integration settings |
|
||||
| Content stuck in draft | No manual status update | Update status via UI or API |
|
||||
| Duplicate content | Re-running generation | Check if content already exists |
|
||||
|
||||
---
|
||||
|
||||
## Planned Changes
|
||||
|
||||
| Feature | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| Content revisions | 🔜 Planned | Track content version history |
|
||||
| Multi-language | 🔜 Planned | Generate content in different languages |
|
||||
| Batch generation | 🔜 Planned | Generate multiple content pieces at once |
|
||||
| Regenerate sections | 🔜 Planned | AI regenerate specific sections |
|
||||
Reference in New Issue
Block a user