Writing the documentation
The documentation is a MkDocs site with the Material theme, built from docs/ and configured in mkdocs.yml.
Preview and build
Run MkDocs through the backend project so the right plugins are installed:
DISABLE_MKDOCS_2_WARNING=true uv run --project backend --group docs mkdocs serve
Use mkdocs build --strict instead of serve to find broken links. The DISABLE_MKDOCS_2_WARNING variable only silences a banner printed by one of the plugins. The site is built and published by the docs GitHub workflow.
Layout
| Folder | Audience | Content |
|---|---|---|
getting-started/ |
People hosting Endurain | Install, reverse proxy, updates, scaling, troubleshooting |
features/ |
Users and administrators | What Endurain does and how to use it |
integrate/ |
People building on the API | Authentication, errors, supported types |
developer-guide/ |
Contributors | Module structure, ingestion, events, UX guidelines |
reference/ |
Contributors | Generated Python API reference |
Every page must be listed under nav: in mkdocs.yml. Name files with hyphens (export-import.md).
Moving or renaming a page
Published URLs are linked from outside the docs: README.md, .env.example, docker/start.sh, blog posts and other sites. When you move or rename a page:
- Add the old path to
redirect_mapsunder theredirectsplugin inmkdocs.yml. - Search the repository for the old path and update the links, including
AGENTS.md, which links to some developer-guide files.
Diagrams
Mermaid diagrams are supported. Use a fenced block with the mermaid language:
```mermaid
flowchart LR
A[Upload] --> B[Parse] --> C[Store]
```
The Mermaid library is loaded in the browser, so readers need internet access to see the rendered diagram. Keep diagrams small and say the same thing in the surrounding text.
Tables generated from the code
Some tables are filled in from the backend source when the docs are built, so they cannot drift. Put a marker on its own line where the table belongs:
| Marker | Fills in |
|---|---|
| ` | Scope |
| ----- | ----------- |
profile |
Privileges over user's own profile |
users:read |
Read privileges over users |
users:write |
Write privileges over users |
sessions:read |
Read privileges over sessions |
sessions:write |
Create/edit/delete privileges over sessions |
gears:read |
Read privileges over gears |
gears:write |
Write privileges over gears |
activities:read |
Read privileges over activities |
activities:write |
Write privileges over activities |
activities:upload |
Upload privileges over activities |
followers:read |
Read privileges over the follower/following graph |
followers:write |
Follow, unfollow, accept and remove followers |
health:read |
Read privileges over health data |
health:write |
Write privileges over health data |
health_targets:read |
Read privileges over health targets data |
health_targets:write |
Write privileges over health targets data |
notifications:read |
Read privileges over notifications |
notifications:write |
Write privileges over notifications |
server_settings:read |
Read privileges over server settings |
server_settings:write |
Write privileges over server settings |
identity_providers:read |
Read privileges over identity providers |
identity_providers:write |
Write privileges over identity providers |
| Every scope inSCOPE_DICT` |
|
| ` | Scope |
| ----- | ----------- |
activities:upload |
Upload privileges over activities |
| ` | The scopes an API key may hold |
| ` | Method |
| ------ | --- |
GET |
/profile/api_keys |
POST |
/profile/api_keys |
PATCH |
/profile/api_keys/{api_key_id}/revoke |
DELETE |
/profile/api_keys/{api_key_id} |
| ` | The API key management routes |
| Status |type` |
Title |
| ------ | ------ |
404 |
urn:endurain:error:not-found |
403 |
urn:endurain:error:permission-denied |
400 |
urn:endurain:error:invalid-input |
409 |
urn:endurain:error:conflict |
412 |
urn:endurain:error:precondition-failed |
406 |
urn:endurain:error:unsupported-format |
415 |
urn:endurain:error:unsupported-media-type |
413 |
urn:endurain:error:payload-too-large |
503 |
urn:endurain:error:service-unavailable |
502 |
urn:endurain:error:upstream-error |
500 |
urn:endurain:error:internal-error |
| ` | The error types and their HTTP statuses |
| ` | Tier |
| ---- | ----- |
DEFAULT |
120/minute |
WRITE |
30/minute |
SENSITIVE |
10/minute |
UPLOAD |
20/minute |
PROVIDER_SYNC |
6/minute |
| ` | The rate-limit tiers |
The code is in mkdocs_hooks/auth_docs.py. It reads the backend with Python's ast module and does not import it, so the docs build needs no backend dependencies. If a source it reads is moved or renamed, the build fails and you update the hook. To add a table, write a function that returns a Markdown table and add it to GENERATORS.
Python API reference
Pages under reference/ use mkdocstrings. A section is a heading followed by a directive naming the module:
## Service
::: backend.app.modules.followers.service
handler: python
options:
docstring_style: google
The text comes from the docstrings, which use the Google style (Args, Returns, Raises). Fix a wrong reference page by fixing the docstring. Add a new module to the page of its area, or add a page and list it in nav:.
Reusing fragments
Shared HTML such as the newsletter form and the secret generators lives in docs/_snippets/ and is included with --8<-- "_snippets/name.html".