# Publishing Progress & Scheduling UX Enhancement Plan

## Document Overview

**Author**: System Analysis  
**Date**: January 2025  
**Status**: Planning Phase  
**Target**: Publishing UX improvements with progress tracking and scheduling interfaces for multi-platform publishing (WordPress, Shopify, Custom Sites)

---

## 1. Executive Summary

This document provides a comprehensive implementation plan for enhancing the publishing workflow with:

1. **Publishing Progress Modals** - Real-time feedback for single and bulk publishing operations
2. **Publishing Limits & Validation** - Direct bulk publish limited to 5 items, unlimited scheduling
3. **Workflow Optimization** - Remove publish from Review page, make it Approved-only
4. **Scheduling UI Enhancement** - Add scheduling/rescheduling interfaces across multiple pages
5. **Site Settings Integration** - Bulk scheduling uses default settings from Site Settings → Publishing tab
6. **Failed Content Handling** - UI for rescheduling failed scheduled publications

### Key Design Principles

- **Pattern Consistency**: Follow existing modal patterns from ImageQueueModal and content generation
- **Progressive Disclosure**: Show appropriate details based on operation complexity
- **Real-time Feedback**: Live progress updates during publishing operations
- **Error Recovery**: Clear paths to retry/reschedule failed operations

---

## 2. Current System Analysis

### 2.1 Existing Publishing Architecture

**Backend System (v2.0)**:
- Service: `PublisherService` at `backend/igny8_core/business/publishing/services/publisher_service.py`
- API Endpoint: `POST /api/v1/publisher/publish`
- Credentials: Stored on `Site` model (`api_key`, `domain`, `platform_type`)
- Supported Platforms: WordPress, Shopify, Custom Sites
- Processing: Synchronous (not queued to Celery)
- Site Settings: Default publishing/scheduling configuration at `/sites/{site_id}/settings?tab=publishing`

**Scheduling System**:
- Celery Beat Task: `process_scheduled_publications` (runs every 5 minutes)
- Content States:
  - `site_status`: `not_published` → `scheduled` → `publishing` → `published`/`failed`
  - `scheduled_publish_at`: ISO8601 datetime
  - `site_status_updated_at`: Timestamp of last status change
- API Endpoints:
  - `POST /api/v1/writer/content/{id}/schedule/` - Schedule for future publishing
  - `POST /api/v1/writer/content/{id}/unschedule/` - Cancel scheduled publishing
  - `POST /api/v1/writer/content/{id}/reschedule/` - Reschedule from any status (NEW)

### 2.2 Current Publishing Workflows

**Review Page** (`frontend/src/pages/Writer/Review.tsx`):
- **Current Behavior**: Shows content with `status='review'`
- **Actions Available**:
  - Single publish: `handlePublishSingle()` → calls `POST /v1/publisher/publish/`
  - Bulk publish: `handlePublishBulk()` → loops through items, publishes individually
  - Approve (changes status to 'approved')
- **Issue**: Publishing from Review bypasses approval workflow
- **No Feedback**: No progress modal, only toast notifications
- **Current Issue**: Uses "WordPress" terminology, limiting perceived platform support

**Approved Page** (`frontend/src/pages/Writer/Approved.tsx`):
- **Current Behavior**: Shows content with `status='approved'` or `status='published'`
- **Actions Available**:
  - Single publish: `handleRowAction('publish_site')` → `POST /v1/publisher/publish/` (no limit)
  - Bulk publish: `handleBulkPublishToSite()` → loops through items (max 5 items)
  - Bulk schedule: Uses site default settings (no limit on items)
- **No Feedback**: No progress modal, only toast notifications
- **No Scheduling**: Cannot schedule for future publishing from UI
- **No Validation**: No limit enforcement for bulk operations
- **Current Issue**: Action names reference specific platforms instead of generic "site" terminology

**Content Calendar** (`frontend/src/pages/Publisher/ContentCalendar.tsx`):
- **Current Behavior**: Shows scheduled items with calendar view
- **Scheduling Method**: Drag-and-drop from approved sidebar to calendar dates
- **Schedule Time**: Defaults to 9 AM on dropped date
- **API Calls**:
  - `scheduleContent(contentId, scheduledDate)` → `POST /v1/writer/content/{id}/schedule/`
  - `unscheduleContent(contentId)` → `POST /v1/writer/content/{id}/unschedule/`
- **No Edit UI**: Cannot edit scheduled time without drag-drop

### 2.3 Existing Modal Patterns

**ImageQueueModal** (`frontend/src/components/common/ImageQueueModal.tsx`):
- **Purpose**: Shows AI image generation progress for multiple images
- **Key Features**:
  - Queue display with individual progress bars
  - Status per item: `pending` → `processing` → `completed`/`failed`
  - Smooth progress animation (1% → 50% in 5s, 50% → 80% at 2%/200ms, 80% → 100% on completion)
  - Real-time polling: `GET /v1/system/settings/task_progress/{taskId}/` every 1 second
  - Visual feedback: Status icons, color-coded progress bars
  - Thumbnail preview on completion
  - Cannot close while processing
- **State Management**:
  ```typescript
  interface ImageQueueItem {
    imageId: number | null;
    index: number;
    label: string;
    status: 'pending' | 'processing' | 'completed' | 'failed';
    progress: number;
    imageUrl: string | null;
    error: string | null;
  }
  ```
- **Progress Tracking**:
  - Backend provides: `current_image`, `current_image_id`, `current_image_progress`, `results[]`
  - Frontend manages smooth animation with `smoothProgress` state
  - Progress intervals cleared on completion/failure

---

## 3. Publishing Progress Modal Implementation

### 3.1 Single Content Publishing Modal

**Component**: `PublishingProgressModal` (new)  
**Location**: `frontend/src/components/common/PublishingProgressModal.tsx`

#### Design Specifications

**Modal Structure**:
```
┌────────────────────────────────────────────────────┐
│ 🚀 Publishing Content                              │
│ Publishing "Article Title Here" to [Site Name]     │
├────────────────────────────────────────────────────┤
│                                                     │
│ ┌────────────────────────────────────────────────┐ │
│ │ 📄 Preparing content...                   25%  │ │
│ │ ████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░    │ │
│ └────────────────────────────────────────────────┘ │
│                                                     │
│ Status: Uploading to WordPress...                  │
│                                                     │
├────────────────────────────────────────────────────┤
│ [Close button - only shown on completion/error]    │
└────────────────────────────────────────────────────┘
```

**Progress Stages**:
1. **Preparing content** (0-25%): Validating content structure
2. **Uploading to site** (25-50%): POST request to publishing platform API
3. **Processing response** (50-75%): Handling platform API response
4. **Finalizing** (75-100%): Updating content record

