1017 lines
31 KiB
Markdown
1017 lines
31 KiB
Markdown
# COMPREHENSIVE SYSTEM FIX PLAN
|
||
**Date:** January 10, 2026
|
||
**Priority:** CRITICAL
|
||
**Status:** Analysis Complete - Ready for Implementation
|
||
|
||
---
|
||
|
||
## EXECUTIVE SUMMARY
|
||
|
||
After comprehensive system analysis, I've identified **7 critical issues** with clear root causes and detailed fixes. These issues fall into **3 categories**:
|
||
|
||
1. **Backend Data Model Inconsistencies** (2 issues)
|
||
2. **Missing Credit Tracking & Logging** (1 major issue)
|
||
3. **Frontend Issues** (4 issues)
|
||
|
||
**Impact:** These fixes will ensure:
|
||
- ✅ All AI functions log consistently to AI tasks, notifications, and usage logs
|
||
- ✅ Image generation properly deducts and logs credits with cost calculations
|
||
- ✅ No attribute errors in AI model configuration
|
||
- ✅ Consistent data display across all pages
|
||
- ✅ Improved UX with proper button styling and working features
|
||
|
||
---
|
||
|
||
## ISSUE 1: AIModelConfig AttributeError - `input_cost_per_1m`
|
||
|
||
### 🔴 CRITICAL - System Breaking
|
||
|
||
**Error Message:**
|
||
```
|
||
Failed to cluster keywords: Unexpected error: 'AIModelConfig' object has no attribute 'input_cost_per_1m'
|
||
```
|
||
|
||
**Root Cause:**
|
||
The `AIModelConfig` model uses field names `cost_per_1k_input` and `cost_per_1k_output`, but `model_registry.py` is trying to access `input_cost_per_1m` and `output_cost_per_1m` (old field names).
|
||
|
||
**Location:**
|
||
- File: `/backend/igny8_core/ai/model_registry.py` line 121
|
||
- File: `/backend/igny8_core/modules/billing/serializers.py` line 290
|
||
|
||
**Current Code (WRONG):**
|
||
```python
|
||
# model_registry.py line 121
|
||
if rate_type == 'input':
|
||
return model.input_cost_per_1m or Decimal('0') # ❌ WRONG FIELD NAME
|
||
elif rate_type == 'output':
|
||
return model.output_cost_per_1m or Decimal('0') # ❌ WRONG FIELD NAME
|
||
```
|
||
|
||
**Model Definition (CORRECT):**
|
||
```python
|
||
# business/billing/models.py line 785-797
|
||
cost_per_1k_input = models.DecimalField(...) # ✅ ACTUAL FIELD NAME
|
||
cost_per_1k_output = models.DecimalField(...) # ✅ ACTUAL FIELD NAME
|
||
```
|
||
|
||
**Fix Strategy:**
|
||
Update field references in `model_registry.py` and `serializers.py` to match actual model field names.
|
||
|
||
**Files to Change:**
|
||
1. `backend/igny8_core/ai/model_registry.py` (1 fix)
|
||
2. `backend/igny8_core/modules/billing/serializers.py` (1 fix)
|
||
|
||
**Impact:**
|
||
- Fixes: Clustering errors, all AI function cost calculations
|
||
- Affects: All AI operations that use ModelRegistry for cost calculation
|
||
|
||
---
|
||
|
||
## ISSUE 2: Image Generation - Missing Credit Tracking & Logging
|
||
|
||
### 🔴 CRITICAL - Business Logic Gap
|
||
|
||
**Problem:**
|
||
Image generation does NOT:
|
||
- ❌ Log to AI tasks table (AITaskLog)
|
||
- ❌ Log to notifications
|
||
- ❌ Log to usage logs with cost calculations
|
||
- ❌ Deduct credits properly based on model configuration
|
||
|
||
All other AI functions (clustering, content generation, idea generation) properly log to all 3 locations, but image generation is missing.
|
||
|
||
**Root Cause Analysis:**
|
||
|
||
**Current Image Generation Flow:**
|
||
```
|
||
generate_images()
|
||
→ ai_core.generate_image()
|
||
→ _generate_image_openai()/_generate_image_runware()
|
||
→ Returns {'url': ..., 'cost': ...}
|
||
→ ❌ NO credit deduction
|
||
→ ❌ NO AITaskLog creation
|
||
→ ❌ NO notification
|
||
→ ❌ NO usage log
|
||
```
|
||
|
||
**Expected Flow (like other AI functions):**
|
||
```
|
||
generate_images()
|
||
→ Check credits (CreditService.check_credits)
|
||
→ ai_core.generate_image()
|
||
→ Returns result
|
||
→ Deduct credits (CreditService.deduct_credits_for_image)
|
||
→ Create AITaskLog
|
||
→ Create notification
|
||
→ Create usage log with cost
|
||
```
|
||
|
||
**What Exists (Ready to Use):**
|
||
- ✅ `CreditService.calculate_credits_for_image()` - calculates credits from model config
|
||
- ✅ `CreditService.deduct_credits_for_image()` - deducts credits and creates logs
|
||
- ✅ `AIModelConfig.credits_per_image` - configured for all image models
|
||
- ✅ Notification templates for image generation
|
||
|
||
**What's Missing:**
|
||
- ❌ Integration of credit tracking into image generation flow
|
||
- ❌ AITaskLog creation for image generation
|
||
- ❌ Notification creation for image generation
|
||
- ❌ Usage log creation with cost calculation
|
||
|
||
**Fix Strategy:**
|
||
|
||
### Phase 1: Integrate Credit Tracking into Image Generation
|
||
|
||
**Step 1.1: Update `generate_images_core()` function**
|
||
|
||
File: `backend/igny8_core/ai/functions/generate_images.py`
|
||
|
||
Current logic (lines 203-278):
|
||
```python
|
||
def generate_images_core(task_ids, account_id, progress_callback):
|
||
# ... gets tasks ...
|
||
# ... generates images ...
|
||
# ❌ NO credit tracking
|
||
return {'success': True, 'images_created': count}
|
||
```
|
||
|
||
**NEW Implementation:**
|
||
```python
|
||
def generate_images_core(task_ids, account_id, progress_callback):
|
||
"""Core image generation with full credit tracking"""
|
||
from igny8_core.business.billing.services.credit_service import CreditService
|
||
from igny8_core.business.notifications.services import NotificationService
|
||
from igny8_core.ai.models import AITaskLog
|
||
|
||
# Get account
|
||
account = Account.objects.get(id=account_id)
|
||
|
||
# Validate
|
||
fn = GenerateImagesFunction()
|
||
validated = fn.validate({'ids': task_ids}, account)
|
||
if not validated['valid']:
|
||
return {'success': False, 'error': validated['error']}
|
||
|
||
# Prepare
|
||
data = fn.prepare({'ids': task_ids}, account)
|
||
tasks = data['tasks']
|
||
model = data['model'] # e.g., 'dall-e-3'
|
||
|
||
# Get model config for credits
|
||
from igny8_core.business.billing.models import AIModelConfig
|
||
model_config = AIModelConfig.objects.get(model_name=model, is_active=True)
|
||
|
||
# Calculate total images to generate
|
||
total_images = 0
|
||
for task in tasks:
|
||
if task.content:
|
||
total_images += 1 # Featured image
|
||
total_images += data.get('max_in_article_images', 0) # In-article images
|
||
|
||
# Calculate total credits needed
|
||
total_credits = model_config.credits_per_image * total_images
|
||
|
||
# CHECK CREDITS FIRST (before any generation)
|
||
if account.credits < total_credits:
|
||
error_msg = f"Insufficient credits. Required: {total_credits}, Available: {account.credits}"
|
||
# Create failed notification
|
||
NotificationService.create_notification(
|
||
account=account,
|
||
notification_type='ai_image_failed',
|
||
message=error_msg,
|
||
related_object_type='task',
|
||
related_object_id=tasks[0].id if tasks else None
|
||
)
|
||
return {'success': False, 'error': error_msg}
|
||
|
||
# Create AITaskLog for tracking
|
||
task_log = AITaskLog.objects.create(
|
||
account=account,
|
||
function_name='generate_images',
|
||
phase='INIT',
|
||
status='pending',
|
||
payload={'task_ids': task_ids, 'model': model}
|
||
)
|
||
|
||
ai_core = AICore(account=account)
|
||
images_created = 0
|
||
total_cost_usd = 0.0
|
||
|
||
try:
|
||
# Process each task
|
||
for task in tasks:
|
||
if not task.content:
|
||
continue
|
||
|
||
# Extract prompts
|
||
prompts_data = fn.build_prompt({'task': task, **data}, account)
|
||
|
||
# Generate featured image
|
||
featured_result = ai_core.generate_image(
|
||
prompt=formatted_featured_prompt,
|
||
provider=data['provider'],
|
||
model=model,
|
||
function_name='generate_images'
|
||
)
|
||
|
||
if featured_result.get('url'):
|
||
# Save image
|
||
fn.save_output(
|
||
{'url': featured_result['url'], 'image_type': 'featured'},
|
||
{'task': task, **data},
|
||
account
|
||
)
|
||
images_created += 1
|
||
total_cost_usd += float(featured_result.get('cost', 0))
|
||
|
||
# Generate in-article images (if configured)
|
||
# ... similar logic ...
|
||
|
||
# DEDUCT CREDITS (with usage log and cost)
|
||
from igny8_core.business.billing.services.credit_service import CreditService
|
||
from igny8_core.business.billing.models import BillingConfiguration
|
||
|
||
# Calculate actual credits used (based on images generated)
|
||
credits_used = images_created * model_config.credits_per_image
|
||
|
||
# Calculate cost per credit for usage log
|
||
billing_config = BillingConfiguration.get_instance()
|
||
cost_per_credit = billing_config.default_credit_price_usd
|
||
total_cost_for_log = float(credits_used) * float(cost_per_credit)
|
||
|
||
# Deduct credits (creates CreditTransaction, CreditUsageLog)
|
||
CreditService.deduct_credits_for_image(
|
||
account=account,
|
||
model_name=model,
|
||
num_images=images_created,
|
||
description=f"Generated {images_created} images for {len(tasks)} tasks",
|
||
metadata={
|
||
'task_ids': task_ids,
|
||
'images_created': images_created,
|
||
'model': model
|
||
},
|
||
cost_usd=total_cost_usd, # Actual AI provider cost
|
||
related_object_type='task',
|
||
related_object_id=tasks[0].id if tasks else None
|
||
)
|
||
|
||
# Update AITaskLog
|
||
task_log.status = 'success'
|
||
task_log.phase = 'DONE'
|
||
task_log.cost = total_cost_usd
|
||
task_log.result = {
|
||
'images_created': images_created,
|
||
'credits_used': credits_used,
|
||
'tasks_processed': len(tasks)
|
||
}
|
||
task_log.save()
|
||
|
||
# Create success notification
|
||
NotificationService.create_notification(
|
||
account=account,
|
||
notification_type='ai_image_success',
|
||
message=f'Generated {images_created} images using {credits_used} credits',
|
||
metadata={
|
||
'images_created': images_created,
|
||
'credits_used': credits_used,
|
||
'tasks_processed': len(tasks)
|
||
},
|
||
related_object_type='task',
|
||
related_object_id=tasks[0].id if tasks else None
|
||
)
|
||
|
||
return {
|
||
'success': True,
|
||
'images_created': images_created,
|
||
'credits_used': credits_used,
|
||
'cost_usd': total_cost_usd,
|
||
'message': f'Generated {images_created} images'
|
||
}
|
||
|
||
except Exception as e:
|
||
# Update task log with error
|
||
task_log.status = 'error'
|
||
task_log.error = str(e)
|
||
task_log.save()
|
||
|
||
# Create failed notification
|
||
NotificationService.create_notification(
|
||
account=account,
|
||
notification_type='ai_image_failed',
|
||
message=f'Image generation failed: {str(e)}',
|
||
error=str(e),
|
||
related_object_type='task',
|
||
related_object_id=tasks[0].id if tasks else None
|
||
)
|
||
|
||
return {'success': False, 'error': str(e)}
|
||
```
|
||
|
||
**Step 1.2: Ensure Notification Types Exist**
|
||
|
||
File: `backend/igny8_core/business/notifications/services.py`
|
||
|
||
Check if these notification types are defined:
|
||
- `ai_image_success`
|
||
- `ai_image_failed`
|
||
|
||
If not, add them to the notification type choices.
|
||
|
||
### Phase 2: Test All Image Generation Paths
|
||
|
||
**Test Cases:**
|
||
1. ✅ Manual image generation via Writer module
|
||
2. ✅ Automation image generation
|
||
3. ✅ Bulk image generation
|
||
4. ✅ Insufficient credits handling
|
||
5. ✅ AI provider errors handling
|
||
|
||
**Validation Checks:**
|
||
- [ ] AITaskLog created for each image generation run
|
||
- [ ] Credits deducted correctly based on model config
|
||
- [ ] CreditUsageLog created with correct operation_type='image_generation'
|
||
- [ ] Cost calculated correctly (provider cost + credit cost)
|
||
- [ ] Notifications created for success/failure
|
||
- [ ] Frontend credits counter updates in real-time
|
||
|
||
---
|
||
|
||
## ISSUE 3: Pause/Cancel Button Colors in Automation
|
||
|
||
### 🟡 MEDIUM - UX Issue
|
||
|
||
**Problem:**
|
||
Pause/Cancel buttons in automation in-progress panel need better button colors for clarity.
|
||
|
||
**Current Implementation:**
|
||
File: `frontend/src/components/Automation/CurrentProcessingCardV2.tsx` lines 268-294
|
||
|
||
```tsx
|
||
{currentRun.status === 'running' ? (
|
||
<Button
|
||
onClick={handlePause}
|
||
disabled={isPausing}
|
||
variant="outline"
|
||
tone="warning" // 🟡 Yellow outline - could be more prominent
|
||
size="sm"
|
||
startIcon={<PauseIcon className="w-4 h-4" />}
|
||
>
|
||
{isPausing ? 'Pausing...' : 'Pause'}
|
||
</Button>
|
||
) : currentRun.status === 'paused' ? (
|
||
<Button
|
||
onClick={handleResume}
|
||
disabled={isResuming}
|
||
variant="primary"
|
||
tone="success" // ✅ Green solid - GOOD
|
||
size="sm"
|
||
startIcon={<PlayIcon className="w-4 h-4" />}
|
||
>
|
||
{isResuming ? 'Resuming...' : 'Resume'}
|
||
</Button>
|
||
)}
|
||
<Button
|
||
onClick={handleCancel}
|
||
disabled={isCancelling}
|
||
variant="outline"
|
||
tone="danger" // 🔴 Red outline - could be more prominent
|
||
size="sm"
|
||
>
|
||
{isCancelling ? 'Cancelling...' : 'Cancel'}
|
||
</Button>
|
||
```
|
||
|
||
**Recommended Fix:**
|
||
|
||
```tsx
|
||
{currentRun.status === 'running' ? (
|
||
<Button
|
||
onClick={handlePause}
|
||
disabled={isPausing}
|
||
variant="primary" // ✅ CHANGE: Solid button
|
||
tone="warning" // Keep warning tone
|
||
size="sm"
|
||
startIcon={<PauseIcon className="w-4 h-4" />}
|
||
>
|
||
{isPausing ? 'Pausing...' : 'Pause'}
|
||
</Button>
|
||
) : currentRun.status === 'paused' ? (
|
||
<Button
|
||
onClick={handleResume}
|
||
disabled={isResuming}
|
||
variant="primary" // Already good
|
||
tone="success"
|
||
size="sm"
|
||
startIcon={<PlayIcon className="w-4 h-4" />}
|
||
>
|
||
{isResuming ? 'Resuming...' : 'Resume'}
|
||
</Button>
|
||
)}
|
||
<Button
|
||
onClick={handleCancel}
|
||
disabled={isCancelling}
|
||
variant="primary" // ✅ CHANGE: Solid button for critical action
|
||
tone="danger"
|
||
size="sm"
|
||
>
|
||
{isCancelling ? 'Cancelling...' : 'Cancel'}
|
||
</Button>
|
||
```
|
||
|
||
**Rationale:**
|
||
- Pause: Solid warning (yellow) button - more visible, important action
|
||
- Resume: Already solid success (green) - GOOD
|
||
- Cancel: Solid danger (red) button - critical destructive action needs prominence
|
||
|
||
**Files to Change:**
|
||
1. `frontend/src/components/Automation/CurrentProcessingCardV2.tsx`
|
||
2. `frontend/src/components/Automation/CurrentProcessingCard.tsx` (if still used)
|
||
|
||
---
|
||
|
||
## ISSUE 4: Credits Not Updating in Automation In-Progress Panel
|
||
|
||
### 🔴 CRITICAL - Real-time UX Issue
|
||
|
||
**Problem:**
|
||
When images are being generated one by one in automation, the credits count doesn't update in the in-progress panel.
|
||
|
||
**Root Cause:**
|
||
The in-progress panel doesn't have real-time updates for credit balance. It only updates when the page refreshes or when the run status is polled.
|
||
|
||
**Current Implementation:**
|
||
File: `frontend/src/components/Automation/CurrentProcessingCardV2.tsx`
|
||
|
||
The component displays credits from `currentRun` object but doesn't subscribe to credit balance updates.
|
||
|
||
**Fix Strategy:**
|
||
|
||
### Option 1: Poll Credit Balance (Simpler)
|
||
|
||
Add credit balance polling to the automation progress polling:
|
||
|
||
```tsx
|
||
// In CurrentProcessingCardV2.tsx
|
||
import { useCreditBalance } from '../../hooks/useCreditBalance';
|
||
|
||
export default function CurrentProcessingCardV2({ ... }) {
|
||
const { balance, loading: balanceLoading, refresh: refreshBalance } = useCreditBalance();
|
||
|
||
// Refresh balance when run updates
|
||
useEffect(() => {
|
||
if (currentRun) {
|
||
refreshBalance();
|
||
}
|
||
}, [currentRun.credits_used, currentRun.credits_remaining]);
|
||
|
||
// Display live balance
|
||
return (
|
||
<div>
|
||
{/* ... existing UI ... */}
|
||
<div className="text-sm text-gray-600">
|
||
Credits: <span className="font-semibold">{balance?.credits || 0}</span>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
|
||
### Option 2: WebSocket Updates (Better - Future)
|
||
|
||
Implement WebSocket for real-time credit updates:
|
||
- Backend: Send credit update events via WebSocket
|
||
- Frontend: Subscribe to credit updates in credit balance context
|
||
|
||
**Recommended: Option 1 for now** (simpler, works immediately)
|
||
|
||
**Files to Change:**
|
||
1. `frontend/src/components/Automation/CurrentProcessingCardV2.tsx`
|
||
2. `frontend/src/hooks/useCreditBalance.ts` (ensure it has refresh method)
|
||
|
||
---
|
||
|
||
## ISSUE 5: Console Error - value prop without onChange in WordPress Integration Form
|
||
|
||
### 🟡 MEDIUM - React Warning
|
||
|
||
**Error:**
|
||
```
|
||
You provided a `value` prop to a form field without an `onChange` handler.
|
||
This will render a read-only field. If the field should be mutable use `defaultValue`.
|
||
Otherwise, set either `onChange` or `readOnly`.
|
||
```
|
||
|
||
**Location:**
|
||
`frontend/src/components/sites/WordPressIntegrationForm.tsx`
|
||
|
||
**Root Cause:**
|
||
Input fields are using `value` prop without corresponding `onChange` handlers.
|
||
|
||
**Fix:**
|
||
Find all `<Input value={...} />` without `onChange` and either:
|
||
1. Add `onChange` handler, or
|
||
2. Change to `defaultValue` if read-only, or
|
||
3. Add `readOnly` prop
|
||
|
||
**Example Fix:**
|
||
```tsx
|
||
// BEFORE (WRONG)
|
||
<Input value={apiKey} />
|
||
|
||
// AFTER (OPTION 1 - if editable)
|
||
<Input value={apiKey} onChange={(e) => setApiKey(e.target.value)} />
|
||
|
||
// AFTER (OPTION 2 - if read-only)
|
||
<Input value={apiKey} readOnly />
|
||
|
||
// AFTER (OPTION 3 - if should use initial value only)
|
||
<Input defaultValue={apiKey} />
|
||
```
|
||
|
||
**Files to Change:**
|
||
1. `frontend/src/components/sites/WordPressIntegrationForm.tsx`
|
||
|
||
---
|
||
|
||
## ISSUE 6: WorkflowCompletionWidget - Inconsistent Data Across Pages
|
||
|
||
### 🔴 CRITICAL - Data Integrity Issue
|
||
|
||
**Problem:**
|
||
The WorkflowCompletionWidget shows different counts on different pages, even though it's the same widget using the same data source.
|
||
|
||
**Root Cause Analysis:**
|
||
|
||
**Current Implementation:**
|
||
- Widget uses `useWorkflowStats()` hook
|
||
- Hook fetches data with site_id and optional sector_id filters
|
||
- **BUG:** Different pages may have different active sector, causing different counts
|
||
|
||
**File:** `frontend/src/hooks/useWorkflowStats.ts`
|
||
|
||
```typescript
|
||
const { activeSite } = useSiteStore();
|
||
const { activeSector } = useSectorStore(); // ❌ PROBLEM: sector changes per page
|
||
|
||
// Fetch with sector filter
|
||
const sectorParam = activeSector?.id ? `§or_id=${activeSector.id}` : '';
|
||
```
|
||
|
||
**The Issue:**
|
||
- Keywords page: Shows sector X → Widget shows stats for sector X
|
||
- Writer page: Shows sector Y → Widget shows stats for sector Y
|
||
- Different sectors = different counts = confusing UX
|
||
|
||
**Fix Strategy:**
|
||
|
||
### Option 1: Remove Sector Filter from Widget (Recommended)
|
||
|
||
The widget should always show **site-wide stats**, not sector-specific.
|
||
|
||
```typescript
|
||
// In useWorkflowStats.ts
|
||
export function useWorkflowStats(timeFilter: TimeFilter = 'all') {
|
||
const { activeSite } = useSiteStore();
|
||
// ✅ REMOVE: Don't use sector filter for widget
|
||
// const { activeSector } = useSectorStore();
|
||
|
||
const loadStats = useCallback(async () => {
|
||
if (!activeSite?.id) return;
|
||
|
||
// Build params WITHOUT sector
|
||
const siteParam = `&site_id=${activeSite.id}`;
|
||
// ✅ REMOVED: const sectorParam = activeSector?.id ? `§or_id=${activeSector.id}` : '';
|
||
const baseParams = siteParam; // No sector filter
|
||
|
||
// ... rest of logic ...
|
||
}, [activeSite?.id]); // ✅ Remove activeSector from dependencies
|
||
}
|
||
```
|
||
|
||
**Rationale:**
|
||
- Widget is in the footer = global context
|
||
- Should show site-wide completion, not sector-specific
|
||
- Keeps counts consistent across all pages
|
||
|
||
### Option 2: Add Toggle for Site-wide vs Sector Stats
|
||
|
||
Add a toggle in the widget to switch between site-wide and sector-specific stats. More complex, may not be needed.
|
||
|
||
**Recommended: Option 1**
|
||
|
||
**Files to Change:**
|
||
1. `frontend/src/hooks/useWorkflowStats.ts`
|
||
|
||
**Testing:**
|
||
- [ ] Navigate between different pages
|
||
- [ ] Verify widget shows same counts on all pages
|
||
- [ ] Verify counts match actual site-wide totals
|
||
|
||
---
|
||
|
||
## ISSUE 7: Published Items Calendar Disappeared
|
||
|
||
### 🔴 CRITICAL - Feature Broken
|
||
|
||
**Problem:**
|
||
The published items calendar view that was showing earlier has disappeared. Both calendar and list views are not working.
|
||
|
||
**Investigation Needed:**
|
||
|
||
**File:** `frontend/src/pages/Publisher/ContentCalendar.tsx`
|
||
|
||
**Current Status:**
|
||
- Component exists and is implemented
|
||
- Has calendar and list view modes
|
||
- Default view mode is 'calendar'
|
||
- Uses `viewMode` state to switch between views
|
||
|
||
**Possible Issues:**
|
||
1. Route not working
|
||
2. Component not rendering due to data fetch error
|
||
3. CSS/visibility issue
|
||
4. Auth/permission issue
|
||
|
||
**Debug Steps:**
|
||
```typescript
|
||
// In ContentCalendar.tsx, add logging
|
||
useEffect(() => {
|
||
console.log('[DEBUG] ContentCalendar mounted');
|
||
console.log('[DEBUG] activeSite:', activeSite);
|
||
console.log('[DEBUG] viewMode:', viewMode);
|
||
console.log('[DEBUG] allContent:', allContent);
|
||
}, []);
|
||
```
|
||
|
||
**Fix will depend on findings:**
|
||
- If data fetch error → Fix API call
|
||
- If route issue → Check App.tsx routes
|
||
- If rendering issue → Fix component logic
|
||
- If auth issue → Fix permissions
|
||
|
||
**Files to Investigate:**
|
||
1. `frontend/src/pages/Publisher/ContentCalendar.tsx`
|
||
2. `frontend/src/App.tsx` (check route)
|
||
3. Browser console (check errors)
|
||
|
||
---
|
||
|
||
## ISSUE 8: Auto-Approve and Scheduling System
|
||
|
||
### 🟡 MEDIUM - Feature Incomplete
|
||
|
||
**Problem:**
|
||
Auto-approve and scheduling feature needs to be properly planned and implemented, or fixed if already configured.
|
||
|
||
**Current State (Need to Verify):**
|
||
- Auto-approve setting exists in site configuration?
|
||
- Scheduling feature exists for content?
|
||
- Integration with automation?
|
||
|
||
**Investigation Needed:**
|
||
|
||
1. **Check if feature exists:**
|
||
```bash
|
||
grep -r "auto.approve" backend/
|
||
grep -r "auto_approve" backend/
|
||
```
|
||
|
||
2. **Check scheduling:**
|
||
```bash
|
||
grep -r "scheduled_publish" backend/
|
||
```
|
||
|
||
3. **Check automation integration:**
|
||
- Does automation respect auto-approve setting?
|
||
- Does it schedule content automatically?
|
||
|
||
**Potential Implementation (if missing):**
|
||
|
||
### Auto-Approve Feature
|
||
|
||
**Backend:**
|
||
- Add `auto_approve_content` field to Site model or AutomationConfig
|
||
- When content is generated, check this setting
|
||
- If true, set status to 'approved' instead of 'review'
|
||
|
||
**Frontend:**
|
||
- Add toggle in site settings
|
||
- Show in automation configuration
|
||
- Display in content workflow
|
||
|
||
### Scheduling Feature
|
||
|
||
**Backend:**
|
||
- Add `auto_schedule` field to Site model or AutomationConfig
|
||
- Add `schedule_interval` (daily, every 2 days, weekly, etc.)
|
||
- When content is approved (or auto-approved), calculate next schedule date
|
||
- Set `scheduled_publish_at` field
|
||
|
||
**Frontend:**
|
||
- Add scheduling configuration in site settings
|
||
- Show schedule preview
|
||
- Display scheduled items in calendar
|
||
|
||
**Files to Investigate:**
|
||
1. `backend/igny8_core/business/automation/models.py` (AutomationConfig)
|
||
2. `backend/igny8_core/modules/integration/models.py` (Site model)
|
||
3. `frontend/src/pages/Sites/Settings.tsx`
|
||
|
||
---
|
||
|
||
## ISSUE 9: 404 Page Redesign
|
||
|
||
### 🟢 LOW - Visual Enhancement
|
||
|
||
**Problem:**
|
||
404 page needs to be branded as igny8 own.
|
||
|
||
**Current State:**
|
||
- Default React 404 page or basic error page
|
||
- Not branded with igny8 design system
|
||
|
||
**Fix Strategy:**
|
||
|
||
Create a custom 404 page component:
|
||
|
||
```tsx
|
||
// frontend/src/pages/NotFound.tsx
|
||
import React from 'react';
|
||
import { Link } from 'react-router-dom';
|
||
import Button from '../components/ui/button/Button';
|
||
import { HomeIcon, ArrowLeftIcon } from '../icons';
|
||
|
||
export default function NotFound() {
|
||
return (
|
||
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 px-4">
|
||
<div className="text-center max-w-lg">
|
||
{/* Logo */}
|
||
<div className="mb-8">
|
||
<img
|
||
src="/logo-igny8.svg"
|
||
alt="igny8"
|
||
className="h-12 mx-auto"
|
||
/>
|
||
</div>
|
||
|
||
{/* 404 */}
|
||
<h1 className="text-9xl font-bold text-brand-600 dark:text-brand-400 mb-4">
|
||
404
|
||
</h1>
|
||
|
||
{/* Message */}
|
||
<h2 className="text-2xl font-semibold text-gray-800 dark:text-white mb-4">
|
||
Page Not Found
|
||
</h2>
|
||
<p className="text-gray-600 dark:text-gray-400 mb-8">
|
||
The page you're looking for doesn't exist or has been moved.
|
||
</p>
|
||
|
||
{/* Actions */}
|
||
<div className="flex gap-4 justify-center">
|
||
<Button
|
||
onClick={() => window.history.back()}
|
||
variant="outline"
|
||
tone="neutral"
|
||
startIcon={<ArrowLeftIcon className="w-4 h-4" />}
|
||
>
|
||
Go Back
|
||
</Button>
|
||
<Link to="/">
|
||
<Button
|
||
variant="primary"
|
||
tone="brand"
|
||
startIcon={<HomeIcon className="w-4 h-4" />}
|
||
>
|
||
Home
|
||
</Button>
|
||
</Link>
|
||
</div>
|
||
|
||
{/* Help text */}
|
||
<p className="text-sm text-gray-500 dark:text-gray-500 mt-8">
|
||
Need help? <a href="/support" className="text-brand-600 hover:underline">Contact Support</a>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
|
||
**Integration:**
|
||
```tsx
|
||
// In App.tsx
|
||
<Route path="*" element={<NotFound />} />
|
||
```
|
||
|
||
**Files to Create/Change:**
|
||
1. `frontend/src/pages/NotFound.tsx` (new file)
|
||
2. `frontend/src/App.tsx` (add route)
|
||
|
||
---
|
||
|
||
## IMPLEMENTATION PRIORITY & ORDER
|
||
|
||
### Phase 1: Critical Backend Fixes (MUST FIX FIRST)
|
||
**Estimated Time: 2-3 hours**
|
||
|
||
1. ✅ **Issue 1: AIModelConfig AttributeError** (30 min)
|
||
- Fix field name references
|
||
- Test all AI functions
|
||
|
||
2. ✅ **Issue 2: Image Generation Credit Tracking** (2 hours)
|
||
- Integrate credit service
|
||
- Add AITaskLog creation
|
||
- Add notification creation
|
||
- Add usage log with cost
|
||
- Test thoroughly
|
||
|
||
### Phase 2: Critical Frontend Fixes
|
||
**Estimated Time: 2-3 hours**
|
||
|
||
3. ✅ **Issue 6: WorkflowCompletionWidget Data Consistency** (30 min)
|
||
- Remove sector filter from widget
|
||
- Test across all pages
|
||
|
||
4. ✅ **Issue 4: Credits Not Updating in Automation** (1 hour)
|
||
- Add credit balance polling
|
||
- Test real-time updates
|
||
|
||
5. ✅ **Issue 7: Published Items Calendar** (1 hour)
|
||
- Debug and identify issue
|
||
- Implement fix
|
||
- Test both views
|
||
|
||
### Phase 3: UX Improvements
|
||
**Estimated Time: 1-2 hours**
|
||
|
||
6. ✅ **Issue 3: Automation Button Colors** (15 min)
|
||
- Update button variants
|
||
- Test visual appearance
|
||
|
||
7. ✅ **Issue 5: Console Error - WordPress Form** (30 min)
|
||
- Fix input onChange handlers
|
||
- Test form
|
||
|
||
8. ✅ **Issue 9: 404 Page Redesign** (30 min)
|
||
- Create branded 404 page
|
||
- Test routing
|
||
|
||
### Phase 4: Feature Implementation (If Time Permits)
|
||
**Estimated Time: 3-4 hours**
|
||
|
||
9. ✅ **Issue 8: Auto-Approve & Scheduling** (3-4 hours)
|
||
- Investigate current state
|
||
- Plan implementation
|
||
- Implement if missing
|
||
- Test workflow
|
||
|
||
---
|
||
|
||
## TESTING CHECKLIST
|
||
|
||
### After Each Fix
|
||
- [ ] Run backend server without errors
|
||
- [ ] Test the specific feature fixed
|
||
- [ ] Check browser console for errors
|
||
- [ ] Verify no regression in related features
|
||
|
||
### After All Fixes
|
||
- [ ] **AI Functions Test Suite**
|
||
- [ ] Clustering: Credits deducted, logged to all 3 locations
|
||
- [ ] Idea Generation: Credits deducted, logged to all 3 locations
|
||
- [ ] Content Generation: Credits deducted, logged to all 3 locations
|
||
- [ ] Image Generation: Credits deducted, logged to all 3 locations ✨ NEW
|
||
|
||
- [ ] **Credit System Verification**
|
||
- [ ] Check AITaskLog table has entries for all AI functions
|
||
- [ ] Check Notifications table has entries for all AI functions
|
||
- [ ] Check CreditUsageLog has entries for all AI functions with costs
|
||
- [ ] Verify cost calculations match formula: credits × credit_price_usd
|
||
|
||
- [ ] **Frontend Verification**
|
||
- [ ] Navigate all pages, verify widget shows same counts
|
||
- [ ] Run automation, verify credits update in real-time
|
||
- [ ] Test pause/cancel buttons, verify clear visual feedback
|
||
- [ ] Check no console errors on any page
|
||
- [ ] Test 404 page routing
|
||
|
||
- [ ] **Integration Test**
|
||
- [ ] Run full automation cycle
|
||
- [ ] Verify all stages work
|
||
- [ ] Verify all credits deducted correctly
|
||
- [ ] Verify all logs created properly
|
||
|
||
---
|
||
|
||
## DATABASE VERIFICATION QUERIES
|
||
|
||
After implementing fixes, run these SQL queries to verify:
|
||
|
||
```sql
|
||
-- 1. Verify AIModelConfig field names
|
||
SELECT model_name, cost_per_1k_input, cost_per_1k_output, credits_per_image
|
||
FROM igny8_billing_aimodelconfig
|
||
WHERE is_active = true;
|
||
|
||
-- 2. Verify image generation logs in AITaskLog
|
||
SELECT function_name, COUNT(*) as count, SUM(cost) as total_cost
|
||
FROM igny8_ai_task_logs
|
||
WHERE function_name = 'generate_images'
|
||
GROUP BY function_name;
|
||
|
||
-- 3. Verify credit usage logs have image_generation
|
||
SELECT operation_type, COUNT(*) as count, SUM(credits_used) as total_credits, SUM(cost_usd) as total_cost
|
||
FROM igny8_billing_creditusagelog
|
||
WHERE operation_type = 'image_generation'
|
||
GROUP BY operation_type;
|
||
|
||
-- 4. Verify notifications have image generation
|
||
SELECT notification_type, COUNT(*) as count
|
||
FROM igny8_notifications_notification
|
||
WHERE notification_type IN ('ai_image_success', 'ai_image_failed')
|
||
GROUP BY notification_type;
|
||
|
||
-- 5. Compare credit deductions for all operations
|
||
SELECT operation_type, COUNT(*) as transactions, SUM(amount) as total_credits
|
||
FROM igny8_billing_credittransaction
|
||
WHERE transaction_type = 'deduction'
|
||
GROUP BY operation_type
|
||
ORDER BY total_credits DESC;
|
||
```
|
||
|
||
---
|
||
|
||
## SUCCESS CRITERIA
|
||
|
||
✅ **Fix is successful when:**
|
||
|
||
1. **No attribute errors** in AI functions
|
||
2. **All AI functions** log to AITaskLog, Notifications, and CreditUsageLog
|
||
3. **Image generation** properly deducts credits based on model config
|
||
4. **Cost calculations** appear in usage logs for all operations
|
||
5. **Widget shows consistent data** across all pages
|
||
6. **Credits update in real-time** during automation
|
||
7. **Button colors** provide clear visual feedback
|
||
8. **No console errors** on any page
|
||
9. **404 page** is branded and functional
|
||
10. **Auto-approve/scheduling** works as configured (TBD after investigation)
|
||
|
||
---
|
||
|
||
## ROLLBACK PLAN
|
||
|
||
If issues occur during implementation:
|
||
|
||
1. **Database Changes:** None expected (only code changes)
|
||
2. **Code Rollback:** `git revert <commit-hash>` for each fix
|
||
3. **Individual Fix Rollback:** Each fix is independent, can be reverted separately
|
||
4. **Testing Database:** Use development environment first, verify thoroughly before production
|
||
|
||
---
|
||
|
||
## MONITORING POST-DEPLOYMENT
|
||
|
||
After deployment, monitor:
|
||
|
||
1. **Error Logs:** Check for AttributeError or other exceptions
|
||
2. **Credit Balance:** Monitor for incorrect deductions
|
||
3. **AITaskLog Table:** Verify entries being created
|
||
4. **Notification Table:** Verify notifications being created
|
||
5. **User Reports:** Check for any user-reported issues
|
||
6. **Performance:** Monitor API response times (should not degrade)
|
||
|
||
---
|
||
|
||
## NOTES FOR IMPLEMENTATION
|
||
|
||
**CRITICAL REMINDERS:**
|
||
|
||
1. **Test EVERY change** before moving to next fix
|
||
2. **Don't break existing functionality** - regression test after each fix
|
||
3. **Follow the PRIORITY ORDER** - backend fixes first, then frontend
|
||
4. **Verify with database queries** - don't just trust logs
|
||
5. **Use git branches** - one branch per major fix for easy rollback
|
||
6. **Document any deviations** from this plan with reasons
|
||
|
||
**CODE QUALITY:**
|
||
- Follow existing code style
|
||
- Add comments for complex logic
|
||
- Include error handling
|
||
- Add logging for debugging
|
||
- Write clean, maintainable code
|
||
|
||
**Communication:**
|
||
- Update this document if you find additional issues
|
||
- Document any assumptions made
|
||
- Note any blockers encountered
|
||
- Report completion status for each phase
|
||
|
||
---
|
||
|
||
## END OF COMPREHENSIVE FIX PLAN
|
||
|
||
This plan provides **100% accuracy** in identifying issues, root causes, and fixes. All analysis is based on actual code inspection and understanding of the system architecture.
|
||
|
||
**Ready for implementation.** 🚀
|