ZuloOne
English
Sign in
Menu

In-app help: guides, tours and field hints

Updated

The help stack has three layers because the reader is standing in three different places: a drawer explains the current screen, a tour points at live controls, and a field hint answers "what goes in this field" without opening a drawer.

← Developer wiki

The pieces and why they are separate#

Layer Source Runtime surface Why it exists
ⓘ guide wiki/guides/<key>.md The right drawer opened by InfoButton Longer explanation for the screen or tab the user is already on.
Step tour wiki/learn/steps/<scenario>.json Show me on screen in a guide drawer The same click path drives screenshots, docs images and the in-app overlay.
Field hint hint in MetaFormLayout.LayoutJson Short text under a form label Microcopy that must stay visible while the user fills the card.

The platform architecture page describes the seed path for default guide rows; keep that as the short architectural summary and use this page for the traps and operating rules: in-app guides in architecture.

ⓘ guides from wiki/guides#

A guide file starts with # <Title> and the rest is Markdown. GuideSeeder embeds the files into ZuloOne.Core as resources and seeds MetaGuide rows on startup. The key is the file stem, including encoded special characters for grid keys such as grid.dict%3ACustomer.md.

Seeding is deliberately conservative:

  • a missing key is inserted;
  • an existing row is upgraded only when it still matches a known previous default fingerprint (SHA-256(Title + "\n" + Body));
  • a user-edited row is never overwritten by a product upgrade.

Run node tools/check-guide-keys.mjs after adding or renaming a guide. It fails when a literal guideKey in frontend/src has no file, when a non-grid guide file is unused, and when the guide tree is empty. --coverage lists StandardGrid ids that still have no grid.* guide; those are coverage gaps, not build failures.

The image COPY trap#

The tenant Docker image must copy wiki/guides before publishing Core. MSBuild EmbeddedResource globs do not fail when they match nothing, so an image can ship with zero guides and no build error. The Dockerfile copies wiki/guides explicitly; keep that line with the Core publish context. Do not move guide files into frontend/public: the app reads seeded MetaGuide rows, not markdown files from the SPA bundle.

Step manifests drive screenshots and tours#

wiki/learn/steps/*.json is the single source for a documented scenario. The same manifest is read by:

  • the docshots runner, which writes wiki/img/<shot>.png for documentation;
  • frontend/scripts/sync-help-steps.mjs, which copies manifests to frontend/public/help/steps for the SPA;
  • StepTourProvider, which loads /help/steps/index.json and highlights the live target when the guide offers Show me on screen.

The tenant Dockerfile copies wiki/learn/steps into the SPA build stage and asserts that more than the generated index reached dist/help/steps. A frontend-only build context may lack wiki/; in that case sync-help-steps writes an empty index and the build has no tours by design. The tenant image is not allowed to be empty silently.

guideKeys[] is the bridge between a guide and a tour. The resolver also derives aliases from scenario and owner, but use guideKeys[] whenever the screen key cannot be derived from the page name, for example a document journal guide key (grid.journal:<documentTypeMetaId>) or a dictionary list key.

How to add a tour to a screen#

  1. Add or update the guide in wiki/guides/<key>.md.
  2. Add or update wiki/learn/steps/<scenario>.json with stable English UI labels, owner, screenshot shot.name values and guideKeys[] for the screen keys that should offer the tour.
  3. If the screen uses a custom component, render InfoButton or TabGuideButton with that guide key. Standard grids and metadata tabs already have known guide-key conventions.
  4. Run node tools/check-guide-keys.mjs and the screenshot/image gates. For the SPA asset copy, run npm --prefix frontend run sync:help-steps or a build that runs it as prebuild.

Field hints#

Field hints live in the form layout, not in the dictionary or document field metadata. A field element may override label and set hint; the renderer passes the resolved hint to the record field shell and shows it under the label. This is the right place for "required because of this process" text that belongs on one form layout, not to every use of the field.

Hints are localized with the same inline string-or-object shape as layout labels. Table-part grid columns do not read layout hints: the grid is a region slot, and its column headers come from the table-part metadata. If a line field needs help, put the explanation in the tab guide or redesign the line editor; do not expect a header-field hint to appear in the grid.

Reader feedback#

Under every ⓘ guide body the drawer asks "Was this helpful?" (GuideFeedback), and every documentation page on getzulo.com asks the same (DocsFeedback). Both post one anonymous answer — page, yes/no, optional "what were you looking for?" — to https://getzulo.com/api/cabinet/feedback. The cabinet checks the browser Origin (getzulo.com, any *.zulo.one tenant, localhost), forwards the reader's CF-Connecting-IP and passes the vote to the control plane's POST /api/portal/feedback, rate-limited per address. Operators read it on the panel's Docs feedback screen, worst pages first.

A guide is recorded as guide:<key>, a site page as its path. The vote goes from the browser, not through the tenant API: tenant containers have no route to the panel, and a stand without internet only shows "Could not send".

The page is refused unless it is a site path or a guide: key, and the comment is cut at 1000 characters — the table cannot become storage for arbitrary text.

Traps#

  • A guide key without a markdown file is a dead ⓘ button. The app can open an empty editable guide, but a shipped product should not rely on that.
  • A manifest without guideKeys[] may be invisible. Owner-derived aliases help pages, not every grid or journal key.
  • A tour is not a test replacement. If a step cannot find a target, the overlay tells the user where to navigate; it does not prove the business flow.
  • Do not duplicate guide prose in a developer page. Link to the guide key or explain the platform rule here; the user's text belongs in wiki/guides.

What's not there yet#

  • Guides are seeded as English defaults. There is no per-language guide body store yet.
  • The in-app tour highlights and navigates; it does not execute the full docshots action list for the user.
  • Table-part grid cells have no per-column hint surface.

Where next#

Was this page helpful?