**State Interface**:
```typescript
interface PublishingProgressState {
  contentId: number;
  contentTitle: string;
  destination: 'wordpress' | 'shopify' | 'custom' | string; // Platform type
  siteName: string; // Actual site name for display
  status: 'preparing' | 'uploading' | 'processing' | 'finalizing' | 'completed' | 'failed';
  progress: number; // 0-100
  statusMessage: string;
  error: string | null;
  externalUrl: string | null; // Published URL on success
  externalId: string | null; // External platform post/page ID
}
```

**Progress Animation**:
- **Phase 1** (0-25%): 1% every 100ms for 2.5 seconds
- **Phase 2** (25-50%): During actual API call (may vary)
- **Phase 3** (50-75%): 2% every 80ms for 1 second
- **Phase 4** (75-100%): Fast animation on success (800ms)

**Error Handling**:
- Show error message in red alert box
- Display "Retry" and "Close" buttons
- Log full error for debugging
- Option to copy error details

**Success State**:
- Green checkmark icon
- "View on Site" button (opens `external_url` in new tab)
- Shows actual site name: "View on [Site Name]"
- "Close" button
- Auto-close after 3 seconds (optional)

#### API Integration

**Endpoint**: `POST /api/v1/publisher/publish/`  
**Request**:
```json
{
  "content_id": 123,
  "destinations": ["wordpress"] // Can be: "wordpress", "shopify", "custom"
}
```

**Response** (success):
```json
{
  "success": true,
  "data": {
    "success": true,
    "results": [
      {
        "destination": "wordpress", // or "shopify", "custom"
        "success": true,
        "external_id": "456",
        "url": "https://site.com/article-title/",
        "publishing_record_id": 789,
        "platform_type": "wordpress"
      }
    ]
  }
}
```

**Response** (failure):
```json
{
  "success": false,
  "error": "Publishing API error: Invalid credentials"
}
```

**Since publishing is synchronous**, the modal flow:
1. Open modal immediately on "Publish" click
2. Show "Preparing" stage with progress 0-25%
3. Make API call (update to "Uploading" at 25%)
4. On response:
   - Success: Animate 25% → 100% with status updates
   - Failure: Show error state
5. Update parent component's content list

### 3.2 Bulk Publishing Modal

**Component**: `BulkPublishingModal` (new)  
**Location**: `frontend/src/components/common/BulkPublishingModal.tsx`

#### Design Specifications

**Modal Structure** (similar to ImageQueueModal):
```
┌──────────────────────────────────────────────────────────┐
│ 🚀 Publishing Content                                    │
│ Publishing 5 articles to [Site Name]                     │
├──────────────────────────────────────────────────────────┤
│                                                           │
│ ┌────────────────────────────────────────────────────┐   │
│ │ 1️⃣ First Article Title                      ✓ 100%│   │
│ │ █████████████████████████████████████████████████  │   │
│ │ Published: https://site.com/article-1/            │   │
│ └────────────────────────────────────────────────────┘   │
│                                                           │
│ ┌────────────────────────────────────────────────────┐   │
│ │ 2️⃣ Second Article Title                     ⏳ 45% │   │
│ │ ████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  │   │
│ │ Status: Uploading to site...                      │   │
│ └────────────────────────────────────────────────────┘   │
│                                                           │
│ ┌────────────────────────────────────────────────────┐   │
│ │ 3️⃣ Third Article Title                       ⏸️ 0% │   │
│ │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  │   │
│ │ Status: Pending                                   │   │
│ └────────────────────────────────────────────────────┘   │
│                                                           │
│ [2 more items...]                                        │
│                                                           │
├──────────────────────────────────────────────────────────┤
│ 1 completed, 1 failed, 3 pending                        │
│                                        [Close - if done] │
└──────────────────────────────────────────────────────────┘
```

**Queue Item State**:
```typescript
interface PublishQueueItem {
  contentId: number;
  contentTitle: string;
  index: number;
  status: 'pending' | 'processing' | 'completed' | 'failed';
  progress: number; // 0-100
  statusMessage: string;
  error: string | null;
  externalUrl: string | null;
  externalId: string | null;
}
```

**Processing Strategy**:
- **Sequential Processing**: Publish one item at a time (not parallel)
- **Reason**: Avoid overwhelming platform APIs, easier error tracking, respects rate limits
- **Progress Animation**: Same as single modal per item
- **Status Updates**: Real-time per item
- **Platform Aware**: Adapts to WordPress, Shopify, or custom platform requirements

**Visual Indicators**:
- ✓ (green) - Completed
- ⏳ (blue) - Processing
- ⏸️ (gray) - Pending
- ❌ (red) - Failed

**Error Recovery**:
- Failed items show "Retry" button
- Can retry individual failed items
- Can skip failed items and continue
- Summary at bottom: X completed, Y failed, Z pending

**Cannot Close Until Complete**:
- Close button disabled while `status='processing'` items exist
- User must wait for all items to complete/fail
- Similar to ImageQueueModal behavior

#### Implementation Flow

```typescript
const handleBulkPublish = async (contentIds: number[]) => {
  // Initialize queue
  const queue: PublishQueueItem[] = contentIds.map((id, index) => ({
    contentId: id,
    contentTitle: getContentTitle(id), // Lookup from parent
    index: index + 1,
    status: 'pending',
    progress: 0,
    statusMessage: 'Pending',
    error: null,
    externalUrl: null,
    externalId: null,
  }));
  
  // Open modal with queue
  setPublishQueue(queue);
  setIsModalOpen(true);
  
  // Process sequentially
  for (let i = 0; i < queue.length; i++) {
    // Update status to processing
    updateQueueItem(i, { status: 'processing', progress: 0, statusMessage: 'Preparing...' });
    
    try {
      // Simulate progress animation
      animateProgress(i, 0, 25, 2500); // 0-25% in 2.5s
      
      // Call API (destination determined by site's platform_type)
      const response = await fetchAPI('/v1/publisher/publish/', {
        method: 'POST',
        body: JSON.stringify({
          content_id: queue[i].contentId,
          destinations: [sitePlatformType] // 'wordpress', 'shopify', or 'custom'
        })
      });
      
      // Handle response
      if (response.success && response.data?.results?.[0]?.success) {
        const result = response.data.results[0];
        animateProgress(i, 25, 100, 1500); // 25-100% in 1.5s
        updateQueueItem(i, {
          status: 'completed',
          progress: 100,
          statusMessage: 'Published',
          externalUrl: result.url,
          externalId: result.external_id,
        });
      } else {
        updateQueueItem(i, {
          status: 'failed',
          progress: 0,
          statusMessage: 'Failed',
          error: response.error || 'Unknown error',
        });
      }
    } catch (error) {
      updateQueueItem(i, {
        status: 'failed',
        progress: 0,
        statusMessage: 'Failed',
        error: error.message,
      });
    }
  }
  
  // All done - enable close button
  setAllComplete(true);
};
```

