Documentation Registry
Introduction
The Docs Registry (core/lib/registries/docs-registry.ts) is an auto-generated TypeScript file containing metadata for all documentation pages. It enables zero runtime I/O by resolving all documentation structure at build time.
Key Benefits:
- ✅ Zero Runtime I/O - All metadata resolved at build time
- ✅ Type-Safe Access - Full TypeScript support
- ✅ Instant Navigation - In-memory lookups (~6ms vs ~140ms)
- ✅ Automatic Discovery - No manual registration required
- ✅ Two Audiences - Public docs (users) and Superadmin docs (administrators)
Generated by: core/scripts/build/docs-registry.mjs
Location: core/lib/registries/docs-registry.ts
Regeneration: Automatic during pnpm dev or pnpm build
Documentation Structure
Themes organize documentation into two categories:
themes/{theme}/docs/
├── public/ # User-facing documentation (accessible at /docs)
│ ├── 01-getting-started/
│ │ ├── 01-introduction.md
│ │ └── 02-installation.md
│ └── 02-features/
│ └── 01-overview.md
└── superadmin/ # Administrator docs (accessible at /superadmin/docs)
├── 01-setup/
│ ├── 01-configuration.md
│ └── 02-deployment.md
└── 02-management/
└── 01-users.md
Note: Core framework docs (packages/core/docs/) are NOT included in the registry. They are development documentation accessed via IDE or LLM tools, not runtime docs.
Registry Structure
TypeScript Interfaces
DocPageMeta:
export interface DocPageMeta {
slug: string // Page identifier (e.g., "introduction")
title: string // Display title (e.g., "Introduction")
order: number // Display order within section
path: string // Absolute path to markdown file
source: 'public' | 'superadmin' // Documentation audience
}
DocSectionMeta:
export interface DocSectionMeta {
title: string // Section title (e.g., "Getting Started")
slug: string // Section identifier (e.g., "getting-started")
order: number // Display order in navigation
pages: DocPageMeta[] // Pages within this section
source: 'public' | 'superadmin'
}
DocsRegistryStructure:
export interface DocsRegistryStructure {
public: DocSectionMeta[] // User-facing documentation
superadmin: DocSectionMeta[] // Administrator documentation
all: DocSectionMeta[] // Combined (public + superadmin)
}
Registry Constant
export const DOCS_REGISTRY: DocsRegistryStructure = {
public: [
{
title: "Getting Started",
slug: "getting-started",
order: 1,
pages: [
{
slug: "introduction",
title: "Introduction",
order: 1,
path: "themes/default/docs/public/01-getting-started/01-introduction.md",
source: "public"
},
{
slug: "installation",
title: "Installation",
order: 2,
path: "themes/default/docs/public/01-getting-started/02-installation.md",
source: "public"
}
],
source: "public"
}
// ... more sections
],
superadmin: [
{
title: "Setup",
slug: "setup",
order: 1,
pages: [
{
slug: "configuration",
title: "Configuration",
order: 1,
path: "themes/default/docs/superadmin/01-setup/01-configuration.md",
source: "superadmin"
}
],
source: "superadmin"
}
// ... more sections
],
all: [
// Merged array of public + superadmin sections, sorted by order
]
} as const
Helper Functions
Exported Functions
The registry exports helper functions for common access patterns:
getAllDocSections():
export function getAllDocSections(): DocSectionMeta[] {
return DOCS_REGISTRY.all
}
// Usage
const sections = getAllDocSections()
getPublicDocSections():
export function getPublicDocSections(): DocSectionMeta[] {
return DOCS_REGISTRY.public
}
// Usage
const publicSections = getPublicDocSections()
getSuperadminDocSections():
export function getSuperadminDocSections(): DocSectionMeta[] {
return DOCS_REGISTRY.superadmin
}
// Usage
const adminSections = getSuperadminDocSections()
findDocSection():
export function findDocSection(slug: string): DocSectionMeta | undefined {
return DOCS_REGISTRY.all.find(section => section.slug === slug)
}
// Usage
const section = findDocSection('getting-started')
findDocPage():
export function findDocPage(
sectionSlug: string,
pageSlug: string
): DocPageMeta | undefined {
const section = findDocSection(sectionSlug)
return section?.pages.find(page => page.slug === pageSlug)
}
// Usage
const page = findDocPage('getting-started', 'introduction')
Build Process
Generation Script
Location: core/scripts/build/docs-registry.mjs
Execution:
# Automatic (part of build)
pnpm dev
pnpm build
# Direct
node packages/core/scripts/build/docs-registry.mjs
Discovery Algorithm
1. Directory Scanning:
function scanDocsDirectory(docsPath, source) {
// Read all directories (sections)
const sections = []
for (const directory of directories) {
const order = extractOrder(directory) // From "01-getting-started"
const slug = cleanName(directory) // Remove "01-"
const title = slugToTitle(slug) // "getting-started" → "Getting Started"
// Scan markdown files (pages)
const pages = []
for (const file of files) {
pages.push({
slug: cleanName(file),
title: slugToTitle(cleanName(file)),
order: extractOrder(file),
path: relativePath,
source
})
}
sections.push({ title, slug, order, pages, source })
}
return sections.sort((a, b) => a.order - b.order)
}
2. Two-Audience Scanning:
const activeTheme = process.env.NEXT_PUBLIC_ACTIVE_THEME || 'default'
const themeDocsDir = `themes/${activeTheme}/docs`
// Scan public docs (user-facing)
const publicDocs = scanDocsDirectory(
path.join(themeDocsDir, 'public'),
'public'
)
// Scan superadmin docs (administrator)
const superadminDocs = scanDocsDirectory(
path.join(themeDocsDir, 'superadmin'),
'superadmin'
)
3. Registry Generation:
const registry = {
public: publicDocs,
superadmin: superadminDocs,
all: [...publicDocs, ...superadminDocs].sort((a, b) => a.order - b.order)
}
// Write to TypeScript file
fs.writeFileSync(
'core/lib/registries/docs-registry.ts',
`export const DOCS_REGISTRY: DocsRegistryStructure = ${JSON.stringify(registry, null, 2)} as const`
)
Accessing the Registry
In Server Components
import { DOCS_REGISTRY } from '@/core/lib/registries/docs-registry'
export default async function DocsPage() {
const sections = DOCS_REGISTRY.all
return (
<div>
{sections.map(section => (
<div key={section.slug}>
<h2>{section.title}</h2>
<ul>
{section.pages.map(page => (
<li key={page.slug}>{page.title}</li>
))}
</ul>
</div>
))}
</div>
)
}
In Client Components
'use client'
import { DOCS_REGISTRY } from '@/core/lib/registries/docs-registry'
import { usePathname } from 'next/navigation'
// For public docs (accessible at /docs)
export function DocsSidebar() {
const pathname = usePathname()
const sections = DOCS_REGISTRY.public
return (
<nav>
{sections.map(section => (
<div key={section.slug}>
<h3>{section.title}</h3>
{section.pages.map(page => {
const href = `/docs/${section.slug}/${page.slug}`
const isActive = pathname === href
return (
<a
key={page.slug}
href={href}
className={isActive ? 'active' : ''}
>
{page.title}
</a>
)
})}
</div>
))}
</nav>
)
}
// For superadmin docs (accessible at /superadmin/docs)
export function SuperadminDocsSidebar() {
const pathname = usePathname()
const sections = DOCS_REGISTRY.superadmin
return (
<nav>
{sections.map(section => (
<div key={section.slug}>
<h3>{section.title}</h3>
{section.pages.map(page => {
const href = `/superadmin/docs/${section.slug}/${page.slug}`
const isActive = pathname === href
return (
<a
key={page.slug}
href={href}
className={isActive ? 'active' : ''}
>
{page.title}
</a>
)
})}
</div>
))}
</nav>
)
}
In API Routes
import { DOCS_REGISTRY, findDocPage } from '@/core/lib/registries/docs-registry'
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const section = searchParams.get('section')
const page = searchParams.get('page')
const docPage = findDocPage(section!, page!)
if (!docPage) {
return Response.json({ error: 'Not found' }, { status: 404 })
}
return Response.json({ docPage })
}
Navigation Generation
Automatic Sidebars
Two sidebar components handle different doc areas:
Public docs layout (/docs):
import { DocsSidebar } from '@/core/components/docs/docs-sidebar'
import { DOCS_REGISTRY } from '@/core/lib/registries/docs-registry'
export default function DocsLayout({ children }) {
return (
<div>
<DocsSidebar sections={DOCS_REGISTRY.public} />
<main>{children}</main>
</div>
)
}
Superadmin docs layout (/superadmin/docs):
import { SuperadminDocsSidebar } from '@/core/components/docs/superadmin-docs-sidebar'
import { DOCS_REGISTRY } from '@/core/lib/registries/docs-registry'
export default function SuperadminDocsLayout({ children }) {
return (
<div>
<SuperadminDocsSidebar sections={DOCS_REGISTRY.superadmin} />
<main>{children}</main>
</div>
)
}
Generated Structure:
📚 Public Documentation (/docs)
├── 📁 Getting Started
│ ├── 📄 Introduction
│ └── 📄 Installation
└── 📁 Features
└── 📄 Overview
🔒 Superadmin Documentation (/superadmin/docs)
├── 📁 Setup
│ ├── 📄 Configuration
│ └── 📄 Deployment
└── 📁 Management
└── 📄 Users
Breadcrumbs
Generate breadcrumbs from registry metadata:
const section = findDocSection(sectionSlug)
const page = findDocPage(sectionSlug, pageSlug)
// For public docs
const publicBreadcrumbs = [
{ label: 'Documentation', href: '/docs' },
{ label: section.title, href: `/docs/${section.slug}` },
{ label: page.title }
]
// For superadmin docs
const adminBreadcrumbs = [
{ label: 'Admin Docs', href: '/superadmin/docs' },
{ label: section.title, href: `/superadmin/docs/${section.slug}` },
{ label: page.title }
]
Performance Characteristics
Build Time
Registry Generation:
- Public docs (3-5 sections, ~15 pages): ~20ms
- Superadmin docs (2-3 sections, ~10 pages): ~10ms
- Total: ~30-50ms
Scaling:
- Linear with documentation size
- No significant impact on build time
- Negligible overhead (~0.2% of total build)
Runtime
Registry Access:
Runtime Discovery (filesystem): ~140ms per lookup
Registry Access (memory): ~6ms per lookup
Improvement: ~17,255x faster
Navigation Rendering:
- Initial render: ~6ms (read from memory)
- Re-renders: ~2ms (React memoization)
- No network requests
- No filesystem I/O
Memory Usage
Registry Size:
- Public docs: ~5KB (raw JSON)
- Superadmin docs: ~3KB
- Total: ~8-10KB in memory
Impact:
- Negligible memory footprint
- Loaded once per process
- Shared across all requests
- No per-request allocation
Integration with Components
DocsSidebar Component
// For public docs
<DocsSidebar sections={DOCS_REGISTRY.public} />
// For superadmin docs
<SuperadminDocsSidebar sections={DOCS_REGISTRY.superadmin} />
Renders collapsible navigation tree from registry.
DocsPage Component
// For public docs
const section = DOCS_REGISTRY.public.find(s => s.slug === sectionSlug)
const page = section?.pages.find(p => p.slug === pageSlug)
// For superadmin docs
const section = DOCS_REGISTRY.superadmin.find(s => s.slug === sectionSlug)
const page = section?.pages.find(p => p.slug === pageSlug)
Looks up page metadata for rendering.
DocsBreadcrumbs Component
<DocsBreadcrumbs items={[
{ label: 'Documentation', href: '/docs' },
{ label: section.title, href: `/docs/${section.slug}` },
{ label: page.title }
]} />
Uses registry data to build navigation trail.
Troubleshooting
Registry Not Updating
Problem: Changes to docs don't appear in navigation
Solution:
# Regenerate registry (from repo root)
node packages/core/scripts/build/docs-registry.mjs
# Restart dev server
pnpm dev
Missing Documentation
Problem: Documentation exists but doesn't appear
Check:
- File naming follows
{order}-{slug}.mdpattern - Directory naming follows
{order}-{slug}/pattern - Files are in correct directory (
themes/{theme}/docs/public/orthemes/{theme}/docs/superadmin/) - Registry was regenerated after adding files
TypeScript Errors
Problem: Import errors from docs-registry.ts
Solution:
# Regenerate registry
node packages/core/scripts/build/docs-registry.mjs
# Registry file should now exist
ls packages/core/src/lib/registries/docs-registry.ts
Route Structure
Public Documentation
- Base route:
/docs - Section route:
/docs/[section](redirects to first page) - Page route:
/docs/[section]/[page]
Example URLs:
/docs- Documentation index/docs/getting-started/introduction- Getting Started > Introduction/docs/features/overview- Features > Overview
Superadmin Documentation
- Base route:
/superadmin/docs - Page route:
/superadmin/docs/[section]/[page]
Example URLs:
/superadmin/docs- Admin docs index/superadmin/docs/setup/configuration- Setup > Configuration/superadmin/docs/management/users- Management > Users
Next Steps
- Public Rendering - How docs are rendered
- Extending Documentation - Adding theme docs
- Architecture - Complete system architecture