Files
igny8/docs/WRITER_MODULE_REFACTORING_PLAN.md
alorig 8d096b383a 21
2025-11-29 14:33:07 +05:00

1307 lines
36 KiB
Markdown

# Writer Module Comprehensive Refactoring Plan
**Date:** December 2024
**Purpose:** Complete refactoring of Writer module pages (Tasks, Content, Images, Published) based on deep analysis and user requirements
---
## Executive Summary
This document outlines a comprehensive refactoring plan for the IGNY8 Writer module. After deep analysis of all Writer pages, configurations, and data flows, we've identified critical issues and improvements needed to create a cohesive, efficient content workflow from task creation through WordPress publishing.
**Key Objectives:**
1. Fix critical bugs (bulk select, delete functions)
2. Restructure Published page to show Content (not Tasks)
3. Implement proper WordPress publishing workflow
4. Add "review" status to content lifecycle
5. Improve UX with better status indicators and content viewing
---
## Current State Analysis
### Page Structure Overview
```
Writer Module Flow:
Tasks (queued/completed) → Content (draft/published) → Images (pending/generated/failed) → Published (?)
```
### 1. Tasks Page (`Tasks.tsx` - 787 lines)
**Purpose:** Task queue management for content generation
**Current Implementation:**
- ✅ Loads Tasks table via `fetchTasks()` API
- ✅ Status workflow: `queued``completed`
- ✅ Row actions: Edit, Generate Content
- ✅ Bulk actions: Update Status, Export
- ✅ Progress modal for AI functions
- ✅ Selection and pagination working
- ✅ AI logs when Resource Debug enabled
**Issues:**
- None critical
**Data Model:**
```typescript
interface Task {
id: number;
title: string;
cluster: string;
taxonomy: string;
content_type: string;
content_structure: string;
status: 'queued' | 'completed';
word_count: number;
created_at: string;
}
```
---
### 2. Content Page (`Content.tsx` - 315 lines)
**Purpose:** Content management and editing
**Current Implementation:**
- ✅ Loads Content table via `fetchContent()` API
- ✅ Status workflow: `draft``published`
- ✅ Row actions: Edit, View on WordPress (if published), Generate Image Prompts
- ✅ Bulk actions: Update Status, Export, Publish Selected
- ✅ Progress modal for image prompt generation
- ✅ Selection and pagination working
**Issues:**
1.**No content viewer link** - Title column not clickable to view content
2.**Missing status indicators** - No visual feedback for:
- Prompt generation status (pending/complete)
- Image generation status (pending/generating/complete)
3. ⚠️ **Publish action ambiguity** - Bulk "Publish Selected" action exists but unclear what it does
**Data Model:**
```typescript
interface ContentType {
id: number;
title: string;
sector: string;
content_type: string;
content_structure: string;
cluster: string;
taxonomy: string;
status: 'draft' | 'published';
word_count: number;
source: string;
created_at: string;
external_id?: string | null; // WordPress post ID
external_url?: string | null; // WordPress post URL
sync_status?: string;
}
```
**Configuration (`content.config.tsx` - 376 lines):**
- Columns: title, sector, content_type, content_structure, cluster, taxonomy, status, word_count, source, created_at
- Missing columns: prompts_status, images_status
---
### 3. Images Page (`Images.tsx` - 738 lines)
**Purpose:** Image management grouped by content
**Current Implementation:**
- ✅ Loads ContentImagesGroup via `fetchContentImages()` API
- ✅ Client-side filtering, sorting, pagination
- ✅ Row actions: Publish to WordPress, Update Status
- ✅ Bulk actions: Bulk Publish Ready to WordPress
- ✅ Image generation functionality with queue modal
- ✅ AI logs when Resource Debug enabled
**Issues:**
1.**Bulk select checkbox not working** - Root cause: `ContentImagesGroup` interface has `content_id` but TablePageTemplate expects `id` field for selection
2.**Delete functions not working** - No delete handlers implemented
3. ⚠️ **Wrong location for WordPress publishing** - Should be on Published page, not here
**Data Model:**
```typescript
interface ContentImagesGroup {
content_id: number; // ⚠️ No 'id' field - breaks selection!
content_title: string;
featured_image: ContentImage | null;
in_article_images: ContentImage[];
overall_status: 'pending' | 'partial' | 'complete' | 'failed';
// Missing fields for WordPress publishing context:
external_id?: string;
external_url?: string;
sync_status?: string;
status?: 'draft' | 'published' | 'review';
}
interface ContentImage {
id: number;
image_url: string | null;
image_path: string | null;
prompt: string | null;
status: 'pending' | 'generated' | 'failed';
position: number;
}
```
**Configuration (`images.config.tsx`):**
- Columns: content_title, featured_image, in_article_1-5, overall_status, actions
- Row actions: publish_wordpress, update_status
- Bulk actions: bulk_publish_wordpress
---
### 4. Published Page (`Published.tsx` - 13 lines)
**Purpose:** Show published content with WordPress publishing capabilities
**Current Implementation:**
```tsx
import Tasks from './Tasks';
export default function Published() {
return <Tasks />;
}
```
**Issues:**
1.**Wrong table loaded** - Renders `<Tasks />` instead of Content table
2.**No WordPress publishing UI** - Should have edit and publish functionality
3.**No published item indicators** - Missing visual styling for published items
**What It Should Be:**
- Load Content table filtered by status
- Show WordPress publishing actions
- Allow editing before publishing
- Display WordPress publish status
- Show external URL links
---
### 5. Table Actions Configuration (`table-actions.config.tsx` - 359 lines)
**Current Implementation:**
-`/writer/tasks` - edit, generate_content
-`/writer/content` - edit, view_on_wordpress, generate_image_prompts, publish
-`/writer/published` - edit (minimal)
-`/writer/images` - publish_wordpress, update_status
**Issues:**
- ⚠️ Published page actions too minimal
- ⚠️ Images page has publishing (should be removed)
---
## Root Cause Analysis
### Issue #1: Images Page Bulk Select Not Working
**Root Cause:** Data model mismatch
- `ContentImagesGroup` uses `content_id` as primary identifier
- `TablePageTemplate` expects `id` field for selection (`selectedIds` array)
- No `id` field exists in `ContentImagesGroup`
**Solution Options:**
1. **Option A (Recommended):** Add `id` field to `ContentImagesGroup` that mirrors `content_id`
2. **Option B:** Modify TablePageTemplate to accept custom ID field name
3. **Option C:** Transform data in Images.tsx to add `id: content_id`
**Recommended Fix:** Option C (least invasive)
```typescript
const transformedImages = images.map(group => ({
...group,
id: group.content_id // Add id field for TablePageTemplate
}));
```
---
### Issue #2: Images Page Delete Not Working
**Root Cause:** No delete handlers implemented
- TablePageTemplate supports `onDelete` and `onBulkDelete` props
- Images.tsx doesn't pass these handlers
- No API endpoints being called
**Solution:** Implement delete handlers using Content API
```typescript
const handleDelete = async (id: number) => {
await deleteContent(id); // Delete content (cascade deletes images)
loadImages();
};
const handleBulkDelete = async (ids: number[]) => {
await bulkDeleteContent(ids);
loadImages();
};
```
---
### Issue #3: Published Page Structure
**Root Cause:** Placeholder implementation
- Published.tsx is just a wrapper around Tasks component
- No actual published content filtering
- No WordPress publishing UI
**Solution:** Complete reimplementation
- Duplicate Content.tsx structure
- Add WordPress-specific actions
- Filter for published/review status
- Add visual indicators
---
### Issue #4: Missing "Review" Status
**Root Cause:** Status workflow incomplete
- Current: Task (queued → completed) → Content (draft → published)
- Missing: Content (draft → **review** → published)
- No auto-status change when images generated
**Solution:**
1. Add "review" status to Content model (backend)
2. Update API to support new status
3. Add auto-transition: when images generated, change status from draft to review
4. Update all frontend status filters and badges
---
## Detailed Implementation Plan
### Priority 1: Critical Bug Fixes
#### Task 1.1: Fix Images Page Bulk Select
**Files to modify:**
- `frontend/src/pages/Writer/Images.tsx`
**Changes:**
```typescript
// In loadImages callback, transform data
const transformedResults = paginatedResults.map(group => ({
...group,
id: group.content_id // Add id field for selection
}));
setImages(transformedResults);
```
**Testing:**
- [ ] Bulk select checkbox appears and works
- [ ] Can select/deselect all
- [ ] Can select individual rows
- [ ] Selected IDs are content_id values
---
#### Task 1.2: Fix Images Page Delete Functions
**Files to modify:**
- `frontend/src/pages/Writer/Images.tsx`
**Changes:**
```typescript
// Add delete handlers
const handleDelete = useCallback(async (id: number) => {
try {
await deleteContent(id);
toast.success('Content and images deleted successfully');
loadImages();
} catch (error: any) {
toast.error(`Failed to delete: ${error.message}`);
throw error;
}
}, [loadImages, toast]);
const handleBulkDelete = useCallback(async (ids: number[]) => {
try {
const result = await bulkDeleteContent(ids);
toast.success(`Deleted ${result.deleted_count} content items and their images`);
loadImages();
return result;
} catch (error: any) {
toast.error(`Failed to bulk delete: ${error.message}`);
throw error;
}
}, [loadImages, toast]);
// In TablePageTemplate
<TablePageTemplate
// ... existing props
onDelete={handleDelete}
onBulkDelete={handleBulkDelete}
/>
```
**Testing:**
- [ ] Single delete works (deletes content + images)
- [ ] Bulk delete works
- [ ] Confirmation modals appear
- [ ] Data refreshes after delete
---
### Priority 2: Published Page Restructuring
#### Task 2.1: Reimplement Published Page
**Files to modify:**
- `frontend/src/pages/Writer/Published.tsx` (complete rewrite)
**Implementation:**
```typescript
/**
* Published Page - Built with TablePageTemplate
* Shows published/review content with WordPress publishing capabilities
*/
import { useState, useEffect, useMemo, useCallback, useRef } from 'react';
import TablePageTemplate from '../../templates/TablePageTemplate';
import {
fetchContent,
ContentType,
ContentListResponse,
ContentFilters,
publishToWordPress, // Use unified publisher API
} from '../../services/api';
import { useToast } from '../../components/ui/toast/ToastContainer';
import { FileIcon, CheckCircleIcon, TaskIcon, ImageIcon } from '../../icons';
import { createPublishedPageConfig } from '../../config/pages/published.config'; // New config file
import PageHeader from '../../components/common/PageHeader';
import ModuleNavigationTabs from '../../components/navigation/ModuleNavigationTabs';
import { useNavigate } from 'react-router';
export default function Published() {
const toast = useToast();
const navigate = useNavigate();
// Data state
const [content, setContent] = useState<ContentType[]>([]);
const [loading, setLoading] = useState(true);
// Filter state - default to published/review status
const [searchTerm, setSearchTerm] = useState('');
const [statusFilter, setStatusFilter] = useState('published'); // Default filter
const [publishStatusFilter, setPublishStatusFilter] = useState(''); // WordPress publish status
const [selectedIds, setSelectedIds] = useState<string[]>([]);
// Pagination state
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [totalCount, setTotalCount] = useState(0);
const pageSize = 20;
// Sorting state
const [sortBy, setSortBy] = useState<string>('created_at');
const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('desc');
const [showContent, setShowContent] = useState(false);
// Load content - filtered for published/review
const loadContent = useCallback(async () => {
setLoading(true);
setShowContent(false);
try {
const ordering = sortBy ? `${sortDirection === 'desc' ? '-' : ''}${sortBy}` : '-created_at';
const filters: ContentFilters = {
...(searchTerm && { search: searchTerm }),
// Filter for published or review status only
...(statusFilter && { status: statusFilter }),
page: currentPage,
page_size: pageSize,
ordering,
};
const data: ContentListResponse = await fetchContent(filters);
setContent(data.results || []);
setTotalCount(data.count || 0);
setTotalPages(Math.ceil((data.count || 0) / pageSize));
setTimeout(() => {
setShowContent(true);
setLoading(false);
}, 100);
} catch (error: any) {
console.error('Error loading content:', error);
toast.error(`Failed to load content: ${error.message}`);
setShowContent(true);
setLoading(false);
}
}, [currentPage, statusFilter, sortBy, sortDirection, searchTerm, toast, pageSize]);
useEffect(() => {
loadContent();
}, [loadContent]);
// Handle sorting
const handleSort = (field: string, direction: 'asc' | 'desc') => {
setSortBy(field || 'created_at');
setSortDirection(direction);
setCurrentPage(1);
};
// Row action handler
const handleRowAction = useCallback(async (action: string, row: ContentType) => {
if (action === 'publish_wordpress') {
try {
const result = await publishToWordPress([row.id]);
if (result.success) {
toast.success(`Published "${row.title}" to WordPress`);
loadContent();
} else {
toast.error(result.error || 'Failed to publish');
}
} catch (error: any) {
toast.error(`Failed to publish: ${error.message}`);
}
} else if (action === 'view_on_wordpress') {
if (row.external_url) {
window.open(row.external_url, '_blank');
}
} else if (action === 'edit') {
// Navigate to content editor
navigate(`/writer/content?id=${row.id}`);
}
}, [toast, loadContent, navigate]);
// Bulk WordPress publish
const handleBulkPublishWordPress = useCallback(async (ids: string[]) => {
try {
const numIds = ids.map(id => parseInt(id));
const result = await publishToWordPress(numIds);
if (result.success) {
toast.success(`Published ${result.published_count || ids.length} items to WordPress`);
loadContent();
} else {
toast.error(result.error || 'Failed to bulk publish');
}
} catch (error: any) {
toast.error(`Failed to bulk publish: ${error.message}`);
throw error;
}
}, [toast, loadContent]);
// Create page config
const pageConfig = useMemo(() => {
return createPublishedPageConfig({
searchTerm,
setSearchTerm,
statusFilter,
setStatusFilter,
publishStatusFilter,
setPublishStatusFilter,
setCurrentPage,
});
}, [searchTerm, statusFilter, publishStatusFilter]);
// Calculate header metrics
const headerMetrics = useMemo(() => {
if (!pageConfig?.headerMetrics) return [];
return pageConfig.headerMetrics.map((metric) => ({
label: metric.label,
value: metric.calculate({ content, totalCount }),
accentColor: metric.accentColor,
}));
}, [pageConfig?.headerMetrics, content, totalCount]);
// Writer navigation tabs
const writerTabs = [
{ label: 'Tasks', path: '/writer/tasks', icon: <TaskIcon /> },
{ label: 'Content', path: '/writer/content', icon: <FileIcon /> },
{ label: 'Images', path: '/writer/images', icon: <ImageIcon /> },
{ label: 'Published', path: '/writer/published', icon: <CheckCircleIcon /> },
];
return (
<>
<PageHeader
title="Published Content"
badge={{ icon: <CheckCircleIcon />, color: 'green' }}
navigation={<ModuleNavigationTabs tabs={writerTabs} />}
/>
<TablePageTemplate
columns={pageConfig.columns}
data={content}
loading={loading}
showContent={showContent}
filters={pageConfig.filters}
filterValues={{
search: searchTerm,
status: statusFilter,
publishStatus: publishStatusFilter,
}}
onFilterChange={(key: string, value: any) => {
if (key === 'search') {
setSearchTerm(value);
} else if (key === 'status') {
setStatusFilter(value);
setCurrentPage(1);
} else if (key === 'publishStatus') {
setPublishStatusFilter(value);
setCurrentPage(1);
}
}}
pagination={{
currentPage,
totalPages,
totalCount,
onPageChange: setCurrentPage,
}}
selection={{
selectedIds,
onSelectionChange: setSelectedIds,
}}
sorting={{
sortBy,
sortDirection,
onSort: handleSort,
}}
headerMetrics={headerMetrics}
onRowAction={handleRowAction}
onBulkAction={async (action: string, ids: string[]) => {
if (action === 'bulk_publish_wordpress') {
await handleBulkPublishWordPress(ids);
}
}}
getItemDisplayName={(row: ContentType) => row.title || `Content #${row.id}`}
/>
</>
);
}
```
---
#### Task 2.2: Create Published Page Configuration
**Files to create:**
- `frontend/src/config/pages/published.config.tsx`
**Implementation:**
```typescript
import { ColumnConfig } from '../../templates/TablePageTemplate';
import { ContentType } from '../../services/api';
import { Badge } from '../../components/ui/badge';
import { ExternalLinkIcon, CheckCircleIcon } from '../../icons';
export function createPublishedPageConfig(params: {
searchTerm: string;
setSearchTerm: (value: string) => void;
statusFilter: string;
setStatusFilter: (value: string) => void;
publishStatusFilter: string;
setPublishStatusFilter: (value: string) => void;
setCurrentPage: (page: number) => void;
}) {
const columns: ColumnConfig[] = [
{
key: 'title',
label: 'Title',
sortable: true,
render: (value: string, row: ContentType) => (
<div className="flex items-center gap-2">
<span className="font-medium">{value}</span>
{row.external_url && (
<a
href={row.external_url}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 hover:text-blue-600"
>
<ExternalLinkIcon className="w-4 h-4" />
</a>
)}
</div>
),
},
{
key: 'status',
label: 'Content Status',
sortable: true,
badge: true,
render: (value: string) => (
<Badge
variant={value === 'published' ? 'success' : value === 'review' ? 'warning' : 'default'}
>
{value}
</Badge>
),
},
{
key: 'sync_status',
label: 'WordPress Status',
sortable: false,
render: (value: string, row: ContentType) => {
if (row.external_id) {
return (
<Badge variant="success">
<CheckCircleIcon className="w-3 h-3 mr-1" />
Published
</Badge>
);
}
return (
<Badge variant="default">Not Published</Badge>
);
},
},
{
key: 'content_type',
label: 'Type',
sortable: true,
},
{
key: 'word_count',
label: 'Words',
sortable: true,
numeric: true,
},
{
key: 'created_at',
label: 'Created',
sortable: true,
date: true,
},
];
const filters = [
{
key: 'search',
label: 'Search',
type: 'text' as const,
placeholder: 'Search published content...',
},
{
key: 'status',
label: 'Content Status',
type: 'select' as const,
options: [
{ value: '', label: 'All' },
{ value: 'review', label: 'In Review' },
{ value: 'published', label: 'Published' },
],
},
{
key: 'publishStatus',
label: 'WordPress Status',
type: 'select' as const,
options: [
{ value: '', label: 'All' },
{ value: 'published', label: 'Published to WP' },
{ value: 'not_published', label: 'Not Published' },
],
},
];
const headerMetrics = [
{
label: 'Total Published',
calculate: (data: { totalCount: number }) => data.totalCount,
accentColor: 'green' as const,
},
{
label: 'On WordPress',
calculate: (data: { content: ContentType[] }) =>
data.content.filter(c => c.external_id).length,
accentColor: 'blue' as const,
},
{
label: 'In Review',
calculate: (data: { content: ContentType[] }) =>
data.content.filter(c => c.status === 'review').length,
accentColor: 'amber' as const,
},
];
return {
columns,
filters,
headerMetrics,
};
}
```
---
#### Task 2.3: Update Table Actions for Published Page
**Files to modify:**
- `frontend/src/config/pages/table-actions.config.tsx`
**Changes:**
```typescript
'/writer/published': {
rowActions: [
{
key: 'edit',
label: 'Edit Content',
icon: EditIcon,
variant: 'primary',
},
{
key: 'publish_wordpress',
label: 'Publish to WordPress',
icon: <ArrowRightIcon className="w-5 h-5" />,
variant: 'success',
shouldShow: (row: any) => !row.external_id, // Only show if not published
},
{
key: 'view_on_wordpress',
label: 'View on WordPress',
icon: <ExternalLinkIcon className="w-5 h-5" />,
variant: 'secondary',
shouldShow: (row: any) => !!row.external_id, // Only show if published
},
],
bulkActions: [
{
key: 'bulk_publish_wordpress',
label: 'Publish to WordPress',
icon: <ArrowRightIcon className="w-4 h-4" />,
variant: 'success',
},
{
key: 'update_status',
label: 'Update Status',
icon: <CheckCircleIcon className="w-4 h-4 text-success-500" />,
variant: 'secondary',
},
{
key: 'export',
label: 'Export Selected',
icon: <DownloadIcon className="w-4 h-4 text-blue-light-500" />,
variant: 'secondary',
},
],
},
```
---
### Priority 3: Content Page Enhancements
#### Task 3.1: Add Content Viewer Link
**Files to modify:**
- `frontend/src/config/pages/content.config.tsx`
**Changes:**
```typescript
// In columns array, update title column
{
key: 'title',
label: 'Title',
sortable: true,
render: (value: string, row: ContentType) => (
<button
onClick={() => {
// Open content viewer modal
if (params.onViewContent) {
params.onViewContent(row);
}
}}
className="text-blue-500 hover:text-blue-600 hover:underline text-left font-medium"
>
{value}
</button>
),
},
```
**Files to modify:**
- `frontend/src/pages/Writer/Content.tsx`
**Changes:**
```typescript
// Add state for content viewer modal
const [isViewerModalOpen, setIsViewerModalOpen] = useState(false);
const [viewerContentId, setViewerContentId] = useState<number | null>(null);
// Add handler
const handleViewContent = useCallback((row: ContentType) => {
setViewerContentId(row.id);
setIsViewerModalOpen(true);
}, []);
// Update pageConfig call
const pageConfig = useMemo(() => {
return createContentPageConfig({
// ... existing params
onViewContent: handleViewContent,
});
}, [/* deps */, handleViewContent]);
// Add ContentViewerModal component (import from shared components)
<ContentViewerModal
isOpen={isViewerModalOpen}
onClose={() => {
setIsViewerModalOpen(false);
setViewerContentId(null);
}}
contentId={viewerContentId}
/>
```
---
#### Task 3.2: Add Status Indicator Columns
**Files to modify:**
- `frontend/src/config/pages/content.config.tsx`
**Changes:**
```typescript
// Add after 'status' column
{
key: 'prompts_status',
label: 'Prompts',
sortable: false,
render: (value: any, row: ContentType) => {
// Check if prompts exist (need to add this to API response)
const hasPrompts = row.image_prompts_count > 0;
return (
<Badge variant={hasPrompts ? 'success' : 'default'}>
{hasPrompts ? (
<>
<CheckCircleIcon className="w-3 h-3 mr-1" />
{row.image_prompts_count} prompts
</>
) : (
'No prompts'
)}
</Badge>
);
},
},
{
key: 'images_status',
label: 'Images',
sortable: false,
render: (value: any, row: ContentType) => {
const generatedCount = row.images_generated_count || 0;
const totalCount = row.images_total_count || 0;
if (totalCount === 0) {
return <Badge variant="default">No images</Badge>;
}
const isComplete = generatedCount === totalCount;
const isPartial = generatedCount > 0 && generatedCount < totalCount;
return (
<Badge variant={isComplete ? 'success' : isPartial ? 'warning' : 'default'}>
{isComplete && <CheckCircleIcon className="w-3 h-3 mr-1" />}
{generatedCount}/{totalCount}
</Badge>
);
},
},
```
**Backend Changes Needed:**
- Add fields to Content API response:
- `image_prompts_count`
- `images_generated_count`
- `images_total_count`
---
### Priority 4: Add "Review" Status Workflow
#### Task 4.1: Backend Model Changes
**Files to modify:**
- `backend/igny8_core/modules/writer/models.py`
**Changes:**
```python
class Content(models.Model):
STATUS_CHOICES = [
('draft', 'Draft'),
('review', 'In Review'), # NEW STATUS
('published', 'Published'),
]
status = models.CharField(
max_length=20,
choices=STATUS_CHOICES,
default='draft',
db_index=True,
)
```
**Migration:**
```bash
cd backend
python manage.py makemigrations writer
python manage.py migrate writer
```
---
#### Task 4.2: Auto-Status Change on Image Generation
**Files to modify:**
- `backend/igny8_core/modules/writer/services/image_generation.py` (or wherever images are generated)
**Changes:**
```python
def on_images_generated(content_id):
"""Called when all images for content are successfully generated"""
content = Content.objects.get(id=content_id)
# Auto-transition draft → review when images complete
if content.status == 'draft':
content.status = 'review'
content.save(update_fields=['status'])
# Optional: Create notification/log entry
logger.info(f"Content {content_id} auto-transitioned to 'review' after image generation")
```
---
#### Task 4.3: Frontend Status Updates
**Files to modify:**
- All status badge renderers
- All status filter options
- All status update modals
**Changes:**
```typescript
// Update status options everywhere
const STATUS_OPTIONS = [
{ value: 'draft', label: 'Draft' },
{ value: 'review', label: 'In Review' }, // NEW
{ value: 'published', label: 'Published' },
];
// Update badge variants
const getStatusVariant = (status: string) => {
switch (status) {
case 'draft': return 'default';
case 'review': return 'warning'; // NEW
case 'published': return 'success';
default: return 'default';
}
};
```
---
### Priority 5: Remove WordPress Publishing from Images Page
#### Task 5.1: Update Images Page Configuration
**Files to modify:**
- `frontend/src/config/pages/table-actions.config.tsx`
**Changes:**
```typescript
'/writer/images': {
rowActions: [
{
key: 'update_status',
label: 'Update Status',
icon: <CheckCircleIcon className="w-5 h-5" />,
variant: 'primary',
},
// REMOVED: publish_wordpress action
],
bulkActions: [
// REMOVED: bulk_publish_wordpress action
],
},
```
---
#### Task 5.2: Clean Up Images Page Code
**Files to modify:**
- `frontend/src/pages/Writer/Images.tsx`
**Changes:**
- Remove WordPress publishing handlers
- Remove related imports
- Simplify row action handler
- Remove WordPress-related state
---
### Priority 6: Visual Indicators for Published Items
#### Task 6.1: Add Published Badge to All Tables
**Files to modify:**
- All page configs (tasks, content, images, published)
**Changes:**
```typescript
// Add to title or status column render
{
key: 'title',
label: 'Title',
render: (value: string, row: any) => (
<div className="flex items-center gap-2">
<span className="font-medium">{value}</span>
{row.external_id && (
<Badge variant="success" size="sm">
<CheckCircleIcon className="w-3 h-3 mr-1" />
WP
</Badge>
)}
</div>
),
},
```
---
## Implementation Checklist
### Phase 1: Critical Bugs (Week 1)
- [ ] Fix Images page bulk select (add `id` field)
- [ ] Fix Images page delete functions
- [ ] Test both fixes thoroughly
### Phase 2: Published Page (Week 1-2)
- [ ] Create `published.config.tsx`
- [ ] Rewrite `Published.tsx` component
- [ ] Update table actions config
- [ ] Add WordPress publishing handlers
- [ ] Test all functionality
### Phase 3: Content Enhancements (Week 2)
- [ ] Add content viewer link to title column
- [ ] Create/import ContentViewerModal
- [ ] Add backend fields for prompt/image counts
- [ ] Add status indicator columns
- [ ] Update content.config.tsx
- [ ] Test viewer and indicators
### Phase 4: Review Status (Week 2-3)
- [ ] Create Django migration for new status
- [ ] Update backend model
- [ ] Add auto-transition logic
- [ ] Update all frontend status options
- [ ] Update all status badge renders
- [ ] Update filters across all pages
- [ ] Test complete workflow
### Phase 5: WordPress Publishing Migration (Week 3)
- [ ] Remove WordPress actions from Images page
- [ ] Remove WordPress code from Images.tsx
- [ ] Verify Published page has all WordPress functionality
- [ ] Test end-to-end publishing workflow
### Phase 6: Visual Polish (Week 3)
- [ ] Add published badges to all table titles
- [ ] Add WordPress status indicators
- [ ] Add color coding for statuses
- [ ] Add icons for published items
- [ ] Polish UI across all pages
### Phase 7: Testing & Documentation (Week 4)
- [ ] Full regression testing
- [ ] User acceptance testing
- [ ] Update user documentation
- [ ] Create migration guide for users
- [ ] Deploy to staging
- [ ] Final production deployment
---
## API Endpoints Required
### New Endpoints
```
POST /v1/publisher/publish/
- Publish content to WordPress
- Body: { content_id, destinations: ['wordpress'] }
- Response: { success, data: { external_id, external_url }, error }
GET /v1/writer/content/{id}/
- Get single content with full details
- Response includes: prompts_count, images_count, etc.
PATCH /v1/writer/content/{id}/
- Update content status
- Body: { status: 'draft' | 'review' | 'published' }
```
### Enhanced Endpoints
```
GET /v1/writer/content/
- Add fields to response:
- image_prompts_count
- images_generated_count
- images_total_count
- sync_status
- external_id
- external_url
```
---
## Data Flow Diagrams
### Current Flow
```
Tasks (queued)
→ Generate Content
→ Tasks (completed) + Content (draft)
→ Generate Image Prompts
→ Content (draft) + ImagePrompts
→ Generate Images
→ Content (draft) + Images
→ [Manual publish from Images page]
→ WordPress
```
### New Flow (After Refactoring)
```
Tasks (queued)
→ Generate Content
→ Tasks (completed) + Content (draft)
→ Generate Image Prompts
→ Content (draft) + ImagePrompts
→ Generate Images
→ Content (review) + Images ← AUTO STATUS CHANGE
→ [Review in Published page]
→ [Edit if needed]
→ [Publish to WordPress from Published page]
→ Content (published) + WordPress Post
```
---
## Risk Assessment
### High Risk
1. **Database Migration for Review Status**
- Mitigation: Test on staging first, have rollback plan
- Impact: Could affect existing content if not handled properly
2. **Breaking Changes to Content API**
- Mitigation: Add new fields as optional, maintain backward compatibility
- Impact: Other parts of app might depend on current response shape
### Medium Risk
1. **Auto-Status Transition Logic**
- Mitigation: Make it configurable, add feature flag
- Impact: Could change status unexpectedly if logic is wrong
2. **WordPress Publishing Removal from Images**
- Mitigation: Ensure Published page fully functional before removing
- Impact: Users might look for publish button in wrong place
### Low Risk
1. **UI Changes (badges, indicators)**
- Mitigation: Can be easily reverted
- Impact: Purely cosmetic
2. **Content Viewer Modal**
- Mitigation: Independent feature, doesn't affect core functionality
- Impact: Just adds convenience
---
## Success Metrics
### Functional Metrics
- [ ] All bulk select checkboxes working across all pages
- [ ] Delete functions working (single and bulk)
- [ ] Published page shows Content table (not Tasks)
- [ ] WordPress publishing only available on Published page
- [ ] "Review" status visible and functional
- [ ] Auto-status change working when images generated
- [ ] Content viewer accessible from title links
- [ ] Status indicators showing prompt/image progress
### User Experience Metrics
- [ ] Reduced clicks to publish content (consolidated on one page)
- [ ] Clear visual feedback for publish status
- [ ] Intuitive workflow: draft → review → published
- [ ] Easy access to content viewing
- [ ] Clear status progression indicators
### Technical Metrics
- [ ] No console errors
- [ ] All API calls successful
- [ ] Proper error handling throughout
- [ ] Consistent response times
- [ ] Proper loading states
---
## Rollback Plan
If critical issues arise:
1. **Phase 1-2 Issues (Bugs/Published Page):**
- Revert Published.tsx to `<Tasks />` wrapper
- Disable new delete handlers
- Restore selection functionality
2. **Phase 4 Issues (Review Status):**
- Rollback database migration
- Restore previous status options
- Disable auto-transition logic
3. **Phase 5 Issues (WordPress Migration):**
- Re-enable WordPress publishing on Images page
- Disable on Published page temporarily
---
## Future Enhancements (Post-Refactoring)
1. **Bulk Edit Mode** - Edit multiple content items at once
2. **Scheduling** - Schedule WordPress publishing for future dates
3. **Publishing Templates** - Save WordPress settings as templates
4. **Draft Revisions** - Track content changes before publishing
5. **Publishing Analytics** - Track WordPress publish success rates
6. **Multi-destination Publishing** - Publish to multiple WordPress sites
7. **Content Preview** - Preview how content will look on WordPress
8. **SEO Checker** - Validate SEO before publishing
---
## Appendix: File Inventory
### Files to Modify
```
frontend/src/pages/Writer/
- Tasks.tsx (minor - visual indicators)
- Content.tsx (major - viewer link, status columns)
- Images.tsx (major - fix select, delete, remove WP)
- Published.tsx (complete rewrite)
frontend/src/config/pages/
- content.config.tsx (add columns, viewer link)
- images.config.tsx (minor updates)
- table-actions.config.tsx (update all writer sections)
- published.config.tsx (NEW FILE)
backend/igny8_core/modules/writer/
- models.py (add review status)
- services/image_generation.py (auto-status change)
- serializers.py (add new fields)
- views.py (update filters)
```
### Files to Create
```
frontend/src/config/pages/published.config.tsx
frontend/src/components/common/ContentViewerModal.tsx (if doesn't exist)
backend/igny8_core/modules/writer/migrations/XXXX_add_review_status.py
```
### Total Estimated Changes
- **Modified Files:** ~15
- **New Files:** ~3
- **Lines Changed:** ~2,000
- **Estimated Hours:** 40-60 hours
- **Estimated Calendar Time:** 3-4 weeks
---
**End of Document**
*Last Updated: December 2024*
*Document Version: 1.0*
*Author: AI Assistant (Deep Analysis Mode)*