### 3.3 Publishing Limits & Validation

#### Direct Publish Limit (5 Items Max)

**Rationale**:
- Direct publishing is synchronous and resource-intensive
- Limits server load and prevents API rate limiting
- Encourages use of scheduling for large batches
- Single-item publish (3-dot menu) has no limit (only 1 item)

**Implementation**:

**Validation in Approved Page**:
```typescript
const handleBulkPublishClick = () => {
  const selectedCount = selectedIds.length;
  
  // Validate: Max 5 items for direct bulk publish
  if (selectedCount > 5) {
    // Show limit exceeded modal
    setShowPublishLimitModal(true);
    return;
  }
  
  // Proceed with bulk publish
  handleBulkPublishToSite(selectedIds);
};
```

**Limit Exceeded Modal**:
```
┌────────────────────────────────────────────────────────────┐
│ ⚠️ Publishing Limit Exceeded                               │
├────────────────────────────────────────────────────────────┤
│ You can publish only 5 content pages to site directly.    │
│                                                             │
│ You have selected {X} items.                                │
│                                                             │
│ Options:                                                    │
│ • Deselect items to publish 5 or fewer                     │
│ • Use "Schedule Selected" to schedule all items            │
│                                                             │
│ ℹ️ Tip: Scheduling has no limit and uses your site's       │
│   default publishing schedule.                              │
├────────────────────────────────────────────────────────────┤
│        [Schedule Selected] [Go Back]                       │
└────────────────────────────────────────────────────────────┘
```

**Modal Component**: `PublishLimitModal` (new)
```typescript
interface PublishLimitModalProps {
  isOpen: boolean;
  onClose: () => void;
  selectedCount: number;
  onScheduleInstead: () => void;
}

const PublishLimitModal = ({ isOpen, onClose, selectedCount, onScheduleInstead }) => {
  return (
    <Modal isOpen={isOpen} onClose={onClose}>
      <div className="text-center">
        <WarningIcon className="w-16 h-16 text-warning-500 mx-auto mb-4" />
        <h3 className="text-lg font-semibold mb-2">Publishing Limit Exceeded</h3>
        <p className="text-gray-600 mb-4">
          You can publish only <strong>5 content pages</strong> to site directly.
        </p>
        <p className="text-gray-600 mb-4">
          You have selected <strong>{selectedCount} items</strong>.
        </p>
        
        <div className="bg-blue-50 border-l-4 border-blue-500 p-4 mb-6 text-left">
          <p className="font-semibold mb-2">Options:</p>
          <ul className="list-disc list-inside space-y-1 text-sm">
            <li>Deselect items to publish 5 or fewer</li>
            <li>Use "Schedule Selected" to schedule all items</li>
          </ul>
          <p className="text-xs text-gray-600 mt-3">
            💡 Tip: Scheduling has no limit and uses your site's default publishing schedule.
          </p>
        </div>
        
        <div className="flex gap-3 justify-center">
          <Button variant="outline" onClick={onClose}>Go Back</Button>
          <Button variant="primary" onClick={onScheduleInstead}>
            Schedule Selected
          </Button>
        </div>
      </div>
    </Modal>
  );
};
```

**Button State Management**:
```typescript
// In Approved.tsx
const [showPublishLimitModal, setShowPublishLimitModal] = useState(false);

// Update primary action button
primaryAction={{
  label: selectedIds.length > 5 ? 'Publish (Limit Exceeded)' : 'Publish to Site',
  icon: <BoltIcon className="w-4 h-4" />,
  onClick: handleBulkPublishClick,
  variant: 'success',
  disabled: selectedIds.length === 0,
  tooltip: selectedIds.length > 5 
    ? 'You can only publish 5 items at once. Use scheduling for more.'
    : undefined
}}
```

#### Scheduling Has No Limit

**Bulk Schedule Action**:
- No limit on number of items
- Uses Site Settings default schedule
- Processes items through scheduling queue
- Better for large batches (10+ items)

**Visual Distinction**:
```typescript
// Bulk actions in Approved page
bulkActions: [
  {
    label: 'Publish Now (Max 5)',
    value: 'bulk_publish_now',
    icon: RocketLaunchIcon,
    variant: 'success',
    disabled: (selectedIds) => selectedIds.length > 5,
    tooltip: (selectedIds) => 
      selectedIds.length > 5 
        ? 'Can only publish 5 items directly. Use scheduling for more.'
        : 'Publish selected items immediately'
  },
  {
    label: 'Schedule Selected',
    value: 'bulk_schedule',
    icon: CalendarIcon,
    variant: 'primary',
    tooltip: 'Schedule items using site default settings (no limit)'
  }
]
```

### 3.4 Site Settings Integration for Bulk Scheduling

#### Default Publishing Schedule Configuration

**Location**: `/sites/{site_id}/settings?tab=publishing`

**Configuration Fields** (already exists in site settings):
- **Auto-publish Schedule**: Time of day to publish (e.g., 9:00 AM)
- **Publishing Frequency**: Daily, every X hours, specific days of week
- **Timezone**: Site's timezone for scheduling
- **Stagger Interval**: Minutes between each publish (e.g., 15 min intervals)
- **Max Daily Publishes**: Limit publications per day (optional)

**Used By**:
1. Automation system (existing)
2. Bulk scheduling from Approved page (new)
3. Content Calendar default times (new)

#### Bulk Schedule Implementation

**API Endpoint**: `POST /api/v1/writer/content/bulk_schedule/`

**Request**:
```json
{
  "content_ids": [123, 124, 125, 126],
  "use_site_defaults": true,
  "site_id": 45
}
```

**Response**:
```json
{
  "success": true,
  "scheduled_count": 4,
  "schedule_preview": [
    {
      "content_id": 123,
      "scheduled_at": "2025-01-17T09:00:00Z",
      "title": "First Article"
    },
    {
      "content_id": 124,
      "scheduled_at": "2025-01-17T09:15:00Z",
      "title": "Second Article"
    },
    {
      "content_id": 125,
      "scheduled_at": "2025-01-17T09:30:00Z",
      "title": "Third Article"
    },
    {
      "content_id": 126,
      "scheduled_at": "2025-01-17T09:45:00Z",
      "title": "Fourth Article"
    }
  ],
  "site_settings": {
    "base_time": "09:00 AM",
    "stagger_interval": 15,
    "timezone": "America/New_York"
  }
}
```

