# Task 013: Draft Assembly, Editor, And Generic Preview Development description: Assemble section scaffolds into a canonical Markdown/MDX draft, provide versioned draft editing, and render a generic rich preview for editor review. ## Implementation Details - Backend endpoints: - `POST /api/articles/{article_id}/draft/assemble` - `GET /api/articles/{article_id}/drafts` - `GET /api/articles/{article_id}/drafts/{draft_id}` - `PATCH /api/articles/{article_id}/drafts/{draft_id}` - Markdown is the canonical editable draft format. - Draft assembly includes: - Title. - Meta title. - Meta description. - Body Markdown/MDX. - FAQ block when applicable. - Visual placeholders. - Evidence references. - Unsupported claim warnings. - Approval-relevant draft edits create new immutable versions. - Frontend includes: - Draft editor. - Generic Markdown/MDX preview. - Version selector/history. - Unsupported-claim warnings near content. - The preview is for editor UX and content-shape validation, not target-site build/runtime validation. ## Public Interface - Editor assembles a draft after production artifacts are ready. - Editor edits Markdown and metadata. - Editor views a generic preview. ## Acceptance Criteria - [x] TDD pre-requirement: before implementation, write one failing behavior test that assembles a draft from successful section scaffolds through the public API; proceed one draft behavior at a time and record evidence in `Result`. - [x] Draft assembly includes all planned sections in order. - [x] Draft includes metadata, FAQ, visual placeholders, evidence references, and unsupported claim warnings. - [x] Draft version 1 is immutable after approval-relevant edits; edits create a new version. - [x] Generic Markdown/MDX preview renders headings, links, tables, images/placeholders, and FAQ. - [x] Editor can compare or select draft versions. - [x] Draft assembly fails clearly if required section scaffolds are missing. ## Verification - Run draft assembly API tests. - Run frontend editor/preview tests. - Run Docker Compose smoke flow from production artifacts to previewed draft. ## Result - Status: Completed. Pre-requirement (RED) and implementation (GREEN) finished. - TDD plan: 1. Keep the original RED pre-requirement behavior test for `POST /api/articles/{article_id}/draft/assemble`. 2. Extend backend integration coverage for draft assembly payload completeness, immutable versioning, missing scaffold conflict, unsupported warning propagation, and not-found paths. 3. Implement backend drafts application layer and public routes for assemble/list/get/patch. 4. Extend shared API contracts (OpenAPI + generated TS types). 5. Implement frontend draft editor with version selector, compare summary, and generic markdown preview parser/renderer. 6. Add frontend model tests for preview parsing and version comparison. - Red evidence: - Pre-requirement test `apps/backend/tests/integration/test_draft_assembly_public_api.py::DraftAssemblyPublicApiTest::test_assemble_draft_from_successful_section_scaffolds` initially failed before implementation. - Observed RED error before implementation: `AssertionError: 201 != 404 : {"detail":"Not Found"}`. - Green evidence: - `POST /api/articles/{article_id}/draft/assemble` implemented and returns `201` with canonical draft payload. - `GET /api/articles/{article_id}/drafts`, `GET /api/articles/{article_id}/drafts/{draft_id}`, and `PATCH /api/articles/{article_id}/drafts/{draft_id}` implemented and covered. - Immutable versioning verified: patch creates `v2+`, base draft remains unchanged. - Missing required successful section scaffolds returns clear `409`. - Frontend generic preview parser renders headings, links, tables, images/placeholders, and FAQ blocks. - Frontend editor supports version selection and compare summary. - Refactor notes: - Added dedicated backend drafts service (`application/drafts.py`) and drafts route module to isolate draft logic from evidence/plan flows. - Extended `article_drafts` persistence model with canonical body and metadata lists (`faq_items`, placeholders, evidence refs, warnings, based_on_draft_id`) for explicit version snapshots. - Verification output: - `PYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_draft_assembly_public_api.py` -> OK (5 tests) - `PYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_parallel_production_public_api.py` -> OK (6 tests) - `PYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_evidence_matrix_public_api.py` -> OK (2 tests) - `node apps/frontend/tests/draft_editor.model.test.mjs` -> OK - `node apps/frontend/tests/article_detail.model.test.mjs` -> OK - `pnpm --dir apps/frontend typecheck` -> OK