Search documentation

Search documentation

Content

CMS Documentation

Content modeling, workflows, publishing, and CMS operations documentation.

How the Contoprix CMS fits together#

Contoprix separates the model from the content and from the frontend. Editors define and fill structured fields; developers use stable codes and a small mapping layer to render the result.

CMS architecture
Tenant
  └─ Content types and component types (shared schemas)
       └─ Fields, rules, relations, and allowed blocks

Website
  ├─ Languages
  ├─ Content entries and pages
  ├─ Media
  └─ Delivery credential
       └─ Published delivery API → SDK → frontend

This distinction matters: a content type is tenant-level, while an entry is created for a particular website and language. A delivery key also resolves the website context, so published requests only see that website's content.

The core building blocks#

Building blockWhat it isUse it for
Content typeA schema for a standalone recordArticles, products, authors, site settings
Component typeA schema for a reusable UI-shaped blockHero, call to action, feature card
FieldA typed value in a typeTitle, slug, image, relation, rich text
Content entryOne record made from a content typeOne Article called “Hello, Contoprix”
PageA route with ordered blocks/about, /pricing
Media itemA reusable uploaded assetImage, document, video

Use a content type when editors manage a record independently. Use a component type when editors configure a reusable block inside a page or another structured field. Use a relation when one record should refer to another rather than copy its values.

A simple example#

For a blog, create two content types:

Example model
Article
  title       Text
  slug        Slug
  summary     Text Area
  author      Relation → Author

Author
  name        Text
  bio         Rich Text
  photo       Image

An editor creates an Author once, then selects that Author on each Article. When the author bio changes, it changes in one place.

Model first, enter content second#

A reliable sequence is:

  1. Describe the editor's job in one sentence: for example, “Editors publish articles.”
  2. Create the content type and give it a stable code such as article.
  3. Add only the fields that the first UI needs.
  4. Create one realistic entry and publish it.
  5. Fetch it through the SDK and map entry.data to UI props.
  6. Add media, relations, components, and more languages one at a time.

Tip

Stable codes are more important than polished labels. Names can be improved for editors later; content-type and field codes are used by the SDK, generated types, and component registry.

What delivery returns#

Published content is delivered as an entry with metadata plus a data object containing your fields:

Delivery entry shape
type ContoprixContentEntry = {
  id: string;
  contentTypeCode: string;
  languageCode?: string;
  slug?: string | null;
  publishedAt?: string | null;
  data: Record<string, unknown>;
};

Media IDs are normalized to delivery-ready media objects, and direct relation fields are expanded to a small related-entry object. Custom fields still live in data, not at the top level.

Map an Article instead of reading entry.title
const entry = await client.content.getBySlug("article", "hello-contoprix");
const data = entry.data as { title?: string };

const title = data.title ?? "Untitled article";

Draft, preview, and published delivery#

State/pathIntended audienceWhat it returns
DraftEditorsWork in progress in the admin
PreviewAuthenticated editorial previewCurrent draft content/page
Published deliveryVisitors and public-site server codePublished pages and entries only

Do not use a preview endpoint as the data source for a public page. Preview requires a protected integration and exists specifically so editors can review before publishing.

Editorial lifecycle#

Content entries can be saved as drafts, published, unpublished, archived, scheduled, and restored from a version. Workflows can require review and approval before a user can publish.

Every save creates a versioned content snapshot. A restore creates a new current draft from an older snapshot and validates it against the current schema, so a restored item should still be reviewed and published deliberately.

A safe model-change workflow#

Changing a model affects editors and frontend code. Use this sequence:

  1. Identify the components and routes that read the existing field code.
  2. Add a new optional field before making a UI depend on it.
  3. Update the frontend mapper to handle missing values.
  4. Test an existing entry and a new entry.
  5. Publish only after preview or delivery checks pass.
  6. If you use the CLI, pull the schema, regenerate types, and validate component coverage.

Avoid renaming codes casually. It is safer to add a replacement field, migrate entries, update the frontend, then retire the old field after it is unused.

Where to go next#

  • Content Types — design a standalone record and its fields.
  • Component Types — design blocks and map their codes to React components.
  • Content Entries — draft, version, publish, and archive content.
  • Relations — reuse content without copying it.
  • Localization — configure website languages and deliver the correct entry.