**Frontend Implementation**:
```typescript
const handleBulkScheduleWithDefaults = async (contentIds: number[]) => {
  try {
    // Show preview modal first
    const preview = await fetchAPI('/v1/writer/content/bulk_schedule_preview/', {
      method: 'POST',
      body: JSON.stringify({
        content_ids: contentIds,
        site_id: activeSite.id
      })
    });
    
    // Open confirmation modal with schedule preview
    setBulkSchedulePreview(preview);
    setShowBulkScheduleConfirmModal(true);
  } catch (error) {
    toast.error(`Failed to generate schedule preview: ${error.message}`);
  }
};

const confirmBulkSchedule = async () => {
  try {
    const response = await fetchAPI('/v1/writer/content/bulk_schedule/', {
      method: 'POST',
      body: JSON.stringify({
        content_ids: selectedIds.map(id => parseInt(id)),
        use_site_defaults: true,
        site_id: activeSite.id
      })
    });
    
    toast.success(`Scheduled ${response.scheduled_count} items`);
    loadContent(); // Refresh
    setShowBulkScheduleConfirmModal(false);
  } catch (error) {
    toast.error(`Failed to schedule: ${error.message}`);
  }
};
```

**Bulk Schedule Preview Modal**:
```
┌────────────────────────────────────────────────────────────┐
│ 📅 Schedule 10 Articles                                    │
├────────────────────────────────────────────────────────────┤
│ Using site default schedule:                               │
│ • Start time: 9:00 AM (America/New_York)                   │
│ • Stagger: 15 minutes between each                         │
│ • First publish: Tomorrow, Jan 17, 2025 at 9:00 AM        │
│ • Last publish: Tomorrow, Jan 17, 2025 at 11:15 AM        │
│                                                             │
│ Schedule Preview:                                           │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ 1. First Article          → Jan 17, 9:00 AM           │ │
│ │ 2. Second Article         → Jan 17, 9:15 AM           │ │
│ │ 3. Third Article          → Jan 17, 9:30 AM           │ │
│ │ 4. Fourth Article         → Jan 17, 9:45 AM           │ │
│ │ 5. Fifth Article          → Jan 17, 10:00 AM          │ │
│ │ ... and 5 more                                         │ │
│ └────────────────────────────────────────────────────────┘ │
│                                                             │
│ ℹ️ Modify defaults at Site Settings → Publishing tab       │
│                                                             │
├────────────────────────────────────────────────────────────┤
│   [Change Settings] [Cancel] [Confirm Schedule]            │
└────────────────────────────────────────────────────────────┘
```

**Link to Site Settings**:
```typescript
const handleChangeSettings = () => {
  // Open site settings in new tab
  window.open(`/sites/${activeSite.id}/settings?tab=publishing`, '_blank');
  // Keep modal open so user can return and confirm
};
```

---

## 4. Workflow Changes: Remove Publish from Review Page

### 4.1 Current Problem

**Review Page** currently allows direct publishing, which:
- Bypasses the approval workflow
- Allows unapproved content to go live
- Creates confusion about content workflow states
- Inconsistent with expected review → approve → publish flow
- Uses platform-specific terminology ("Publish to WordPress") limiting perceived capabilities

### 4.2 Proposed Changes

**Review Page** (`frontend/src/pages/Writer/Review.tsx`):

**Remove**:
- ❌ `handlePublishSingle()` function
- ❌ `handlePublishBulk()` function
- ❌ "Publish to WordPress" action (replace with generic "Publish" in Approved page)
- ❌ "Publish to Site" bulk action button from Review page

**Keep**:
- ✅ `handleApproveSingle()` - Approve individual items
- ✅ `handleApproveBulk()` - Approve multiple items
- ✅ "Approve" action (changes status to 'approved')
- ✅ View, Edit, Delete actions

**New Primary Action**:
```typescript
primaryAction={{
  label: 'Approve',
  icon: <CheckCircleIcon className="w-4 h-4" />,
  onClick: () => handleBulkAction('bulk_approve', selectedIds),
  variant: 'success',
}}
```

**Updated Page Description**:
```typescript
// Old: "Shows content with status='review' ready for publishing"
// New: "Shows content with status='review' ready for approval"
```

**Impact**:
- Content in Review can only be approved
- To publish, content must first move to Approved page
- Clearer workflow: Draft → Review → Approved → Publish
- No breaking changes to backend

### 4.3 Updated Row Actions Config

**File**: `frontend/src/config/pages/review.config.tsx`

**Before**:
```typescript
rowActions: [
  { label: 'Approve', value: 'approve', icon: CheckCircleIcon },
  { label: 'Publish to WordPress', value: 'publish_wordpress', icon: RocketLaunchIcon }, // Platform-specific
  { label: 'View', value: 'view', icon: EyeIcon },
  { label: 'Edit', value: 'edit', icon: PencilIcon },
  { label: 'Delete', value: 'delete', icon: TrashBinIcon, danger: true },
]
```

**After**:
```typescript
rowActions: [
  { label: 'Approve', value: 'approve', icon: CheckCircleIcon },
  { label: 'View', value: 'view', icon: EyeIcon },
  { label: 'Edit', value: 'edit', icon: PencilIcon },
  { label: 'Delete', value: 'delete', icon: TrashBinIcon, danger: true },
]
```

---

## 5. Scheduling UI Implementation

### 5.1 Schedule/Reschedule in Approved Page

**Component**: Add scheduling button to row actions and bulk actions

#### Row Action: Schedule Single Item

**Modal**: `ScheduleContentModal` (new)  
**Location**: `frontend/src/components/common/ScheduleContentModal.tsx`

**Design**:
```
┌────────────────────────────────────────┐
│ 📅 Schedule Content Publishing         │
├────────────────────────────────────────┤
│ Content: "Article Title Here"          │
│                                         │
│ Schedule Date:                          │
│ [Date Picker: MM/DD/YYYY        ▼]     │
│                                         │
│ Schedule Time:                          │
│ [Time Picker: HH:MM AM/PM       ▼]     │
│                                         │
│ Preview: January 15, 2025 at 9:00 AM   │
│                                         │
├────────────────────────────────────────┤
│              [Cancel] [Schedule]        │
└────────────────────────────────────────┘
```

