Skip to content

Publishing and projection

Publishing a version:

  1. sets the version to published;
  2. demotes the previous published version to superseded;
  3. moves the locale’s published pointer;
  4. writes an outbox event and an audit record.

Before that, required fields and allowed types are checked; on a non-master locale only localized fields are. A failure is 422 with an error per field, which the editor places on the field.

The Projector consumes outbox events and rebuilds the affected documents in the published read model: the published locale, plus the other locales when a shared field on the master changed. A document carries everything Delivery needs:

{
"id": "…", "type": "ArticlePage", "base": "page",
"locale": "pl", "masterLocale": "en", "existingLocales": ["en", "pl"],
"path": "/pl/witaj-z-optimizely/",
"url": "http://localhost:3000/pl/witaj-z-optimizely/",
"fields": {"summary": "…", "mainBody": {"html": "…"}, "author": "…", "image": {"id": "…"}},
"fieldKinds": {"summary": "text", "mainBody": "richText", "author": "text", "image": "reference"},
"audiences": null
}
  • fields are keyed by JSON field name (mainBody), so front-ends read natural JSON. Shared fields come from the master locale.
  • fieldKinds lets Delivery expand and render without loading the schema.
  • Rich text is sanitized here, whatever wrote the version.
  • audiences is null for public content; otherwise it lists who may read it (see Security).
  • The ETag is a hash of the canonical document, computed once at projection time.

Why a projection. Delivery never joins, merges languages or checks version status. It reads a row by key and returns it with its ETag. That makes low latency cheap and lets Delivery scale without touching the authoring database. The projection can be rebuilt from versions at any time (POST /authoring/v1/projection/rebuild).

The cost is a short delay between publish and visibility. In a process with both the authoring and projector roles, projection runs inside the publish transaction, so the delay is zero. Split deployments see it within the outbox poll interval (SEEAMESS_OUTBOX_POLL_MS, 250 ms by default).

  • Schedule. Save a draft with a future startPublish and publish it: the version becomes scheduled and the live version stays live. The scheduled-publish job later runs the very same publish command, with validation, interceptors, projection and audit. A version that fails when due becomes rejected.
  • Expiry. Delivery hides documents at or after their stopPublish.
  • Unpublish takes the locale off Delivery and keeps the version publishable (ready).
  • Review. “Ready for review” marks a version ready; “Reject” sets it rejected with an optional comment shown to everyone who can read the content. Extensions can subscribe to content.ready and content.rejected.

Jobs are claimed with a database lease: one update … returning claims a due job, so it runs once however many runners exist, and a runner that dies loses its job to another after the lease. Core jobs cover scheduled publishing and cleanup; extensions can declare their own (see Extending SeeAMess).