Help System Concept
Help in LaravelUi5 is written as Markdown, compiled at build time, and served as static HTML. Each document is identified by a UUID rather than by its path or its title — so you may rename it, move its module, or restructure your app, and every link to it keeps working.
A document is a directory named by a UUID, holding one Markdown file per locale and whatever assets it needs:
ui5/Orders/
├── src/OrdersModule.php
└── doc/
└── 8f3e6b1c-0a44-4a7e-9a1f-27e5c4b90d11/
├── en.md ← the authoring locale
├── de.md ← optional
└── states.png ← flat assets, copied as they areThe doc/ directory sits beside your module's src/, not at the namespace root — which is what makes help travel with the package: a module installed into vendor/ carries its documents along, and the host compiles them from there without any configuration. The whole of production help on pragmatiqu.io is compiled out of vendor/.
Only a declared UUID is compiled
This is the rule that decides whether your document ever reaches a reader:
A folder is compiled when something declares its UUID. Declare it, and it is compiled or the build tells you why not. Declare it nowhere, and it is skipped in silence.
There are two declaration channels:
| Channel | Declared where | Reaches the reader as |
|---|---|---|
| The module's root document | #[Help(locale, uuid)] on the module class | the module's entry in the table of contents |
| A catalog row's document | helpUuid() on a Customizing entry | the help of that row, through its synced help_uuid column. Collected only from modules that also carry #[Help] |
use LaravelUi5\Sdk\Help\Attributes\Help;
#[Help(locale: 'en', uuid: 'c55ea118-751d-483f-929f-3fc30f8195cc')]
class OrdersModule extends AbstractUi5Module { /* … */ }#[Help] goes on the module, once; a second is a build error. Its locale is the module's authoring locale: the one whose frontmatter is validated, and the only one that reaches the table of contents and the search index.
Binding is not declaring
The Context control is how a view asks for help: wrap a region in it, give it a UUID, and the region's indicator and F1 open that document (Help Surface).
<lux:Context uuid="c55ea118-751d-483f-929f-3fc30f8195cc">
<Table id="ordersTable"><!-- … --></Table>
</lux:Context>The binding declares nothing. ui5:help never reads your views, so a UUID that only a view names is not compiled, and nothing tells you so: the folder sits in doc/, the build passes, and F1 on the region answers Help is unavailable (Help Surface).
What works today, and what does not:
- A literal
uuidworks when a channel declares the same UUID — the module's root, as above, or a catalog row's document. - A bound
uuid="{help_uuid}"works the same way: the value arrives at runtime from a catalog row, and that channel is validated. - A page of its own for one region, or for one artifact — a dashboard, a dialog, a report — has no channel yet. Put what the reader needs on the module's root document and bind the region to that. Closing this gap is on the SDK's roadmap.
How F1 finds a page
F1 always answers, in one of two ways:
- the nearest
Contextaround what has focus — a region of the screen, with everyContextabove it shown as a breadcrumb; - failing that, the table of contents.
There is nothing in between. F1 outside every Context does not fall back to the module's root or to anything about the artifact on screen; it opens the table of contents. If a screen should answer F1 with its module's page, wrap the screen in a Context bound to the root's UUID.
A help indicator does the same for the one context it sits in, and search reaches every compiled document in its authoring locale.
Cross-links between documents are ordinary Markdown links whose target is the other document's UUID (Authoring).
What the UUID buys, and what it doesn't
It survives: renaming the document's title, renaming or moving the module's class, renaming the app root, restructuring your views. Nothing in the pipeline derives an identifier from a heading, a filename or a namespace.
It does not survive: moving the folder into another module's doc/ directory. A catalog row's document must live in the module that declares the row — the compiler checks that and refuses.
What help is not
- It is not access-controlled. The help routes require a signed-in user and nothing else: anyone who can log in can fetch any compiled document by its UUID. Keep customer-specific figures, credentials and internal notes out of help documents.
- It is not negotiated per user. F1 opens the locale configured installation-wide, and there is no server-side fallback from
detoen— an uncompiled locale is a 404, not a substitution. - It is not rendered at request time. Markdown never reaches the request path. If a change is not visible, the compiler has not run (Build Pipeline).
What ships with the SDK today
Partners ships a root document and six documents on its relationship types, in English. The Settings and Launchpad apps ship no help yet — F1 on them opens the table of contents. Their topics are on the SDK's roadmap; the pages here describe the mechanism, not a filled corpus.
See also
- Authoring: the recipe, frontmatter, links and assets
- Build Pipeline:
ui5:help, what it writes, and every message it can give you - Runtime: the endpoints and the storage layout
- Help Surface: F1, the viewer, and binding help in a view