**Implementation**:
```typescript
interface ScheduleContentModalProps {
  isOpen: boolean;
  onClose: () => void;
  content: Content;
  onSchedule: (contentId: number, scheduledDate: string) => Promise<void>;
}

const ScheduleContentModal = ({ isOpen, onClose, content, onSchedule }) => {
  const [selectedDate, setSelectedDate] = useState<Date>(getDefaultScheduleDate());
  const [selectedTime, setSelectedTime] = useState<string>('09:00 AM');
  
  const getDefaultScheduleDate = () => {
    const tomorrow = new Date();
    tomorrow.setDate(tomorrow.getDate() + 1);
    return tomorrow;
  };
  
  const handleSchedule = async () => {
    // Combine date and time
    const scheduledDateTime = combineDateAndTime(selectedDate, selectedTime);
    
    try {
      await onSchedule(content.id, scheduledDateTime.toISOString());
      toast.success(`Scheduled for ${formatScheduledTime(scheduledDateTime)}`);
      onClose();
    } catch (error) {
      toast.error(`Failed to schedule: ${error.message}`);
    }
  };
  
  return (
    <Modal isOpen={isOpen} onClose={onClose}>
      {/* Date/Time pickers */}
      <Button onClick={handleSchedule}>Schedule</Button>
    </Modal>
  );
};
```

**API Call**:
```typescript
const handleScheduleContent = async (contentId: number, scheduledDate: string) => {
  const response = await fetchAPI(`/v1/writer/content/${contentId}/schedule/`, {
    method: 'POST',
    body: JSON.stringify({ scheduled_publish_at: scheduledDate }),
  });
  
  // Update local state
  setContent(prevContent =>
    prevContent.map(c => c.id === contentId ? {
      ...c,
      site_status: 'scheduled',
      scheduled_publish_at: scheduledDate,
    } : c)
  );
};
```

#### Row Action: Reschedule Item

**Trigger**: Show "Reschedule" action when:
- `site_status === 'scheduled'` (scheduled but not yet published)
- `site_status === 'failed'` (scheduled publishing failed)

**Modal**: Reuse `ScheduleContentModal` but:
- Title: "Reschedule Content Publishing"
- Pre-fill with existing `scheduled_publish_at` date/time
- API: `POST /v1/writer/content/{id}/reschedule/`

**Implementation**:
```typescript
const handleRescheduleContent = async (contentId: number, scheduledDate: string) => {
  const response = await fetchAPI(`/v1/writer/content/${contentId}/reschedule/`, {
    method: 'POST',
    body: JSON.stringify({ scheduled_at: scheduledDate }),
  });
  
  // Update local state
  setContent(prevContent =>
    prevContent.map(c => c.id === contentId ? {
      ...c,
      site_status: 'scheduled',
      scheduled_publish_at: scheduledDate,
    } : c)
  );
  
  toast.success('Rescheduled successfully');
};
```

#### Row Action: Unschedule Item

**Trigger**: Show when `site_status === 'scheduled'`

**Confirmation Modal**:
```
┌────────────────────────────────────────┐
│ ⚠️ Unschedule Content?                 │
├────────────────────────────────────────┤
│ Are you sure you want to unschedule    │
│ "Article Title Here"?                   │
│                                         │
│ Current schedule: Jan 15, 2025 9:00 AM │
│                                         │
├────────────────────────────────────────┤
│              [Cancel] [Unschedule]      │
└────────────────────────────────────────┘
```

**API Call**:
```typescript
const handleUnscheduleContent = async (contentId: number) => {
  await fetchAPI(`/v1/writer/content/${contentId}/unschedule/`, {
    method: 'POST',
  });
  
  setContent(prevContent =>
    prevContent.map(c => c.id === contentId ? {
      ...c,
      site_status: 'not_published',
      scheduled_publish_at: null,
    } : c)
  );
  
  toast.success('Unscheduled successfully');
};
```

#### Updated Row Actions for Approved Page

**File**: `frontend/src/config/pages/approved.config.tsx`

**Dynamic row actions based on content state** (platform-agnostic):
```typescript
const getRowActions = (content: Content, siteName: string) => {
  const actions = [];
  
  // Always available
  actions.push({ label: 'View', value: 'view', icon: EyeIcon });
  actions.push({ label: 'Edit', value: 'edit', icon: PencilIcon });
  
  // Publishing actions based on site_status (platform-agnostic)
  if (content.site_status === 'not_published') {
    actions.push({ label: 'Publish Now', value: 'publish_site', icon: RocketLaunchIcon });
    actions.push({ label: 'Schedule', value: 'schedule', icon: CalendarIcon });
  } else if (content.site_status === 'scheduled') {
    actions.push({ label: 'Reschedule', value: 'reschedule', icon: CalendarIcon });
    actions.push({ label: 'Unschedule', value: 'unschedule', icon: XIcon });
    actions.push({ label: 'Publish Now', value: 'publish_site', icon: RocketLaunchIcon });
  } else if (content.site_status === 'failed') {
    actions.push({ label: 'Publish Now', value: 'publish_site', icon: RocketLaunchIcon });
    actions.push({ label: 'Reschedule', value: 'reschedule', icon: CalendarIcon });
  } else if (content.site_status === 'published' && content.external_url) {
    // Use actual site name for dynamic label
    actions.push({ 
      label: `View on ${siteName}`, 
      value: 'view_on_site', 
      icon: ExternalLinkIcon 
    });
  }
  
  actions.push({ label: 'Delete', value: 'delete', icon: TrashBinIcon, danger: true });
  
  return actions;
};
```

#### Bulk Actions for Scheduling

**New bulk action**: "Schedule Selected"

**Modal**: `BulkScheduleModal` (new)
```
┌────────────────────────────────────────┐
│ 📅 Schedule 5 Articles                 │
├────────────────────────────────────────┤
│ Schedule all selected articles for:    │
│                                         │
│ Date: [MM/DD/YYYY              ▼]      │
│ Time: [HH:MM AM/PM             ▼]      │
│                                         │
│ Preview: January 15, 2025 at 9:00 AM   │
│                                         │
│ ⚠️ All 5 articles will be scheduled    │
│    for the same date and time.         │
│                                         │
├────────────────────────────────────────┤
│              [Cancel] [Schedule All]    │
└────────────────────────────────────────┘
```

**Implementation**:
```typescript
const handleBulkSchedule = async (contentIds: number[], scheduledDate: string) => {
  let successCount = 0;
  let failedCount = 0;
  
  for (const contentId of contentIds) {
    try {
      await fetchAPI(`/v1/writer/content/${contentId}/schedule/`, {
        method: 'POST',
        body: JSON.stringify({ scheduled_publish_at: scheduledDate }),
      });
      successCount++;
    } catch (error) {
      console.error(`Failed to schedule content ${contentId}:`, error);
      failedCount++;
    }
  }
  
  if (successCount > 0) {
    toast.success(`Scheduled ${successCount} item(s)`);
  }
  if (failedCount > 0) {
    toast.warning(`${failedCount} item(s) failed to schedule`);
  }
  
  loadContent(); // Refresh
};
```

