# Publishing Failure - Root Cause Analysis & Fixes

**Date:** November 29, 2025  
**Issue:** "Failed to publish" notification when trying to publish from Review page  
**Status:** FIXED

---

## Root Causes Identified

### Critical Issue 1: Incorrect Publish Endpoint Architecture

**Problem:** The IGNY8 backend `publish()` endpoint was using an incompatible publishing approach
- **File:** `igny8_core/modules/writer/views.py` (ContentViewSet.publish)
- **Issue:** Tried to use `WordPressAdapter` with username/app_password authentication
- **Why it failed:**
  - WordPress integration is configured with **API key**, not username/password
  - Credentials weren't stored in site.metadata as expected
  - WordPressAdapter expected sync publishing (blocking), but we need async with Celery

### Critical Issue 2: Broken Celery Task

**Problem:** The Celery task was trying to import from non-existent model
- **File:** `igny8_core/tasks/wordpress_publishing.py`
- **Root Cause:** 
  ```python
  from igny8_core.models import ContentPost, SiteIntegration  # ❌ igny8_core/models.py doesn't exist!
  ```
- **Referenced non-existent fields:**
  - `ContentPost` model doesn't exist (should be `Content`)
  - `wordpress_sync_status` field doesn't exist
  - `wordpress_post_id` field doesn't exist
  - `wordpress_sync_attempts` field doesn't exist
  - `last_wordpress_sync` field doesn't exist

### Critical Issue 3: Field Name Mismatches

**Problem:** Task was looking for fields on Content model that don't exist
- `content.wordpress_sync_status` → ❌ Doesn't exist
- `content.wordpress_post_id` → ❌ Doesn't exist  
- Correct field: `content.external_id`

---

## Fixes Applied

### Fix #1: Redesigned Publish Endpoint

**File:** `igny8_core/modules/writer/views.py`  
**Function:** `ContentViewSet.publish()`  
**Lines:** 760-830

**What Changed:**
- ✅ **REMOVED** the `WordPressAdapter` approach entirely
- ✅ **REMOVED** username/app_password lookup from site.metadata
- ✅ **CHANGED** to use `SiteIntegration` model (which has API key)
- ✅ **CHANGED** to queue a Celery task instead of sync publishing
- ✅ **ADDED** automatic integration detection by site and platform

**Before (Broken):**
```python
# Wrong approach - sync publishing with wrong credentials
from igny8_core.business.publishing.services.adapters.wordpress_adapter import WordPressAdapter

wp_credentials = site.metadata.get('wordpress', {})  # ❌ Not stored here
wp_username = wp_credentials.get('username')  # ❌ These fields don't exist
wp_app_password = wp_credentials.get('app_password')  # ❌

adapter = WordPressAdapter()
result = adapter.publish(...)  # ❌ Sync - blocks while publishing
```

**After (Fixed):**
```python
# Correct approach - async publishing via Celery
from igny8_core.business.integration.models import SiteIntegration
from igny8_core.tasks.wordpress_publishing import publish_content_to_wordpress

# Find WordPress integration for this site
site_integration = SiteIntegration.objects.filter(
    site=content.site,
    platform='wordpress',
    is_active=True
).first()

# Queue async task
result = publish_content_to_wordpress.delay(
    content_id=content.id,
    site_integration_id=site_integration.id
)

# Returns 202 ACCEPTED immediately
return success_response(
    data={
        'content_id': content.id,
        'task_id': result.id,
        'status': 'queued'
    },
    status_code=status.HTTP_202_ACCEPTED
)
```

### Fix #2: Fixed Celery Task Imports and Field References

**File:** `igny8_core/tasks/wordpress_publishing.py`  
**Function:** `publish_content_to_wordpress()`

**Imports Fixed:**
```python
# ❌ OLD (Broken)
from igny8_core.models import ContentPost, SiteIntegration

# ✅ NEW (Correct)
from igny8_core.business.content.models import Content
from igny8_core.business.integration.models import SiteIntegration
```

**Field References Fixed:**

| Old Field | Status | New Field | Reason |
|---|---|---|---|
| `content.wordpress_sync_status` | ❌ Doesn't exist | `content.external_id` | Unified Content model uses external_id |
| `content.wordpress_post_id` | ❌ Doesn't exist | `content.external_id` | Same as above |
| `content.wordpress_post_url` | ❌ Doesn't exist | `content.external_url` | Same as above |
| `content.wordpress_sync_attempts` | ❌ Doesn't exist | ✅ Removed | Not needed in unified model |
| `content.last_wordpress_sync` | ❌ Doesn't exist | ✅ Removed | Using updated_at instead |
| Check: `if content.wordpress_sync_status == 'syncing'` | ❌ Wrong field | ✅ Removed | No syncing status needed |

**Status Update Logic Fixed:**
```python
# ✅ NOW: Updates unified Content model fields
if response.status_code == 201:
    content.external_id = wp_data.get('post_id')
    content.external_url = wp_data.get('post_url')
    content.status = 'published'  # ✅ Set status to published
    content.save(update_fields=['external_id', 'external_url', 'status'])
```

### Fix #3: Updated Helper Celery Functions

**Functions Updated:**
1. `process_pending_wordpress_publications()` - Updated imports and queries
2. `bulk_publish_content_to_wordpress()` - Updated imports and field checks
3. `wordpress_status_reconciliation()` - Simplified (was broken)
4. `retry_failed_wordpress_publications()` - Simplified (was broken)

