Spaces:
Sleeping
Unified Publishing Center
Architecture
The Publishing Center is a composition layer over app/social. It does not
own provider connections, tokens, media files, publishing jobs, retries, or
provider payload translation.
The authoritative flow is:
- A canonical
SocialPostreferences a workspace project and Social media asset. - Each exact connected account creates one
SocialPostTarget. PublishingServicevalidates account state, authorization scopes, provider capabilities, canonical asset ownership, project provenance, and adapter media constraints.- Publish-now creates idempotent
SocialJobrecords. Scheduling creates one durableSocialSchedulestored in UTC with its IANA display timezone. - Existing Social workers claim jobs atomically and call the registered provider adapter.
- Provider results and reconciliation update each target independently.
Post reconciliation reports
published,failed, orpartial_success.
Provider adapters remain the only components that translate canonical post
data into provider API payloads. An adapter that is registered but does not
advertise publishing remains unavailable and must raise
SOCIAL_PROVIDER_NOT_IMPLEMENTED or SOCIAL_CAPABILITY_UNSUPPORTED; neither
condition is converted to success.
Canonical post and targets
SocialPost now records optional immutable project provenance, a bounded
canonical caption, and bounded canonical hashtags. Platform overrides remain
on targets and never mutate the canonical copy.
Target input is strict. YouTube, TikTok, X, and LinkedIn use their existing typed provider metadata models. Providers without implemented publishing contracts are capability-gated instead of accepting arbitrary payloads.
No binary media or credentials are stored in Social records. A Social media asset binds an existing canonical MediaRouter asset to a validated immutable output locator.
Validation
POST /v1/social/posts/{post_id}/validate returns a structured result for
every target. Validation reuses:
- connected-account and OAuth scope checks;
- provider capability metadata;
- canonical Social media resolution;
- existing FFprobe/media validation;
- each provider adapter's
validate_mediaimplementation.
The publish and schedule paths revalidate server-side. Frontend validation is advisory and cannot authorize publishing.
Scheduling and jobs
Scheduling uses SocialSchedule; timestamps must be offset-aware and are
stored as UTC. The supplied IANA timezone is retained for display. The
existing scheduler claims due records using row locks and SKIP LOCKED.
Publishing jobs use deterministic per-target idempotency keys and bounded
worker concurrency.
Provider-native scheduling is used only by an adapter when explicitly supported. The Publishing Center otherwise relies on MediaRouter's durable scheduler. The separate Calendar interface is outside this phase.
Retries, reconciliation, and partial success
The existing worker retry classifier applies exponential backoff and jitter
to transient errors. Invalid credentials, invalid media, permission denial,
unsupported operations, cancellation, and non-retryable provider responses
are not retried indefinitely. OAuth 401 handling refreshes once through
OAuthService.
The Publishing Center also exposes a target-scoped retry endpoint. It only accepts a failed target with no external provider ID, rejects permanent configuration/auth/media failures, and derives a deterministic retry job key. It never requeues successful or uncertain provider operations.
Async provider acceptance is reconciled through the adapter's status or recovery contract. MediaRouter does not claim exactly-once external delivery where the provider cannot support lookup or idempotency; local idempotency prevents duplicate internal operations.
Targets reconcile independently. A mixture of published and failed targets
produces partial_success, never published.
Cancellation
Draft, scheduled, queued, and retrying jobs can transition to cancelled.
Preparing, processing, uploading, and publishing jobs instead record
cancellation_requested_at. Their target remains in its actual state until
the worker/provider result is reconciled. This prevents MediaRouter from
claiming cancellation after a provider may have accepted a post.
Security, permissions, and RLS
The API uses existing Social scopes:
social:accounts:read/social:accounts:writesocial:posts:read/social:posts:writesocial:posts:publishsocial:schedules:write
Project and asset ownership is checked server-side. The additive migration adds a project foreign key, a same-workspace integrity trigger, indexes, and retains forced RLS on posts, targets, and jobs. Social accounts, media references, targets, schedules, and jobs continue using the existing workspace policies. Runtime PostgreSQL RLS certification remains deferred.
Tokens are available only through TokenService. REST, SDK, MCP, n8n, logs,
audits, and job payloads never expose access tokens, refresh tokens, provider
secrets, authorization headers, or signed upload/session URLs.
Audit and retention
The Publishing Center uses existing bounded Social audit records, including post creation, validation, scheduling, publish start, completion/failure, and cancellation. Audit and application logs contain opaque resource identifiers, provider, status, duration, and error categories only.
Raw provider payloads are not retained by the composer. Provider recovery state that must survive restarts remains encrypted in the existing dedicated job field. Public result metadata is filtered before transport.
Frontend
Routes:
/publish/projects/[projectId]/publish
TanStack Query owns providers, accounts, assets, posts, jobs, and validation responses. The composer keeps only draft selections in local UI state. It requires exact account selection, capability-gates unavailable adapters, registers an existing project output as a Social media reference when needed, and requires an accessible confirmation dialog before external publishing. Status uses the existing Social job polling rather than a second realtime system.
Project actions link to the project-aware route. Content Studio, AI Studio, and template-created projects use the same project/asset provenance and publishing APIs; there is no specialized publishing path.
Copilot
The shared Copilot action registry contains:
publishing.validatepublishing.create_postpublishing.schedulepublishing.publishpublishing.cancel
Publish, schedule, and cancellation are registered as external side effects and always require confirmation. Copilot uses exact post/account identifiers and the canonical Social services; it cannot invoke an adapter or arbitrary function directly.
SDK, MCP, and n8n
TypeScript and Python SDKs extend the existing Social resource with structured validation and the new canonical fields. Existing methods remain compatible.
MCP exposes typed validation and job listing alongside existing create, publish, schedule, cancel, and status tools. Authorization remains enforced by the MCP registry.
The existing n8n Social node adds List Posts, Validate Post, and List Publishing Jobs. Operations use the official SDK, preserve idempotency and Continue On Fail, and return real per-target backend state.
Provider certification boundary
Unit tests may mock provider boundaries. Live provider certification, live
OAuth credentials, Docker, PostgreSQL runtime/RLS verification, FFmpeg runtime
verification, and final production hardening remain deferred. An
implementation_status of registered or a false publishing capability is
shown as unavailable and is never simulated.