### 5.2 Scheduling in Content Calendar Page

**Current State**: Scheduling via drag-and-drop works well

**Enhancement**: Add "Edit Schedule" button to scheduled items

**Design**:
- Each scheduled item in calendar has an "Edit" button
- Opens `ScheduleContentModal` with existing date/time pre-filled
- User can change date/time
- Calls reschedule API

**Implementation** (add to calendar item render):
```typescript
{item.site_status === 'scheduled' && (
  <IconButton
    icon={<PencilIcon className="w-4 h-4" />}
    onClick={() => openRescheduleModal(item)}
    title="Edit schedule"
    size="sm"
  />
)}
```

**Failed Items Handling**:
- Show failed items in a separate section (not on calendar)
- Red error badge
- Two buttons: "Reschedule" and "Publish Now"
- Clicking "Reschedule" opens `ScheduleContentModal`

**Design**:
```
┌──────────────────────────────────────────────────────────┐
│ ❌ Failed Scheduled Publications (2)                     │
├──────────────────────────────────────────────────────────┤
│ ⚠️ Article Title 1                                       │
│    Site: My WordPress Blog                               │
│    Scheduled: Jan 13, 2025 9:00 AM                       │
│    Error: Publishing API error: Invalid credentials      │
│    [Reschedule] [Publish Now]                            │
│                                                           │
│ ⚠️ Article Title 2                                       │
│    Site: My Shopify Store                                │
│    Scheduled: Jan 13, 2025 10:00 AM                      │
│    Error: Network timeout                                │
│    [Reschedule] [Publish Now]                            │
└──────────────────────────────────────────────────────────┘
```

### 5.3 Scheduling in ContentView Template

**File**: `frontend/src/templates/ContentView.tsx` (if exists)

**Note**: File not found during analysis - may not exist or may be different path

**If this is the content detail view**:
- Add "Schedule" button in header actions (if `site_status === 'not_published'`)
- Add "Reschedule" button (if `site_status === 'scheduled'` or `site_status === 'failed'`)
- Add "Publish Now" button (if approved)
- Show current schedule prominently if scheduled

**Alternate**: If ContentView doesn't exist, check if content detail page is at:
- `frontend/src/pages/Writer/ContentDetail.tsx`
- Or individual content pages use a different template

---

## 6. Failed Content Handling

### 6.1 Identifying Failed Content

**Query**: Content where `site_status = 'failed'`

**Display Locations**:
1. **Approved Page**: Filter by `site_status = 'failed'`
2. **Content Calendar**: Separate "Failed" section
3. **Dashboard Widget**: "Failed Publications" count

### 6.2 Failed Item UI Treatment

**Visual Indicators**:
- ❌ Red error badge: "Failed"
- 🕐 Show original scheduled time
- 📄 Show error message (truncated)
- 🔄 Retry options: "Publish Now" or "Reschedule"

**Row Actions for Failed Items**:
```typescript
{
  label: 'Publish Now',
  value: 'publish_site',
  icon: RocketLaunchIcon,
}
{
  label: 'Reschedule',
  value: 'reschedule',
  icon: CalendarIcon,
}
{
  label: 'View Error Details',
  value: 'view_error',
  icon: ErrorIcon,
}
```

**Error Details Modal**:
```
┌────────────────────────────────────────────────────────────┐
│ ❌ Publishing Error Details                                │
├────────────────────────────────────────────────────────────┤
│ Content: "Article Title Here"                              │
│ Site: My WordPress Blog (WordPress)                        │
│ Scheduled: January 13, 2025 at 9:00 AM                     │
│ Failed: January 13, 2025 at 9:05 AM                        │
│                                                             │
│ Error Message:                                              │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Publishing API error: Invalid credentials              │ │
│ │                                                         │ │
│ │ The publishing site returned a 403 Forbidden error.    │ │
│ │ Please check the API key in Site Settings.             │ │
│ └────────────────────────────────────────────────────────┘ │
│                                                             │
│ Actions:                                                    │
│ [Fix Site Settings] [Publish Now] [Reschedule] [Close]    │
└────────────────────────────────────────────────────────────┘
```

### 6.3 Retry Logic

**Publish Now** (from failed state):
- Opens `PublishingProgressModal`
- Same flow as normal publish
- On success: `site_status` → `published`, clear error
- On failure: Update error message, keep as `failed`

**Reschedule** (from failed state):
- Opens `ScheduleContentModal`
- Pre-fill with original scheduled time (or next day)
- On save: `site_status` → `scheduled`, clear error
- Celery task will retry at new scheduled time

---

## 7. Implementation Phases

### Phase 1: Publishing Progress Modals (Week 1-2)

**Tasks**:
1. Create `PublishingProgressModal.tsx` component (platform-agnostic)
2. Create `BulkPublishingModal.tsx` component (platform-agnostic)
3. Create `PublishLimitModal.tsx` component (new - limit validation)
4. Update `Approved.tsx`:
   - Integrate single publish modal
   - Integrate bulk publish modal (max 5 items)
   - Add limit validation: show `PublishLimitModal` if > 5 selected
   - Rename `handleBulkPublishWordPress` to `handleBulkPublishToSite`
   - Update action names: `publish_wordpress` → `publish_site`
   - Display actual site name in UI
   - Add "Schedule Selected" bulk action (no limit)
5. Test with WordPress, Shopify, and custom sites
6. Handle platform-specific error states and retry logic
7. Test limit validation (6+ items selected)

**Deliverables**:
- ✅ Single publish with progress feedback (all platforms)
- ✅ Bulk publish with queue progress (max 5 items)
- ✅ Publishing limit validation modal
- ✅ Error handling with retry
- ✅ Success state with "View on [Site Name]" link
- ✅ Platform-agnostic terminology throughout

### Phase 2: Remove Publish from Review (Week 2)

**Tasks**:
1. Update `Review.tsx`:
   - Remove `handlePublishSingle()` function
   - Remove `handlePublishBulk()` function
   - Remove publish actions from row actions
   - Update primary action to "Approve"
2. Update `review.config.tsx`:
   - Remove publish actions from rowActions array
3. Test workflow: Review → Approve → Approved → Publish

**Deliverables**:
- ✅ Review page only approves content
- ✅ No publishing from Review page
- ✅ Clearer workflow separation

### Phase 3: Scheduling UI in Approved Page (Week 3)