---

## Complete Publishing Flow (After Fixes)

```
┌─────────────────────────────────────────────────────────────────┐
│ IGNY8 Frontend - Content Review Page                            │
│                                                                 │
│  User clicks "Publish" button                                   │
└─────────────────────────┬───────────────────────────────────────┘
                          │ POST /api/v1/writer/content/{id}/publish/
                          ▼
┌─────────────────────────────────────────────────────────────────┐
│ IGNY8 Backend - REST Endpoint                                   │
│ (ContentViewSet.publish)                                        │
│                                                                 │
│  1. Get Content object                                           │
│  2. Check if already published (external_id exists)             │
│  3. Find WordPress SiteIntegration for this site                │
│  4. Queue Celery task: publish_content_to_wordpress             │
│  5. Return 202 ACCEPTED immediately ✅                          │
│     (Frontend shows: "Publishing..." spinner)                   │
└─────────────────────────┬───────────────────────────────────────┘
                          │ Async Celery Task Queue
                          ▼
┌─────────────────────────────────────────────────────────────────┐
│ Celery Worker - Background Task                                 │
│ (publish_content_to_wordpress)                                  │
│                                                                 │
│  1. Get Content from database (correct model)                   │
│  2. Get SiteIntegration with API key                            │
│  3. Prepare payload with content_html                           │
│  4. POST to WordPress: /wp-json/igny8/v1/publish-content/       │
│  5. Update Content model:                                       │
│     - external_id = post_id from response                       │
│     - external_url = post_url from response                     │
│     - status = 'published'                                      │
│  6. Return success ✅                                           │
└─────────────────────────┬───────────────────────────────────────┘
                          │ 
                          ▼
┌─────────────────────────────────────────────────────────────────┐
│ WordPress Plugin                                                │
│ (Receives REST request with full content_html)                 │
│                                                                 │
│  Creates post with:                                             │
│  - Title ✅                                                     │
│  - Full HTML content ✅                                         │
│  - SEO metadata ✅                                              │
│  - Cluster/sector IDs ✅                                        │
└─────────────────────────────────────────────────────────────────┘
```

---

## What Changed from User Perspective

### Before Fixes ❌
```
User action: Click "Publish" button
IGNY8 Response: "Failed to publish"
Result: Nothing happens, content not published

Cause: 
- Endpoint tries to find WordPress credentials in wrong location
- Celery task crashes trying to import non-existent model
- User sees generic error
```

### After Fixes ✅
```
User action: Click "Publish" button
IGNY8 Response: "Publishing..." → "Published successfully"
Result: Content published to WordPress with full HTML content

Flow:
1. Endpoint immediately queues task (fast response)
2. Celery worker processes in background
3. WordPress receives full content_html + metadata
4. Post created with complete content
5. IGNY8 updates Content model with external_id/external_url
```

---

## Testing the Fix

### Manual Testing
1. Go to IGNY8 Content Review page
2. Select content with full HTML content
3. Click "Publish" button
4. Should see: "Publishing queued - content will be published shortly"
5. Check WordPress in 5-10 seconds - post should appear with full content

### Checklist
- ✅ Content publishes without "Failed to publish" error
- ✅ WordPress post has full HTML content (not just title)
- ✅ WordPress post has SEO metadata
- ✅ IGNY8 Content model updated with `external_id` and `external_url`
- ✅ Cluster and sector IDs stored in WordPress postmeta

### Monitoring
- Enable `IGNY8_DEBUG = True` in Django settings to see logs
- Monitor Celery worker logs for any publish failures
- Check WordPress `/wp-json/igny8/v1/publish-content/` endpoint logs

---

## Files Modified

1. **IGNY8 Backend - Writer Views**
   - File: `igny8_core/modules/writer/views.py`
   - Function: `ContentViewSet.publish()`
   - Change: Redesigned to use SiteIntegration + Celery

2. **IGNY8 Backend - Celery Tasks**
   - File: `igny8_core/tasks/wordpress_publishing.py`
   - Changes:
     - Fixed imports: ContentPost → Content
     - Fixed field references: wordpress_sync_status → external_id
     - Updated all Celery functions to use correct model

---

## Architecture Alignment

The fixes align publishing with the designed architecture:

| Component | Before | After |
|---|---|---|
| Publishing Method | Sync (blocks) | Async (Celery) ✅ |
| Credentials | site.metadata | SiteIntegration ✅ |
| Model Import | igny8_core.models (doesn't exist) | igny8_core.business.content.models ✅ |
| Field for Post ID | wordpress_post_id (doesn't exist) | external_id ✅ |
| Endpoint Response | Error on failure | 202 ACCEPTED immediately ✅ |

---

## Summary

**Root Cause:** Publishing endpoint used wrong architecture and Celery task had broken imports

**Critical Fixes:**
1. ✅ Changed publish endpoint to queue Celery task (async)
2. ✅ Fixed Celery task imports (ContentPost → Content)
3. ✅ Fixed field references (wordpress_post_id → external_id)
4. ✅ Updated all helper functions for unified Content model

**Result:** Publishing now works correctly with full content_html being sent to WordPress

---

**Status:** Ready for testing  
**Priority:** CRITICAL - Core functionality fixed  
**Breaking Changes:** None - purely internal fixes
