Page naming
This page is the live, in-site form of the docs naming convention. If you’re authoring a new page, this is the reference. The same content lives in the repo as docs/specs/002-docs-naming-convention/contracts/naming-convention.md — that file is the source of truth; this page renders the same rules so you can read them in context.
Why titles look the way they do
Every page title follows the pattern <Context>: <Leaf>. The prefix isn’t decoration — it answers “what zone is this in?” in every context that strips away the sidebar: search results, chatbot citations, browser tabs, link previews. Without it, a reader landing cold has to do mental indexing on every page view. With it, the title alone locates the page.
The on-page # Heading may drop the prefix — the sidebar already shows the reader where they are.
Quick reference: title prefixes
Audience zones
| Where pages live | Title prefix | Example |
|---|---|---|
app/overview/<module>/page.mdx | Overview: | Overview: Skill levels |
app/business-logic/<module>/page.mdx | Business logic: | Business logic: Member lifecycle |
Component zones (one per deployable)
| Where pages live | Title prefix | Notes |
|---|---|---|
app/api/<...>/page.mdx | API: | Backend service. Per-service / per-tag pages are generated by docs/scripts/openapi-to-mdx.ts from Bruno collections and emit their own titles; the rule applies to authored MDX (index, conventions, getting-started). |
app/www/<...>/page.mdx | WWW: | The Express/Backbone public site. |
app/admin/<...>/page.mdx | Admin: | The Next.js admin dashboard. |
app/mobile/<...>/page.mdx | Mobile: | The mobile app (separate repo). |
app/assistant/<...>/page.mdx | Assistant: | The TunnelFlight Assistant (separate project). |
app/integrations/<provider>/page.mdx | Integration: | Third-party systems we connect to (Fuzemetrix, Convergence, Tunn3l). |
Cross-cutting zones
| Where pages live | Title prefix | Notes |
|---|---|---|
app/common-tasks/<action>/page.mdx | Common task: | Operational runbooks. Slug MUST start with a verb. |
app/infra/<module>/page.mdx | Infra: | Genuine platform infrastructure (CI, data storage, request patterns, architecture). Not a catch-all — if content doesn’t fit a component or audience zone, prefer a new zone over expanding infra/. |
app/conventions/<topic>/page.mdx | Convention: | Meta-docs about how we work — like this page. |
Utility routes (exempt)
/, /changelog, and /graph are single-page utilities. They have a title: but no archetype prefix.
Slug rules
Directory names become URL fragments. They MUST:
- Match
^[a-z0-9]+(-[a-z0-9]+)*$— lowercase ASCII, hyphen-separated. - Not start with a numeric prefix (
01-foo,02-bar). Ordering belongs in_meta.tsx. - Use full English words OR an acronym from the allow-list:
api,www,db,oauth,sso,c4,pwa,mfa,jwt,cdn,ci. - For common-task pages: start with a verb (
add-,update-,remove-,enable-,disable-,configure-,rotate-,migrate-, …) so the URL itself tells the reader what the page does.
Sidebar labels
Labels in _meta.tsx SHOULD:
- Drop the archetype prefix — the sidebar’s tree position already supplies it.
- Be concise (typically 1–3 words).
- Be parallel within a section (same voice, same length).
Example — app/overview/_meta.tsx:
export default {
'platform-at-a-glance': 'At a glance',
'members': 'Members',
'skill-levels': 'Skill levels',
'tunnels': 'Tunnels',
}The frontmatter title (Overview: Skill levels) and the sidebar label (Skill levels) deliberately differ.
Legacy pages
Pages preserved for historical reference MAY keep their existing titles but SHOULD gain a Legacy · prefix:
title: "Legacy · API: Status codes"No new pages should be added under a (legacy) directory.
Redirects
When you rename a slug or move a page between zones, you MUST add a corresponding entry to docs/next.config.mjs:
{
source: '/old/path/here',
destination: '/new/path/here',
permanent: true,
}This is non-negotiable — bookmarks must not silently break. For sub-tree moves, use Next.js wildcard syntax (source: '/old/:path*').
Authoring a new page
- Pick the right archetype + zone from the tables above.
- Copy the matching template from
docs/_templates/:overview.mdxbusiness-logic.mdxcommon-task.mdxcomponent.mdx(works for any component, integration, infra, or convention page — pick the prefix per the comment block in the file)
- Replace the
REPLACEplaceholders. - Add an entry to the parent
_meta.tsxfor the sidebar. - Run
npm run audit-namingfromdocs/to catch any non-conformance before opening the PR.
Enforcement
- At authoring time: copy from
docs/_templates/. - At review time:
npm run audit-namingreports any non-conformance with a specific reason. - At CI time: not enforced today. Lifting the audit into CI is a one-line follow-up if manual review proves insufficient.
Adding a new zone
The convention’s appendix lists the 13 top-level zones. Adding a new one is a deliberate act — update:
docs/specs/002-docs-naming-convention/contracts/naming-convention.md§3 and Appendixdocs/specs/002-docs-naming-convention/data-model.mdZone vocabulary tabledocs/scripts/audit-naming.tszone-prefix constants- This page
The friction is intentional — every zone earns its slot.
Adding a new infra/ module
infra/ is deliberately narrow. Adding a module requires justifying in the PR description why the content belongs to platform infrastructure rather than a component or audience zone. This friction is intentional — infra/ previously absorbed unrelated content under its old tech/ name, and the convention is designed to prevent that recurring.