Writing Documentation
Everything in this portal is Markdown or MDX in src/content/docs/, partitioned by product. Writing documentation means creating a file and adding one line to the navigation config.
The shortest possible page
Section titled “The shortest possible page”Create src/content/docs/bpp/sales/credit-note.mdx:
---title: Credit Notedescription: Reverse all or part of a confirmed sales invoice.---
A credit note reverses a confirmed sales invoice, in whole or in part.
## Opening the screen
<NavPath path="Sales > Transactions > Credit Note" />
<Screenshot src="/images/bpp/sales/credit-note.svg" caption="The Credit Note screen." alt="Credit Note screen with the source invoice selected."/>
<Tip>Always raise the credit note from the source invoice rather than from scratch — the lines, rates and tax are then guaranteed to match.</Tip>No imports. Every component listed in the component library is available in any page automatically.
Then add it to the navigation in src/config/projects.ts:
{ label: 'Sales', icon: 'cart', index: 'bpp/sales', items: [ { label: 'Sales Invoice', slug: 'bpp/sales/sales-invoice' }, { label: 'Credit Note', slug: 'bpp/sales/credit-note', summary: 'Reverse all or part of a confirmed invoice.', }, ],},That one entry gives you the sidebar row, the breadcrumb trail, the prev/next pagination, the card on the section overview page, and inclusion in the search index.
Frontmatter
Section titled “Frontmatter”Only title is required. The rest is optional and mostly feeds the training metadata under the page heading.
| Field | Type | Required | Default | Description | Notes |
|---|---|---|---|---|---|
| title | String | Yes | — | The page heading and the browser tab title. | |
| description | String | No | — | Meta description and Open Graph description. Write one — it is what shows in search results. | One sentence |
| level | Enum | No | — | Beginner, Intermediate or Advanced. Shown as a chip. | |
| audience | String | No | — | Who the page is written for, e.g. Sales Executive. | |
| readingTime | String | No | — | Rough time to work through, e.g. 10 min. | |
| appliesTo | String | No | — | Which release the page was verified against. | Update this as you re-verify |
| keywords | String[] | No | — | Extra terms for the search index. | |
| sidebar | Object | No | — | Starlight sidebar overrides — order, label, badge. | |
| pagefind | Boolean | No | true | Set false to exclude the page from search. | |
| draft | Boolean | No | false | Excluded from production builds; visible in dev. |
Page frontmatter
The custom fields are declared in src/content.config.ts. Add your own there and they are available in frontmatter immediately.
The shape of a good page
Section titled “The shape of a good page”Every generated page follows the same structure, and keeping to it is what makes the manual feel authored rather than assembled.
| Step | Action | Result |
|---|---|---|
| 1 | Lead paragraph | What this is and why it matters, in two sentences |
| 2 | ## Overview | How it fits with everything else |
| 3 | ## Prerequisites | <Prerequisites> — what must already be true |
| 4 | ## Opening the screen | <NavPath> and a <Screenshot> |
| 5 | ## Procedure | <Steps> with <Step> children |
| 6 | Expected result | <ExpectedResult> — how to tell it worked |
| 7 | ## Field reference | <FieldTable> |
| 8 | ## Important notes | Callouts, strongest first |
| 9 | ## Common problems | <Accordion> of symptom and fix |
| 10 | ## Frequently asked questions | <FAQ> |
| 11 | ## Related documentation | <RelatedDocumentation> |
The standard page structure
Screenshots
Section titled “Screenshots”Images live in public/images/<product>/<section>/, mirroring the content tree, and are referenced by absolute path.
Using a real capture
Section titled “Using a real capture”Drop the file in and pass dual={false}, because a real capture has no dark twin:
<Screenshot src="/images/bpp/sales/credit-note.png" dual={false} caption="The Credit Note screen." alt="Credit Note screen with the source invoice selected and two lines being reversed."/>Using a generated mock
Section titled “Using a generated mock”The portal ships generated mock screenshots so it looks finished before anyone captures a real screen. They are produced by npm run gen:screenshots from the specs in scripts/content/specs.mjs, as light/dark SVG pairs:
'bpp/sales/credit-note': { entity: 'Credit Note', screens: [ { template: 'form', // form | list | dashboard | login | report | dialog caption: 'The Credit Note screen.', alt: 'Credit Note screen with the source invoice selected.', mock: { fields: [ { label: 'Credit Note No.', value: 'AUTO', disabled: true }, { label: 'Against Invoice', value: 'INV/2026/00881', type: 'select', required: true }, ], }, }, ],},Alt text
Section titled “Alt text”Writing alt text for a screenshot
| Aspect | Poor | Good |
|---|---|---|
| Text | "Screenshot of the Credit Note screen" | "Credit Note screen with invoice INV/2026/00881 selected and two lines being reversed" |
| Why | Says it is a screenshot — which the reader already knows | Says what is in it, so someone who cannot see it still follows the procedure |
Adding a section
Section titled “Adding a section”A section is one entry in a product’s nav array:
{ label: 'Inventory', icon: 'layers', // from src/components/ui/Icon.astro index: 'bpp/inventory', // the overview page's content id summary: 'Stock levels, movements and adjustments.', collapsed: false, items: [ { label: 'Stock Summary', slug: 'bpp/inventory/stock-summary', summary: 'Quantity on hand by product and location.' }, { label: 'Stock Adjustment', slug: 'bpp/inventory/adjustment', summary: 'Correct a discrepancy found at stock take.' }, ],},Then create the overview page at src/content/docs/bpp/inventory/index.mdx. It needs almost nothing, because <SectionIndex /> builds the card list from the config:
---title: Inventorydescription: Stock levels, movements and adjustments.---
The inventory module tracks what you hold, where it is, and how it has moved.
<SectionIndex />Or scaffold the whole section — overview page and topic pages — with:
npm run gen:contentIt writes any page in the navigation that does not have a file yet and leaves existing files alone.
Adding a product
Section titled “Adding a product”See the README section “Adding a fifth product” for the full walkthrough. In summary:
Add the product to the registry
Append one object to projects in src/config/projects.ts with its id, name, basePath, accent, version and nav.
Scaffold the content
npm run gen:content creates every page the navigation declares.
Generate the screenshots
npm run gen:screenshots creates light/dark mocks at the paths those pages reference.
Write the content
Replace the scaffolded prose with the real thing, page by page.
Local workflow
Section titled “Local workflow”npm run dev # http://localhost:4321, hot reloads on savenpm run build # production build + Pagefind search indexnpm run preview # serve the build — the only way to test searchnpm run check # TypeScript and Astro diagnosticsStyle conventions
Section titled “Style conventions”| Field | Description | Notes |
|---|---|---|
| UI labels | Bold, exactly as on screen. | Write: Click **Save** (the asterisks are the Markdown) |
| Menu paths | Use <NavPath>, not prose. | Not "go to Sales then Transactions" |
| Values and codes | Inline code. | `SO/2026/00142` |
| Keyboard | Use <KeyboardShortcut>. | Not hand-written bold |
| Voice | Second person, present tense, active. | "Click Save", not "Save should be clicked" |
| Severity | Match the callout to the consequence. | Danger is for data loss only |
| Headings | Sentence case. Never skip a level. | h2 → h3, never h2 → h4 |
House style