DocHub
MarkdownService, ManifestService, and TemplateService internals

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.js for fenced code blocks (dark theme, #1e293b background)
  • markdown-it-anchor for heading permalinks using headerLink style

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
---

buildNavTree() walks the content directory recursively:

  • Skips entries starting with . or _
  • Directories become nav sections, reading _project.yaml or _subproject.yaml for the display name
  • .md files 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:

  1. {cwd}/src/templates/styles.css (dev — source directory)
  2. {__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