Definition
A local document graph is the set of nodes and edges collected by starting from one document (the root) and running BFS (breadth-first search) — exploring neighbors level by level — through related fields, wikilinks, and similar links up to a maximum of N hops. Visualization places nodes on screen with a force-directed layout (a simulation that applies attraction and repulsion between nodes).
Only published/public documents become nodes; draft and private entries are excluded so readers see a knowledge map that matches what they can actually access.
Why it matters
TIL and Knowledge detail pages convey relationships only as text — body links and related lists. A depth-limited graph shows promotion paths, prerequisites, and hub documents at a glance. Showing only the neighborhood of the current article — not the whole site graph — keeps node count predictable.
Authors also use it to spot orphan nodes (no neighbors) and overloaded hubs (dozens of edges at depth 1).
How it works
- RelationIndex: At build time, normalize frontmatter
relatedand body wikilinks into adjacency lists keyed by slug/type. getLocalGraph(root, maxDepth): Queue-based BFS. Depth 0 is the root; expand frontier for hops 1 through N.- Filter: Skip nodes and edges when
isPublishedPublic(neighbor)is false. - Edge dedupe: Canonical key
source|target|kind(drop duplicates regardless of direction). - UI: Depth slider (1–3), color by type, highlight root, navigate on click via locale-aware router.
- Bundle: Heavy canvas libs like
force-graphload vianext/dynamic({ ssr: false })into a separate client chunk.
Practical application
- Keep
graph.tsas pure functions + Vitest (depth, filter, dedupe, exclude non-public). DocumentGraphViewaccepts onlyLocalGraphDataprops; dynamic-import the canvas component.- Playwright: graph mount, depth change,
prefers-reduced-motionsmoke. - Node
hrefmust preserve document locale — verify alongside i18n router. - Adjacent UI copy on home/stats goes through
messages/*.jsonkeys.
Trade-offs
| Choice | Pros | Cons |
|---|---|---|
| BFS local graph | Predictable node count; detail-page context | No global map or cluster analysis |
| Full-site graph | Structure at a glance | Hundreds of nodes; slow load; unstable layout |
| Text related list only | Light; simple a11y | Hard to see density and paths |
| SSR canvas | Graph image for SEO | force-graph depends on window |
When not to use
- Draft documents with no relations data (need empty-graph UX).
- Opening a hub with thousands of nodes at depth 3 (explosion — depth UI and caps required).
- When the graph is the only source of essential information for accessibility (keep text related alongside).
Common mistakes
- Hard-coding 1-hop only without BFS, so "nearby knowledge" looks shallow.
- Including draft documents and exposing private titles.
- Synchronous import of force-graph at page top, hurting LCP and TTI.
- Rendering bidirectional edges twice by swapping source/target order only.
- Node clicks via plain
next/link— locale loss (use i18n router).
Related concepts
- hierarchical-document-navigation — text list navigation
- list-virtualization-windowing — virtual list for long lists instead of graph
- inverted-index-full-text-search — full-text search index (separate from relation axis)