Authoring Help
A help document is one Markdown file per locale in a UUID-named folder. This page is the recipe: how to create one, what its frontmatter must say, what Markdown you may use, and how links and images work.
Create the document
php artisan ui5:doc Orders "Order states"The command generates a uuid4, creates ui5/Orders/doc/<uuid>/en.md from the stub, and prints the UUID and the path. Use --locale=de to author in another language.
Two things it does not do:
- It does not touch your module or your views. Declare the UUID yourself, through one of the two channels (Concept):
#[Help(locale: 'en', uuid: '…')]on the module for its root document, or thehelpUuidof a Customizing entry. Until one of them names it, the folder is not compiled. AContextcontrol in a view binds a document but does not declare one (Concept). - It refuses modules under
vendor/. It finds the module in the registry and writes to itsdoc/folder, wherever the module lives. For a module installed as a package, generate the UUID in a dev host or by hand and create the folder next to that module'ssrc/. Any RFC 4122 UUID is accepted.
The stub's guidance lines
The generated file opens with commented lines that show the two ways to declare the UUID and the one way to bind it, with the reminder that a binding alone compiles nothing. They are YAML comments, not content — delete them once you have declared it. (If you are on an older SDK whose stub shows a one-argument #[Help('<uuid>')]: that form does not compile, the attribute takes (locale, uuid).)
The frontmatter
---
title: Employee
description: Links a person to the organization they work for.
tags: [relationship, employee, employed by, organization, staff]
---| Key | Required | What it is used for |
|---|---|---|
title | yes | the document's name in the table of contents and in search results |
description | yes | the line under the title, in the TOC and in search results |
tags | no, defaults to [] | search terms; the viewer's index weights tags highest, above the title |
| anything else | — | ignored, silently. The stub's id: is one of those: it repeats the folder name and nothing reads it |
Two rules that follow from how the compiler reads this:
- Only the authoring locale's frontmatter is validated. A
de.mdbeside youren.mdneeds no frontmatter at all — and gets none of it into search either. - Presence is all that is checked.
description: TBDpasses. The SDK's own root document shipped that way for months; write the sentence while you are there.
Missing title or description or missing frontmatter are errors and fail the run. Unparsable YAML is worse: the parser throws and the command stops on an uncaught exception (Build Pipeline).
What Markdown you may use
CommonMark, plus exactly four extensions: YAML frontmatter, footnotes, attributes ({.class} on a block) and tables.
Deliberately not enabled: heading permalinks — the ¶ anchors would clutter a help panel — and a [TOC] placeholder. There is no GitHub flavour either: no autolinks (write the link), no strikethrough, no task lists, no syntax highlighting. A fenced code block renders as a code block; it is just not colourised.
A host that needs more rebinds MarkdownEnvironmentFactoryInterface and adds its own extensions.
Linking between documents
An internal link is a normal Markdown link whose target is the other document's UUID with a #:
See [how relationships are scoped](#23529704-2e7b-4c0e-9e4f-6f6e6a8a6c11).The compiler recognises the UUID and turns it into a viewer-internal jump, so the reader stays in the panel. Never link to a compiled path — the path is an implementation detail; the UUID is the contract.
An external link (https://…) is rewritten to open in a new tab, with rel="noopener noreferrer". You write a plain link.
Images and other assets
Assets live flat in the document's folder and are referenced relatively:
Every non-Markdown file in the folder is copied to the compiled output and served beside the document.
Two hard limits, both worth knowing before you organise a folder:
- No subdirectories. A path with a slash in it —
img/states.png— aborts the build with an exception, and it does so after validation has already passed clean. Keep the files flat. - Absolute and remote sources are left alone.
/img/x.pngandhttps://…/x.pngare passed through untouched, so they must be reachable by the browser on their own.
A second locale
Drop another file next to the first one. The filename is the locale code — de.md becomes locale de, and the compiler emits de.html beside en.html.
Consequences of that simplicity:
- There is no allowlist.
notes.mdbecomes a "locale" callednotesand is happily compiled and served. Keep the folder to locale files and assets. - The authoring locale from
#[Help]must be present, or the document is skipped with an error. - The table of contents and search are monolingual by construction: they carry the authoring locale only. A translated document is reachable by UUID, not by searching in that language.
- One module has one authoring locale for all its documents.
A real document
From the Partners app — the document behind the employed_by relationship type:
---
title: Employee
description: Links a person to the organization they work for.
tags: [relationship, employee, employed by, organization, staff]
---
# Employee
The **Employee** relationship records that a **person works for an organization**. It
is the everyday staff link between someone and the company that employs them.
## How to read it
* Forward: *the person **is employed by** the organization.*
* Reverse: *the organization **employs** the person.*Short, one job, written for the person looking at the screen — a help document is not a manual chapter.
Then compile
php artisan ui5:help --allNothing you write is visible until this has run, and a single error anywhere stops it writing at all. The next page explains what it does and what every message means.
See also
- Concept: why UUIDs, and the declaration rule that decides whether your folder compiles
- Build Pipeline: the command, its outputs, and the full diagnostics table
- Reference Catalogs: a catalog row's
helpUuid - Help Surface: binding a document to a control in the view