**Tasks**:
1. Create `ScheduleContentModal.tsx` component
2. Create `BulkScheduleModal.tsx` component (manual date/time)
3. Create `BulkSchedulePreviewModal.tsx` component (site defaults preview)
4. Create backend endpoint: `POST /v1/writer/content/bulk_schedule/`
5. Create backend endpoint: `POST /v1/writer/content/bulk_schedule_preview/`
6. Update `Approved.tsx`:
   - Add "Schedule" row action
   - Add "Reschedule" row action (conditional)
   - Add "Unschedule" row action (conditional)
   - Add "Schedule Selected" bulk action (uses site defaults)
   - Dynamic row actions based on `site_status`
   - Link to site settings from schedule preview modal
7. Test scheduling, rescheduling, unscheduling
8. Test bulk scheduling with site defaults (10+ items)
9. Verify site settings integration

**Deliverables**:
- ✅ Schedule content for future publishing
- ✅ Reschedule existing scheduled content
- ✅ Unschedule content
- ✅ Bulk scheduling with site default settings
- ✅ Schedule preview before confirmation
- ✅ Link to Site Settings → Publishing tab
- ✅ No limit on scheduled items

### Phase 4: Failed Content Handling (Week 3-4)

**Tasks**:
1. Add failed content filter to Approved page
2. Create failed items section in Content Calendar
3. Create `ErrorDetailsModal.tsx` for viewing full errors
4. Add retry logic for failed items
5. Update row actions for failed items

**Deliverables**:
- ✅ Visual indication of failed content
- ✅ Error details modal
- ✅ Retry/Reschedule options
- ✅ Clear error messages

### Phase 5: Content Calendar Enhancements (Week 4)

**Tasks**:
1. Add "Edit Schedule" button to calendar items
2. Add failed items section to calendar
3. Improve calendar item tooltips
4. Test drag-drop with new scheduling modals

**Deliverables**:
- ✅ Edit scheduled items from calendar
- ✅ Failed items displayed prominently
- ✅ Improved UX for scheduling

### Phase 6: Testing & Documentation (Week 5)

**Tasks**:
1. E2E testing of all workflows
2. Test error scenarios
3. Update user documentation
4. Create user guide for new scheduling features
5. Performance testing for bulk operations

**Deliverables**:
- ✅ All features tested and working
- ✅ Documentation updated
- ✅ User guide created
- ✅ Performance benchmarks

---

## 8. Technical Considerations

### 8.1 State Management

**Local State** (per page):
- Modal open/close states
- Queue items for bulk operations
- Selected date/time for scheduling

**Global State** (if needed):
- Active publishing operations (prevent duplicate publishes)
- Recent errors (for error dashboard)

**Recommendation**: Use local component state with React hooks. No need for Redux/Zustand unless state sharing becomes complex.

### 8.2 Performance

**Bulk Operations**:
- Sequential processing (not parallel) to avoid API rate limits
- Show progress per item
- Allow cancellation (future enhancement)

**Calendar View**:
- Lazy load calendar months
- Limit displayed items per date (show "X more..." if > 3)
- Virtual scrolling for large lists

**Polling** (if needed for async publishing):
- Currently publishing is synchronous, so no polling needed
- If made async in future, poll task status like ImageQueueModal does

### 8.3 Error Handling

**Network Errors**:
- Catch and display user-friendly messages
- Log full error to console for debugging
- Provide retry button

**Platform API Errors**:
- Parse platform-specific error messages (WordPress, Shopify, Custom API)
- Highlight common issues (invalid credentials, missing fields, rate limits)
- Link to Site Settings for credential fixes
- Show platform type in error messages for clarity

**Validation Errors**:
- Validate schedule date/time (must be in future)
- Validate content is approved before publishing
- Check site configuration exists (API key, domain)
- Verify platform-specific requirements are met

### 8.4 Accessibility

**Modals**:
- Keyboard navigation (Tab, Esc)
- ARIA labels for screen readers
- Focus trap when modal is open
- Announce status changes

**Progress Bars**:
- ARIA role="progressbar"
- aria-valuenow, aria-valuemin, aria-valuemax
- Announce percentage changes

**Color Indicators**:
- Don't rely only on color (use icons too)
- High contrast for dark mode
- Color-blind friendly palette

---

## 9. UI/UX Best Practices

### 9.1 Loading States

- Show skeleton loaders for content lists
- Disable buttons during API calls
- Show spinner in button: "Publishing..." (with spinner icon)
- Progress bars for multi-step operations

### 9.2 Success Feedback

- Green toast notification: "Published successfully"
- Green checkmark icon in modal
- Auto-refresh content list on success
- Optional: Confetti animation for first publish

### 9.3 Error Feedback

- Red toast notification: "Failed to publish: [error]"
- Red alert box in modal with full error
- "Copy error details" button for debugging
- "Contact support" link if needed

### 9.4 Empty States

- No scheduled content: Show calendar with "Drag approved content here"
- No failed content: "No failed publications" with green checkmark
- No approved content: "Approve content from Review page"

### 9.5 Tooltips and Help Text

- Calendar dates: "Drag content here to schedule"
- Schedule button: "Schedule for future publishing to site"
- Publish button: "Publish immediately to [Site Name]"
- Failed badge: "Publishing failed - click for details"
- Site name shown in all tooltips where relevant

---

## 10. Future Enhancements

### 10.1 Advanced Scheduling

- **Recurring schedules**: Publish every Monday at 9 AM
- **Bulk schedule spread**: Schedule 10 items over next 2 weeks (evenly distributed)
- **Optimal timing**: AI suggests best time to publish based on traffic data
- **Timezone support**: Schedule in site's timezone (not user's)

### 10.2 Publishing Queue Management

- **Pause/Resume queue**: Pause all scheduled publications
- **Reorder queue**: Drag to reorder in list view
- **Priority flag**: Mark content as high priority (publish first)
- **Batch limits**: Limit to X publications per day

### 10.3 Multi-Platform Publishing

- **Social media**: Publish to Facebook, Twitter, LinkedIn
- **Multiple sites**: Publish to multiple sites simultaneously (WordPress, Shopify, Custom)
- **Cross-post**: Publish same content to blog + Medium + Dev.to
- **Mixed platforms**: Schedule content to WordPress site and Shopify store at different times

### 10.4 Advanced Error Handling

- **Auto-retry**: Retry failed publications X times before marking as failed
- **Error patterns**: Detect common errors and suggest fixes
- **Health checks**: Pre-flight check before scheduling (test credentials)

### 10.5 Analytics Integration

- **Publishing stats**: Track success/failure rates
- **Performance metrics**: Average time to publish
- **Engagement tracking**: Track views/clicks on published content
- **Calendar heatmap**: Visual representation of publishing activity

---

## 11. Testing Checklist

### 11.1 Single Publishing

