Two audiences, not one
The samples split into two kinds of writing, and they are not interchangeable. Some are for the people using the product, and some are for the people building it. Mixing the two is the most common way documentation goes wrong: a help article stuffed with field types, or a specification that assumes the reader already knows the flow.
Help centre article, Scribe guide, user guide, onboarding plan, video tutorial. Task-based, plain language, screenshots.
Page specifications, component docs, CRM field specs. Component IDs, display logic, field types, data sources, empty states.
The SOP. How an article gets researched, reviewed, published and kept current, so quality does not depend on who is doing it.
↑ samples 01 and 07 document the same task, as an article and as a video
How to Create a Job
The clearest single example of my day-to-day output. Written to the structure a mature public help centre uses: what you need before you start, numbered steps with one action each, annotated screenshots, what happens after you save, and a troubleshooting table built from the things people actually get stuck on.
How to Create a Job
Applies to: JobPilot Desktop (Web) · Available on all plans · Requires Create Jobs permission
A job is the central record in JobPilot. Everything else (quotes, scheduling, forms, photos, materials and invoices) attaches to a job. This article walks you through creating a job from scratch, assigning it to a staff member, and sending the booking confirmation to your client.
Before you start
- A JobPilot account with the Create Jobs permission (Admin, Office Manager and Scheduler have this by default).
- At least one staff member under Settings → Staff, if you want to assign the job immediately.
- Your job categories set up. Categories drive your reporting later, so it's worth doing first.
You don't need the client's full details to create a job. You can save a job with just a site address and add the client later. That's useful when you're on a call and need to book the work in quickly.
Step 1. Create the job
- From any screen in JobPilot, click the + New button in the top navigation bar.
- Select Job from the dropdown menu.
The New Job window opens with an automatically generated job number (for example, JOB-1042). Job numbers are sequential and can't be edited.
Press N then J from the Dispatch Board to open the New Job window directly.
Step 2. Add the client and site address
- In the Client field, start typing the client's name. JobPilot searches your existing client list as you type.
- Select the matching client from the dropdown. If they don't exist yet, click + Create new client, enter their name, phone and email, then Save client.
- Check the Site address. If the work is happening somewhere else, such as a second property, a rental or a commercial site, click Change and enter the correct address.
Changing the site address on a job does not change the client's saved default address. To update that permanently, edit the client record under Clients.
Step 3. Describe the work
Enter a short job title. This is what your team sees on the Dispatch Board and in the mobile app, so keep it specific:
| Weak title | Strong title |
|---|---|
| Plumbing | Replace leaking hot water unit, garage |
| Service call | Annual split system service, 2 units |
Add the full job description. Include anything the technician needs before they arrive: access instructions, gate codes, parking notes, equipment to bring, and what the client has already been told.
Troubleshooting
| Problem | Cause | What to do |
|---|---|---|
| The + New button is missing | Your role doesn't include Create Jobs | Ask an Admin to update it under Settings → Staff → Permissions |
| A staff member isn't in Assign to | They're inactive, or on approved leave that day | Check Settings → Staff, or choose a different date |
| "Overlaps an existing booking" | The technician already has a job in that slot | Adjust the time, add a second technician, or click Book anyway |
| Confirmation never arrived | No email on the client record, or they unsubscribed | Check the Activity tab on the job for send status |
My role
This is my main output. I research the task by doing it myself in a staging account, structure the article around one task, write it in plain language, capture and annotate the screenshots, and manage the review with whoever owns the feature.
I put effort into the troubleshooting table because it is what keeps tickets down. It comes from reading actual support tickets and finding the handful of things that repeatedly go wrong, then answering them in the article.
M03_01 Client Directory
The other kind of documentation I write in Mintlify, and the closest to my previous work. A page specification describes one screen component by component: what each one does, what the user sees under each condition, what happens on each interaction, and what every field contains down to its type, validation, data source and empty state. Engineering builds from it, design checks against it, and QA tests from it.
M03_01 Client Directory
Module: CRM · Desktop and mobile web · Login required
The Client Directory page lists all client accounts held in the JobPilot workspace. It serves as the entry point for office staff to find a client, review account status, and open the Client Detail page.
This page references data from the Client content type within the CRM module, configured in the CCMS to manage client listings, sorting, and display order.
1 Dynamic Cards Carousel Mini
GLOBAL_DISPLAY_DynamicCardsCarouselMini
Global carousel reused across multiple modules (e.g. Job Directory, Site Directory). Please refer to the global component documentation for display details.
Key Function
- Links to the Client Detail page, containing the Client content type in a compact tile layout
Visual Reference
Field List
| Fields | Description |
|---|---|
client_id | Unique ID linked to the client record |
tile_image | Hero or thumbnail image of each client |
short_title | Client display name |
subtitle | Primary site address and site count |
status_tag | Account status label |
Display Logic
- The carousel shows the five most recently opened clients for the signed-in user, ordered most recent first.
- The
short_titleof each Client is displayed at the bottom of each tile. The text colour is determined by the ColorPickerFunction. - If the user has opened fewer than three clients, the carousel is hidden entirely rather than shown with empty slots.
- If
tile_imageis absent, the tile falls back to a generated monogram using the client's initials.
Field Specification · tile_image
| Specification Item | Details |
|---|---|
| Field Type | Image (JPG / WebP ≤ 2 MB, recommended size 500 KB) |
| Dimensions | 640 × 800 px, 4:5 portrait |
| Input Validation | Optional |
| Data Source | CCMS → Client |
| Empty State | Monogram tile generated from short_title initials |
2.2 Sort Function
GLOBAL_SELECT_SortFunction
- By default, clients are arranged in the recommended order, as defined by the Recommended Sort attribute within the content type.
- If the user has clients with overdue invoices, those clients are pushed to the top and override the default sorting logic.
- Archived clients are excluded from all sort orders and are reachable only through the filter.
Navigation configuration
{
"name": "JobPilot Product Documentation",
"navigation": {
"tabs": [
{ "tab": "Page Specifications", "groups": [
{ "group": "CRM", "pages": [
"page-specs/M03_01-client-directory",
"page-specs/M03_02-client-detail" ] } ] },
{ "tab": "Global Components", "groups": [
{ "group": "Display", "pages": [
"global-components/dynamic-cards-carousel-mini",
"global-components/show-card",
"global-components/status-tag" ] } ] },
{ "tab": "Help Centre", "groups": [ ... ] }
]
}
}
My role
I write page and module specifications covering key functions, display logic, interaction logic and field-level detail, and I maintain the global component library they reference. The structural decision that matters most is the split: a global component is documented once, and module pages describe only the data bound to it plus anything specific to that module. Without that split, the same carousel gets described eleven different ways and they drift apart.
I work from design files and directly with product and engineering to keep the specifications accurate as flows change. The change log at the end of each page records why a revision happened, which is usually a support ticket trend or a review finding.
Set Up a Recurring Job
For tasks where people need to see the screen rather than read a paragraph. Every step has one action and one capture. The rule I follow is one action per step: if a step contains the words "and then", it should be two steps.
Set Up a Recurring Job
Audience: office staff and schedulers · Last updated 6 August 2026
Step 7. Turn on recurrence
Scroll down to the Scheduling section and switch on Repeat this job.
"Repeat this job" toggle in the ON position, red arrow pointing to it.
Step 8. Set the frequency
| Field | Value for this example |
|---|---|
| Repeats | Every 3 months |
| On | The first Monday of the month |
| Starting | 1 September 2026 |
Step 11. Review the generated schedule
Click Preview schedule. JobPilot lists the next eight visit dates. Check for public holidays or shutdown periods before continuing.
Managing the series afterwards
| I want to… | Do this |
|---|---|
| Change one visit only | Open that visit → edit → Save this occurrence |
| Change all future visits | Open any visit → Actions → Edit series |
| Pause the contract | Open the series → Actions → Pause recurrence |
| End the contract early | Open the series → Actions → End series |
My role
I produce step-by-step capture guides: the screen capture, the annotation, the step writing and the cleanup. Raw capture-tool output is only a starting point. The version I publish has rewritten step text, added context and warnings, redacted data, and a section on what to do after the task is finished.
JobPilot User Guide
Long-form reference, written so people can start at any chapter and still follow it. I always include a key concepts section early. In a system like this, many support problems come from people misunderstanding how the records relate, then creating duplicate clients or using one job for a whole annual contract. Explaining the data model up front prevents a lot of those.
JobPilot is built around five record types. Understanding how they relate saves a lot of confusion later.
CLIENT ──┬── SITE (one or many addresses)
│
└── JOB ──┬── QUOTE (before the work)
├── SCHEDULE (who, when, how long)
├── ACTIVITY (photos, forms, signatures)
├── MATERIALS (parts and labour used)
└── INVOICE (after the work)
| Concept | What it means | Common mistake |
|---|---|---|
| Client | The person or business you bill | Creating a duplicate client instead of adding a second site |
| Site | A physical address where work happens | Assuming the site address is the billing address |
| Job | One unit of work at one site | Using one job for a whole annual contract |
| Job category | How work is classified for reporting | Leaving everything as "General", making reports useless |
3. The JobPilot workspace
7. In the field: the mobile app
My role
I write long-form guides that work as reference material. I plan the structure, write it, build the tables and the concept diagram, and update it across releases, including going back through every screenshot after an interface change.
Your First 14 Days
Onboarding content designed around what the customer needs to do, rather than around the feature list. The plan is built so the customer pushes one real job through the whole system by Day 3, then expands from there. Someone who has completed one full cycle understands the rest more easily than someone who has only seen a demo.
Stage 2. Run one job end to end
Days 2 to 3 · about 45 minutes · Goal: you have personally taken one job from booking to paid invoice
Use a real job, ideally a small one happening this week.
- Create a client
- Create a job for that client and schedule it
- Assign it to yourself and install the mobile app
- On the day, run it from the app: Start travel → Arrive → photos → materials → signature → Complete job
- Back at the office, raise the invoice from the job
- Send the invoice, then record the payment when it lands
The job's status reads Paid, and the photos your technician took appear on the job record.
Don't import historical jobs. It takes far longer than expected and the data is rarely used. Keep your old system in read-only mode for history and start fresh.
The matching email sequence
| Day | Subject | Job of the email |
|---|---|---|
| 0 | Welcome to JobPilot, start here | Drive to the Stage 1 checklist |
| 1 | Your first job takes 5 minutes | Drive to Stage 2 |
| 3 | You've run a job. Now bring the team | Stage 3 + Quick Start PDF |
| 8 | Ready to move your client list across? | Stage 4 + import template |
| 14 | How did your first two weeks go? | Feedback + book the 30-day check-in |
My role
I write the in-app checklists, the email sequence copy and the supporting quick-start material. I also included objection handling for when a technician resists using the mobile app, because whoever delivers onboarding needs those answers ready.
SOP-014: Publishing a Help Centre Article
The process documentation for my own function, so that quality does not depend on who is doing the work. It includes a review cycle and a logged screenshot capture date, because outdated screenshots are the thing most likely to go unnoticed.
4. Responsibilities
| Role | Responsible for |
|---|---|
| Technical Writer | Drafting, screenshots, self-review, publishing, post-publish checks |
| SME | Technical accuracy review within 3 business days |
| Documentation Lead | Style and structure approval, final publish sign-off |
| Product Support | Flagging articles that generate repeat tickets |
5.4 Screenshots and visuals
- Capture in the staging account using the standard demo dataset. Never capture real customer data.
- Use a 1440 × 900 browser window at 100% zoom, light theme.
- Crop to the relevant region. Don't paste full-screen captures.
- Annotate with the standard callout style: 2px red rectangles, red arrows, numbered circles.
- Redact any email, phone number or address not from the demo dataset.
- Write alt text describing what the reader should see, not "screenshot".
Screenshots are the fastest part of an article to go stale. Log every article's screenshot capture date so the review cycle catches outdated visuals.
6. Turnaround targets
| Article type | Target |
|---|---|
| New feature article (tied to a release) | Published on release day |
| Standard new article | 5 business days from intake |
| Update to an existing article | 2 business days |
| Urgent correction (factually wrong, live) | Same day |
My role
I write the SOPs for my own function: screenshot standards, style rules, the split between subject-matter review and editorial review, and what to do when the product changes without the documentation team being told.
"How to Create a Job": script and storyboard
The full production package for a screen-recorded tutorial. I script before recording, because unscripted screen recordings run long and are harder to caption cleanly. Below is an extract of the two-column script: what the viewer sees on the left, what they hear on the right.
| Visual | Voiceover |
|---|---|
| 1:07 · Job title field Split screen: ✗ "Plumbing" / ✓ "Replace leaking hot water unit, garage" |
Now the title. This is what your technician sees on their phone, so be specific. "Plumbing" tells them nothing. "Replace leaking hot water unit, garage" tells them what to bring. |
| 1:22 · Description field Types a multi-line description including a gate code |
In the description, put everything they need before they arrive. Access instructions. Gate codes. Where to park. Every one of those details is a phone call your office doesn't have to take. |
| 2:05 · Assign to dropdown One name shows ⚠ Callout: "already booked at this time" |
Then assign it. If someone's already booked in that slot, you'll see a warning next to their name, so you catch the clash now, not at seven the next morning. |
Chapter markers
0:00 Introduction
0:14 Opening the New Job window
0:28 Adding the client
0:47 Setting the site address
1:07 Describing the work
1:52 Scheduling and assigning
2:24 Saving and notifying the client
2:40 Recap
Accessibility checklist
- Captions human-reviewed against the script, not auto-generated
- All essential information spoken aloud, not conveyed by colour or motion alone
- On-screen text held for at least 3 seconds
- Callout text meets 4.5:1 contrast against its background
- Transcript published alongside the video in the help article
- Video is never the only path to the information. The written article covers the same steps
My role
I plan, script, record and edit screen-recorded tutorials, then handle the captions and chapter markers. I correct captions by hand instead of shipping auto-generated ones, since auto-captions tend to get product names and interface labels wrong, and those are exactly the words a new user is trying to learn.
The script also lists its own re-record triggers: any interface change to the window shown, any renamed field, any change to the save flow. That is what stops a video library quietly going out of date.
Button component
Documentation aimed at the people building with a design system rather than the people using the product. Component docs live or die on the edge cases, so most of the work is in the state matrix: every variant against every state, rendered in one frame, with hover, focus and pressed forced so nothing has to be clicked to be reviewed.
Button
The primary action trigger. Variants and sizes cover every action context, with built-in loading and icon support.
Choosing a variant
One primary action per view. If two buttons on a screen are both default, the user has no way to tell which one you want them to press.
| Variant | Use for | Example |
|---|---|---|
default | The one action you want the user to take on this view | Save job |
secondary | Supporting actions of equal weight to each other | Duplicate |
outline | Actions next to a primary, where a filled button would compete | Cancel |
ghost | Low-emphasis actions in dense areas such as tables and toolbars | Row menu |
destructive | Actions that delete data or cannot be undone | Delete client |
link | Navigation dressed as a button, inline in a sentence | Learn more |
States
The full state matrix: every variant in default, hover, focus, pressed, loading and disabled. Hover, focus and pressed are forced via the pseudo-states addon, so the matrix renders every combination at once instead of asking a reviewer to interact with each button.
| State | Treatment | Notes |
|---|---|---|
| Hover | One step darker, or a tint for ghost and outline | Pointer devices only |
| Focus | 2px ring, offset outside the button edge | Must be visible on every background |
| Pressed | 60% opacity | Applies while the pointer is down |
| Loading | 50% opacity, spinner added before the label | Label stays visible |
| Disabled | 45% opacity, pointer events removed | Not focusable |
Focus is never removed. If a design calls for no visible focus ring, the design is wrong. The ring sits outside the button boundary so it stays legible against filled, outlined and ghost backgrounds alike.
Loading
- The label stays visible and changes to the present participle:
SavebecomesSaving. Don't replace the label with a bare spinner, or the user loses the record of what they pressed. - The button width is held steady while loading, so a row of controls doesn't jump.
aria-busy="true"is set and further presses are blocked. Double submission is prevented by the component, not by the calling code.
Content guidelines
| Rule | Do | Do not |
|---|---|---|
| Lead with a verb | Create job | Job creation |
| Match the outcome exactly | Delete client | OK |
| Sentence case | Save changes | Save Changes |
| Under three words | Send invoice | Send this invoice to the client |
Accessibility
- Renders a real
<button>. UseasChildto render an anchor when the action navigates, so the correct element and keyboard behaviour are preserved. - Every icon-only button requires an
aria-label. There is no visible text to fall back on. - Disabled buttons leave the tab order. If a user needs to know why an action is unavailable, don't disable it silently. Keep it enabled and explain the block when they press it.
- Hit target is a minimum of 24 × 24px even at
xs, with padding extending the target beyond the visible bounds.
My role
I document design system components for the people who build with them: the usage rules, the do and do not list, the content guidelines for each label and text slot, and the accessibility notes, including which ARIA role or attribute applies and why.
I also write the stories. The matrix stories are the ones that earn their keep. Forcing hover, focus and pressed through the pseudo-states addon turns "does this still hold?" into something a reviewer answers at a glance, instead of by clicking through thirty buttons. It is also what makes the component safe to change later.
CRM_01 Client Record
This is the sample closest to my previous work. A module specification describing what each panel does, what the user sees under each condition, what happens on every interaction, and what each field contains down to its type, source, validation and empty state. I document sync behaviour and error states too, since those are the parts most often left undefined and then discovered late.
CRM_01 Client Record
Module: CRM · Desktop (Web), read-only on mobile · Login required
The Client Record is the single source of truth for everything JobPilot knows about a customer. Every other module reads from it: a job reads the default site address, an invoice reads the billing address and payment terms, and the mobile app reads the site notes. Changing a field here changes what field staff see on their next sync.
Access and permissions
| Role | View | Edit | Merge | Delete |
|---|---|---|---|---|
| Admin | Yes | Yes | Yes | Yes |
| Office Manager | Yes | Yes | Yes | No |
| Scheduler | Yes | Yes | No | No |
| Technician | Site details only | No | No | No |
Financial panels are hidden entirely for the Scheduler role, not disabled. A disabled control implies the user could gain access by asking, which isn't the case here.
1 Identity Header · Display logic
| Condition | Behaviour |
|---|---|
credit_hold is true | Red "On credit hold" banner pinned above the header. Job creation is blocked. |
balance_outstanding > 0 | Balance shown with the count of overdue invoices |
balance_outstanding = 0 | Balance row hidden entirely |
| Imported, not yet reviewed | Amber "Imported, unconfirmed" chip beside the title |
3 Field Specification · email
| Property | Value |
|---|---|
| Type | String, email format |
| Source | User entered or imported |
| Required | No |
| Validation | Standard email format. Duplicates allowed but flagged by Find duplicates. |
| Displayed | Identity header, and as the send target on quotes and invoices |
| Empty state | Header shows "No email on file". Send options disabled with an inline explanation. |
| Notes | The most common cause of a ticket reading "the client never got the confirmation". |
4 Sync Behaviour
Client data is read by the mobile app but never written by it. Technicians can't edit client records from the field.
| Event | Sync behaviour |
|---|---|
| Client edited in CRM | Pushed to assigned technicians on next sync, within 5 minutes on a connection |
| Technician offline at time of edit | Applied on reconnect. Job screen shows a "details updated" chip for 24 hours. |
| Site note added or changed | High priority in the sync queue, because of its safety relevance |
| Conflict between CRM and device | CRM always wins. The device holds no authoritative client state. |
The surviving record keeps its client_id. The merged record's ID is retained as an alias so old links still resolve. The merge can't be undone, so the confirmation dialog requires the user to type the surviving client's name.
Change log
| Date | Change | Reason |
|---|---|---|
| 6 Aug 2026 | Added credit_hold spec and header banner behaviour | New feature in release 3.2 |
| 22 Jul 2026 | Clarified that merge can't be undone, added type-to-confirm | Four accidental merges in one month |
| 3 Jun 2026 | Documented sync priority for site_notes | Raised in a field safety review |
My role
I write page and module specifications covering key functions, display logic, interaction logic and field-level detail. In my previous work this was the bulk of what I produced: page-by-page specs for a large consumer application, written from design files and kept accurate through repeated flow changes.
The change log at the end matters more than it looks. Recording why each revision happened, usually a support ticket trend or a review finding, is what stops the same question being re-litigated six months later.
How I work
- I do the task myself in a test environment before writing about it, rather than working only from a specification.
- One article covers one task. If a draft covers two, I split it.
- I read support tickets to find out what people actually ask, rather than guessing.
- I keep a register of what's published and when its screenshots were captured, so outdated content is caught on a schedule.
- I use dummy data for every capture. That is why this whole pack exists.