Documentation Authoring and Publishing
Audiences and Source Roots
| Source | Published destination | Content |
|---|---|---|
docs/handbook/ |
/handbook/ |
Staff procedures, expected results, checks and escalation |
docs/systems/ |
/systems/ |
Business rules, rationale, reports, designs and engineering |
docs/notes/ |
Not published | Research, working comments and unfinished drafts |
docs/archive/ |
Not published | Dated evidence and completed migration records |
docs/local/ |
Not published or committed | Private source evidence and captures |
docs/assets/ |
Not published | Retained attachments for repository notes |
docs/handbook/assets/ |
/handbook/assets/ |
Approved Handbook attachments |
docs/systems/assets/ |
/systems/assets/ |
Approved Systems attachments |
docs/theme/ |
Both sites, under theme/ |
Explicitly included shared logo and CSS |
The two sites share branding and Obsidian normalization through
mkdocs.shared.yml and mkdocs_hooks.py. Each has its own navigation, search
index and output directory. mkdocs.handbook.yml builds the Handbook;
mkdocs.systems.yml builds Systems.
Specify the site's configuration explicitly when building or serving it; there
is no default mkdocs.yml.
Folder-Based Navigation
Both configurations omit nav. MkDocs discovers Markdown pages from the source
folders, puts each folder's index.md first, and sorts other entries
alphanumerically by filename. A page's first heading supplies its title.
The folder tree is the navigation structure; there is no separate menu manifest
or navigation-generation hook to maintain.
The Handbook's processes/ folder contains staff procedures. Systems uses:
| Folder | Responsibility |
|---|---|
business-rules/ |
Implemented rules, their rationale and the workflow register |
design/ |
Intended models, proposals and delivery plans |
engineering/ |
Development, architecture, integrations and documentation tooling |
maintenance/ |
Reviewed migrations and administrative configuration |
reference/ |
External API and platform reference material |
reports/ |
Report interpretation, calculations and technical models |
Use descriptive kebab-case filenames without ordering numbers. Create an
index.md overview when adding a subject folder. Explain the useful reading
paths there, and link directly between related procedures, rules and technical
references. These links serve readers independently of the sidebar's order.
Links between the Handbook and Systems live in the overview and subject pages.
Adding a page requires no MkDocs configuration change.
Choose a Page's Responsibility
Staff procedures explain what to do, the expected result, what to review and when to ask the responsible process owner for help. Use the CRM labels staff see. Keep the explanation needed to act confidently on the procedure itself.
Business-rule pages own definitions, calculation rules, eligibility, exceptions and worked examples. Rationale pages explain consequential choices and tradeoffs. Do not invent historical motivation; distinguish an explanation of current behavior from an evidenced decision record.
Engineering pages own APIs, mappings, setup, commands, tests and troubleshooting. Maintenance references own reviewed migrations and administrative operations. Keep customer-specific evidence in the repository archive or private storage.
Design proposals identify intended behavior, implemented boundaries and open
decisions explicitly. Keep them in design/, separate from
current operating instructions. Working drafts remain outside the published
source roots until they are suitable for their intended audience.
The MSP documentation demonstrates the pattern:
When behavior changes, update the owning rule page and affected procedure together, then update the workflow register if its trigger, scope or references changed. Link to the detailed rule instead of maintaining a second full specification in the handbook.
Links and Attachments
Within a site, use relative Markdown links. Between sites, use published paths
such as /systems/business-rules/msp-billing/ and
/handbook/processes/msp-invoicing/. Both sites must be mounted at
those prefixes on the same host for these links to work. Repository-only
references use explicit GitHub links and require repository access.
Open the repository root as the Obsidian vault. Put new notes in docs/notes
until their destination is decided. Use three document-attachment folders:
docs/handbook/assets/for approved Handbook attachments.docs/systems/assets/for approved Systems attachments.docs/assets/for unpublished notes and drafts.
An attachment in a site source root is published with it, even if no page links
to it. Keep private evidence in docs/local/, not in the default attachment
folder. Theme resources are not document attachments.
In Obsidian's Files and links settings, set the default location for new
attachments to In the folder specified below, with docs/assets as the
attachment folder path. Keep Automatically update internal links enabled.
These local settings are ignored by Git; configure them when opening a new vault.
Obsidian does not automatically route pastes to the owning site's assets folder.
Before publishing a draft, move its approved attachments into that site's
assets/ folder using Obsidian so existing links are updated. If an attachment
is still needed by unpublished notes, update their links to the moved file too.
Wiki links and image embeds resolve within the current site's source root; use Markdown links for cross-site links. Callouts and nested list indentation are normalized during the build.
Shared branding is limited to docs/theme/peppermint-mark.svg and
docs/theme/peppermint.css. The hook includes only those two files in both
builds under theme/, without copying unrelated repository attachments.
Build and Preview
pip install -r requirements-docs.txt
python -m mkdocs build --strict --config-file mkdocs.handbook.yml
python -m mkdocs build --strict --config-file mkdocs.systems.yml
python -m http.server 8000 --bind 127.0.0.1 --directory site
Open http://127.0.0.1:8000/handbook/ or
http://127.0.0.1:8000/systems/. Rebuild after editing when using the combined
static preview. Each build cleans only its own output directory.
When replacing an older combined build, move its generated files out of site/
before building these two sites. A clean combined output contains only
handbook/ and systems/; building either site does not remove stale files at
the output root. The Docker build starts with a fresh output directory.
For live reload of one site, use
python -m mkdocs serve --config-file mkdocs.handbook.yml or
python -m mkdocs serve --config-file mkdocs.systems.yml. The other site's
links require the combined preview above.
Deployment and Access
Dockerfile.docs builds both sites with strict validation, then copies only
their generated output into Nginx. It copies only the two source roots and
shared branding into its builder. The Compose docs service uses host port 8081.
The docs Nginx redirects / to /handbook/.
Publish the middleware and documentation images with
scripts/publish-images.sh, then run the digest-based Actions release. Both sites
are validated before publishing and checked again from the selected image in CI.
The server pulls the finished image. See deployment for the
check-only run, production release and recovery commands.
The configured URLs are https://peppermint.fxbn.dev/handbook/ and
https://peppermint.fxbn.dev/systems/. The repository prepares these routes;
editing the files does not deploy them or configure authentication.
Apply staff authentication at the VPS reverse proxy for the Handbook, and the appropriate product/engineering group policy for Systems. These are separate publication and search boundaries, not access controls. Existing hosting notes describe temporary public access; verify and configure the host's access policy before publishing internal material. Actual staff costs and private source captures never belong in either source root.
Nginx redirects old maintained-page URLs to their owning site without publishing
duplicate pages. docs.redirects.conf contains only legacy URL mappings; it
does not control navigation. When moving a previously published page, update
its incoming source links and add a redirect there. The combined Python preview
serves current paths only; legacy redirects run in the Nginx container.
Notes and archives have no published redirects. Links to MSP
sections moved into maintenance need their new Systems URL: a server redirect
cannot route on a browser's fragment identifier. Update shared bookmarks to the
relevant new site paths. Historical repository links remain available through
Git history.