* docs(sidebar): regroup Administration Guide Onboard and Scale sections Onboard (34 files) and Scale (28 files) were still flat, unrouped lists unlike their already-regrouped Configure/Manage/Integrations siblings. Apply the same manual-grouping-override pattern: - Onboard: SAML SSO, Other SSO & Identity (OAuth/OIDC/AD-LDAP), Multi-Factor & Certificate Auth, Guest Accounts & Delegated Administration, User Provisioning & Bulk Data, Migrating to Mattermost. - Scale: Capacity Planning (scale-to-N-users pages + storage sizing), High Availability & Architecture, Search Infrastructure, Observability & Monitoring, Caching — with Scaling for Enterprise kept as a standalone landing page since it's a general entry point, not a group member. Extends the existing orphan-check warning logic in buildAdminGuideSidebar to also cover Onboard/Scale, so future filesystem drift surfaces the same way it already does for Configure/Manage. Files stay flat on disk, no URLs move. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(sidebar): align Onboard/Scale subgroups with Sphinx's live nav Sphinx's actual toctree groups these files differently than the initial regroup guessed: SAML/OAuth/OIDC/AD-LDAP all live under one identity bucket (not split SAML vs "other"), guest/permissions pages sit under a plain "User management" label, and — most notably — 21 of Scale's 28 files (capacity planning, HA/architecture, search infra, caching) are navigated to from Deployment Guide -> Reference Architecture in Sphinx, not Administration Guide, even though their Sphinx URLs stay under /administration-guide/scale/. - Merge Onboard's samlSso/otherSso groups into one "SSO & Identity" group, with SAML nested as its own sub-category inside it. - Rename "Guest Accounts & Delegated Administration" to "User Management". - Physically move the 21 Scale files that Sphinx navigates to from Deployment Guide into deployment-guide/reference-architecture/scale/, and add a new `scaling` group to DEPLOYMENT_GROUPS mirroring that split. Administration Guide -> Scale keeps only the 7 monitoring/observability pages. - Rewrite the ~130 internal .mdx links that pointed at the old /administration-guide/scale/* paths for the moved files, and update the 31 matching Sphinx->Docusaurus redirect targets in active-redirects.json. Regenerated the sidebar with zero orphan warnings; all files accounted for exactly once. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(sidebar): flatten Scale's remaining Observability & Monitoring group With the 21 architecture/capacity/search files moved to Deployment Guide, Scale is down to 7 monitoring pages under one theme — wrapping them in their own "Observability & Monitoring" sub-category just adds a redundant nesting level (Scale > Observability & Monitoring > 7 files). List them flat directly under Scale instead. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(sidebar): move Calls docs to deployment-guide, dissolve Storage & Database group Calls (RTCD, offloader, Kubernetes, logging, metrics) is a deployment/ operations concern, not settings-reference material — physically move the 6 Calls docs from administration-guide/configure/ into a new deployment-guide/calls/ directory and add a matching `calls` group to DEPLOYMENT_GROUPS, slotted right after Server/Scaling. Rewrite every cross-reference across docs/ (including the two PDF book manifests) to the new /deployment-guide/calls/calls-* paths, and add/update the matching active-redirects.json entries so old URLs keep resolving. Also dissolve the "Storage & Database" group in Configure — its three pages (configuration-in-your-database, environment-variables, azure-blob-storage) become plain top-level entries instead of a single-purpose subgroup; no files move since their URLs are unchanged. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(calls,scale): fix RST-migration artifacts and stale links flagged in review Fixes still-valid review findings on the Calls/Scale content moved in this branch: - calls-metrics-monitoring.mdx: unescape HTML-entity braces in inline RTCD metric names ({/} -> {}), which is unnecessary in fenced/inline code and rendered literally; convert two legacy docs.mattermost.com absolute links to root-relative internal links, pointing the Prometheus/Grafana link at its current post-move location under deployment-guide/reference-architecture/scale/ rather than the stale administration-guide/scale/ path. - calls-rtcd-setup.mdx: convert the ICE Host Override link to a root-relative path; convert two leftover Sphinx ```{note}``` fences to the <Note> component (one of these was rendering as barely-readable plain text due to being an unrecognized code-fence language, not a proper admonition); add a <Warning> ahead of the community-maintained installation scripts link. - elasticsearch-setup.mdx: remove a stray leftover ":start-after: :nosearch:" Sphinx directive rendering as literal page text. - opensearch-setup.mdx: remove blockquote (`>`) prefixes wrapping every numbered-step code fence (another RST-migration artifact), convert a raw <div class="note"> to <Note>, and unescape HTML-entity braces/angle brackets in the YAML/JSON/Terraform examples. - deploy-rhel.mdx: fix the "RTCD setup and configuration" link to point at calls-rtcd-setup instead of the general calls-deployment-guide page. - pdf/books/deployment-guide.json: add the two Calls pages missing from the PDF spine (calls-metrics-monitoring, calls-rtcd-setup). Skipped: the raw entity-escaped `{}` in calls-rtcd-setup.mdx's <style> block is intentional (real JSX context, not a code fence/span) and the "code comment colors nearly invisible" screenshot turned out to be the same {note}-fence bug above, not a separate Prism/CSS issue -- fixed by the <Note> conversion. Two more Sphinx ```{note}``` fences exist in administration-guide/onboard/sso-saml-keycloak.mdx and sso-saml-adfs-msws2016.mdx but weren't part of the flagged findings, so left untouched. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
Phase 2 — PDF pipeline
Builds brand-aligned PDF books from the docs site using headless Chromium + a print-only stylesheet.
What's here
pdf/
├── books/ # Spine config: ordered list of URLs per book
│ └── api.json
├── scripts/
│ ├── build-page-pdf.mjs # Capture a single page → PDF (the on-demand primitive)
│ └── build-book-pdf.mjs # Concatenate a section's pages → branded book PDF
├── styles/
│ └── print.css # Brand-aligned print stylesheet (cover, headers, page numbers)
├── build/ # Output (gitignored)
└── package.json # Puppeteer
Pipeline
docs site (npm start | npm run serve)
│
│ HTTP fetches per spine entry
▼
build-book-pdf.mjs
│
├── fetches each <article> via Puppeteer page navigation
├── prepends a brand-aligned cover (denim + marigold + Mission in Motion)
├── composes static HTML, includes Google Fonts + the docs site's bundled CSS
├── overrides everything for paper via styles/print.css (only thing the print pass cares about)
▼
Puppeteer page.pdf({ format: 'A4', preferCSSPageSize: true })
│
▼
build/mattermost-api.pdf
The print stylesheet does:
@pagerules for A4 size, margins, and running headers/footersstring-set: chapter content()on h1 → fed into@top-rightfor chapter namescounter(page) " / " counter(pages)in@bottom-rightfor page numbers- Hides every site-chrome element (navbar, sidebar, footer, breadcrumbs, edit-this-page, OpenAPI right panel)
- Brand-aligned typography (Archivo Black headlines, Inter body, JetBrains Mono code)
- Page-break controls (
page-break-before: alwayson h1,page-break-inside: avoidon figures/code/tables) - Print-mode treatments for every branded MDX component (Hero flattens, Callouts get a thin denim left bar, StatStrip becomes a 4-up grid, CardGrid becomes a list)
Usage
Single-page (on-demand) PDF
# Pre-req: docs site is running on port 3000 (npm start in docs-site/)
node pdf/scripts/build-page-pdf.mjs http://localhost:3000/api pdf/build/api-overview.pdf
Suitable as the unit primitive for the eventual "Download PDF" button on every page (CF Worker calls this against the production URL).
Multi-page book
node pdf/scripts/build-book-pdf.mjs --book api
# → pdf/build/mattermost-api.pdf
Spine controlled by pdf/books/api.json — add/remove URL paths to change what's in the book. Future work auto-generates the spine from the OpenAPI tag list.
Current state
| Capability | Status |
|---|---|
| Single-page PDF capture | ✓ Working |
| Multi-page book with cover | ✓ Working |
| Brand-aligned cover (denim + marigold + Mission in Motion + version + date) | ✓ Working |
| Running header (chapter name on right) | ✓ Working |
| Running footer (page X / N) | ✓ Working |
| Page-break-before on each chapter (h1) | ✓ Working |
| Branded typography (Archivo Black headlines) | ✓ Working |
| Branded MDX components in print mode | ✓ Working |
| Coming in v1.1 / future | |
|---|---|
| Auto-generated TOC with page numbers | Needs Paged.js (target-counter) — see §below |
| Cross-reference page numbers ("see chapter X on page N") | Needs Paged.js |
| Watermarked customer PDFs (per-buyer "Provided to …") | CF Worker injecting watermark via page.evaluate before page.pdf |
| Auto-generated index | Needs Paged.js + index plugin |
| All sections, all versions (per PLAN.md §6.1) | Needs spine generators per OpenAPI / per RST tree |
Paged.js — when to add
Puppeteer's native page.pdf() covers the basic book layout (cover, headers, footers, page breaks) using just @page rules. We use that today.
Paged.js adds:
- TOC generation via
target-counter()(the printed page number a heading lands on) - "Continued on page N" bridges
- Automatic figure / table cross-references
- Better break-balancing across columns
Add Paged.js when we hit a real need for any of those — likely Phase 5 (main docs migration, where the admin guide is 100+ pages and a good TOC matters more). For now, the cover + chapter breaks + page numbers are sufficient.
To add: load pagedjs from npm or CDN, mount it via Paged.Previewer().preview(content, stylesheets, container) before calling page.pdf.
On-demand Worker (deferred)
The on-demand per-page "Download PDF" button (PLAN.md §6.2) is the same build-page-pdf.mjs primitive, hosted on a Cloudflare Worker:
User clicks "Download PDF" on /docs/11.0/admin/saml-config
▼
CF Worker /api/pdf?url=…
▼
Browser Rendering API loads the URL, applies print.css, returns PDF stream
▼
Worker streams PDF back with Content-Disposition: attachment
This is straightforward to add once production is up (Browser Rendering API needs a domain). Defer to Phase 6 (cut first release branch) or later.
Costs
Local: free. Headless Chromium runs on your machine.
Production (CF Browser Rendering API): ~$0.001–0.005 per render. At 1000 PDFs/day (per PLAN.md §6.2), ~$50–150/mo.