# Integrations Module

**Last Verified:** January 3, 2026  
**Version:** 1.3.2  
**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 |
| AI Core | `ai/ai_core.py` | OpenAI, Anthropic, Runware, Bria clients |
| Model Registry | `ai/model_registry.py` | Centralized model configs |
| Frontend | `pages/Settings/IntegrationSettings.tsx` | Integration UI |

---

## AI Provider Integrations (v1.3.0)

### Supported Providers

| Provider | Type | Models | API Key Field |
|----------|------|--------|---------------|
| OpenAI | Text/Image | gpt-4o, gpt-4o-mini, dall-e-3 | `openai_api_key` |
| Anthropic | Text | claude-3-5-sonnet, claude-3-opus, claude-3-haiku | `anthropic_api_key` |
| Runware | Image | runware-v2 | `runware_api_key` |
| Bria AI | Image | bria-2.3, bria-2.3-fast, bria-2.2 | `bria_api_key` |

### GlobalIntegrationSettings

Located in `modules/system/global_settings_models.py`:

| Field | Type | Purpose |
|-------|------|---------|
| openai_api_key | CharField | OpenAI API key |
| anthropic_api_key | CharField | Anthropic API key (v1.3.0) |
| runware_api_key | CharField | Runware API key |
| bria_api_key | CharField | Bria AI API key (v1.3.0) |
| default_text_model | CharField | Default text model |
| default_image_model | CharField | Default image model |
| default_image_provider | CharField | openai/runware/bria |

### Model Registry

Centralized model configuration with caching:

```python
from igny8_core.ai.model_registry import ModelRegistry

# Get model config
model = ModelRegistry.get_model('gpt-4o-mini')

# Calculate cost
cost = ModelRegistry.calculate_cost('gpt-4o-mini', input_tokens=1000, output_tokens=500)

# List all models
models = ModelRegistry.list_models(model_type='text', provider='openai')
```

### Migrations

- `0012_add_bria_integration.py` - Adds Bria AI integration settings
- `0013_add_anthropic_integration.py` - Adds Anthropic integration settings
- `0009_seed_ai_model_configs.py` - Seeds model configurations

---

## Purpose

The Integrations module manages:
- AI provider connections (OpenAI, Anthropic, Runware, Bria)
- WordPress site connections
- Two-way content synchronization
- Webhook handling
- External platform integrations

---

## Data Models

### Authentication Note

**⚠️ Important:** For WordPress integrations, `Site.wp_api_key` is the **SINGLE source of truth** for API authentication, NOT SiteIntegration fields. The SiteIntegration model is used for sync tracking and multi-platform support (future: Shopify).

### SiteIntegration

| Field | Type | Purpose |
|-------|------|---------|
| account | FK | Owner account |
| site | FK | IGNY8 site |
| platform | CharField | wordpress/shopify |
| external_site_url | URLField | External site URL |
| is_active | Boolean | Enable/disable |
| sync_enabled | Boolean | Enable auto-sync |
| last_sync_at | DateTime | Last sync time |
| sync_status | CharField | pending/syncing/completed/error |
| sync_error | TextField | Sync error message |
| connection_status | CharField | connected/error |
| config_json | JSON | Platform-specific configuration |
| credentials_json | JSON | (Reserved for future platforms, NOT used for WordPress) |
| 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 |

### PublishingSettings (v1.3.2)

Site-level publishing configuration. Used by the publishing scheduler.

| Field | Type | Purpose |
|-------|------|---------|
| site | OneToOneField | Parent site (unique per site) |
| auto_approval_enabled | BooleanField | Auto-approve content (default: False) |
| auto_publish_enabled | BooleanField | Auto-publish approved content (default: False) |
| daily_publish_limit | IntegerField | Max publications per day (default: 5) |
| weekly_publish_limit | IntegerField | Max per week (default: 20) |
| monthly_publish_limit | IntegerField | Max per month (default: 60) |
| publish_days | JSONField | Days for publishing ["mon","wed","fri"] |
| publish_time_slots | JSONField | Time slots [{"start":"09:00","end":"17:00"}] |

**Helper Method:**
```python
# Get or create settings for a site
settings, created = PublishingSettings.get_or_create_for_site(site)
```

**Related:** See [PUBLISHER.md](PUBLISHER.md) for publishing scheduler details.

---

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