# Publishing Operations — Phase 9 ## Status Publishing operations are implemented in the current working tree with durable unified jobs, calendar/queue/draft flows, retries, idempotency, and SDK/MCP/n8n transport coverage. PostgreSQL/RLS runtime verification, Docker, FFmpeg, Hugging Face startup, live provider certification, and final production certification remain deferred until all planned product phases are complete. ## Audit The Phase 8 audit found one authoritative publishing domain under `app/social/`. `SocialPost` is already the canonical draft/post record, a post owns multiple `SocialPostTarget` rows, `SocialSchedule` stores UTC timestamps plus the requested IANA timezone, and `SocialJob` is the durable per-target queue consumed by the existing scheduler and publisher workers. Provider adapters, OAuth/TokenService, capability discovery, asset ownership, RLS, retries, cancellation requests, reconciliation, partial success, SDK, MCP, n8n, Copilot, project provenance, and Content Studio integration are reused. No duplicate post, account, asset, or job tables were introduced. Phase 9 adds revision-safe draft mutation and rescheduling, queue/calendar read models, and durable bounded bulk orchestration. `revision` on posts and schedules is additive and is checked server-side for updates, duplication, and rescheduling. `social_publishing_batches` and `social_publishing_batch_items` are additive, workspace-isolated orchestration records; individual posts/jobs retain their own state and idempotency. ## State and APIs Existing `/v1/social/posts`, `/publish`, `/schedule`, `/cancel`, validation, jobs, accounts, and provider routes remain canonical. Phase 9 adds: - `GET /v1/social/drafts` - `PATCH/DELETE /v1/social/drafts/{post_id}` - `PATCH /v1/social/posts/{post_id}` - `POST /v1/social/posts/{post_id}/duplicate` - `POST /v1/social/posts/{post_id}/reschedule` - `GET /v1/social/publishing-context` - `GET /v1/social/calendar` - `GET /v1/social/queue` - `POST /v1/social/bulk` The batch operation is `schedule`, `reschedule`, `cancel`, `duplicate`, or `delete`. Batch items are claimed with `FOR UPDATE SKIP LOCKED` by the existing Social scheduler boundary and report independent completion/failure. Drafts remain `draft` until server validation. `validating` and `ready` are reserved state vocabulary for future asynchronous validation materialization; provider execution continues to use the existing `queued` → `preparing` → `processing` → `uploading` → `publishing` → terminal transitions. No frontend can arbitrarily mutate execution state. ## Calendar and timezone model The calendar accepts an aware UTC range and returns scheduled posts with the stored schedule timezone and schedule revision. Workspace timezone is read from authoritative workspace metadata, defaulting to UTC only when no workspace timezone has been configured. UI date-time inputs are explicitly labelled with that timezone and converted to an instant before mutation. Invalid, past, unordered, or excessively broad ranges are rejected. ## Queue and bulk behavior Queue filtering supports provider, account, project, status, search, bounded pagination, and live polling through TanStack Query. Bulk requests are bounded to 100 posts, idempotent at batch level, and never clone provider job IDs or provider references. Batch processing runs through the existing worker loop; partial item failure produces `partial_success` at the batch level. ## Security, permissions, RLS, and audit Existing Social scopes are reused: `social:posts:read/write/publish`, `social:schedules:read/write`, and account scopes. The BFF continues to enforce same-origin and session permission checks before forwarding authenticated requests. Migration `0009_publishing_operations.sql` enables and forces RLS for batch tables, adds workspace checks, foreign keys, indexes, and revision columns without destructive changes. Audit events use bounded `publishing.*` names alongside legacy Social event names; credentials, signed URLs, provider payloads, and binary media are never recorded. ## Integrations The Composer, Calendar, Queue, and Drafts routes use the existing Workspace shell, design system, Social hooks, canonical project assets, and provider capabilities. TypeScript and Python SDK Social resources expose draft, duplicate, reschedule, calendar, queue, and bulk methods. MCP exposes narrowly scoped queue/calendar/reschedule/duplicate/bulk tools through the shared service. The official n8n Social node exposes deterministic queue/calendar, duplicate, reschedule, and bulk operations through the SDK credential. ## Runtime limitations Local validation is limited by the available Termux environment. PostgreSQL RLS runtime checks, Docker, FFmpeg, Hugging Face startup, live provider credentials, provider certification, production OpenAPI verification, and final production hardening remain intentionally deferred until all MediaRouter product phases are complete.