# Writer Module (Backend) — Code-Sourced Overview (Dec 2025)

Scope: `backend/igny8_core/modules/writer` (ViewSets/serializers/urls) backed by models in `backend/igny8_core/business/content`.

## Endpoints (from `modules/writer/urls.py`)
- `/api/v1/writer/tasks/` — CRUD + bulk delete/update, auto content generation.
- `/api/v1/writer/images/` — CRUD + serve file, auto generate images, bulk status update (by content or ids), grouped content images.
- `/api/v1/writer/content/` — CRUD + publish/unpublish to WordPress, check WordPress status, AI prompt generation, validation, metadata mapping, taxonomy/tag management.
- `/api/v1/writer/taxonomies/` — CRUD for content taxonomies (categories/tags). Attributes endpoint disabled (serializer removed).

## Models (business/content/models.py)
- **Tasks** (`SiteSectorBaseModel`, soft-delete): title, description, FK `cluster` (required, same sector), optional `idea`, `content_type` (post/page/product/taxonomy), `content_structure` (article/guide/landing_page/etc.), optional `taxonomy_term`, comma keywords, word_count, status (`queued|completed`). Indexes on title/status/cluster/type/structure/site+sector.
- **Content** (`SiteSectorBaseModel`, soft-delete): title, HTML, word_count, SEO fields, FK `cluster`, `content_type/structure`, M2M `taxonomy_terms` (through `ContentTaxonomyRelation`), external publishing fields (`external_id/url/type/metadata/sync_status`), source (`igny8|wordpress`), status (`draft|review|published`). Indexes on title/cluster/type/structure/source/status/external_id/site+sector.
- **ContentTaxonomy** (`SiteSectorBaseModel`): name, slug, `taxonomy_type (category|tag)`, external_taxonomy/id, sync_status, description, count, metadata. Unique per site+slug+type and site+external_id+external_taxonomy.
- **Images** (`SiteSectorBaseModel`, soft-delete): FK `content` (preferred) or `task` (legacy), `image_type (featured|desktop|mobile|in_article)`, `image_url/path`, prompt, status (`pending|generated|failed`), position. save() inherits account/site/sector from content/task. Indexes on content/task type/status/position.
- **ContentClusterMap** (summary): links content/tasks to clusters with roles (hub/supporting/attribute) and source (blueprint/manual/import); tracks keywords + slugs.
- **ContentTaxonomyRelation**: through table for content↔taxonomy.

## Serializers (modules/writer/serializers.py)
- **TasksSerializer**: requires cluster/content_type/content_structure on create; defaults status=queued; exposes cluster_name/sector_name; accepts site_id/sector_id (write-only).
- **ImagesSerializer**: exposes task_title/content_title; read-only account/timestamps.
- **ContentSerializer**: requires cluster/content_type/content_structure/title on create; defaults source=igny8, status=draft; exposes taxonomy terms, tags, categories, image flags/status; site_id/sector_id write-only.
- **ContentTaxonomySerializer** (in file but not shown above): manages taxonomy fields and external sync data.
- Group serializers for content images (`ContentImageSerializer`, `ContentImagesGroupSerializer`).

## ViewSets & Actions (modules/writer/views.py)
- **TasksViewSet** (`SiteSectorModelViewSet`):
  - Filters/search/order: search title/keywords; filter status/cluster/content_type/structure; order by title/created_at/status.
  - Bulk: `bulk_delete`, `bulk_update` (status).
  - AI: `auto_generate_content` → `ContentGenerationService.generate_content(ids, account)`; limits 10 ids; returns task_id or sync result; 402 on `InsufficientCreditsError`.
  - Create requires explicit `site_id` and `sector_id`; validates site/sector association; account resolved from request user/site.
- **ImagesViewSet**:
  - Filters/order: filter task_id/content_id/image_type/status; order by created_at/position/id.
  - Create enforces site/sector (from request context, falling back to user active site/default sector); sets account/site/sector.
  - Actions:
    - `serve_image_file` streams local file if `image_path` exists.
    - `auto_generate_images` queues `run_ai_task(generate_images)` (Celery if available) for up to 10 task_ids.
    - `bulk_update` sets status by `content_id` or `ids`.
    - `content_images` returns grouped images (featured + in-article) via grouped serializer.
- **ContentViewSet** (not fully shown above but key actions):
  - CRUD with filters/search/order (title, status, cluster, content_type/structure, source); tenant scoping via base class.
  - Taxonomy management: add/remove terms, sync helpers (uses `ContentTaxonomy`).
  - AI helpers: `generate_image_prompts` (queues `run_ai_task(generate_image_prompts)`), validation (`ContentValidationService`), metadata mapping (`MetadataMappingService`), content generation pathways tied to `ContentGenerationService`.
  - Publishing: `publish` queues `publish_content_to_wordpress` Celery task (optimistically sets status=published), `wordpress_status` fetches WP status via integration, `unpublish` clears external links and reverts to draft.
  - Image status helpers and grouped image retrieval also exposed.
- **ContentTaxonomyViewSet**: CRUD for categories/tags; supports external sync fields.

## Permissions, tenancy, throttling
- Permissions: `IsAuthenticatedAndActive` + `IsViewerOrAbove` across Writer; certain actions (e.g., `unpublish`) use `IsEditorOrAbove`.
- Tenancy: `SiteSectorModelViewSet` enforces account/site/sector scoping; create operations require site_id+sector_id or context site/sector; Images save derives account/site/sector from content/task.
- Throttling: `DebugScopedRateThrottle` with scope `writer`.

## AI/Background Tasks & Limits
- Content generation: `auto_generate_content` (max 10 task IDs) → `ContentGenerationService`; credits enforced (402 on insufficient).
- Image generation: `auto_generate_images` (max 10 task IDs) via `run_ai_task`; Celery preferred, sync fallback.
- Image prompt generation: `generate_image_prompts` via `run_ai_task`.

## Publishing Integration
- Publish: `/writer/content/{id}/publish/` → queues WordPress publish; refuses if already published.
- Status: `/writer/content/{id}/wordpress_status/` → checks WordPress via site integration.
- Unpublish: clears external_id/url, sets status to draft (does not delete WP post).

## CSV / Bulk Notes
- Tasks: bulk delete/update supported.
- Images: bulk status update by content or ids; grouped retrieval.
- Content: bulk operations primarily around AI prompt/image generation and publishing; no CSV import/export.

## Observations / gaps
- Tasks status choices limited to `queued/completed`; no explicit error/cancel states.
- Images bulk_update exposed on same ViewSet name as Tasks bulk_update (distinct routes under images vs tasks); OK but keep consistent naming.
- ContentViewSet file is large; ensure doc readers reference actions for validation/metadata mapping if extending.


