Service Layer
MarkdownService
File: src/services/MarkdownService.ts (308 lines)
Handles all markdown processing. Uses markdown-it configured with:
- HTML passthrough enabled
- Linkify (auto-links URLs)
- Typographer (smart quotes)
highlight.jsfor fenced code blocks (dark theme,#1e293bbackground)markdown-it-anchorfor heading permalinks usingheaderLinkstyle
Key Methods
| Method | Returns | Description |
|---|---|---|
renderPage(filePath) |
DocPage | null |
Parses frontmatter with gray-matter, renders markdown to HTML, extracts TOC from heading tokens |
getNavTree() |
NavItem[] |
Recursively scans content/ building a tree of directories and files, reads _project.yaml/_subproject.yaml for display names |
listProjects() |
ProjectMeta[] |
Lists top-level directories with their _project.yaml metadata |
listSubprojects(project) |
SubprojectMeta[] |
Lists subdirectories within a project |
listPages(project, subproject) |
page array | Lists .md files with frontmatter title/summary/order |
getRawContent(filePath) |
string | null |
Returns raw file contents for the API |
searchContent(query) |
result array | Case-insensitive substring search across all .md files, returns up to 50 results with excerpts |
Frontmatter Schema
Every .md file can have YAML frontmatter:
---
title: Page Title # Displayed in nav, breadcrumbs, browser tab
summary: Brief description # Shown below breadcrumbs, used in manifests
order: 1 # Sort order in sidebar (default 999)
references: # Cross-references to other subprojects
- target: dochub/api
type: depends_on
---
Navigation Tree Building
buildNavTree() walks the content directory recursively:
- Skips entries starting with
.or_ - Directories become nav sections, reading
_project.yamlor_subproject.yamlfor the display name .mdfiles become nav links, reading frontmatter for title and order- Sorts: directories first, then by
order, then alphabetically
Search Implementation
searchContent() does a recursive directory walk, reading each .md file and checking if the lowercase content contains the lowercase query. For matches, it extracts a ~150-character excerpt centered on the first match. Limited to 50 results.
ManifestService
File: src/services/ManifestService.ts (178 lines)
Generates structured JSON manifests designed for Claude CLI consumption.
Schema Sections
Every subproject is evaluated against 8 schema sections:
purpose, architecture, variables, api_endpoints,
handshakes, data_model, dependencies, status
Coverage is declared in _subproject.yaml via schema_coverage — it is not auto-detected from content.
Manifest Levels
Master manifest (getMasterManifest()):
{
"generated_at": "ISO timestamp",
"projects": [{ "id", "name", "description", "subproject_count", "doc_count" }],
"total_documents": 8
}
Project manifest (getProjectManifest(id)):
{
"project": { "id", "name", "description" },
"subprojects": [{ "id", "name", "description", "doc_count" }]
}
Subproject manifest (getSubprojectManifest(project, subproject)):
{
"project": "dochub",
"subproject": { "id", "name", "description" },
"schema_coverage": { "purpose": true, "architecture": true, ... },
"documents": [{
"id": "overview",
"title": "Architecture Overview",
"summary": "...",
"raw_url": "/api/raw/dochub/architecture/overview",
"references": [{ "target": "dochub/api", "type": "provides" }]
}]
}
TemplateService
File: src/services/TemplateService.ts (170 lines)
Generates complete HTML pages by compositing rendered markdown content into a layout with navigation.
Template Resolution
The constructor looks for styles.css in two locations:
{cwd}/src/templates/styles.css(dev — source directory){__dirname}/../templates/styles.css(prod — dist directory)
CSS is read once at startup and inlined into every page via a <style> tag (no external stylesheet requests).
Two Render Methods
renderDoc() — for individual documentation pages:
- Header bar with brand, nav links (Home, API, Report), and search input
- Left sidebar with expandable nav sections
- Main content area with breadcrumbs, optional summary line, and rendered markdown
- Right-side TOC (h2/h3 headings, hidden below 1200px)
renderIndex() — for directory listing pages:
- Same header and sidebar
- Card grid layout for child items (subprojects or pages)
CSS Architecture
All styles live in src/templates/styles.css (290 lines). Key design choices:
- CSS custom properties for colors, widths, heights
- Fixed header (56px) and fixed sidebar (280px)
- Dark header (
#0f172a) with light content area - Code blocks use dark background (
#1e293b) matching highlight.js theme - Responsive: TOC hides at 1200px, sidebar hides at 768px