Writing standards
These standards keep every page consistent regardless of who (or what) wrote it.
Page types
Every page is exactly one of five types — never mix them:
| Type | Purpose | Template |
|---|---|---|
| Concept | What something is and why it matters — no steps | templates/concept.md |
| Task | One goal, numbered steps | templates/task.md |
| Reference | Tables of settings, limits, fields | templates/reference.md |
| API endpoint | One REST endpoint: schemas, samples, errors, business rules | templates/api-endpoint.md |
| Troubleshooting | Symptom → cause → fix | templates/troubleshooting.md |
Page templates
Start every new page by copying its template from the templates/ folder at the repo root. The task template skeleton:
---
title: <Verb + object, e.g. "Invite team members">
description: <One sentence, ≤160 chars, states the outcome>
sidebar_position: <n>
---
One-paragraph intro: what you'll accomplish and when you'd want to.
## Before you begin
## Steps
## Verify
## Troubleshooting (only if needed)
## Related
KB frontmatter fields
Every template also carries three fields that map the page into the knowledge base (in-app help and the AI support assistant):
| Field | Purpose |
|---|---|
category | The KB component the page belongs to (Items, POS, Sale Invoices, …) — groups pages in the KB. |
keywords | What users actually type when searching. Include the synonyms users use, not only the product's terms — bill/invoice, label/barcode. |
audience | vendor or internal — controls whether the page is visible in the customer-facing KB. |
Pages marked audience: internal must also set draft: true in their frontmatter: drafts never ship in the public production build, while the KB export still includes them with internal visibility. A test gate (npm test) enforces the pairing.
Style rules
- Second person ("you"), imperative steps ("Select Save"), present tense.
- One action per numbered step — if a step needs "and," split it.
- Bold UI element names exactly as the product shows them: Settings.
- Keyboard keys in
<kbd>tags. - Define jargon at first use or link its concept page.
- Banned words in docs:
simply,just,easy,easily, marketing superlatives. Vale enforces these as errors (Docs.BannedWords). - Every step must be self-contained in text — never "as shown below", "click the highlighted button", or any instruction whose meaning lives only in an image. Screenshots illustrate; text carries the meaning. Guide content is also consumed without images — by the in-app help search and by an AI support assistant that reads the text alone.
:::warningbefore any destructive or irreversible action.
Map the product's navigation
The User Guide is grouped by what the reader is doing — setting up, selling, buying, closing the day — not by the app's menu tree. A newcomer does not know the menu yet, and a menu name like "Day Books" tells them nothing; a section called "Money & daily close" does. Inside that grouping every screen stays findable by its app name. The rules:
- One folder per journey section (
docs/guides/<section>/with a_category_.jsonwhoselabelis plain language — "Money & daily close"). Itsindex.mdis the landing page: one sentence on what the section is for, an In the app: line naming the app menu or menus it covers, and a table of the screens linking to their guides. - One page per screen (submenu item). The page
title(and H1) is the exact on-screen label ("Sale Invoices"); thesidebar_labelkeeps that name and appends what the screen is for after an em-dash ("Sale Invoices — GST billing") — the sidebar stays navigable by the app's own names while telling a newcomer what each entry does. The intro sentence names the path in the app ("Open it from Day Books → Day Book"). - Task pages nested under a screen (
products-stock/items/add-edit-items.md) keep the task template (Before you begin → Steps → Verify) and a plain task title; the screen page above them is the video-first one. sidebar_positionfollows the reader's order of need within a section — never the alphabet.- Every app menu is covered from day one, even before its guides exist: an overview page with a "Coming soon" marker, so each guide has a predictable home before it is written.
- Moving a page changes its URL. Add a redirect in
docusaurus.config.tsfor every published URL that moves.
API reference pages
Start from templates/api-endpoint.md and follow it exactly:
- One page per endpoint, under
docs/developers/<resource>-api/— never append endpoints to a shared page. - Section order is fixed: Overview (with role and plan
<Badge>chips) → Request → Response → Status and error codes → Business rules. - Sample request tabs use
<Tabs groupId="lang">so the reader's language choice syncs site-wide. Tab order: JSON payload first (when the endpoint has a body), then curl, Java, Python, JavaScript. - Role and plan badges sit directly under the
<ApiEndpoint>line, above Overview — "what this endpoint is" and "who may call it" belong in the same block, and a reader deciding whether an endpoint is available to them should not have to read a paragraph first. - Required parameters are marked
Yes *in the Required column. The asterisk is the scannable signal; the word carries the meaning for screen readers and for the plain-text knowledge-base export. - Response includes a
Field | Type | Descriptionschema table, with a lead-in link to the shared object definition. - Every error row carries a machine-readable code slug (
validation_failed,rate_limited,server_error, …) matching the API error format. - When you add an endpoint, update the endpoints table on the resource's index page (for example the Items API index).
Media pipeline
Screenshots
npm run capture -- --url /settings --out static/img/settings/api-keys.png --highlight "#new-key-btn"
- 1280×800 viewport at 2× scale, element highlighting built in.
- Name files
verb-object.pngunderstatic/img/<section>/. - Every image needs real alt text — describe what's shown.
- Only seeded demo data on screen. Never real customer data.
Walkthrough videos
npm run record -- --flow tools/flows/purchase-invoices.mjs \
--out static/video/purchases/purchase-invoices --poster marker:success --storage-state auth.json
-
Run as long as the operation takes. A clip shows one job from start to finish. A full create, read, update, and delete pass is legitimately several minutes, and cutting it short to hit a target length leaves out the part the viewer came for.
-
Anything long needs chapters. Give each stage a
chapter:cue in the flow and viewers jump straight to the step they want. The quality gate requires a chapter track past 90 seconds, and never caps how long a clip may run. -
Every step needs a
say:cue. Those become the caption track, which is a WCAG 2.1 §1.2.2 Level A requirement and the only searchable text a video has. -
Pin the poster to a marker.
ui.mark('success')in the flow plus--poster marker:successkeeps the poster on the right frame after a re-record, where a fixed timestamp drifts. The recorder also rejects a blank frame and picks another. -
Playwright records
.webm; ffmpeg produces the web-ready.mp4. Each recording also writes a.webpposter, a.vttcaption track, a.chapters.vttchapter track, and a.meta.jsonholding the duration, the poster's origin, and a transcript. -
Store the files under
static/video/<section>/and embed every track:<Videosrc="/video/purchases/purchase-invoices.mp4"poster="/video/purchases/purchase-invoices.webp"captions="/video/purchases/purchase-invoices.vtt"chapters="/video/purchases/purchase-invoices.chapters.vtt"/> -
Check the result with
npm run media -- --manifest tools/media/<module>.json --check-videos. It reads the committed files only, so it needs no running app.
Quality gates
Run before committing — all six must pass:
npm run lint:md # markdownlint-cli2: structure
npm run lint:prose # Vale: errors block; Microsoft-style warnings are advisory
npm run lint:js # ESLint over tools/ and tests/
npm run typecheck # components and config
npm test # tooling unit tests
npm run build # broken-link check
PDF manual
The same Markdown builds a printable manual (chapters listed in tools/pdf-manifest.json):
npm run pdf
Component notes: Figure becomes a plain image, Video becomes a link line, Mermaid diagrams are skipped in PDF output.