Docs Authoring Conventions
Use these patterns when writing or updating any page under docs/. They ensure consistent rendering with the branded VitePress theme.
Callouts / Admonitions
VitePress natively renders ::: fenced blocks — no plugin required. Use them instead of blockquote-style callouts (> **Note:** …).
Tip
Use for a helpful aside or a shortcut the reader will appreciate.
Source:
::: tip
Run `npm run storybook` to preview every component in isolation before opening a PR.
:::Rendered:
TIP
Run npm run storybook to preview every component in isolation before opening a PR.
Info
Use for neutral context — something the reader should know but that doesn't require action.
Source:
::: info
Docker Compose maps the frontend to port 8282. Local Vite dev (`npm run dev`) uses port 5173.
:::Rendered:
INFO
Docker Compose maps the frontend to port 8282. Local Vite dev (npm run dev) uses port 5173.
Warning
Use for a non-blocking caution — something that can go wrong if the reader doesn't pay attention.
Source:
::: warning
The header is `SessionToken` (PascalCase), not `Authorization: Bearer`. Wrong header = silent auth failure.
:::Rendered:
WARNING
The header is SessionToken (PascalCase), not Authorization: Bearer. Wrong header = silent auth failure.
Danger
Use for a destructive or irreversible action — data loss, breaking changes, or security-sensitive steps.
Source:
::: danger
PITR replaces the instance's data. Confirm the target timestamp carefully. Do this on staging first if the cause is unclear.
:::Rendered:
DANGER
PITR replaces the instance's data. Confirm the target timestamp carefully. Do this on staging first if the cause is unclear.
Details (collapsible)
Use for supplementary information that most readers can skip — long rationale, historical context, or edge-case details.
Source:
::: details Why we use `public_id` instead of database IDs
Integer primary keys leak record counts and insertion order to clients. `public_id` is a URL-safe base64 token auto-generated by `PublicRecord` — it's opaque, short, and safe to expose in URLs and API responses.
:::Rendered:
Why we use public_id instead of database IDs
Integer primary keys leak record counts and insertion order to clients. public_id is a URL-safe base64 token auto-generated by PublicRecord — it's opaque, short, and safe to expose in URLs and API responses.
Tabbed Code Groups
Use ::: code-group to show equivalent commands or configs side-by-side.
Source:
::: code-group
```bash [npm]
cd ionic_frontend
npm install
npm run dev
```
```bash [Docker]
docker-compose up --build
# Frontend available at http://localhost:8282
```
```ruby [Rails console]
# Rails API only
cd rails_api
bin/rails server
```
:::Rendered:
cd ionic_frontend
npm install
npm run devdocker-compose up --build
# Frontend available at http://localhost:8282# Rails API only
cd rails_api
bin/rails serverWhen to Use Which
| Block | Use when |
|---|---|
::: tip | Helpful shortcut or best-practice the reader will thank you for |
::: info | Neutral context — good to know, no action required |
::: warning | Non-blocking caution — something can go wrong without care |
::: danger | Destructive or irreversible — data loss, credential exposure, breaking change |
::: details | Collapsible extra — rationale, history, or edge cases most readers can skip |
Do NOT use raw blockquote callouts (> **Note:** …) for new content — convert existing ones to the matching native block when you edit a page.
Cross-Linking PRDs and Feature Docs
When a PRD ships and is archived to docs/product/completed/, it and its corresponding docs/features/*.md page must link to each other. This keeps product rationale discoverable from the shipped doc, and the shipped implementation discoverable from the design history. See docs/features/meet-coach.md / docs/product/completed/meet-coach-prd.md for a reference pair (established in OBJ-1467).
Feature doc → PRD. Add a bullet to the page's existing "Related" list (usually near the top):
- [<PRD Title>](../product/completed/<prd-slug>.md) — original product rationale and design explorationPRD → feature doc. Add a bullet to the PRD's "Related" list, or a ## Related Documentation section near the bottom (before the **Last updated:** line) if it doesn't have one:
- [<Feature Title>](../../features/<feature-slug>.md) — feature doc for the shipped implementationChecklist when archiving a PRD to completed/:
- [ ] Check whether a
docs/features/*.mdpage exists for the shipped feature — not every PRD has one, skip if so. - [ ] Add the backward link (feature doc → PRD) using the phrasing above.
- [ ] Add the forward link (PRD → feature doc) using the phrasing above.
- [ ] Keep the phrasing consistent — it signals link intent (rationale vs. implementation), not just "see also."
Page Footers
Every page under docs/ ends with exactly one **Last updated:** line — one entry, one line. This is non-optional.
**Last updated:** YYYY-MM-DD (OBJ-NNNN: <one clause describing the change>)This file's own footer, at the very bottom of this page, is a live example of the correct shape.
Never chain entries. Do not prepend Previous entry:, Same day:, Prior entry:, Earlier entry:, or any similar construction onto an existing footer to preserve older changes. When you touch a page, replace the whole footer line with a single new entry describing the most recent change. Change history belongs in git log (git log --follow <path>), not in the footer — every prior entry already cites its own OBJ/PR number there and is fully recoverable.
A chained footer isn't just noisy: because it's one physical line, any two concurrent PRs touching the same doc conflict on it with certainty, and because the line carries prose from multiple unrelated tickets, resolving the conflict requires synthesizing narrative rather than a mechanical pick. See the gotcha write-up for the incident this rule was written to prevent.
Last updated: 2026-08-14 (OBJ-2562: codified the one-entry footer rule)