@ebitex/content-mcp 0.5.212 → 1.0.215

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -71,6 +71,14 @@ Every result also names the organization and environment it was answered in, and
71
71
  explicitly. A key reads and writes exactly one authoring environment, so "no Contracts" always means
72
72
  "none here" — an agent that reads it as "none anywhere" creates duplicates.
73
73
 
74
+ ## Authoring is half the job
75
+
76
+ This server builds and publishes a content model. The site that **renders** it reads the Content
77
+ Delivery API, and that has its own client, [`@ebitex/content-sdk`](https://www.npmjs.com/package/@ebitex/content-sdk)
78
+ (or `Ebitex.Content.Delivery` for .NET). The server's instructions and the
79
+ `ebitex-content://help/rendering-your-site` resource tell an agent so before it writes a renderer; if
80
+ you are briefing an agent yourself, say the same.
81
+
74
82
  ## Why it cannot drift
75
83
 
76
84
  The server encodes **no knowledge of the content model**. It does not know what field types exist,
@@ -1 +1 @@
1
- {"version":3,"file":"helpCorpus.generated.d.ts","sourceRoot":"","sources":["../../src/resources/helpCorpus.generated.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAErE,eAAO,MAAM,WAAW,EAAE,SAAS,EAmIlC,CAAA"}
1
+ {"version":3,"file":"helpCorpus.generated.d.ts","sourceRoot":"","sources":["../../src/resources/helpCorpus.generated.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAErE,eAAO,MAAM,WAAW,EAAE,SAAS,EAwIlC,CAAA"}
@@ -6,7 +6,7 @@ export const HELP_TOPICS = [
6
6
  {
7
7
  "slug": "agent-authoring",
8
8
  "title": "Building a content model through the API",
9
- "body": "# Building a content model through the API\n\nThe rest of this help corpus describes Content as you drive it in Composer — tabs, panels, buttons.\nThe concepts all transfer; the steps do not. This page is the same model described in terms of the\nAPI, for a script or an agent working through the Content Management API rather than the interface.\n\nRead this first if you are about to create anything. Everything here is about *what the pieces are*;\nthe exact shape of each request is answered live by the API itself, and you should never guess it.\n\n## The one rule that saves the most time\n\n**Ask the server what things look like; do not assume.**\n\n`GET /field-types` returns every field type this platform has, each with its **own JSON Schema for\nits settings**. That schema is generated from the field type's own definition, so it is never out of\ndate — Composer's Contract builder renders its settings form from exactly this, rather than\nhard-coding a form per type. Use it the same way.\n\n`GET /contracts` and `GET /templates` tell you what this environment already has. Check before\ncreating: a duplicate is much harder to undo than it is to avoid.\n\nWhen a write is refused, the refusal names the failing field and says what is wrong with it. That\nmessage is the fastest route to a correct request. Read it and correct the one thing it names,\nrather than rewriting the payload.\n\n## The pieces, and what each one is for\n\nContent separates four concerns that many systems collapse into one. The separation is the reason\nthe same content can be rendered several ways, and reused in places its author never anticipated.\n\n### Contract — what content *is*\n\nA Contract is a type. It has a name, an external id, and a list of **fields**. Each field names a\nfield type (short text, rich text, number, date, blob, reference, component, presentation, category,\nlink, and so on) and carries that type's own settings.\n\nContracts support **inheritance**. A Contract may name a parent, and it then has the parent's fields\nplus its own. A Contract may be **abstract**, meaning nothing is ever an instance of it directly —\nit exists to be inherited from, and to be named where several concrete types should be accepted.\n\nContracts describe content and nothing about how it looks. No colours, no layout, no \"variant\".\n\n### Component — an instance of a Contract\n\nA Component is a piece of content: a Contract, plus a **document** holding a value for each field.\nIt has its own name and external id and lives in a folder.\n\nThe document's shape follows the Contract's fields exactly. What a field's value looks like depends\non its type *and* on its modifiers, below.\n\n### Template — how content is *rendered*\n\nA Template names which Contracts it can render, and has its own **settings Contract**: an ordinary\nContract describing the presentational choices that template offers — a variant, an alignment, how\nmany columns.\n\nThis is why Contracts stay free of presentation. \"A statement, centred, with a ghost button\" is one\nTemplate's settings over a plain statement Contract, not three fields on the Contract itself.\n\n### Presentation — a Template bound to content\n\nA **presentation value** is where the two meet: it names a Template, binds a Component (or holds an\ninline document), and carries settings and contextual values for this one use.\n\nA page is usually a Component whose fields hold presentation values — a hero, then some sections —\nand each of those points at content that may be used elsewhere, rendered differently.\n\n### Adapter — a reusable mapping between Contracts\n\nSometimes a Template needs a `card` and what you have is a `blog-page`. An Adapter is a named,\nreusable mapping from one Contract to another: one rule per output field, plus a small set of logic\nnodes for lists, conditions and type dispatch.\n\nAn Adapter is applied by the server — at preview, at publish, and at delivery — so the mapping is\ndefined once and behaves identically everywhere.\n\n### Experience — where content lives on the web\n\nThe Experience tree is the site's address space. A **site** is a root; **nodes** under it are pages,\neach with a slug. A node's path is its ancestors' slugs plus its own.\n\nA node's **payload** says what it renders — usually a presentation value, sometimes a redirect,\nsometimes nothing at all (a node with no payload is pure structure, giving its children a path\nsegment without being a page itself).\n\nCreating a node and setting its payload are **two separate calls**. That is not an oversight: a\nnode's identity and location change for different reasons than its content does.\n\n## The five modifiers\n\nAny field can carry any combination of these. They compose, and each one changes the shape of the\nvalue stored in the document — which is the part worth understanding before writing one.\n\n| Modifier | What it means | Effect on the value |\n|---|---|---|\n| Mandatory | A value is required | Validation refuses an empty one |\n| Enumerable | Many rather than one | The value becomes a list |\n| Localizable | Translatable per locale | The value becomes `{ default, translations }` |\n| Personalizable | Varies by audience | The value becomes `{ default, variants }` |\n| Contextual | Overridable per use | The value may be supplied where the Component is *used*, not only where it is defined |\n\nCardinality is Enumerable's job, never the field type's. There is no \"list of text\" field type;\nthere is a text field that is enumerable.\n\n**Contextual** is the one worth dwelling on, because it has no counterpart in most systems. A\ncontextual field's value can be set on the Component (a default) *and* overridden by whoever binds\nthat Component somewhere — a heading that reads one way on the home page and another on a listing,\nfrom one Component with one document. Those overrides are the `contextualValues` that travel with a\nreference or a presentation value.\n\n## An order of operations that works\n\nDependencies run one way, so build in this order and nothing is ever waiting on something that does\nnot exist yet.\n\n1. **Describe.** `GET /field-types`, `/contracts`, `/templates`. Learn what exists before adding to\n it.\n2. **Contracts.** Parents before children, since a child names its parent.\n3. **Templates.** After the Contracts they render, since a Template names them.\n4. **Components.** After their Contract, and after any Contract they reference.\n5. **A site**, if the environment has none. Then **nodes** under it, parents before children.\n6. **Node payloads.** After both the node and the Component it binds.\n7. **Publish.** Plan first, read the blockers, then publish.\n\nTwo ordering facts that are easy to get wrong: a Component referencing another Component needs that\none to exist first, and publishing follows the dependency closure automatically — so publishing a\npage will normally publish the content it binds, and the plan is where you see exactly what that\nmeans before it happens.\n\n## Publishing\n\nPublishing is two calls, and collapsing them would hide the thing that matters.\n\n**Plan** resolves the full dependency closure of what you asked to publish and reports every\n**blocker** — an unresolvable reference, a workflow state that forbids publishing, a document that\nfails validation. **Execute** publishes what the plan named.\n\nBoth are jobs: each returns an operation id, and you poll it. A real closure is too large to finish\ninside an HTTP request, which is why.\n\nRead the plan. It is the only place the system tells you what is about to change beyond what you\nexplicitly named.\n\n## Where writes land\n\nA management key is bound to exactly one organization and one **authoring environment**, and it acts\nas one **role**. It cannot reach another environment, and it is subject to the same branch access\nrules and workflow gating a person with that role is.\n\nThat binding is the real safety boundary, so it is worth confirming rather than assuming: ask the\nAPI who the key is before writing anything. If the answer is not the environment you expected, stop\n— nothing else about the request will tell you.\n\nThen ask where the environment sits (`GET /topology`, or the `content_topology` tool). It names this\nenvironment's direct neighbours, and each one tells you something about your own work:\n\n- **Publishes to.** Where a publish from here lands. If one of these is a live website, a publish\n changes that website. With two or more, a publish has to say which one.\n- **Inherits from.** Content synced from this parent is read-only here. A refusal saying content is\n inherited means the change has to be made in the parent instead.\n- **Inherited by.** These environments receive this one's library the next time they sync, so a\n change here spreads there.\n- **Promoted from.** Someone promoting from one of these can overwrite what you write here.\n- **Promotes to.** Where this content goes when someone promotes it. You cannot promote yourself.\n\nNothing in the answer says which environment is production. Judge that from the names, and ask the\nperson you are working for when it is not obvious.\n\n## What an empty answer means\n\nThe binding governs **reads** exactly as it governs writes, and that changes how an empty result\nshould be read. `GET /contracts` returning nothing means *this environment has no Contracts*. It does\nnot mean the organization has none, and it certainly does not mean the account has no content.\n\nThe difference matters because acting on the wrong reading is expensive in one direction: concluding\n\"nothing exists\" and creating a model that already exists elsewhere produces duplicates, which are\nmuch harder to undo than to avoid. The safe habit is to confirm the scope before concluding anything\nfrom an empty list — `GET /whoami`, or the `content_whoami` tool, which needs no permissions at all\nprecisely so that a key holding almost nothing can still ask.\n\nA `404` on a single-entity read is the same fact in another shape: not found *here*. The entity may\nexist in another environment, and this key cannot see it.\n\n## When a write is refused for a permission\n\nA key has two limits, and they are different. Its **scopes** say which kinds of call it may make at\nall (`read`, `authoring`, `publish`). The **role it runs as** says what that role may do, and a few\nkinds need a permission on top of the `authoring` scope:\n\n| To write or delete | The role needs |\n|---|---|\n| a Contract | `content.contracts.manage` |\n| a Template | `content.templates.manage` |\n\nThe Member role does not hold either. The `ContentSchemaAdmin` role holds both, as does Owner, but\nOwner grants far more than an agent needs; prefer `ContentSchemaAdmin` or a custom role with just\nthese. Any role in the organization can be chosen as a key's \"run as\" role.\n\nA refusal for this reason is `403 permission_denied`, and it names the permission. The MCP server\nsays so plainly and, when it already knows the role lacks the permission, declines the call without\nsending it. `content_whoami` lists the kinds withheld for this role, each with the permission it\nneeds. When you see this, tell the person which permission is missing; changing the role is theirs\nto do, in the key's settings, and not something to work around.\n\n## Things that commonly go wrong\n\n- **Guessing a field type's settings** instead of reading its schema. Every field type declares its\n own; there is nothing to guess.\n- **Creating a duplicate** because an external id was not checked first. External ids are how a\n model refers to itself across environments; a duplicate is a lasting problem.\n- **Putting presentation on a Contract.** If you are adding a field called `variant`, `align`,\n `theme` or `columns` to a Contract, it almost certainly belongs in a Template's settings.\n- **Forgetting a node's payload.** A node created and never given one is a real, published,\n completely blank page.\n- **Treating a publish plan as a formality.** It is where blockers appear, and they do not appear\n anywhere else until something is already wrong.\n\n## Related\n\n- [Contracts](contracts.md) — the type system in depth\n- [Templates](templates.md) — presentation\n- [Components](components.md) — authoring content\n- [Content Adapters](content-adapters.md) — mappings\n- [Composer](content-composer.md) — the Experience tree\n- [Publishing](publishing.md) — the publish pipeline\n- [Management keys](management-keys.md) — minting and scoping a key\n"
9
+ "body": "# Building a content model through the API\n\nThe rest of this help corpus describes Content as you drive it in Composer — tabs, panels, buttons.\nThe concepts all transfer; the steps do not. This page is the same model described in terms of the\nAPI, for a script or an agent working through the Content Management API rather than the interface.\n\nRead this first if you are about to create anything. Everything here is about *what the pieces are*;\nthe exact shape of each request is answered live by the API itself, and you should never guess it.\n\n## The one rule that saves the most time\n\n**Ask the server what things look like; do not assume.**\n\n`GET /field-types` returns every field type this platform has, each with its **own JSON Schema for\nits settings**. That schema is generated from the field type's own definition, so it is never out of\ndate — Composer's Contract builder renders its settings form from exactly this, rather than\nhard-coding a form per type. Use it the same way.\n\n`GET /contracts` and `GET /templates` tell you what this environment already has. Check before\ncreating: a duplicate is much harder to undo than it is to avoid.\n\nWhen a write is refused, the refusal names the failing field and says what is wrong with it. That\nmessage is the fastest route to a correct request. Read it and correct the one thing it names,\nrather than rewriting the payload.\n\n## The pieces, and what each one is for\n\nContent separates four concerns that many systems collapse into one. The separation is the reason\nthe same content can be rendered several ways, and reused in places its author never anticipated.\n\n### Contract — what content *is*\n\nA Contract is a type. It has a name, an external id, and a list of **fields**. Each field names a\nfield type (short text, rich text, number, date, blob, reference, component, presentation, category,\nlink, and so on) and carries that type's own settings.\n\nContracts support **inheritance**. A Contract may name a parent, and it then has the parent's fields\nplus its own. A Contract may be **abstract**, meaning nothing is ever an instance of it directly —\nit exists to be inherited from, and to be named where several concrete types should be accepted.\n\nContracts describe content and nothing about how it looks. No colours, no layout, no \"variant\".\n\n### Component — an instance of a Contract\n\nA Component is a piece of content: a Contract, plus a **document** holding a value for each field.\nIt has its own name and external id and lives in a folder.\n\nThe document's shape follows the Contract's fields exactly. What a field's value looks like depends\non its type *and* on its modifiers, below.\n\n### Template — how content is *rendered*\n\nA Template names which Contracts it can render, and has its own **settings Contract**: an ordinary\nContract describing the presentational choices that template offers — a variant, an alignment, how\nmany columns.\n\nThis is why Contracts stay free of presentation. \"A statement, centred, with a ghost button\" is one\nTemplate's settings over a plain statement Contract, not three fields on the Contract itself.\n\n### Presentation — a Template bound to content\n\nA **presentation value** is where the two meet: it names a Template, binds a Component (or holds an\ninline document), and carries settings and contextual values for this one use.\n\nA page is usually a Component whose fields hold presentation values — a hero, then some sections —\nand each of those points at content that may be used elsewhere, rendered differently.\n\n### Adapter — a reusable mapping between Contracts\n\nSometimes a Template needs a `card` and what you have is a `blog-page`. An Adapter is a named,\nreusable mapping from one Contract to another: one rule per output field, plus a small set of logic\nnodes for lists, conditions and type dispatch.\n\nAn Adapter is applied by the server — at preview, at publish, and at delivery — so the mapping is\ndefined once and behaves identically everywhere.\n\n### Experience — where content lives on the web\n\nThe Experience tree is the site's address space. A **site** is a root; **nodes** under it are pages,\neach with a slug. A node's path is its ancestors' slugs plus its own.\n\nA node's **payload** says what it renders — usually a presentation value, sometimes a redirect,\nsometimes nothing at all (a node with no payload is pure structure, giving its children a path\nsegment without being a page itself).\n\nCreating a node and setting its payload are **two separate calls**. That is not an oversight: a\nnode's identity and location change for different reasons than its content does.\n\n## The five modifiers\n\nAny field can carry any combination of these. They compose, and each one changes the shape of the\nvalue stored in the document — which is the part worth understanding before writing one.\n\n| Modifier | What it means | Effect on the value |\n|---|---|---|\n| Mandatory | A value is required | Validation refuses an empty one |\n| Enumerable | Many rather than one | The value becomes a list |\n| Localizable | Translatable per locale | The value becomes `{ default, translations }` |\n| Personalizable | Varies by audience | The value becomes `{ default, variants }` |\n| Contextual | Overridable per use | The value may be supplied where the Component is *used*, not only where it is defined |\n\nCardinality is Enumerable's job, never the field type's. There is no \"list of text\" field type;\nthere is a text field that is enumerable.\n\n**Contextual** is the one worth dwelling on, because it has no counterpart in most systems. A\ncontextual field's value can be set on the Component (a default) *and* overridden by whoever binds\nthat Component somewhere — a heading that reads one way on the home page and another on a listing,\nfrom one Component with one document. Those overrides are the `contextualValues` that travel with a\nreference or a presentation value.\n\n## An order of operations that works\n\nDependencies run one way, so build in this order and nothing is ever waiting on something that does\nnot exist yet.\n\n1. **Describe.** `GET /field-types`, `/contracts`, `/templates`. Learn what exists before adding to\n it.\n2. **Contracts.** Parents before children, since a child names its parent.\n3. **Templates.** After the Contracts they render, since a Template names them.\n4. **Components.** After their Contract, and after any Contract they reference.\n5. **A site**, if the environment has none. Then **nodes** under it, parents before children.\n6. **Node payloads.** After both the node and the Component it binds.\n7. **Publish.** Plan first, read the blockers, then publish.\n\nTwo ordering facts that are easy to get wrong: a Component referencing another Component needs that\none to exist first, and publishing follows the dependency closure automatically — so publishing a\npage will normally publish the content it binds, and the plan is where you see exactly what that\nmeans before it happens.\n\n## Publishing\n\nPublishing is two calls, and collapsing them would hide the thing that matters.\n\n**Plan** resolves the full dependency closure of what you asked to publish and reports every\n**blocker** — an unresolvable reference, a workflow state that forbids publishing, a document that\nfails validation. **Execute** publishes what the plan named.\n\nBoth are jobs: each returns an operation id, and you poll it. A real closure is too large to finish\ninside an HTTP request, which is why.\n\nRead the plan. It is the only place the system tells you what is about to change beyond what you\nexplicitly named.\n\n## Where writes land\n\nA management key is bound to exactly one organization and one **authoring environment**, and it acts\nas one **role**. It cannot reach another environment, and it is subject to the same branch access\nrules and workflow gating a person with that role is.\n\nThat binding is the real safety boundary, so it is worth confirming rather than assuming: ask the\nAPI who the key is before writing anything. If the answer is not the environment you expected, stop\n— nothing else about the request will tell you.\n\nThen ask where the environment sits (`GET /topology`, or the `content_topology` tool). It names this\nenvironment's direct neighbours, and each one tells you something about your own work:\n\n- **Publishes to.** Where a publish from here lands. If one of these is a live website, a publish\n changes that website. With two or more, a publish has to say which one.\n- **Inherits from.** Content synced from this parent is read-only here. A refusal saying content is\n inherited means the change has to be made in the parent instead.\n- **Inherited by.** These environments receive this one's library the next time they sync, so a\n change here spreads there.\n- **Promoted from.** Someone promoting from one of these can overwrite what you write here.\n- **Promotes to.** Where this content goes when someone promotes it. You cannot promote yourself.\n\nNothing in the answer says which environment is production. Judge that from the names, and ask the\nperson you are working for when it is not obvious.\n\n## What an empty answer means\n\nThe binding governs **reads** exactly as it governs writes, and that changes how an empty result\nshould be read. `GET /contracts` returning nothing means *this environment has no Contracts*. It does\nnot mean the organization has none, and it certainly does not mean the account has no content.\n\nThe difference matters because acting on the wrong reading is expensive in one direction: concluding\n\"nothing exists\" and creating a model that already exists elsewhere produces duplicates, which are\nmuch harder to undo than to avoid. The safe habit is to confirm the scope before concluding anything\nfrom an empty list — `GET /whoami`, or the `content_whoami` tool, which needs no permissions at all\nprecisely so that a key holding almost nothing can still ask.\n\nA `404` on a single-entity read is the same fact in another shape: not found *here*. The entity may\nexist in another environment, and this key cannot see it.\n\n## When a write is refused for a permission\n\nA key has two limits, and they are different. Its **scopes** say which kinds of call it may make at\nall (`read`, `authoring`, `publish`). The **role it runs as** says what that role may do, and a few\nkinds need a permission on top of the `authoring` scope:\n\n| To write or delete | The role needs |\n|---|---|\n| a Contract | `content.contracts.manage` |\n| a Template | `content.templates.manage` |\n\nThe Member role does not hold either. The `ContentSchemaAdmin` role holds both, as does Owner, but\nOwner grants far more than an agent needs; prefer `ContentSchemaAdmin` or a custom role with just\nthese. Any role in the organization can be chosen as a key's \"run as\" role.\n\nA refusal for this reason is `403 permission_denied`, and it names the permission. The MCP server\nsays so plainly and, when it already knows the role lacks the permission, declines the call without\nsending it. `content_whoami` lists the kinds withheld for this role, each with the permission it\nneeds. When you see this, tell the person which permission is missing; changing the role is theirs\nto do, in the key's settings, and not something to work around.\n\n## Things that commonly go wrong\n\n- **Guessing a field type's settings** instead of reading its schema. Every field type declares its\n own; there is nothing to guess.\n- **Creating a duplicate** because an external id was not checked first. External ids are how a\n model refers to itself across environments; a duplicate is a lasting problem.\n- **Putting presentation on a Contract.** If you are adding a field called `variant`, `align`,\n `theme` or `columns` to a Contract, it almost certainly belongs in a Template's settings.\n- **Forgetting a node's payload.** A node created and never given one is a real, published,\n completely blank page.\n- **Treating a publish plan as a formality.** It is where blockers appear, and they do not appear\n anywhere else until something is already wrong.\n\n## Rendering the site is a separate job\n\nEverything above builds the content. The site that shows it reads the published result from the\nContent Delivery API, and for that there is a client: **`@ebitex/content-sdk`** (npm), or\n`Ebitex.Content.Delivery` on a .NET server. Read [Rendering your site](rendering-your-site.md)\nbefore you write any code that fetches published content, and do not write a Delivery client by\nhand without a reason.\n\n## Related\n\n- [Contracts](contracts.md) — the type system in depth\n- [Templates](templates.md) — presentation\n- [Components](components.md) — authoring content\n- [Content Adapters](content-adapters.md) — mappings\n- [Composer](content-composer.md) — the Experience tree\n- [Publishing](publishing.md) — the publish pipeline\n- [Management keys](management-keys.md) — minting and scoping a key\n- [Rendering your site](rendering-your-site.md) — the SDK that reads what you publish\n"
10
10
  },
11
11
  {
12
12
  "slug": "blog-series",
@@ -16,7 +16,7 @@ export const HELP_TOPICS = [
16
16
  {
17
17
  "slug": "components",
18
18
  "title": "Authoring Components",
19
- "body": "# Authoring Components\n\nA Component is one piece of content built from a Contract — for example,\na specific article. This guide covers creating and editing Components,\norganizing them in folders, and the friction the app shows you when a\nContract changes underneath a Component you've already created. See\n[Modeling content with Contracts](contracts.md) first if you haven't\ncreated a Contract yet.\n\n## Creating a Component\n\n1. From the Content page, select **New Component** (optionally after\n opening the folder you want it created in).\n2. Enter a **Name** — the **Id** fills in from it automatically and can\n still be edited by hand.\n3. Choose a **Contract**. If you started from a specific folder that\n restricts which Contracts are allowed there, only those (and their\n descendants) are offered.\n4. Fill in the form that appears — every field from the Contract, laid\n out in order. Fields marked with a red **\\*** are required.\n5. Select **Create**. If a required field is missing or a value doesn't\n match the Contract's rules, the field is highlighted with an\n explanation — fix it and select **Create** again.\n\n## Filling in fields\n\nMost fields are a straightforward text box, number box, or checkbox.\nA few work differently:\n\n- **Reference** and **Nested** are older field types kept working for\n existing Contracts, but no longer offered when adding a new field — new\n Contracts should use **Component** instead (below), which offers the\n same two behaviors plus a third, chosen per value instead of committed\n to for the whole field.\n- **Component** fields ask you to choose, each time you fill one in:\n **Choose…** to link to an existing Component (same search box as\n Reference, with **Change**/**Remove** once chosen); **Create new…** to\n create a brand-new Component and link to it in one step (fill in its\n name, Contract, and any required fields right there); or **Create\n inline…** to embed a value that only ever exists inside this one — pick\n a Contract and an **Edit** panel slides in, exactly like Nested below.\n If the Contract only allows one of these choices, only that one is\n offered. If a linked Component can't be found — most often because it\n was skipped during a promotion into this environment (see\n [content-environments.md](content-environments.md)'s \"Unresolved\n references\" section) — you'll see a distinct **Unresolved** badge\n instead of the usual resolved name, with a link to Component Sync to\n see the full picture and fix it. **Change**/**Remove** still work\n normally on an unresolved value.\n- **Blob** fields (images and other files) show an **Upload** button.\n Once uploaded, you'll see a preview (for images) and a link to download\n the file, plus a **Replace** button.\n- **Nested** fields show a small **Edit** panel once a Contract is chosen\n for them (automatically, if only one is allowed for that field, or via a\n picker if more than one is allowed) — selecting **Edit** opens the\n nested content in its own panel, sliding in over the current one. Any\n unsaved changes you've made — at every level — are kept even if you\n drill several levels deep and back out again; nothing is lost until you\n actually leave the page without saving. A Component field's own **Create\n inline…** choice opens the identical panel.\n- Fields marked **Localizable** always show a small translations icon next\n to their label — select it to add per-locale overrides alongside the\n default value. It's disabled (with an explanation on hover) until your\n organization has a language configured under **Localization** settings\n with at least one language added under it to translate into; once one\n exists, the icon becomes selectable. This works the same way for every\n field type, including Blob, Reference, Nested, Component, and\n Presentation fields: each locale gets its own independent\n **Upload**/**Edit**/**Choose…** affordance, so a Nested value's translated\n content — or a different linked Component or uploaded file per locale —\n is fully separate from the default. The default-locale row in the\n translations panel is always read-only (a reflection of the default\n value, not a second copy of it); translate from the other locale rows.\n- **Presentation** fields let you instantiate a Template inline — pick a\n Template, bind it to a Component, and set contextual values and settings\n for this specific placement. See\n [Presenting content with Templates](templates.md) for the full flow.\n\n## Links to the live page\n\nIf the Contract has **External links**, they appear as buttons under the\nComponent's name, and at the top of the quick-edit panel. A button opens that\nComponent's page on your site in a new tab. If it is greyed out, the reason is\nwritten beside it, usually that the Component has not been published yet. The\nlink always shows what is *published*, not the changes you are typing. See\n[Links to your site](contracts.md) to set them up.\n\n## Status, and what to do next\n\nUnder the Component's name, one **status strip** says whether it can be published and, if not, why. It also\nholds the next step, so you do not have to hunt for it:\n\n- **Draft**, **Published** or **Modified since it was published**, with one line about the live site\n (\"The live site shows an older version\").\n- If your organization uses an [editorial workflow](content-workflow.md) for this folder, the strip shows the\n workflow's state beside the headline. While that state does not allow publishing it reads **Can't be\n published yet**, and the workflow's next step (for example **Approve**) sits beside it. Choose it, add an\n optional comment and confirm, all without leaving the Content tab. **Republish…** stays available, but it is\n no longer the highlighted button; its tooltip gives the reason, and the publish panel explains the block.\n- Once the state allows publishing it reads **Ready to publish** and **Publish…** is highlighted instead.\n- If you have edited since a review was started, the strip says so, and that publishing will use the version\n that was reviewed.\n- A Component that no longer fits its folder's rules gets a **Move it…** row.\n- If the Component has translations in progress, they are listed here too, with **Review…** for one that is\n waiting for you.\n\nThe full workflow panel, with its comment box and **Cancel run**, and the complete translations list stay on the\n**Settings** tab. Where the Component is used (**Used in N places**) and whether it is **Inherited** are in the line\nunder the name.\n\n## Version history\n\nEvery time a Component's content is saved, ebitex keeps a copy, so you can\nsee what changed, who changed it, and undo an unwanted edit.\n\nOpen the **More actions** menu near the top of a Component and choose\n**Version history…**. Each entry shows a version number, who saved it and\nwhen. Select an entry to see what changed compared to the version before\nit: the fields that were added, removed or changed, named as you see them\nin the editor. The very first version has nothing to compare against.\n\nSaving the exact same content twice in a row doesn't add an entry: only a\nsave that actually changes something does. Entries can show **Unknown**\ninstead of a name when none was recorded, which is the case for changes\nmade by promotion, import or inheritance rather than by a person typing in\nthe editor. It doesn't mean the person has left your organization.\n\n**Restoring** a version puts that version's name and document back as the\nComponent's current content. Its folder stays where it is. Nothing is\ndeleted: restoring adds a *new* entry to the history, marked **restored**,\nso you can undo a restore by restoring again. Any unsaved edits on the page\nare discarded when you restore, and the confirmation says so. A restore\ndoes not publish anything. If the restored content differs from what is live\nthe Component reads **Modified** until you publish it; if it matches what is\nlive, it reads Published again.\n\nRestoring needs a permission beyond the one for viewing history (today,\nOwners hold it), and the same edit access on the folder that saving does.\nWithout them the option is shown but disabled, with the reason on hover.\nIt is also unavailable on an inherited Component, which you can't edit\nhere. Viewing history needs the version-history permission, which Members\nhold; a role you manage that should see history needs it added on the\nRoles page.\n\nTwo things worth knowing before you restore:\n\n- **Referenced items aren't included.** A version remembers this Component's\n own name and document, not what an item it references looked like at that\n time. A restored version shows those items as they are today.\n- **A version can become unrestorable.** If it was written against a version\n of its Contract that no longer exists, or points at content that has since\n been deleted, restoring explains why and leaves the Component unchanged.\n\nIf someone else saves the Component while you have its history open, a\nrestore is rejected like an ordinary save would be. Reload to see the latest\ncontent, then try again.\n\nPages in the Composer have the same **Version history…** action. Their history\nis read-only for now: you can see what changed and who changed it, but not\nrestore a page.\n\n## Jumping to a field\n\nWhen a Contract has eight or more fields, a **Jump to field** menu appears beside the **Content** and **Settings**\ntabs. Choosing a field scrolls to it and puts the cursor there. A red dot marks a field that needs attention after\na failed save.\n\n## Editing a tree of Components\n\nWhen a Contract is set up to be edited as a tree (see\n[Editing fields as a tree](contracts.md)), its Component editor shows one\nsection, such as **Pedigree**, in place of the separate pickers. The Component\nyou are editing is the root, and each slot is a Component of its own.\n\n- **Chart or outline.** A slot-based tree such as a pedigree is drawn as a chart,\n one column per generation, or as an outline. Choose with the buttons above it;\n the outline is used on narrow screens. **Generations** shows fewer levels\n without changing anything. A list, such as the parts of a product, is always\n an outline you can collapse and expand.\n- **Fill a slot.** Select an empty slot to search for an existing Component, or\n **Create new** to make one on the spot. A slot only lists Components it can\n hold, such as dogs for a sire.\n- **Options you can't choose are greyed out, with the reason.** *Would become its\n own ancestor* or *Would contain itself* means choosing it would make something\n its own ancestor. *Already used elsewhere in this tree* appears when the\n Contract doesn't allow repeats. *Already in this list* means it is there\n already. If the server still refuses a change, the reason is shown above the\n tree.\n- **Edit without leaving.** **Edit** on a filled slot opens that Component in a\n panel over the page. Change it, save it and close the panel, and you are back\n in the tree.\n- **Change or remove.** Point at a filled slot for **Change** and the remove\n button. Removing only empties the slot; the Component itself is kept.\n- **A slot under an empty parent is greyed out**, because there is nothing to\n attach it to yet. Fill the parent first.\n- **A name with ×2 or \"in 2\"** is one Component that appears in more than one\n place. Editing it changes it everywhere.\n\n**Records from another app.** A field can take records that another app owns, such as dogs held in\nData, instead of Components. The tree draws them the same way, and the first level (the slots of the\nComponent you are editing) is changed like any other. What is beneath it belongs to the other app, and\nwhat you can do to it is decided by that app, record by record. Where it lets you edit a record, **Edit**\nopens that record in a panel and **Save** saves it **there**, under its own rules (a refusal is shown on the\nfield it names); slots beneath it can be added, changed and removed, and are saved there too. Where it does\nnot, the record is shown but cannot be changed: a slot it has not filled reads *not set*, and **Edit**\nbecomes **Open in** the other app, which opens its own screen for that record in a new tab. If the other app has no screen for a\nrecord, no link is offered. When a slot takes only that app's records, the picker also offers **Create a {record kind} in {app}** (only for a kind you are allowed to create there): it opens that app's own form, starts with the name you typed in the search box, and **Save** makes the record **there** and puts it in the slot. Cancelling makes nothing. A record it cannot return, because it was deleted or because you may not see it, is shown as *Unavailable* and does not stop the page.\n\n**A slot can be described inline.** Some fields accept a description written\nin place instead of an existing Component, for example a dam who is not in your\narchive and never will be. Where a field allows it, the picker has an\n**Enter … inline instead** button. An inline slot is drawn with a dashed\noutline and an **Inline** chip, and its own slots (her sire and dam, say) are\ndrawn under it and filled in the same way as any other.\n\n- **Edit** on an inline slot opens its own fields in a panel at the side. The\n slots the tree draws are not repeated there. Choose **Done** to keep your\n changes.\n- **Change** or the remove button on an inline slot replaces or removes it\n *together with everything under it*. The picker says how many entries that\n is before you choose, and a notice with **Undo** appears for a few seconds\n afterwards. Undo puts the whole description back.\n- A field that only accepts an existing Component has no inline button.\n- Nothing else can point at an inline description, so it shows no ×2 count.\n\n**What saves when.** The first level, the slots of the Component you have open,\nis part of that Component: it is saved with **Save**, like any other field.\nSlots deeper down belong to the Components above them, so filling one saves that\nComponent straight away, and a **Saved as you go** note under the tree says so.\nA slot under an inline description belongs to the Component that holds the\ndescription, so it follows the same rule: with **Save** when that Component is\nthe one you have open, at once otherwise.\n\n## Contextual defaults\n\nFields marked Contextual on the Contract appear in a separate\n**\"Defaults for usage sites\"** section, clearly labeled optional — even if\nthe Contract also marks them Mandatory. That's intentional: a Contextual\nfield's real value is supplied wherever the content is *used*, not here;\nwhat you set in this section is only a fallback for places that don't\nsupply their own value.\n\n### Setting per-usage values on a Reference\n\nWhen you link to another Component via a Reference field (or a Component\nfield's **Choose…**/**Create new…** path — both link the same way), select\n**Contextual values** to open a panel listing that target's own Contextual\nfields, each with three distinct states you can switch between:\n\n- **Inheriting the Component's default** — nothing set here; the linked\n Component's own default value is used.\n- **Overridden** — set a value here to use instead of the default, just\n for this one link. This works for every field type the target Contract\n declares as Contextual, not just simple text/number/checkbox fields — a\n Contextual Reference field gets the same **Choose…** picker, a Contextual\n Blob field the same **Upload** button, and a Contextual Nested field the\n same drill-in **Edit** panel you'd see editing that field directly on a\n Component.\n- **Explicitly cleared** — select **Clear** to force \"no value\" at this\n usage, ignoring the default entirely (only available when the field\n isn't required).\n\nSelect **Reset to default** at any time to go back to inheriting. The same\nthree states and the same per-type widgets apply to a Presentation field's\nown contextual-values panel (see\n[Presenting content with Templates](templates.md)).\n\n### Editing the linked Component itself\n\nNext to **Contextual values**, a linked Component also offers **Quick\nedit**, which opens that Component in a layer over the page you're on —\nits own fields, its own **Save**, and a note of everywhere else it's used,\nsince saving changes it there too. How layers stack, and the difference\nbetween a layer that saves on its own and one that's part of your page, is\nexplained in\n[Editing something from where it's used](content-authoring.md#editing-something-from-where-its-used).\n\n## Organizing with folders\n\nThe **Authoring** page shows your folder tree on the left. At the top are **All components** (everything in\nthis environment, across every folder) and **Top level** (Components that aren't in any folder). Below them\nare your folders, each with a count; a folder's count includes everything beneath it. A long folder name wraps\nrather than being cut off.\n\nPoint at a folder to see its actions: the **+** icon creates a subfolder inside it, the pencil renames it or\nmoves it (choose where it goes under **Inside**), the trash icon deletes it (only possible once it's empty,\nand it asks first), and the handle drags it. Selecting a folder shows two tabs: **Contents** (the Components\ninside it) and, if you have the right permissions, **Settings** (that folder's **Access rules**, **Allowed\nContracts**, and editorial workflow assignment). The double-arrow at the top of the panel collapses the whole\ntree to a narrow rail of icons with count badges; select one to open that folder, or the arrow to bring the\npanel back.\n\nEach Component is a row with its title (its id underneath), Contract, publish status (**Draft**, **Published**,\n**Changed** or **Unpublished**), and who last updated it and when. Select the **Title** or **Updated** heading\nto sort by it. Above the list, a search box matches a title, id or Contract, and the **Contract**,\n**Category** and **Status** chips narrow further; **Clear filters** resets them. **Status** lets you tick\none or more of Draft, Published, Changed and Unpublished, for example to find everything that has changed since\nit was published. The count under the list follows the filter, so it is the number that match, not the number\non the page. **Import**, beside **New Component**, opens the [bundle import](export-import.md) for bringing\nComponents in from another environment. Beneath the list, **Rows per page** and\n**Previous / Next** page through long folders, and a line says how many of the total you are looking at.\n\n### Moving Components by dragging, or with the menu\n\nDrag a Component by the handle at the start of its row onto a folder in the tree — or onto **Top level** to take\nit out of its folder — to move it. If you've ticked several rows, dragging one drags them all. A message\nconfirms what moved and offers **Undo**, which puts each Component back where it came from.\n\nTo move without dragging, open the row's **⋯** menu and choose **Move to folder…**, then pick the folder. When\nthe row is part of a selection, the menu says \"Move 3 selected to folder…\" and moves all of them. A folder you\ncan't edit is shown but not choosable. A move is not all-or-nothing: if a Component can't go there (the folder\ndoesn't allow its Contract, say, or you can't edit it), the message names it and why, and the rest still move.\nDragging a folder onto another moves the whole folder inside it; a folder can't be dropped into itself or one\nof its own subfolders. Folders are always listed alphabetically, so there is no manual order to drag into.\n\n### Working on several Components at once\n\nTick rows (the box in the heading ticks every row on the page) and a bar replaces the search tools, showing how\nmany are selected and in which publish states:\n\n- **Publish** applies to everything selected, and reads **Republish** when none of the selection is a draft.\n It opens the usual publish dialog, which lists what else would be published with them.\n- **Unpublish** applies only to what is published or changed. It shows \"2 of 5\" when some of the selection\n can't be unpublished, is switched off with the reason when none can, and asks you to confirm, with a breakdown\n of what comes off the live site.\n- **Move to folder…** moves what you can edit and says how many of the selection that is.\n\nUnder **Settings**:\n\n- **Access rules** restrict which roles can view, edit, delete, or publish\n content in that folder and everything below it (until a subfolder sets\n its own, narrower rules). No rules anywhere on a branch means it's open\n to every member. Select **Add Rule** to grant a role access: pick the\n role from the list and check whichever of View/Edit/Delete/Publish it\n should have. Editing, deleting, or publishing all imply viewing, so you\n don't need to check View separately for those.\n- **Allowed Contracts** restrict which Contracts new Components in that\n folder (and its subfolders, unless they set their own) can use — useful\n for keeping a folder focused on one kind of content. Select **Add\n Contract** and search for the Contract to allow; select **Remove** next\n to an already-allowed Contract to take it off the list. This only\n affects *new* or *moved* Components; it never breaks ones already there,\n though they'll show a **Non-conforming** badge as a reminder.\n\nIf you don't have permission to manage a folder's access rules or allowed\nContracts, you can still see what you're allowed to do there — the panel\njust won't let you change it.\n\n### Moving a Component from its own page\n\nOpen the Component, select the **Settings** tab, and select **Move…**\nnext to the **Folder** label. A picker lists every folder (and **Root**);\npick one to move the Component there once you save. A folder you don't\nhave edit access to is shown but disabled, with an explanation. A folder\nwhose **Allowed Contracts** don't include this Component's Contract is\ndisabled too — unlike an *existing* Component whose folder's rules later\nchange (the **Non-conforming** badge case above), a move that would\nviolate the target folder's rules is rejected outright, so the picker\nwon't offer it as an option in the first place.\n\n### Making copies of a Component\n\nWhen you need several near-identical records (a litter, a series of events,\nproduct variants), build one and **duplicate** it. Open the Component and\nselect **Duplicate…** next to **Preview…**. The button is there whenever you\ncould create a Component in the same folder, and absent when you couldn't.\n\nChoose a **number of copies** (1 to 25) and a **name**. Each copy is named\nwith a number after it (`Puppy A 1`, `Puppy A 2`, …), and the dialog previews\nthe first three, with their external ids, before you start.\n\n- **Values are copied, references are shared.** A copy gets its own\n copy of every value in the document. A Component it *references* is not\n copied: every copy points at the same one, so changing that referenced\n Component changes it in all of them.\n- **Copies are drafts.** They are not published, and carry none of the\n original's published state, history, workflow state, or where it is used.\n They sit in the same folder and use the same Contract as the original.\n- **Copies are made from the saved version.** If you have unsaved edits, the\n dialog says so; save first if you want them included.\n- **External ids** follow the original's (`puppy-a-copy-1`) and move to the\n next free number if one is taken, so a batch never fails over a clash.\n\nCopies are created one at a time. If your plan only has room for some of them,\nthe dialog says how many fit and won't start until the number is lowered. If\nsomething goes wrong part-way, it lists which copies exist, which failed and\nwhich were never attempted, and offers **Create the remaining N**, which\ncarries on from where it stopped instead of making extras. If the original no\nlonger matches the latest version of its Contract, nothing is created and the\ndialog names the field to fix first.\n\n### Finding your way back to a folder\n\nThe Component editor shows a breadcrumb above its title (**Content** /\nthe folder it's in / the Component's name) — select the folder name to\nreturn straight to that folder's Contents tab, rather than using your\nbrowser's back button.\n\n## The upgrade badge\n\nIf a Contract changes after a Component was created from it, that\nComponent keeps working exactly as it did — nothing breaks automatically.\nInstead:\n\n- If the Component still satisfies the Contract's latest version, you'll\n see a badge offering **Upgrade to v_N_** — select it to move the\n Component onto the latest version immediately.\n- If it no longer satisfies the latest version, you'll see a\n **Not valid against latest** badge listing exactly what's wrong. Select\n **Start guided upgrade** to switch into editing against the latest\n version, fix the listed issues, and save — the Component moves onto the\n new version as part of that save.\n\nYou're never forced to upgrade; an older Component keeps validating against\nthe version it was created with until you choose to move it forward.\n\n## Asking the assistant to edit this Component\n\nThe assistant (open it from the magenta ebitex-mark icon in the header, beside **?**) can see and edit the\nComponent you have open, not only answer questions about it — see **The assistant** in\n[Getting help](../general/getting-help.md). A field edit it makes saves immediately with the same\nversion history a manual edit gets; anything bigger, like deleting the Component, is proposed for\nyou to review first.\n"
19
+ "body": "# Authoring Components\n\nA Component is one piece of content built from a Contract — for example,\na specific article. This guide covers creating and editing Components,\norganizing them in folders, and the friction the app shows you when a\nContract changes underneath a Component you've already created. See\n[Modeling content with Contracts](contracts.md) first if you haven't\ncreated a Contract yet.\n\n## Creating a Component\n\n1. From the Content page, select **New Component** (optionally after\n opening the folder you want it created in).\n2. Enter a **Name** — the **Id** fills in from it automatically and can\n still be edited by hand.\n3. Choose a **Contract**. If you started from a specific folder that\n restricts which Contracts are allowed there, only those (and their\n descendants) are offered.\n4. Fill in the form that appears — every field from the Contract, laid\n out in order. Fields marked with a red **\\*** are required.\n5. Select **Create**. If a required field is missing or a value doesn't\n match the Contract's rules, the field is highlighted with an\n explanation — fix it and select **Create** again.\n\n## Filling in fields\n\nMost fields are a straightforward text box, number box, or checkbox.\nA few work differently:\n\n- **Reference** and **Nested** are older field types kept working for\n existing Contracts, but no longer offered when adding a new field — new\n Contracts should use **Component** instead (below), which offers the\n same two behaviors plus a third, chosen per value instead of committed\n to for the whole field.\n- **Component** fields ask you to choose, each time you fill one in:\n **Choose…** to link to an existing Component (same search box as\n Reference, with **Change**/**Remove** once chosen); **Create new…** to\n create a brand-new Component and link to it in one step (fill in its\n name, Contract, and any required fields right there); or **Create\n inline…** to embed a value that only ever exists inside this one — pick\n a Contract and an **Edit** panel slides in, exactly like Nested below.\n If the Contract only allows one of these choices, only that one is\n offered. If a linked Component can't be found — most often because it\n was skipped during a promotion into this environment (see\n [content-environments.md](content-environments.md)'s \"Unresolved\n references\" section) — you'll see a distinct **Unresolved** badge\n instead of the usual resolved name, with a link to Component Sync to\n see the full picture and fix it. **Change**/**Remove** still work\n normally on an unresolved value.\n- **Blob** fields (images and other files) show an **Upload** button.\n Once uploaded, you'll see a preview (for images) and a link to download\n the file, plus a **Replace** button.\n- **Nested** fields show a small **Edit** panel once a Contract is chosen\n for them (automatically, if only one is allowed for that field, or via a\n picker if more than one is allowed) — selecting **Edit** opens the\n nested content in its own panel, sliding in over the current one. Any\n unsaved changes you've made — at every level — are kept even if you\n drill several levels deep and back out again; nothing is lost until you\n actually leave the page without saving. A Component field's own **Create\n inline…** choice opens the identical panel.\n- Fields marked **Localizable** always show a small translations icon next\n to their label — select it to add per-locale overrides alongside the\n default value. It's disabled (with an explanation on hover) until your\n organization has a language configured under **Localization** settings\n with at least one language added under it to translate into; once one\n exists, the icon becomes selectable. This works the same way for every\n field type, including Blob, Reference, Nested, Component, and\n Presentation fields: each locale gets its own independent\n **Upload**/**Edit**/**Choose…** affordance, so a Nested value's translated\n content — or a different linked Component or uploaded file per locale —\n is fully separate from the default. The default-locale row in the\n translations panel is always read-only (a reflection of the default\n value, not a second copy of it); translate from the other locale rows.\n- **Presentation** fields let you instantiate a Template inline — pick a\n Template, bind it to a Component, and set contextual values and settings\n for this specific placement. See\n [Presenting content with Templates](templates.md) for the full flow.\n\n## Links to the live page\n\nIf the Contract has **External links**, they appear as buttons under the\nComponent's name, and at the top of the quick-edit panel. A button opens that\nComponent's page on your site in a new tab. If it is greyed out, the reason is\nwritten beside it, usually that the Component has not been published yet. The\nlink always shows what is *published*, not the changes you are typing. See\n[Links to your site](contracts.md) to set them up.\n\n## Noting which channels a Component is made for\n\nOn a Component's **Settings** tab, **Made for** lets you note that it suits **Email**, **Web**, or\nboth. It is optional and only advises: it never stops you saving or publishing, and a Component with\nno note is \"unknown\". Pages that are noted for a channel warn about Components that say they are not\nmade for it. The **Made for** column in the Components list shows the note. See\n[Building your site in Composer](content-composer.md#made-for).\n\n## Status, and what to do next\n\nUnder the Component's name, one **status strip** says whether it can be published and, if not, why. It also\nholds the next step, so you do not have to hunt for it:\n\n- **Draft**, **Published** or **Modified since it was published**, with one line about the live site\n (\"The live site shows an older version\").\n- If your organization uses an [editorial workflow](content-workflow.md) for this folder, the strip shows the\n workflow's state beside the headline. While that state does not allow publishing it reads **Can't be\n published yet**, and the workflow's next step (for example **Approve**) sits beside it. Choose it, add an\n optional comment and confirm, all without leaving the Content tab. **Republish…** stays available, but it is\n no longer the highlighted button; its tooltip gives the reason, and the publish panel explains the block.\n- Once the state allows publishing it reads **Ready to publish** and **Publish…** is highlighted instead.\n- If you have edited since a review was started, the strip says so, and that publishing will use the version\n that was reviewed.\n- A Component that no longer fits its folder's rules gets a **Move it…** row.\n- If the Component has translations in progress, they are listed here too, with **Review…** for one that is\n waiting for you.\n\nThe full workflow panel, with its comment box and **Cancel run**, and the complete translations list stay on the\n**Settings** tab. Where the Component is used (**Used in N places**) and whether it is **Inherited** are in the line\nunder the name.\n\n## Version history\n\nEvery time a Component's content is saved, ebitex keeps a copy, so you can\nsee what changed, who changed it, and undo an unwanted edit.\n\nOpen the **More actions** menu near the top of a Component and choose\n**Version history…**. Each entry shows a version number, who saved it and\nwhen. Select an entry to see what changed compared to the version before\nit: the fields that were added, removed or changed, named as you see them\nin the editor. The very first version has nothing to compare against.\n\nSaving the exact same content twice in a row doesn't add an entry: only a\nsave that actually changes something does. Entries can show **Unknown**\ninstead of a name when none was recorded, which is the case for changes\nmade by promotion, import or inheritance rather than by a person typing in\nthe editor. It doesn't mean the person has left your organization.\n\n**Restoring** a version puts that version's name and document back as the\nComponent's current content. Its folder stays where it is. Nothing is\ndeleted: restoring adds a *new* entry to the history, marked **restored**,\nso you can undo a restore by restoring again. Any unsaved edits on the page\nare discarded when you restore, and the confirmation says so. A restore\ndoes not publish anything. If the restored content differs from what is live\nthe Component reads **Modified** until you publish it; if it matches what is\nlive, it reads Published again.\n\nRestoring needs a permission beyond the one for viewing history (today,\nOwners hold it), and the same edit access on the folder that saving does.\nWithout them the option is shown but disabled, with the reason on hover.\nIt is also unavailable on an inherited Component, which you can't edit\nhere. Viewing history needs the version-history permission, which Members\nhold; a role you manage that should see history needs it added on the\nRoles page.\n\nTwo things worth knowing before you restore:\n\n- **Referenced items aren't included.** A version remembers this Component's\n own name and document, not what an item it references looked like at that\n time. A restored version shows those items as they are today.\n- **A version can become unrestorable.** If it was written against a version\n of its Contract that no longer exists, or points at content that has since\n been deleted, restoring explains why and leaves the Component unchanged.\n\nIf someone else saves the Component while you have its history open, a\nrestore is rejected like an ordinary save would be. Reload to see the latest\ncontent, then try again.\n\nPages in the Composer have the same **Version history…** action. Their history\nis read-only for now: you can see what changed and who changed it, but not\nrestore a page.\n\n## Jumping to a field\n\nWhen a Contract has eight or more fields, a **Jump to field** menu appears beside the **Content** and **Settings**\ntabs. Choosing a field scrolls to it and puts the cursor there. A red dot marks a field that needs attention after\na failed save.\n\n## Editing a tree of Components\n\nWhen a Contract is set up to be edited as a tree (see\n[Editing fields as a tree](contracts.md)), its Component editor shows one\nsection, such as **Pedigree**, in place of the separate pickers. The Component\nyou are editing is the root, and each slot is a Component of its own.\n\n- **Chart or outline.** A slot-based tree such as a pedigree is drawn as a chart,\n one column per generation, or as an outline. Choose with the buttons above it;\n the outline is used on narrow screens. **Generations** shows fewer levels\n without changing anything. A list, such as the parts of a product, is always\n an outline you can collapse and expand.\n- **Fill a slot.** Select an empty slot to search for an existing Component, or\n **Create new** to make one on the spot. A slot only lists Components it can\n hold, such as dogs for a sire.\n- **Options you can't choose are greyed out, with the reason.** *Would become its\n own ancestor* or *Would contain itself* means choosing it would make something\n its own ancestor. *Already used elsewhere in this tree* appears when the\n Contract doesn't allow repeats. *Already in this list* means it is there\n already. If the server still refuses a change, the reason is shown above the\n tree.\n- **Edit without leaving.** **Edit** on a filled slot opens that Component in a\n panel over the page. Change it, save it and close the panel, and you are back\n in the tree.\n- **Change or remove.** Point at a filled slot for **Change** and the remove\n button. Removing only empties the slot; the Component itself is kept.\n- **A slot under an empty parent is greyed out**, because there is nothing to\n attach it to yet. Fill the parent first.\n- **A name with ×2 or \"in 2\"** is one Component that appears in more than one\n place. Editing it changes it everywhere.\n\n**Records from another app.** A field can take records that another app owns, such as dogs held in\nData, instead of Components. The tree draws them the same way, and the first level (the slots of the\nComponent you are editing) is changed like any other. What is beneath it belongs to the other app, and\nwhat you can do to it is decided by that app, record by record. Where it lets you edit a record, **Edit**\nopens that record in a panel and **Save** saves it **there**, under its own rules (a refusal is shown on the\nfield it names); slots beneath it can be added, changed and removed, and are saved there too. Where it does\nnot, the record is shown but cannot be changed: a slot it has not filled reads *not set*, and **Edit**\nbecomes **Open in** the other app, which opens its own screen for that record in a new tab. If the other app has no screen for a\nrecord, no link is offered. When a slot takes only that app's records, the picker also offers **Create a {record kind} in {app}** (only for a kind you are allowed to create there): it opens that app's own form, starts with the name you typed in the search box, and **Save** makes the record **there** and puts it in the slot. Cancelling makes nothing. A record it cannot return, because it was deleted or because you may not see it, is shown as *Unavailable* and does not stop the page.\n\n**A slot can be described inline.** Some fields accept a description written\nin place instead of an existing Component, for example a dam who is not in your\narchive and never will be. Where a field allows it, the picker has an\n**Enter … inline instead** button. An inline slot is drawn with a dashed\noutline and an **Inline** chip, and its own slots (her sire and dam, say) are\ndrawn under it and filled in the same way as any other.\n\n- **Edit** on an inline slot opens its own fields in a panel at the side. The\n slots the tree draws are not repeated there. Choose **Done** to keep your\n changes.\n- **Change** or the remove button on an inline slot replaces or removes it\n *together with everything under it*. The picker says how many entries that\n is before you choose, and a notice with **Undo** appears for a few seconds\n afterwards. Undo puts the whole description back.\n- A field that only accepts an existing Component has no inline button.\n- Nothing else can point at an inline description, so it shows no ×2 count.\n\n**What saves when.** The first level, the slots of the Component you have open,\nis part of that Component: it is saved with **Save**, like any other field.\nSlots deeper down belong to the Components above them, so filling one saves that\nComponent straight away, and a **Saved as you go** note under the tree says so.\nA slot under an inline description belongs to the Component that holds the\ndescription, so it follows the same rule: with **Save** when that Component is\nthe one you have open, at once otherwise.\n\n## Contextual defaults\n\nFields marked Contextual on the Contract appear in a separate\n**\"Defaults for usage sites\"** section, clearly labeled optional — even if\nthe Contract also marks them Mandatory. That's intentional: a Contextual\nfield's real value is supplied wherever the content is *used*, not here;\nwhat you set in this section is only a fallback for places that don't\nsupply their own value.\n\n### Setting per-usage values on a Reference\n\nWhen you link to another Component via a Reference field (or a Component\nfield's **Choose…**/**Create new…** path — both link the same way), select\n**Contextual values** to open a panel listing that target's own Contextual\nfields, each with three distinct states you can switch between:\n\n- **Inheriting the Component's default** — nothing set here; the linked\n Component's own default value is used.\n- **Overridden** — set a value here to use instead of the default, just\n for this one link. This works for every field type the target Contract\n declares as Contextual, not just simple text/number/checkbox fields — a\n Contextual Reference field gets the same **Choose…** picker, a Contextual\n Blob field the same **Upload** button, and a Contextual Nested field the\n same drill-in **Edit** panel you'd see editing that field directly on a\n Component.\n- **Explicitly cleared** — select **Clear** to force \"no value\" at this\n usage, ignoring the default entirely (only available when the field\n isn't required).\n\nSelect **Reset to default** at any time to go back to inheriting. The same\nthree states and the same per-type widgets apply to a Presentation field's\nown contextual-values panel (see\n[Presenting content with Templates](templates.md)).\n\n### Editing the linked Component itself\n\nNext to **Contextual values**, a linked Component also offers **Quick\nedit**, which opens that Component in a layer over the page you're on —\nits own fields, its own **Save**, and a note of everywhere else it's used,\nsince saving changes it there too. How layers stack, and the difference\nbetween a layer that saves on its own and one that's part of your page, is\nexplained in\n[Editing something from where it's used](content-authoring.md#editing-something-from-where-its-used).\n\n## Organizing with folders\n\nThe **Authoring** page shows your folder tree on the left. At the top are **All components** (everything in\nthis environment, across every folder) and **Top level** (Components that aren't in any folder). Below them\nare your folders, each with a count; a folder's count includes everything beneath it. A long folder name wraps\nrather than being cut off.\n\nPoint at a folder to see its actions: the **+** icon creates a subfolder inside it, the pencil renames it or\nmoves it (choose where it goes under **Inside**), the trash icon deletes it (only possible once it's empty,\nand it asks first), and the handle drags it. Selecting a folder shows two tabs: **Contents** (the Components\ninside it) and, if you have the right permissions, **Settings** (that folder's **Access rules**, **Allowed\nContracts**, and editorial workflow assignment). The double-arrow at the top of the panel collapses the whole\ntree to a narrow rail of icons with count badges; select one to open that folder, or the arrow to bring the\npanel back.\n\nEach Component is a row with its title (its id underneath), Contract, publish status (**Draft**, **Published**,\n**Changed** or **Unpublished**), and who last updated it and when. Select the **Title** or **Updated** heading\nto sort by it. Above the list, a search box matches a title, id or Contract, and the **Contract**,\n**Category** and **Status** chips narrow further; **Clear filters** resets them. **Status** lets you tick\none or more of Draft, Published, Changed and Unpublished, for example to find everything that has changed since\nit was published. The count under the list follows the filter, so it is the number that match, not the number\non the page. **Import**, beside **New Component**, opens the [bundle import](export-import.md) for bringing\nComponents in from another environment. Beneath the list, **Rows per page** and\n**Previous / Next** page through long folders, and a line says how many of the total you are looking at.\n\n### Moving Components by dragging, or with the menu\n\nDrag a Component by the handle at the start of its row onto a folder in the tree — or onto **Top level** to take\nit out of its folder — to move it. If you've ticked several rows, dragging one drags them all. A message\nconfirms what moved and offers **Undo**, which puts each Component back where it came from.\n\nTo move without dragging, open the row's **⋯** menu and choose **Move to folder…**, then pick the folder. When\nthe row is part of a selection, the menu says \"Move 3 selected to folder…\" and moves all of them. A folder you\ncan't edit is shown but not choosable. A move is not all-or-nothing: if a Component can't go there (the folder\ndoesn't allow its Contract, say, or you can't edit it), the message names it and why, and the rest still move.\nDragging a folder onto another moves the whole folder inside it; a folder can't be dropped into itself or one\nof its own subfolders. Folders are always listed alphabetically, so there is no manual order to drag into.\n\n### Working on several Components at once\n\nTick rows (the box in the heading ticks every row on the page) and a bar replaces the search tools, showing how\nmany are selected and in which publish states:\n\n- **Publish** applies to everything selected, and reads **Republish** when none of the selection is a draft.\n It opens the usual publish dialog, which lists what else would be published with them.\n- **Unpublish** applies only to what is published or changed. It shows \"2 of 5\" when some of the selection\n can't be unpublished, is switched off with the reason when none can, and asks you to confirm, with a breakdown\n of what comes off the live site.\n- **Move to folder…** moves what you can edit and says how many of the selection that is.\n\nUnder **Settings**:\n\n- **Access rules** restrict which roles can view, edit, delete, or publish\n content in that folder and everything below it (until a subfolder sets\n its own, narrower rules). No rules anywhere on a branch means it's open\n to every member. Select **Add Rule** to grant a role access: pick the\n role from the list and check whichever of View/Edit/Delete/Publish it\n should have. Editing, deleting, or publishing all imply viewing, so you\n don't need to check View separately for those.\n- **Allowed Contracts** restrict which Contracts new Components in that\n folder (and its subfolders, unless they set their own) can use — useful\n for keeping a folder focused on one kind of content. Select **Add\n Contract** and search for the Contract to allow; select **Remove** next\n to an already-allowed Contract to take it off the list. This only\n affects *new* or *moved* Components; it never breaks ones already there,\n though they'll show a **Non-conforming** badge as a reminder.\n\nIf you don't have permission to manage a folder's access rules or allowed\nContracts, you can still see what you're allowed to do there — the panel\njust won't let you change it.\n\n### Moving a Component from its own page\n\nOpen the Component, select the **Settings** tab, and select **Move…**\nnext to the **Folder** label. A picker lists every folder (and **Root**);\npick one to move the Component there once you save. A folder you don't\nhave edit access to is shown but disabled, with an explanation. A folder\nwhose **Allowed Contracts** don't include this Component's Contract is\ndisabled too — unlike an *existing* Component whose folder's rules later\nchange (the **Non-conforming** badge case above), a move that would\nviolate the target folder's rules is rejected outright, so the picker\nwon't offer it as an option in the first place.\n\n### Making copies of a Component\n\nWhen you need several near-identical records (a litter, a series of events,\nproduct variants), build one and **duplicate** it. Open the Component and\nselect **Duplicate…** next to **Preview…**. The button is there whenever you\ncould create a Component in the same folder, and absent when you couldn't.\n\nChoose a **number of copies** (1 to 25) and a **name**. Each copy is named\nwith a number after it (`Puppy A 1`, `Puppy A 2`, …), and the dialog previews\nthe first three, with their external ids, before you start.\n\n- **Values are copied, references are shared.** A copy gets its own\n copy of every value in the document. A Component it *references* is not\n copied: every copy points at the same one, so changing that referenced\n Component changes it in all of them.\n- **Copies are drafts.** They are not published, and carry none of the\n original's published state, history, workflow state, or where it is used.\n They sit in the same folder and use the same Contract as the original.\n- **Copies are made from the saved version.** If you have unsaved edits, the\n dialog says so; save first if you want them included.\n- **External ids** follow the original's (`puppy-a-copy-1`) and move to the\n next free number if one is taken, so a batch never fails over a clash.\n\nCopies are created one at a time. If your plan only has room for some of them,\nthe dialog says how many fit and won't start until the number is lowered. If\nsomething goes wrong part-way, it lists which copies exist, which failed and\nwhich were never attempted, and offers **Create the remaining N**, which\ncarries on from where it stopped instead of making extras. If the original no\nlonger matches the latest version of its Contract, nothing is created and the\ndialog names the field to fix first.\n\n### Finding your way back to a folder\n\nThe Component editor shows a breadcrumb above its title (**Content** /\nthe folder it's in / the Component's name) — select the folder name to\nreturn straight to that folder's Contents tab, rather than using your\nbrowser's back button.\n\n## The upgrade badge\n\nIf a Contract changes after a Component was created from it, that\nComponent keeps working exactly as it did — nothing breaks automatically.\nInstead:\n\n- If the Component still satisfies the Contract's latest version, you'll\n see a badge offering **Upgrade to v_N_** — select it to move the\n Component onto the latest version immediately.\n- If it no longer satisfies the latest version, you'll see a\n **Not valid against latest** badge listing exactly what's wrong. Select\n **Start guided upgrade** to switch into editing against the latest\n version, fix the listed issues, and save — the Component moves onto the\n new version as part of that save.\n\nYou're never forced to upgrade; an older Component keeps validating against\nthe version it was created with until you choose to move it forward.\n\n## Asking the assistant to edit this Component\n\nThe assistant (open it from the magenta ebitex-mark icon in the header, beside **?**) can see and edit the\nComponent you have open, not only answer questions about it — see **The assistant** in\n[Getting help](../general/getting-help.md). A field edit it makes saves immediately with the same\nversion history a manual edit gets; anything bigger, like deleting the Component, is proposed for\nyou to review first.\n"
20
20
  },
21
21
  {
22
22
  "slug": "content-adapters",
@@ -31,7 +31,7 @@ export const HELP_TOPICS = [
31
31
  {
32
32
  "slug": "content-composer",
33
33
  "title": "Building your site in Composer",
34
- "body": "# Building your site in Composer\n\nComposer is where content becomes a website. A **site** is a named tree of\n**pages**; each page's slug (and its ancestors' slugs) form its **path** —\nthe URL it will eventually be served at. A page can be pure structure (a\n**Folder**, with no page of its own, just a place to organize its\nchildren), or it can carry a payload: either a **Presentation** (content\nshown at that path) or a **Redirect** (send visitors somewhere else).\nContracts, Components, and Templates (see\n[Modeling content with Contracts](contracts.md),\n[Authoring Components](components.md), and\n[Presenting content with Templates](templates.md)) define *what* content\nis and *how* it's presented; Composer decides *where* it lives. Nothing\nbuilt here is publicly visible yet — publishing is a later phase.\n\nComposer is the suite's *top-down* authoring surface — site, then tree,\nthen page. [Content](content-authoring.md) is its *bottom-up* counterpart:\nthe Component library, edited independently of any one page. Both appear\nas their own item in the sidebar.\n\n## Choosing a site\n\nComposer's header has a site switcher — select it to see every site in\nthis organization and pick one, or select **Manage sites →** to create,\nrename, or delete a site. Composer's tree always shows exactly one site's\npages at a time; switching sites swaps the whole tree beneath it.\n\nSites themselves are managed from **Settings > Sites**: create a new one\nby name, rename an existing one, or delete one (deleting a site deletes\nits entire page tree, including every page's payload — typing the site's\nname confirms you mean it).\n\n## Building the tree\n\nA large tree can be searched by category — see \"Filtering by category\" in\n[Taxonomy](content-taxonomy.md) for how the tree's own **Filter by\ncategory** control auto-expands to reveal matches without hiding anything\nelse.\n\nTo add a page:\n\n1. Select the parent page (the site's own root, shown at the top of the\n tree, or any page under it), then select **+ Add page** at the top of\n the tree panel.\n2. Pick a type — **Presentation**, **Redirect**, or **Folder** —\n Presentation is pre-selected, since it's what most new pages are for.\n You can change a page's type at any time later, from its own\n Experience tab.\n3. Enter a **Name** — the path preview beneath it fills in from it\n automatically (`/campaigns-launch`, for example). You can give the page\n a different slug later, from its **Configuration** tab.\n4. Select **Create**.\n\nEvery page shows its computed **path** at the top of the detail panel —\nthe site root's own path is always `/`.\n\n### Localized slugs\n\nA page's slug can have a different value per locale, just like other\nlocalizable content — select the translate icon beside **Slug** (in the\n**Configuration** tab) to add per-locale overrides. Two sibling pages can\nnever resolve to the same slug in the same locale, whether that's their\nshared default or one sibling's override colliding with another's\ndefault; you'll see exactly which locale and which sibling conflicts if\nthat happens.\n\n### Moving and reordering pages\n\nThe tree supports two different drags, depending on where you drop:\n\n- Drop a page **onto** another page to reparent it there — the dropped\n page becomes that page's child.\n- Drop a page **between** two sibling rows to reorder it among its\n current siblings, without changing its parent.\n\nEither kind of drag can also be done without a mouse: select **Move…** in\na page's **Configuration** tab and pick a target the same way dragging\nwould. You can't move a page into itself or one of its own descendants,\nand a site's root can't be moved or reordered at all — it has no grip\nhandle to drag by, and its Configuration tab shows no **Move…** button.\n\nIf someone else changes the tree while you're mid-drag, Composer notices,\nrefreshes the sibling list automatically, and asks you to try again rather\nthan silently applying a stale order.\n\nDeleting a page requires it to have no children first; a page that's the\ntarget of a **Redirect** elsewhere in the tree can't be deleted until that\nredirect is removed or repointed. A site's root can't be deleted from\nComposer at all — that's a **Settings > Sites** action, since it deletes\nthe whole tree beneath it.\n\n## The Experience tab\n\nA page's **Experience** tab opens with one question: **What does `/path` do?** The three\nanswers are the page's type, and exactly one is true of an address at a time:\n\n- **Presentation** shows a page built from a Template and a Component.\n- **Redirect** sends visitors to another page.\n- **Folder** only groups the pages beneath it, and has no content of its own.\n\nWhat sits below the question is only the chosen type's settings. Choosing a different type is an\nedit like any other: it shows in the save bar, and nothing changes until you save. Use the arrow\nkeys to move between the three.\n\nFor a **Presentation** page, the card below the question shows how the page is built, as pieces\nthat fit together from top to bottom:\n\n- **Template, sets the shape.** The layout. It decides the shape of content the page needs: a\n Contract, which is a list of fields. It shows the shape it **needs**.\n- **Adapter, reshapes to fit.** Only there when the Component's shape is not the one the Template\n needs. It shows the shape it **takes** and the shape it **gives**. See\n [Adapters](content-adapters.md) if that's new to you.\n- **Component, fills the shape.** The content itself: its text, images and fields. It shows the\n shape it **is**.\n\nBetween each pair is a joint. A tick means the shapes fit. A red mark means they do not, and a row\nbeneath offers **Add an Adapter…** to bridge them. Each piece keeps its own actions: **Change** on\nthe Template and on the Component, **Configure** where there are settings or contextual values to\nfill in, **Mapping** on an Adapter, and **Quick edit** on the Component. See\n[Presenting content with Templates](templates.md) for the **Contextual values** and **Settings**\npanels. If the Template declares a settings field that's both mandatory and Contextual, it must be\nfilled in here: a page is the last stop for that value, so there's nowhere further downstream to\ninherit it from. **Quick edit** opens the\n bound Component itself in a layer over the tree — and the same layer\n opens *this* page from any Link or Experience-reference field elsewhere\n that points at it; see\n [Editing something from where it's used](content-authoring.md#editing-something-from-where-its-used).\n\nSwitching a page's type here always lands you on that type's own normal\nstarting point (no Template chosen yet, no redirect target chosen yet) —\nit never carries over or invents a binding from whatever the page was\nbefore.\n\nFor a **Redirect** page, select **Pick a target page…** and browse to it.\nA page can't redirect to itself. A **Folder** page has no payload of its\nown — it exists only to organize the pages beneath it.\n\n## Version history for a page\n\nChoose **Version history…** from **More actions** to see every saved version of\nthe selected page: who changed it, when, and what changed (its name, address,\nand content). Page history is read-only: it shows you what the page used to\nsay, but restoring an earlier version isn't available yet. See\n[Version history](components.md#version-history) for how history works for\nComponents.\n\n## The Configuration tab\n\nEverything about a page other than what it renders lives in **Configuration**. The settings most\npeople use stay in view: the page's **Name** and **Slug**, its **Location** in the tree (parent,\nMove…), and its **Categories**. Everything else is folded into **Advanced**, a single row that\nsays how those settings are set while it is closed, for example *Access: no rules · Templates: any ·\nReview: none · Search engines: listed*. Open it for:\n\n- **Who can work on this branch**: access rules.\n- **Templates pages here can use**: which Templates new pages here may use.\n- **Review before publishing**: the editorial workflow assigned to this page.\n- **Search engines**: whether the page is listed in your sitemap.\n\n**Delete this page**, for a non-root page, stays separate at the bottom and asks you to confirm\nfirst.\n\nA page has one **Save** bar along the bottom, whichever tab is open. It counts\neverything you have changed on the page (name, slug, search visibility, page\ntype and what it shows) and lists each change when you select the count.\n**Save** writes them all; **Discard** puts them back. If part of a save is\nrefused, for example a slug a sibling page already uses, the bar keeps listing\nwhat is still unsaved and says why. If you select another page while this one\nhas unsaved edits, Composer asks\nbefore it drops them.\n\nUnder the page's name, one **status strip** says whether the page can be published. It reads\n**Draft**, **Published** or **Modified since it was published**, with a line about what the live site\nshows, and it holds **Publish…** or **Republish…**. If the page has an editorial workflow, the strip\nshows the workflow's state and its next step (for example **Approve**) beside it, so you can move it\non without leaving the tab. While the state does not allow publishing it reads **Can't be published\nyet**; **Republish…** is still there, but it is not the highlighted button, and the publish panel\nexplains the block. The page's other actions, **Preview**, **Promote…** and **Unpublish**, are in the\nrow above, and **Used in N places** is beside the path. The full workflow panel, with its comment box\nand **Cancel run**, is in **Configuration**.\n\nIf you have **unsaved changes**, the strip says so and offers **Save changes**. Publishing and\npromoting use the *saved* page, so pressing **Publish…** or **Promote…** with unsaved changes asks\nfirst, naming each change. Choose **Save and publish** to save and then publish, **Publish the saved\nversion** to publish without them, or **Cancel**. The Component editor asks the same question.\n\n## Live preview\n\nClick **Preview…** on any page to open live preview: your site, rendered\nright there in Composer, showing your unsaved draft — not what's actually\npublished. Nothing you do here goes live until you choose to publish it.\n\nAcross the top of live preview:\n\n- **The host.** The address of the site being previewed, with what it does\n underneath: **Click-to-edit** (the site can show pins and be clicked\n through) or **Reloads on change** (the site builds its pages on its own\n server; see below). If your site has more than one address, choose one\n here. The list is managed under **Settings › Sites**.\n- **Edit and Browse.** Hover either for what it does. **Edit** shows pins\n you can click to change content; **Browse** hides them so you can click\n through the site like a visitor.\n- **Phone, Tablet and Full** set how wide the page is. You can also drag the\n page's left or right edge to any width, with a readout and a snap to\n Phone and Tablet. The panel on the right has its own handle on its left\n edge, so you can make the page phone-sized and still keep room to edit.\n Press an arrow key on a handle to move it 10 px (50 with Shift), or\n double-click it to reset. Both widths are remembered.\n- **Language and audience** (for example *Default language · Everyone*)\n opens **Preview as a visitor**, to see the page as a visitor in another\n language or audience would, or to show referenced content in full.\n- **Open site** opens the page in its own browser tab.\n\nOn a phone-sized screen the header has three rows: the page name and status\nwith **Close**, then the host with **Pins** and **⋯** (Open site, Language and\naudience), then Edit and Browse. **Pins** opens the panel as a sheet from the\nbottom, and the width handles are not shown.\n\nPress **Esc** to close an open Quick edit form; press it again to close live\npreview.\n\nThe page renders with numbered pins over anything you can edit. Shape\ntells you what a pin is, so it reads even in black and white:\n\n- A **magenta circle** is a single field — a headline, a paragraph, a date.\n- A **solid blue rounded rectangle** is a whole Component — either the\n Presentation bound at that spot, or something rendered outside the page\n itself (see \"Also on this page\" below).\n- A **dashed blue rounded rectangle** is content produced by an Adapter —\n mapped in from somewhere else, with no field of its own on this page.\n- A **red rectangle** marks something that couldn't be resolved.\n\nEvery pinned part of the page also gets a light outline in its pin's own\ncolor the whole time you're in Edit mode, not just on hover — so you can\nsee everything on the page that's editable at a glance, before you click\nanything. Hovering or selecting a pin (from the page or from its row in\nthe panel on the right) strengthens that outline and shows a tag naming\nwhat it is.\n\nWhat clicking a pin does depends on its shape:\n\n- A **field** pin opens a small **docked editor** right at the top of the\n panel — no matter how deep inside the page's content that field actually\n lives — with its name, its type, and a magenta **Own save** badge, above\n the rest of the page summary (dimmed while you're editing). Deep inside\n something (a section, a card, a list item), the docked editor also shows\n a breadcrumb (\"Referenced by *the page* → *Section 4* *Statement* →\n `actions`\") so you know exactly where you are. What docks depends on the\n field:\n - A **Component**, **Reference**, or **Presentation** field — the kind\n that points at other content — gets a compact list: one row per item,\n with a label, where it links to (if anywhere), a drag handle to\n reorder, an edit button, a remove button, and an **Add item** row at\n the bottom. Click a row's edit button to open that item — an item\n authored right here opens its own full editor; an item that's really a\n separate, shared Component re-targets this same panel to that\n Component instead of opening a second one.\n - Every other field (Rich text, a plain text field, a date, and so on)\n gets its own usual editor, docked as a single row.\n Type, then **Save** or **Cancel** — or **Open full editor** if you'd\n rather see the whole Component or page it belongs to.\n A pin whose field can't be matched this way falls back to opening the\n whole Component or page in full, with that field already focused.\n- A **Component** pin (solid rectangle) opens that Component for editing\n in full, the same as clicking **Quick edit** next to it — a magenta\n **Own save** badge marks it while you're in it.\n- An **Adapter-mapped** pin (dashed rectangle) never opens an editor\n directly — there's no field of yours behind it. Instead it explains\n where the content comes from: which Adapter produced it, and a look at\n the actual source underneath. From there, **Edit source field** jumps\n straight to the one field that's a direct, one-to-one copy (when there\n is one), and **Edit mapping…** opens the mapping itself for a deeper\n change.\n- A **red (unresolved)** pin opens on whatever it belongs to, so you can\n see and fix why it isn't resolving.\n\nType in a docked or full editor, and the page updates within a second or\nso either way.\n\n**Browse** switches off the pins so you can click around the page the way a\nvisitor would — following links to see other pages of the same site, still\nagainst your unsaved drafts. The panel says the pins are hidden on purpose;\nswitch back to **Edit** to see them.\n\n**Also on this page** lists anything the site renders that isn't part of\nthe page itself — a shared header or footer, for instance. These are\nedited and saved the same way as anything else with a pin: click **Quick\nedit** next to it, make your change, and save. Because a shared header or\nfooter isn't part of any one page, saving it doesn't publish it along with\nthe page — after saving, use the **Publish…** button that appears right\nthere to make the change live. If a site is set up to show something\nthat doesn't exist in the environment you're working in, it's listed as\n**not in this environment** — nothing to worry about, and never something\nthat stops the rest of the page from previewing normally.\n\n### Previewing a site that renders on its server\n\nSome sites build every page on their own server and send finished pages to\nthe browser, with nothing re-drawn in the browser afterwards. Live preview\ncan't hand those sites your draft directly, so it works a little\ndifferently there.\n\nYour developer sets it up once:\n\n- Under **Settings › Sites**, open the site and set its host's **Live\n preview** to **Server**.\n- Under **API Keys**, the site's key needs **Allow draft preview** turned\n on. Only a server-side key can have it.\n\nAfter that, live preview on that host behaves like this:\n\n- Composer starts a private preview session for you. Your draft, unsaved\n edits included, goes to that session, and the site's server reads it from\n there.\n- Each time you pause typing, the page reloads with your latest edits. That\n takes a moment longer than on other sites.\n- **Pins work if the site adds one script.** Out of the box a\n server-rendered site has nothing running in the browser to draw pins.\n Where Edit and Browse would be, live preview shows **Reloads on change**,\n and the panel says pins aren't available on this site — use it to edit\n the page and the Component it shows.\n If your developer adds ebitex's preview script to the site (a single\n `<script>` tag, and marks which part of the page shows which field), you\n get the same numbered pins and click-to-edit as any other site. Nothing\n changes for visitors: the script does nothing unless Composer is framing\n the page. Ask them for \"the ebitex preview script\" and point them at\n developers.ebitex.io.\n- Only the page you're previewing shows your draft. Follow a link and the\n other page shows what's published — and if the site runs the script,\n Composer follows you there and starts previewing that page instead.\n- If the preview says **The site is showing its published page, not your\n draft**, what you're looking at isn't your draft. Usually the site isn't\n set up for server previews yet, its key doesn't allow draft preview, or\n your browser blocked the site's cookie inside Composer. **Open the site in\n a new tab** gets around that last one. **Copy details for your developer**\n puts what they need on your clipboard, and **Technical details** shows it\n on screen.\n- Closing live preview ends the session straight away. Nobody can use it\n afterwards.\n\n### If the preview can't reach the site\n\nIf the site isn't answering, a message appears above the page: **The site\nisn't answering at *address***. It may not be running, or it may not be set\nup for preview yet. **Try again** checks again, **Open the site in a new tab**\nshows you what the site itself does, and **Copy details for your developer**\nputs the likely causes on your clipboard to send on. The same causes are\nunder **Technical details**.\n\n## Opening a page from the site itself\n\nWhen you're signed in to Content and browsing one of your own published sites, a small **Click to\nedit** button appears in the corner of the page. It takes you straight to that page in Composer, with\nlive preview already open.\n\nIf the page belongs to a **different organization** than the one you're currently working in, Content\nswitches for you and shows a notice saying so, with a **Switch back** button. That switch applies to\nyour whole ebitex session — Hub and Forms in other tabs will show the new organization the next time\nyou navigate in them — so the notice stays until you dismiss it.\n\nA few cases where the link won't open a page, and what each means:\n\n- **\"This page no longer exists, or belongs to an organization you are not currently signed in to.\"**\n Either the page was deleted, or it belongs to an organization you're not a member of. If a\n colleague sent you the link, ask them to add you to that organization.\n- **Nothing switches and the page doesn't load.** The site's hostname isn't mapped to a site in any\n organization you belong to. Check **Settings > Delivery** for that organization's host mappings.\n- **Two organizations claim the same hostname.** Content won't guess which one you meant. Fix the\n duplicate mapping in **Settings > Delivery**, then follow the link again.\n\n## Restricting what can go where\n\nTwo governance controls apply to a branch of the tree, the same way they\napply to Component folders (see \"Folders and access rules\" in\n[Authoring Components](components.md)) — both live in the **Configuration**\ntab's **Advanced** section:\n\n- **Who can work on this branch** (access rules) grants specific roles view/edit/delete/publish on a\n branch — no rules anywhere on the branch means it's open to everyone; a\n rule anywhere on a root even restricts an entire site. A role needs view\n to see a branch at all; edit, delete, and publish are each independent\n beyond that.\n- **Templates pages here can use** restricts which Templates a Presentation payload\n can use anywhere at or beneath a page — useful for keeping, say, a\n campaigns section limited to a handful of approved layouts. Leaving it\n empty allows any Template. Tightening this later never breaks a payload\n already in place; it's only checked when a payload is assigned or\n changed.\n\nBoth panels are only editable by someone with elevated access-management\npermission; everyone else sees a read-only summary of what they\npersonally can do on that branch.\n"
34
+ "body": "# Building your site in Composer\n\nComposer is where content becomes a website. A **site** is a named tree of\n**pages**; each page's slug (and its ancestors' slugs) form its **path** —\nthe URL it will eventually be served at. A page can be pure structure (a\n**Folder**, with no page of its own, just a place to organize its\nchildren), or it can carry a payload: either a **Presentation** (content\nshown at that path) or a **Redirect** (send visitors somewhere else).\nContracts, Components, and Templates (see\n[Modeling content with Contracts](contracts.md),\n[Authoring Components](components.md), and\n[Presenting content with Templates](templates.md)) define *what* content\nis and *how* it's presented; Composer decides *where* it lives. Nothing\nbuilt here is publicly visible yet — publishing is a later phase.\n\nComposer is the suite's *top-down* authoring surface — site, then tree,\nthen page. [Content](content-authoring.md) is its *bottom-up* counterpart:\nthe Component library, edited independently of any one page. Both appear\nas their own item in the sidebar.\n\n## Choosing a site\n\nComposer's header has a site switcher — select it to see every site in\nthis organization and pick one, or select **Manage sites →** to create,\nrename, or delete a site. Composer's tree always shows exactly one site's\npages at a time; switching sites swaps the whole tree beneath it.\n\nSites themselves are managed from **Settings > Sites**: create a new one\nby name, rename an existing one, or delete one (deleting a site deletes\nits entire page tree, including every page's payload — typing the site's\nname confirms you mean it).\n\n## Building the tree\n\nA large tree can be searched by category — see \"Filtering by category\" in\n[Taxonomy](content-taxonomy.md) for how the tree's own **Filter by\ncategory** control auto-expands to reveal matches without hiding anything\nelse.\n\nTo add a page:\n\n1. Select the parent page (the site's own root, shown at the top of the\n tree, or any page under it), then select **+ Add page** at the top of\n the tree panel.\n2. Pick a type — **Presentation**, **Redirect**, or **Folder** —\n Presentation is pre-selected, since it's what most new pages are for.\n You can change a page's type at any time later, from its own\n Experience tab.\n3. Enter a **Name** — the path preview beneath it fills in from it\n automatically (`/campaigns-launch`, for example). You can give the page\n a different slug later, from its **Configuration** tab.\n4. Select **Create**.\n\nEvery page shows its computed **path** at the top of the detail panel —\nthe site root's own path is always `/`.\n\n### Localized slugs\n\nA page's slug can have a different value per locale, just like other\nlocalizable content — select the translate icon beside **Slug** (in the\n**Configuration** tab) to add per-locale overrides. Two sibling pages can\nnever resolve to the same slug in the same locale, whether that's their\nshared default or one sibling's override colliding with another's\ndefault; you'll see exactly which locale and which sibling conflicts if\nthat happens.\n\n### Moving and reordering pages\n\nThe tree supports two different drags, depending on where you drop:\n\n- Drop a page **onto** another page to reparent it there — the dropped\n page becomes that page's child.\n- Drop a page **between** two sibling rows to reorder it among its\n current siblings, without changing its parent.\n\nEither kind of drag can also be done without a mouse: select **Move…** in\na page's **Configuration** tab and pick a target the same way dragging\nwould. You can't move a page into itself or one of its own descendants,\nand a site's root can't be moved or reordered at all — it has no grip\nhandle to drag by, and its Configuration tab shows no **Move…** button.\n\nIf someone else changes the tree while you're mid-drag, Composer notices,\nrefreshes the sibling list automatically, and asks you to try again rather\nthan silently applying a stale order.\n\nDeleting a page requires it to have no children first; a page that's the\ntarget of a **Redirect** elsewhere in the tree can't be deleted until that\nredirect is removed or repointed. A site's root can't be deleted from\nComposer at all — that's a **Settings > Sites** action, since it deletes\nthe whole tree beneath it.\n\n## The Experience tab\n\nA page's **Experience** tab opens with one question: **What does `/path` do?** The three\nanswers are the page's type, and exactly one is true of an address at a time:\n\n- **Presentation** shows a page built from a Template and a Component.\n- **Redirect** sends visitors to another page.\n- **Folder** only groups the pages beneath it, and has no content of its own.\n\nWhat sits below the question is only the chosen type's settings. Choosing a different type is an\nedit like any other: it shows in the save bar, and nothing changes until you save. Use the arrow\nkeys to move between the three.\n\nFor a **Presentation** page, the card below the question shows how the page is built, as pieces\nthat fit together from top to bottom:\n\n- **Template, sets the shape.** The layout. It decides the shape of content the page needs: a\n Contract, which is a list of fields. It shows the shape it **needs**.\n- **Adapter, reshapes to fit.** Only there when the Component's shape is not the one the Template\n needs. It shows the shape it **takes** and the shape it **gives**. See\n [Adapters](content-adapters.md) if that's new to you.\n- **Component, fills the shape.** The content itself: its text, images and fields. It shows the\n shape it **is**.\n\nBetween each pair is a joint. A tick means the shapes fit. A red mark means they do not, and a row\nbeneath offers **Add an Adapter…** to bridge them. Each piece keeps its own actions: **Change** on\nthe Template and on the Component, **Configure** where there are settings or contextual values to\nfill in, **Mapping** on an Adapter, and **Quick edit** on the Component. See\n[Presenting content with Templates](templates.md) for the **Contextual values** and **Settings**\npanels. If the Template declares a settings field that's both mandatory and Contextual, it must be\nfilled in here: a page is the last stop for that value, so there's nowhere further downstream to\ninherit it from. **Quick edit** opens the\n bound Component itself in a layer over the tree — and the same layer\n opens *this* page from any Link or Experience-reference field elsewhere\n that points at it; see\n [Editing something from where it's used](content-authoring.md#editing-something-from-where-its-used).\n\nSwitching a page's type here always lands you on that type's own normal\nstarting point (no Template chosen yet, no redirect target chosen yet) —\nit never carries over or invents a binding from whatever the page was\nbefore.\n\nFor a **Redirect** page, select **Pick a target page…** and browse to it.\nA page can't redirect to itself. A **Folder** page has no payload of its\nown — it exists only to organize the pages beneath it.\n\n## Version history for a page\n\nChoose **Version history…** from **More actions** to see every saved version of\nthe selected page: who changed it, when, and what changed (its name, address,\nand content). Page history is read-only: it shows you what the page used to\nsay, but restoring an earlier version isn't available yet. See\n[Version history](components.md#version-history) for how history works for\nComponents.\n\n## The Configuration tab\n\nEverything about a page other than what it renders lives in **Configuration**. The settings most\npeople use stay in view: the page's **Name** and **Made for** (below), its **Slug**, its **Location**\nin the tree (parent, Move…), and its **Categories**. Everything else is folded into **Advanced**, a single row that\nsays how those settings are set while it is closed, for example *Access: no rules · Templates: any ·\nReview: none · Search engines: listed*. Open it for:\n\n- **Who can work on this branch**: access rules.\n- **Templates pages here can use**: which Templates new pages here may use.\n- **Review before publishing**: the editorial workflow assigned to this page.\n- **Search engines**: whether the page is listed in your sitemap.\n\n**Delete this page**, for a non-root page, stays separate at the bottom and asks you to confirm\nfirst.\n\n### Made for\n\nUnder **Name**, **Made for** notes which channels the page is built for: **Email**, **Web**, or\nboth. It is optional and only advises. It never stops you saving or publishing, and a page with no\nnote is simply \"unknown\", which warns about nothing.\n\nWhen a page is made for a channel, the **Experience** tab warns you about any Component it uses that\nsays it is not (for example a page made for email that uses a Component marked **Web** only). The\nwarning lists those Components, and it also covers Components used inside other Components. It follows\nthe note as you change it, before you save. A Component with no note never triggers it.\n\nOther apps read the note too. Audience's template picker shows each page as **Made for email**, **Made\nfor web only** or **No channel noted**, and still lets you choose a web-only page after a warning.\n\nA page has one **Save** bar along the bottom, whichever tab is open. It counts\neverything you have changed on the page (name, slug, search visibility, page\ntype and what it shows) and lists each change when you select the count.\n**Save** writes them all; **Discard** puts them back. If part of a save is\nrefused, for example a slug a sibling page already uses, the bar keeps listing\nwhat is still unsaved and says why. If you select another page while this one\nhas unsaved edits, Composer asks\nbefore it drops them.\n\nUnder the page's name, one **status strip** says whether the page can be published. It reads\n**Draft**, **Published** or **Modified since it was published**, with a line about what the live site\nshows, and it holds **Publish…** or **Republish…**. If the page has an editorial workflow, the strip\nshows the workflow's state and its next step (for example **Approve**) beside it, so you can move it\non without leaving the tab. While the state does not allow publishing it reads **Can't be published\nyet**; **Republish…** is still there, but it is not the highlighted button, and the publish panel\nexplains the block. The page's other actions, **Preview**, **Promote…** and **Unpublish**, are in the\nrow above, and **Used in N places** is beside the path. The full workflow panel, with its comment box\nand **Cancel run**, is in **Configuration**.\n\nIf you have **unsaved changes**, the strip says so and offers **Save changes**. Publishing and\npromoting use the *saved* page, so pressing **Publish…** or **Promote…** with unsaved changes asks\nfirst, naming each change. Choose **Save and publish** to save and then publish, **Publish the saved\nversion** to publish without them, or **Cancel**. The Component editor asks the same question.\n\n## Live preview\n\nClick **Preview…** on any page to open live preview: your site, rendered\nright there in Composer, showing your unsaved draft — not what's actually\npublished. Nothing you do here goes live until you choose to publish it.\n\nAcross the top of live preview:\n\n- **The host.** The address of the site being previewed, with what it does\n underneath: **Click-to-edit** (the site can show pins and be clicked\n through) or **Reloads on change** (the site builds its pages on its own\n server; see below). If your site has more than one address, choose one\n here. The list is managed under **Settings › Sites**.\n- **Edit and Browse.** Hover either for what it does. **Edit** shows pins\n you can click to change content; **Browse** hides them so you can click\n through the site like a visitor.\n- **Phone, Tablet and Full** set how wide the page is. You can also drag the\n page's left or right edge to any width, with a readout and a snap to\n Phone and Tablet. The panel on the right has its own handle on its left\n edge, so you can make the page phone-sized and still keep room to edit.\n Press an arrow key on a handle to move it 10 px (50 with Shift), or\n double-click it to reset. Both widths are remembered.\n- **Language and audience** (for example *Default language · Everyone*)\n opens **Preview as a visitor**, to see the page as a visitor in another\n language or audience would, or to show referenced content in full.\n- **Open site** opens the page in its own browser tab.\n\nOn a phone-sized screen the header has three rows: the page name and status\nwith **Close**, then the host with **Pins** and **⋯** (Open site, Language and\naudience), then Edit and Browse. **Pins** opens the panel as a sheet from the\nbottom, and the width handles are not shown.\n\nPress **Esc** to close an open Quick edit form; press it again to close live\npreview.\n\nThe page renders with numbered pins over anything you can edit. Shape\ntells you what a pin is, so it reads even in black and white:\n\n- A **magenta circle** is a single field — a headline, a paragraph, a date.\n- A **solid blue rounded rectangle** is a whole Component — either the\n Presentation bound at that spot, or something rendered outside the page\n itself (see \"Also on this page\" below).\n- A **dashed blue rounded rectangle** is content produced by an Adapter —\n mapped in from somewhere else, with no field of its own on this page.\n- A **red rectangle** marks something that couldn't be resolved.\n\nEvery pinned part of the page also gets a light outline in its pin's own\ncolor the whole time you're in Edit mode, not just on hover — so you can\nsee everything on the page that's editable at a glance, before you click\nanything. Hovering or selecting a pin (from the page or from its row in\nthe panel on the right) strengthens that outline and shows a tag naming\nwhat it is.\n\nWhat clicking a pin does depends on its shape:\n\n- A **field** pin opens a small **docked editor** right at the top of the\n panel — no matter how deep inside the page's content that field actually\n lives — with its name, its type, and a magenta **Own save** badge, above\n the rest of the page summary (dimmed while you're editing). Deep inside\n something (a section, a card, a list item), the docked editor also shows\n a breadcrumb (\"Referenced by *the page* → *Section 4* *Statement* →\n `actions`\") so you know exactly where you are. What docks depends on the\n field:\n - A **Component**, **Reference**, or **Presentation** field — the kind\n that points at other content — gets a compact list: one row per item,\n with a label, where it links to (if anywhere), a drag handle to\n reorder, an edit button, a remove button, and an **Add item** row at\n the bottom. Click a row's edit button to open that item — an item\n authored right here opens its own full editor; an item that's really a\n separate, shared Component re-targets this same panel to that\n Component instead of opening a second one.\n - Every other field (Rich text, a plain text field, a date, and so on)\n gets its own usual editor, docked as a single row.\n Type, then **Save** or **Cancel** — or **Open full editor** if you'd\n rather see the whole Component or page it belongs to.\n A pin whose field can't be matched this way falls back to opening the\n whole Component or page in full, with that field already focused.\n- A **Component** pin (solid rectangle) opens that Component for editing\n in full, the same as clicking **Quick edit** next to it — a magenta\n **Own save** badge marks it while you're in it.\n- An **Adapter-mapped** pin (dashed rectangle) never opens an editor\n directly — there's no field of yours behind it. Instead it explains\n where the content comes from: which Adapter produced it, and a look at\n the actual source underneath. From there, **Edit source field** jumps\n straight to the one field that's a direct, one-to-one copy (when there\n is one), and **Edit mapping…** opens the mapping itself for a deeper\n change.\n- A **red (unresolved)** pin opens on whatever it belongs to, so you can\n see and fix why it isn't resolving.\n\nType in a docked or full editor, and the page updates within a second or\nso either way.\n\n**Browse** switches off the pins so you can click around the page the way a\nvisitor would — following links to see other pages of the same site, still\nagainst your unsaved drafts. The panel says the pins are hidden on purpose;\nswitch back to **Edit** to see them.\n\n**Also on this page** lists anything the site renders that isn't part of\nthe page itself — a shared header or footer, for instance. These are\nedited and saved the same way as anything else with a pin: click **Quick\nedit** next to it, make your change, and save. Because a shared header or\nfooter isn't part of any one page, saving it doesn't publish it along with\nthe page — after saving, use the **Publish…** button that appears right\nthere to make the change live. If a site is set up to show something\nthat doesn't exist in the environment you're working in, it's listed as\n**not in this environment** — nothing to worry about, and never something\nthat stops the rest of the page from previewing normally.\n\n### Previewing a site that renders on its server\n\nSome sites build every page on their own server and send finished pages to\nthe browser, with nothing re-drawn in the browser afterwards. Live preview\ncan't hand those sites your draft directly, so it works a little\ndifferently there.\n\nYour developer sets it up once:\n\n- Under **Settings › Sites**, open the site and set its host's **Live\n preview** to **Server**.\n- Under **API Keys**, the site's key needs **Allow draft preview** turned\n on. Only a server-side key can have it.\n\nAfter that, live preview on that host behaves like this:\n\n- Composer starts a private preview session for you. Your draft, unsaved\n edits included, goes to that session, and the site's server reads it from\n there.\n- Each time you pause typing, the page reloads with your latest edits. That\n takes a moment longer than on other sites.\n- **Pins work if the site adds one script.** Out of the box a\n server-rendered site has nothing running in the browser to draw pins.\n Where Edit and Browse would be, live preview shows **Reloads on change**,\n and the panel says pins aren't available on this site — use it to edit\n the page and the Component it shows.\n If your developer adds ebitex's preview script to the site (a single\n `<script>` tag, and marks which part of the page shows which field), you\n get the same numbered pins and click-to-edit as any other site. Nothing\n changes for visitors: the script does nothing unless Composer is framing\n the page. Ask them for \"the ebitex preview script\" and point them at\n developers.ebitex.io.\n- Only the page you're previewing shows your draft. Follow a link and the\n other page shows what's published — and if the site runs the script,\n Composer follows you there and starts previewing that page instead.\n- If the preview says **The site is showing its published page, not your\n draft**, what you're looking at isn't your draft. Usually the site isn't\n set up for server previews yet, its key doesn't allow draft preview, or\n your browser blocked the site's cookie inside Composer. **Open the site in\n a new tab** gets around that last one. **Copy details for your developer**\n puts what they need on your clipboard, and **Technical details** shows it\n on screen.\n- Closing live preview ends the session straight away. Nobody can use it\n afterwards.\n\n### If the preview can't reach the site\n\nIf the site isn't answering, a message appears above the page: **The site\nisn't answering at *address***. It may not be running, or it may not be set\nup for preview yet. **Try again** checks again, **Open the site in a new tab**\nshows you what the site itself does, and **Copy details for your developer**\nputs the likely causes on your clipboard to send on. The same causes are\nunder **Technical details**.\n\n## Opening a page from the site itself\n\nWhen you're signed in to Content and browsing one of your own published sites, a small **Click to\nedit** button appears in the corner of the page. It takes you straight to that page in Composer, with\nlive preview already open.\n\nIf the page belongs to a **different organization** than the one you're currently working in, Content\nswitches for you and shows a notice saying so, with a **Switch back** button. That switch applies to\nyour whole ebitex session — Hub and Forms in other tabs will show the new organization the next time\nyou navigate in them — so the notice stays until you dismiss it.\n\nA few cases where the link won't open a page, and what each means:\n\n- **\"This page no longer exists, or belongs to an organization you are not currently signed in to.\"**\n Either the page was deleted, or it belongs to an organization you're not a member of. If a\n colleague sent you the link, ask them to add you to that organization.\n- **Nothing switches and the page doesn't load.** The site's hostname isn't mapped to a site in any\n organization you belong to. Check **Settings > Delivery** for that organization's host mappings.\n- **Two organizations claim the same hostname.** Content won't guess which one you meant. Fix the\n duplicate mapping in **Settings > Delivery**, then follow the link again.\n\n## Restricting what can go where\n\nTwo governance controls apply to a branch of the tree, the same way they\napply to Component folders (see \"Folders and access rules\" in\n[Authoring Components](components.md)) — both live in the **Configuration**\ntab's **Advanced** section:\n\n- **Who can work on this branch** (access rules) grants specific roles view/edit/delete/publish on a\n branch — no rules anywhere on the branch means it's open to everyone; a\n rule anywhere on a root even restricts an entire site. A role needs view\n to see a branch at all; edit, delete, and publish are each independent\n beyond that.\n- **Templates pages here can use** restricts which Templates a Presentation payload\n can use anywhere at or beneath a page — useful for keeping, say, a\n campaigns section limited to a handful of approved layouts. Leaving it\n empty allows any Template. Tightening this later never breaks a payload\n already in place; it's only checked when a payload is assigned or\n changed.\n\nBoth panels are only editable by someone with elevated access-management\npermission; everyone else sees a read-only summary of what they\npersonally can do on that branch.\n"
35
35
  },
36
36
  {
37
37
  "slug": "content-environments",
@@ -111,7 +111,12 @@ export const HELP_TOPICS = [
111
111
  {
112
112
  "slug": "publishing",
113
113
  "title": "Publishing content",
114
- "body": "# Publishing content\n\nEverything you build in Content — Components and Experience nodes — stays\nprivate to your organization until you **publish** it. Publishing takes a\nsnapshot of what you're looking at and copies it into a separate,\nread-optimized space that the Content Delivery API serves to the outside\nworld. Editing something after it's published never changes what's live;\nyou have to publish again. (Developers building the site that shows this\ncontent start from `docs/content-sdk.md`.)\n\n## The lifecycle\n\nEvery publishable item shows a status badge:\n\n- **Draft** — never published.\n- **Published** — a snapshot is live, and it matches your current edits.\n- **Modified since publish** — a snapshot is live, but you've made\n changes since. Visitors still see the old snapshot until you publish\n again.\n- **Unpublished** — was published once, then taken down. The item still\n exists in Content; it's just not being served anymore.\n\n## Publishing an item\n\nSelect **Publish…** on a Component or an Experience node's detail panel.\nThis opens the **publish plan** — a list of everything that needs to go\nout together: the item itself, plus anything it depends on (a node's\nbound Component, a Component's own references, and so on, however deep\nthat chain goes).\n\nOn an item that's already live, the same button reads **Republish…** and\nsits next to **Unpublish** — use it to push new snapshots without taking\nanything down first. This is also how a change *inside* the dependency\nchain goes live: editing a published node's bound Component doesn't\nchange the node's own badge, but republishing the node re-freezes the\nwhole plan, the edited Component included.\n\nFor each item in the plan you'll see:\n\n- Its current status.\n- Whether it's valid to publish as-is. An invalid item is shown with its\n error and can't be included — fix the problem first, then reopen the\n plan.\n- A warning (not a blocker) if the item doesn't validate against the\n *latest* version of its Contract or Template, even though it's fine\n against the version it's actually pinned to. It will still publish; the\n warning is a heads-up that something upstream has moved on.\n\nUncheck anything you don't want to publish yet — a skipped item simply\nisn't included this time; nothing else in the plan is affected. If your\norganization has mapped more than one delivery environment from where\nyou're authoring (see [content-environments.md](content-environments.md)),\nchoose which one to publish to — otherwise it goes to the one delivery\nenvironment mapped here, exactly as before. Select **Publish** to go live\nwith everything still checked.\n\nPublishing requires the **Publish** permission on that item's branch\n(folder for Components, node branch for Experience nodes) — a separate\npermission from **Edit**, so an organization can have editors who can't\npush content live, and publishers who review before it goes out. If you\ndon't have it, the button is disabled and explains why.\n\n### What the publish panel tells you\n\n**Publish** (or **Republish**, once it has been published) opens a panel that says where the content will go,\nfor example *Publishing from Authoring → Production*, and what will happen: how many items will go live, how many\nare already up to date, and how many need attention first.\n\n- A page or Component is published together with the Components it uses, so the live page never points at\n something that is missing. Only the ones that changed are ticked. Open **Show 1 Component this page uses**\n to see them.\n- If everything is already live and unchanged, the panel says so and nothing is ticked. Tick an item to publish\n it again anyway.\n- An item that cannot be published says why beside it, for example that it is waiting in a review step or is\n missing a required field.\n- If your organization publishes to more than one place, choose the target first. Your choice is remembered.\n\nPublishing uses the **saved** version. If you have unsaved changes when you press **Publish…**\nor **Promote…**, you are asked first, with each change listed: **Save and publish** (or **Save and\npromote**) saves them and carries on, **Publish the saved version** carries on without them, and\n**Cancel** goes back. A save that fails stops there and shows its error.\n\nThe panel stays open while it works, with a count such as *Publishing 1 of 3*, and then lists what went live.\nYou can close it at any time and the publish carries on; a message tells you when it finishes.\n\nIf something could not be published, the list names the item that stopped the run and the reason. Items after it\nwere not attempted, and items before it are already live. Fix the reason, then press **Try the failed items again**\n(or **Reload plan** when nothing went live). If you contact support, quote the reference shown under the list.\n\n## Unpublishing\n\nSelect **Unpublish** to take a live item down immediately. Its URL (if it\nhad one) stops resolving. The item itself is untouched in Content — you\ncan publish it again at any time.\n\n**Images and files are different: unpublishing doesn't take them down.**\nThe first time an image or file field is published, it gets a permanent,\npublic link — anyone who has that link can still open it even after you\nunpublish the item that used it, or after you replace the image with a\ndifferent one. This is because the file's link never changes once\npublished (so it keeps working in caches, emails, and anywhere else it was\ncopied), and there's no way to \"recall\" a link once it's been shared.\nNothing changes about who can *edit* the file or where it appears in your\nsite — only the direct link to the file itself stays reachable.\n\nIf you publish a Component or page whose image field hasn't been made\npublic yet, **publishing itself requires a one-time setup on our end** —\nif that hasn't happened yet, publishing is blocked with a message saying\nso rather than silently publishing a broken image link. Contact support if\nyou see this.\n\n## Promoting content between environments\n\nIf your organization authors in more than one environment (Staging and\nProduction, say), **Promote…** — next to **Publish…** on a Component or\nExperience node — copies it, and everything it depends on, into another\nauthoring environment, ready to be published there in turn. This is\nseparate from publishing: promoting moves draft content between authoring\nspaces; publishing takes draft content live. See\n[content-environments.md](content-environments.md) for the full picture.\n\n## Renaming or moving a published Experience node\n\nIf you change a published node's slug (or move it), republishing\nre-computes every affected path. The **old** path automatically becomes a\nredirect to the new one, so existing links and bookmarks keep working —\nyou don't have to do anything extra. You can review and remove these\nredirects from a site's own **Manage** view under **Sites** (see below).\n\n## Keeping a page out of search results\n\nSome published pages shouldn't be advertised to search engines — a search\nresults page, an internal index, a section you'd rather people reached only\nfrom a link you sent them.\n\nOpen the page in **Composer**, go to the **Configuration** tab, and use\n**Search visibility**. Turning it off (and selecting **Save**) means the page is left out of the\n**sitemap** — the list of URLs your site gives search engines. Everything\nelse stays exactly as it was: the page is still published, still live, and\nstill works for anyone who visits or links to its URL.\n\nTwo things to know:\n\n- **It applies to everything beneath it.** Excluding a section page\n excludes every page under it too, however deep. A page excluded this way\n shows you which parent is responsible, with a link to it, so you can\n change it there.\n- **It takes effect when you publish.** Toggling it marks the page as\n **Modified**, exactly like editing its content — publish the page and the\n change reaches your live site.\n\nThis isn't the same as telling search engines not to *index* a page they\nalready know about. Leaving a page out of the sitemap means you aren't\nadvertising it; a search engine that finds it another way (a link from\nsomewhere else, say) can still list it.\n\n## When search engines are told a page changed\n\nYour sitemap tells search engines when each page last changed, so they know\nwhich pages are worth re-reading. You don't configure this and there's\nnothing to keep up to date — but it's worth knowing what it reflects:\n\n- It's the date the page's **content** last changed, not the date it was\n last published. Republishing a page you haven't edited doesn't move it,\n so publishing a whole site doesn't tell search engines that everything\n changed at once.\n- Renaming a page or editing its content moves it. Reordering pages or\n moving one to a different parent doesn't — neither changes what's on the\n page.\n- Editing the content a page is built from — the Component it's bound to —\n moves it too, even if you only publish that Component. Content nested a\n further step away (a Component referenced by *that* Component) doesn't,\n so the date can occasionally be a little older than the last real change.\n That's deliberate: an early date costs nothing, while a date that's too\n recent teaches search engines to stop trusting it.\n\n## Delivery settings\n\nThe **Delivery** page (in the app navigation) is where you manage delivery\nkeys — credentials external systems use to call the Content Delivery API.\nSelect **Create key**, give it a name, and copy the value shown — it's only\ndisplayed once. If more than one delivery environment is mapped here,\nchoose which one the key reads from. Revoke a key at any time to cut off\nwhatever's using it immediately.\n\nThere are two ways to use a key, and the **Browser-safe key** switch decides\nwhich you're creating:\n\n- **Server-side** (the default) — works from anywhere, so it must stay on\n your server, in a build step, or behind an edge function. Never put one in\n a web page.\n- **Browser-safe** — only works from the **allowed origins** (the websites\n you list, pre-filled from your sites' host mappings; add\n `http://localhost:<port>` for local development) and, optionally, the\n **allowed IP ranges** you list. Because it can't be used from anywhere\n else, it's safe to include in a website's own code. Everything a delivery\n key can read is already published, so a browser-safe key never exposes\n anything a visitor to your site couldn't see.\n\nEach key shows a **Browser-safe** or **Server-side** badge, and **Manage**\nlets you change a key's restrictions later — for example to add a new\nhostname. Removing every restriction from a browser-safe key asks you to\nconfirm, since that key may already be in a shipped site.\n\nRunning the same site against several delivery environments (development,\ntest, acceptance, production)? Create one browser-safe key per environment\nand give the site the matching key per deployment — the site's code stays\nidentical. To keep a non-production environment private, restrict its key\nto your office or VPN address range; the CMS never refuses to issue a key\nfor an environment. Not sure which address your office or server shows up\nas? Open `https://api.ebitex.io/diagnostics/client-address` from it — the\n`clientAddress` it returns is the one to allow.\n\nHost mapping and redirect aliases live on the **Sites** page instead — see\nbelow.\n\n## Host mapping and redirect aliases\n\nOpen **Sites** (in the app navigation) and select **Manage** on a site to\nreach:\n\n- **Host mapping** — which hostname(s) serve this site, for systems that\n resolve content by host rather than passing a site id explicitly. Enter\n one hostname per line and select **Save hosts**.\n- **Redirect aliases** — the list of old paths automatically created by\n renaming/moving this site's published nodes (see above). Delete one if\n you no longer want that old link to redirect.\n\nIf your authoring environment publishes to more than one delivery\nenvironment, a **Delivery environment** picker appears above the host\nmapping and redirect-alias sections — each delivery environment has its\nown independent set of hostnames and aliases, so choose which one you're\nviewing or editing before making a change. With a single delivery\nenvironment mapped, the picker stays hidden and there's nothing extra to\nchoose.\n\nManaging keys uses the same permission as Hub's API Keys page; host\nmapping and aliases use the same access-management permission as branch\nrules.\n"
114
+ "body": "# Publishing content\n\nEverything you build in Content — Components and Experience nodes — stays\nprivate to your organization until you **publish** it. Publishing takes a\nsnapshot of what you're looking at and copies it into a separate,\nread-optimized space that the Content Delivery API serves to the outside\nworld. Editing something after it's published never changes what's live;\nyou have to publish again. (Developers building the site that shows this\ncontent start from [Rendering your site](rendering-your-site.md).)\n\n## The lifecycle\n\nEvery publishable item shows a status badge:\n\n- **Draft** — never published.\n- **Published** — a snapshot is live, and it matches your current edits.\n- **Modified since publish** — a snapshot is live, but you've made\n changes since. Visitors still see the old snapshot until you publish\n again.\n- **Unpublished** — was published once, then taken down. The item still\n exists in Content; it's just not being served anymore.\n\n## Publishing an item\n\nSelect **Publish…** on a Component or an Experience node's detail panel.\nThis opens the **publish plan** — a list of everything that needs to go\nout together: the item itself, plus anything it depends on (a node's\nbound Component, a Component's own references, and so on, however deep\nthat chain goes).\n\nOn an item that's already live, the same button reads **Republish…** and\nsits next to **Unpublish** — use it to push new snapshots without taking\nanything down first. This is also how a change *inside* the dependency\nchain goes live: editing a published node's bound Component doesn't\nchange the node's own badge, but republishing the node re-freezes the\nwhole plan, the edited Component included.\n\nFor each item in the plan you'll see:\n\n- Its current status.\n- Whether it's valid to publish as-is. An invalid item is shown with its\n error and can't be included — fix the problem first, then reopen the\n plan.\n- A warning (not a blocker) if the item doesn't validate against the\n *latest* version of its Contract or Template, even though it's fine\n against the version it's actually pinned to. It will still publish; the\n warning is a heads-up that something upstream has moved on.\n\nUncheck anything you don't want to publish yet — a skipped item simply\nisn't included this time; nothing else in the plan is affected. If your\norganization has mapped more than one delivery environment from where\nyou're authoring (see [content-environments.md](content-environments.md)),\nchoose which one to publish to — otherwise it goes to the one delivery\nenvironment mapped here, exactly as before. Select **Publish** to go live\nwith everything still checked.\n\nPublishing requires the **Publish** permission on that item's branch\n(folder for Components, node branch for Experience nodes) — a separate\npermission from **Edit**, so an organization can have editors who can't\npush content live, and publishers who review before it goes out. If you\ndon't have it, the button is disabled and explains why.\n\n### What the publish panel tells you\n\n**Publish** (or **Republish**, once it has been published) opens a panel that says where the content will go,\nfor example *Publishing from Authoring → Production*, and what will happen: how many items will go live, how many\nare already up to date, and how many need attention first.\n\n- A page or Component is published together with the Components it uses, so the live page never points at\n something that is missing. Only the ones that changed are ticked. Open **Show 1 Component this page uses**\n to see them.\n- If everything is already live and unchanged, the panel says so and nothing is ticked. Tick an item to publish\n it again anyway.\n- An item that cannot be published says why beside it, for example that it is waiting in a review step or is\n missing a required field.\n- If your organization publishes to more than one place, choose the target first. Your choice is remembered.\n\nPublishing uses the **saved** version. If you have unsaved changes when you press **Publish…**\nor **Promote…**, you are asked first, with each change listed: **Save and publish** (or **Save and\npromote**) saves them and carries on, **Publish the saved version** carries on without them, and\n**Cancel** goes back. A save that fails stops there and shows its error.\n\nThe panel stays open while it works, with a count such as *Publishing 1 of 3*, and then lists what went live.\nYou can close it at any time and the publish carries on; a message tells you when it finishes.\n\nIf something could not be published, the list names the item that stopped the run and the reason. Items after it\nwere not attempted, and items before it are already live. Fix the reason, then press **Try the failed items again**\n(or **Reload plan** when nothing went live). If you contact support, quote the reference shown under the list.\n\n## Unpublishing\n\nSelect **Unpublish** to take a live item down immediately. Its URL (if it\nhad one) stops resolving. The item itself is untouched in Content — you\ncan publish it again at any time.\n\n**Images and files are different: unpublishing doesn't take them down.**\nThe first time an image or file field is published, it gets a permanent,\npublic link — anyone who has that link can still open it even after you\nunpublish the item that used it, or after you replace the image with a\ndifferent one. This is because the file's link never changes once\npublished (so it keeps working in caches, emails, and anywhere else it was\ncopied), and there's no way to \"recall\" a link once it's been shared.\nNothing changes about who can *edit* the file or where it appears in your\nsite — only the direct link to the file itself stays reachable.\n\nIf you publish a Component or page whose image field hasn't been made\npublic yet, **publishing itself requires a one-time setup on our end** —\nif that hasn't happened yet, publishing is blocked with a message saying\nso rather than silently publishing a broken image link. Contact support if\nyou see this.\n\n## Promoting content between environments\n\nIf your organization authors in more than one environment (Staging and\nProduction, say), **Promote…** — next to **Publish…** on a Component or\nExperience node — copies it, and everything it depends on, into another\nauthoring environment, ready to be published there in turn. This is\nseparate from publishing: promoting moves draft content between authoring\nspaces; publishing takes draft content live. See\n[content-environments.md](content-environments.md) for the full picture.\n\n## Renaming or moving a published Experience node\n\nIf you change a published node's slug (or move it), republishing\nre-computes every affected path. The **old** path automatically becomes a\nredirect to the new one, so existing links and bookmarks keep working —\nyou don't have to do anything extra. You can review and remove these\nredirects from a site's own **Manage** view under **Sites** (see below).\n\n## Keeping a page out of search results\n\nSome published pages shouldn't be advertised to search engines — a search\nresults page, an internal index, a section you'd rather people reached only\nfrom a link you sent them.\n\nOpen the page in **Composer**, go to the **Configuration** tab, and use\n**Search visibility**. Turning it off (and selecting **Save**) means the page is left out of the\n**sitemap** — the list of URLs your site gives search engines. Everything\nelse stays exactly as it was: the page is still published, still live, and\nstill works for anyone who visits or links to its URL.\n\nTwo things to know:\n\n- **It applies to everything beneath it.** Excluding a section page\n excludes every page under it too, however deep. A page excluded this way\n shows you which parent is responsible, with a link to it, so you can\n change it there.\n- **It takes effect when you publish.** Toggling it marks the page as\n **Modified**, exactly like editing its content — publish the page and the\n change reaches your live site.\n\nThis isn't the same as telling search engines not to *index* a page they\nalready know about. Leaving a page out of the sitemap means you aren't\nadvertising it; a search engine that finds it another way (a link from\nsomewhere else, say) can still list it.\n\n## When search engines are told a page changed\n\nYour sitemap tells search engines when each page last changed, so they know\nwhich pages are worth re-reading. You don't configure this and there's\nnothing to keep up to date — but it's worth knowing what it reflects:\n\n- It's the date the page's **content** last changed, not the date it was\n last published. Republishing a page you haven't edited doesn't move it,\n so publishing a whole site doesn't tell search engines that everything\n changed at once.\n- Renaming a page or editing its content moves it. Reordering pages or\n moving one to a different parent doesn't — neither changes what's on the\n page.\n- Editing the content a page is built from — the Component it's bound to —\n moves it too, even if you only publish that Component. Content nested a\n further step away (a Component referenced by *that* Component) doesn't,\n so the date can occasionally be a little older than the last real change.\n That's deliberate: an early date costs nothing, while a date that's too\n recent teaches search engines to stop trusting it.\n\n## Delivery settings\n\nThe **Delivery** page (in the app navigation) is where you manage delivery\nkeys — credentials external systems use to call the Content Delivery API.\nSelect **Create key**, give it a name, and copy the value shown — it's only\ndisplayed once. If more than one delivery environment is mapped here,\nchoose which one the key reads from. Revoke a key at any time to cut off\nwhatever's using it immediately.\n\nThere are two ways to use a key, and the **Browser-safe key** switch decides\nwhich you're creating:\n\n- **Server-side** (the default) — works from anywhere, so it must stay on\n your server, in a build step, or behind an edge function. Never put one in\n a web page.\n- **Browser-safe** — only works from the **allowed origins** (the websites\n you list, pre-filled from your sites' host mappings; add\n `http://localhost:<port>` for local development) and, optionally, the\n **allowed IP ranges** you list. Because it can't be used from anywhere\n else, it's safe to include in a website's own code. Everything a delivery\n key can read is already published, so a browser-safe key never exposes\n anything a visitor to your site couldn't see.\n\nEach key shows a **Browser-safe** or **Server-side** badge, and **Manage**\nlets you change a key's restrictions later — for example to add a new\nhostname. Removing every restriction from a browser-safe key asks you to\nconfirm, since that key may already be in a shipped site.\n\nRunning the same site against several delivery environments (development,\ntest, acceptance, production)? Create one browser-safe key per environment\nand give the site the matching key per deployment — the site's code stays\nidentical. To keep a non-production environment private, restrict its key\nto your office or VPN address range; the CMS never refuses to issue a key\nfor an environment. Not sure which address your office or server shows up\nas? Open `https://api.ebitex.io/diagnostics/client-address` from it — the\n`clientAddress` it returns is the one to allow.\n\nHost mapping and redirect aliases live on the **Sites** page instead — see\nbelow.\n\n## Host mapping and redirect aliases\n\nOpen **Sites** (in the app navigation) and select **Manage** on a site to\nreach:\n\n- **Host mapping** — which hostname(s) serve this site, for systems that\n resolve content by host rather than passing a site id explicitly. Enter\n one hostname per line and select **Save hosts**.\n- **Redirect aliases** — the list of old paths automatically created by\n renaming/moving this site's published nodes (see above). Delete one if\n you no longer want that old link to redirect.\n\nIf your authoring environment publishes to more than one delivery\nenvironment, a **Delivery environment** picker appears above the host\nmapping and redirect-alias sections — each delivery environment has its\nown independent set of hostnames and aliases, so choose which one you're\nviewing or editing before making a change. With a single delivery\nenvironment mapped, the picker stays hidden and there's nothing extra to\nchoose.\n\nManaging keys uses the same permission as Hub's API Keys page; host\nmapping and aliases use the same access-management permission as branch\nrules.\n"
115
+ },
116
+ {
117
+ "slug": "rendering-your-site",
118
+ "title": "Rendering your site",
119
+ "body": "# Rendering your site\n\nRead this before you write any code that fetches published content. Content is published to the\n**Content Delivery API**, and ebitex ships a client for it: **`@ebitex/content-sdk`** on npm (and\n`Ebitex.Content.Delivery` on NuGet for a .NET server). Use it unless you have a reason not to. The\nreasons are below, because a hand-written client looks easy on the day it is written and costs the\nmost later.\n\nThis page is for the person or agent building the site that shows the content. Building the content\nmodel itself is [Building a content model through the API](agent-authoring.md).\n\n## Start from the SDK\n\n```sh\nnpm install @ebitex/content-sdk\n```\n\n- **A Vite and React site** that renders in the browser: `createContentClient` and the components in\n `@ebitex/content-sdk/react`.\n- **A Next.js (or other server-rendered) site**: the same package, with the key kept on the server.\n The guide is *Render content on a server* at developers.ebitex.io.\n- **A .NET server**: `Ebitex.Content.Delivery`.\n\nGuides, the API reference and the SDK reference are all at **developers.ebitex.io**. For the exact\nshape of a request or a response, read the OpenAPI document at `https://api.ebitex.io/openapi/public.json`\nrather than inferring it from a few responses you have seen.\n\n## What you stop maintaining\n\nA site that calls the Delivery API with its own `fetch` code owns all of this, and none of it shows\nup until something breaks:\n\n- **Path resolution, components, streams and facets, media and response parsing.** The SDK has one\n method per endpoint and is updated when the API is. A client written against the responses seen on\n one day is wrong the first day the API adds a member or a mode.\n- **The sitemap.** `buildSitemapDocuments` (in `@ebitex/content-sdk/sitemap`) splits at the protocol\n limits, writes the index, and emits `hreflang` alternates when given a `localeUrl`. A hand-built\n sitemap usually has none of these, and joining URLs by string concatenation produces addresses\n like `//sitemap.xml`.\n- **Live preview and click-to-edit.** `@ebitex/content-sdk/preview` needs the annotated responses\n of a preview session. A client that parses only the fields it renders discards the annotations,\n so the editor cannot point at anything on the page. This is the feature a hand-written client\n most often loses without anyone noticing.\n- **Locale addressing.** Under the *path prefix* and *locale host* strategies every address the API\n returns already carries its language (see [Locale addressing](locale-addressing.md)). A client\n that adds its own `/${locale}` prefix doubles it (`/fr/fr/cafes`), and one that assumes a prefix\n where the site has none links its home page to a 404.\n- **Caching and invalidation.** What may be cached, for how long, under which key, and what a\n publish should purge.\n- **References that need expanding.** A delivered Presentation is usually a reference. A renderer\n that does not ask the API to resolve it renders a hollow page and nothing reports it.\n\nIf you do write your own client, treat that list as the checklist of what you are taking on.\n\n## Moving a hand-written client to the SDK\n\nYou can move in steps and keep your own renderers and parsers:\n\n1. Install the package and create a client with the same key you use now.\n2. Replace the fetch calls with the client's methods, one endpoint at a time. The responses are the\n API's own, so the code that reads them keeps working.\n3. Remove any locale prefix your code adds, if the site's locale addressing is not *invariant*.\n4. Replace the sitemap and `robots` code with `buildSitemapDocuments`.\n5. Add the preview bridge from `@ebitex/content-sdk/preview`, and have your preview route call the\n preview endpoints so the responses carry their annotations.\n6. Delete the hand-written client and its tests.\n\n## Related\n\n- [Building a content model through the API](agent-authoring.md): the model, before the site\n- [Locale addressing](locale-addressing.md): how addresses carry a language\n- [Publishing content](publishing.md): what the Delivery API serves, and when\n- [Management keys](management-keys.md) and [Deployment keys](deployment-keys.md): the two kinds of key\n"
115
120
  },
116
121
  {
117
122
  "slug": "sample-references",
@@ -1 +1 @@
1
- {"version":3,"file":"helpCorpus.generated.js","sourceRoot":"","sources":["../../src/resources/helpCorpus.generated.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"helpCorpus.generated.js","sourceRoot":"","sources":["../../src/resources/helpCorpus.generated.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAEnE,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAE3D,OAAO,EAAmC,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAG5E;;;GAGG;AAEH,eAAO,MAAM,WAAW,mBAAmB,CAAA;AAE3C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,cAAc,EAAE,MAAsB,CAAA;AAiBnD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,SAAS,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE;IAC1C,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB,GAAG,OAAO,CAAC,WAAW,CAAC,CAkCvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAuB5E"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAEnE,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAE3D,OAAO,EAAmC,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAG5E;;;GAGG;AAEH,eAAO,MAAM,WAAW,mBAAmB,CAAA;AAE3C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,cAAc,EAAE,MAAsB,CAAA;AAiBnD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,SAAS,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE;IAC1C,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB,GAAG,OAAO,CAAC,WAAW,CAAC,CAyCvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAuB5E"}
package/dist/server.js CHANGED
@@ -70,7 +70,14 @@ export async function buildServer(options) {
70
70
  // would otherwise misread as "nothing exists".
71
71
  'This key is bound to exactly one organization and one authoring environment, so every ' +
72
72
  'result is scoped to that environment: an empty list means nothing matched there, not that ' +
73
- 'nothing exists. content_whoami reports the binding, and needs no scope.',
73
+ 'nothing exists. content_whoami reports the binding, and needs no scope. ' +
74
+ // The authoring half of this server builds the model; the half that renders it is a separate
75
+ // job with its own client. An agent that was pointed here for authoring and at the REST reference
76
+ // for rendering is never told the SDK exists, and writes a Delivery client by hand.
77
+ 'Building the site that renders this content is a separate job, and it has a client: ' +
78
+ 'install @ebitex/content-sdk (npm) or Ebitex.Content.Delivery (.NET) instead of writing a ' +
79
+ 'Delivery API client by hand. Read ebitex-content://help/rendering-your-site before you write ' +
80
+ 'any code that fetches published content.',
74
81
  });
75
82
  registerTools(server, { client, session, target, serverVersion: SERVER_VERSION });
76
83
  registerResources(server, { client, session });
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ebitex/content-mcp",
3
- "version": "0.5.212",
3
+ "version": "1.0.215",
4
4
  "description": "An MCP server for ebitex Content: build and publish a content model from an AI agent.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://developers.ebitex.io/getting-started/content-as-code/",