- [ ] Publish single approved content
- [ ] Progress modal shows correct stages
- [ ] Success state displays site URL (works for WordPress, Shopify, Custom)
- [ ] Modal shows actual site name, not platform type
- [ ] Error state displays error message
- [ ] Retry button works on failure
- [ ] Close button disabled during publish
- [ ] Content list refreshes on success
- [ ] Test with WordPress site
- [ ] Test with Shopify site
- [ ] Test with Custom site

### 11.2 Bulk Publishing

- [ ] Publish multiple approved content items (up to 5)
- [ ] Limit validation: 6+ items shows PublishLimitModal
- [ ] PublishLimitModal offers "Schedule Selected" option
- [ ] Single record publish (3-dot menu) has no limit
- [ ] Queue displays all items
- [ ] Sequential processing works
- [ ] Individual progress per item
- [ ] Mixed success/failure handling
- [ ] Retry individual failed items
- [ ] Close button enabled after completion
- [ ] Button tooltip shows limit info when > 5 selected

### 11.3 Scheduling

**Manual Scheduling:**
- [ ] Schedule single content (manual date/time)
- [ ] Schedule bulk content (manual date/time)
- [ ] Date/time picker validation
- [ ] Schedule in past shows error
- [ ] Scheduled items appear in calendar
- [ ] Drag-and-drop scheduling works
- [ ] Reschedule changes date/time
- [ ] Unschedule removes from calendar

**Bulk Scheduling with Site Defaults:**
- [ ] Select 10+ items for scheduling (no limit)
- [ ] "Schedule Selected" button opens preview modal
- [ ] Preview shows schedule with stagger intervals
- [ ] Preview displays site settings (time, stagger, timezone)
- [ ] "Change Settings" link opens site settings in new tab
- [ ] Confirm schedule applies to all selected items
- [ ] Items appear in calendar with scheduled times
- [ ] Site settings at `/sites/{id}/settings?tab=publishing` has scheduling config
- [ ] Automation uses same scheduling config
- [ ] Bulk scheduled items respect site's daily limits (if configured)

### 11.4 Failed Content

- [ ] Failed items display with error badge
- [ ] Error details modal shows full error
- [ ] Retry from failed state works
- [ ] Reschedule from failed state works
- [ ] Failed section in calendar shows items
- [ ] Filter failed items in Approved page

### 11.5 Review Page Changes

- [ ] Publish actions removed
- [ ] Approve action works
- [ ] Bulk approve works
- [ ] No direct publishing possible
- [ ] Approved content moves to Approved page

### 11.6 Edge Cases

- [ ] No site credentials: Error message
- [ ] Missing API key: Error message
- [ ] Unsupported platform type: Error message
- [ ] Network timeout: Error message
- [ ] Invalid content (missing required fields): Error
- [ ] Publishing already published content: Handled
- [ ] Scheduling already scheduled content: Reschedule
- [ ] Deleting scheduled content: Removes from calendar
- [ ] Site change: Refresh content
- [ ] Platform-specific validation (WordPress categories, Shopify collections, etc.)

**Publishing Limits:**
- [ ] Selecting exactly 5 items: Direct publish allowed
- [ ] Selecting 6 items: PublishLimitModal shown
- [ ] Selecting 10+ items: PublishLimitModal shown, suggests scheduling
- [ ] From limit modal: "Schedule Selected" opens bulk schedule preview
- [ ] From limit modal: "Go Back" closes modal, keeps selection
- [ ] Single publish (3-dot): Always allowed, no limit modal
- [ ] Bulk button disabled when no items selected
- [ ] Bulk button shows tooltip when > 5 items selected

**Bulk Scheduling:**
- [ ] No site scheduling config: Uses defaults (9 AM, 15 min stagger)
- [ ] Site has custom schedule: Preview reflects custom settings
- [ ] Scheduling 50+ items: No error, all scheduled
- [ ] Site settings link opens correct tab
- [ ] Return from site settings: Preview refreshes with new settings

---

## 12. Documentation Updates Required

### 12.1 User Documentation

**File**: `docs/40-WORKFLOWS/CONTENT-PUBLISHING.md` (new or update existing)

**Sections**:
1. Publishing Workflow Overview
2. Publishing from Approved Page
3. Scheduling Content
4. Managing Scheduled Content
5. Handling Failed Publications
6. Bulk Operations
7. Troubleshooting

### 12.2 Developer Documentation

**File**: `docs/30-FRONTEND/PUBLISHING-MODALS.md` (new)

**Sections**:
1. Modal Architecture
2. Component API Reference
3. State Management
4. API Integration
5. Progress Animation Logic
6. Error Handling Patterns
7. Testing Guidelines

### 12.3 API Documentation

**File**: `docs/20-API/PUBLISHER.md` (update existing)

**Add**:
- Schedule endpoint: `POST /v1/writer/content/{id}/schedule/`
- Reschedule endpoint: `POST /v1/writer/content/{id}/reschedule/`
- Unschedule endpoint: `POST /v1/writer/content/{id}/unschedule/`
- Examples with request/response

---

## 13. Conclusion

This comprehensive plan provides:

1. ✅ **Publishing Progress Modals** - Real-time feedback for single and bulk operations
2. ✅ **Publishing Limits & Validation** - Max 5 direct publish, unlimited scheduling
3. ✅ **Workflow Optimization** - Clear separation of Review (approve only) and Approved (publish)
4. ✅ **Scheduling UI** - Full scheduling/rescheduling capabilities across multiple pages
5. ✅ **Site Settings Integration** - Bulk scheduling uses default configuration
6. ✅ **Failed Content Handling** - Clear error display with retry/reschedule options
7. ✅ **Pattern Consistency** - Follows existing modal patterns from ImageQueueModal
8. ✅ **User Experience** - Intuitive, informative, and forgiving interface
9. ✅ **Platform Agnostic** - Supports WordPress, Shopify, Custom sites with unified terminology
10. ✅ **Scalable Architecture** - Easy to add new publishing platforms in the future

### Key Success Metrics

- **User Satisfaction**: Fewer support tickets about "where did my content go?"
- **Publishing Success Rate**: Increased from tracking and retry capabilities
- **Workflow Clarity**: Users understand: Review → Approve → Publish
- **Error Recovery**: Failed publications can be easily rescheduled
- **Time Savings**: Bulk operations with progress tracking reduce manual work

### Next Steps

1. Review this plan with stakeholders
2. Prioritize phases based on business needs
3. Begin Phase 1 implementation (Publishing Progress Modals)
4. Conduct user testing after Phase 3
5. Iterate based on feedback

---

**Document Version**: 1.0  
**Last Updated**: January 2025  
**Status**: Ready for Implementation
