Skip to main content
Every edit is a patch: a component id, a dotted path to a field, and a new value. Nothing matches on text.

Why ids and paths

A page is an array of components. Each has a stable id (assigned once, never changed), a type and props:
Rendered HTML carries the id on the wrapper and the path on each field. A click on props.items.1.name inside m81xq0ze identifies one value even if two logos share a name. Array items are addressed by index, so a reorder is a patch on the array. Articles and forms use the same model: their body is a component stream. Row-level fields (title, date) use a reserved meta id, so a patch can target the row itself.

Saving: compare-and-swap

Every page, article and form row has a version integer plus updated_by and updated_by_name. A save sends the working state along with the version it was based on. The update is conditional:
If the row is still at the loaded version, the write lands. If someone saved first, the update matches nothing and the save reconciles instead of overwriting.

Reconciling: three-way merge

On a miss the editor fetches the current row (theirs) and merges its working state (ours) against the snapshot it loaded (base):
  • Components merge by id, so two people editing different sections both keep their work.
  • Fields inside a component merge when only one side changed them.
  • A field both sides changed differently is a conflict. The save throws a WriteConflictError carrying theirs, base, ours and the conflicting paths. The admin reports it rather than guess. What the user sees is in Guides: Edit mode.
A successful merge retries against the new version.

Drafts

An unpublished article or form saves straight to its row. A published one autosaves to a shadow drafts table, so builds only ever ship published content; Publish folds the shadow into the live columns. Scheduling is a publish_at column plus an embargo in the public read policy.

Presence

While a page is open the editor joins a realtime channel for it. Peers appear in the top bar with the field they are on. Presence is awareness, not locking; the version check keeps writes safe.

Where it lives

All in the SDK, framework-agnostic: In production the admin’s saves route through the API’s content routes, which reconstruct the same conflict contract as a 409.