定義
ローカル文書グラフとは、1 つの文書(ルート)から出発し、related・wikilink などで接続された近傍を BFS(幅優先探索) で最大 N ホップまで集めたノード・エッジの集合です。可視化は force-directed layout(ノード間の引力・斥力シミュレーション)で画面に配置します。
published/public の文書だけをノードに含め、draft・private はグラフから除外し、読者に見える知識マップだけを表示します。
なぜ必要か
TIL・Knowledge 詳細は、本文リンクと related 一覧で関係をテキストだけで伝えます。昇格パス・前提知識・ハブ文書を一目で見るには、深さ制限付きグラフの方が適しています。サイト全体のグラフではなく現在の記事の周辺だけを見せれば、ノード数を制御できます。
執筆者には、孤立ノード(近傍なし)・過度なハブ(深さ 1 で数十エッジ)の診断にも使えます。
動作の仕組み
- RelationIndex: ビルド時に frontmatter
related・本文 wikilink を slug/type 基準の隣接リストに正規化。 getLocalGraph(root, maxDepth): キュー型 BFS。depth 0 = ルート、1〜N ホップで frontier を拡張。- フィルタ:
isPublishedPublic(neighbor)が false ならノード・エッジをスキップ。 - エッジ dedupe:
source|target|kind正規キー(方向を問わず重複除去)。 - UI: depth スライダー(1〜3)、タイプ別色、ルート強調、クリックで locale-aware router へ移動。
- バンドル:
force-graphなど重い canvas はnext/dynamic({ ssr: false })でクライアントチャンク分離。
実務での適用
graph.tsは純粋関数 + Vitest(深さ・フィルタ・dedupe・非公開除外)。DocumentGraphViewは props でLocalGraphDataのみ受け取り、canvas コンポーネントは dynamic import。- Playwright: グラフマウント、depth 変更、
prefers-reduced-motionスモーク。 - ノード
hrefは文書 locale を維持 — i18n router と一緒に検証。 - ホーム・stats など隣接 UI のコピーは
messages/*.jsonキーで分離。
トレードオフ
| 選択 | 利点 | 欠点 |
|---|---|---|
| BFS ローカルグラフ | ノード数が予測可能、詳細ページの文脈を維持 | 全体マップ・クラスタ分析不可 |
| サイト全体グラフ | 構造を一目で把握 | 数百ノード・初期ロード・レイアウト不安定 |
| テキスト related 一覧のみ | 軽量で a11y が単純 | 密度・パス把握が難しい |
| SSR canvas | SEO にグラフ画像 | force-graph は window 依存 |
使うべきでない場合
- 関係データがない、または related が空の下書き文書(空グラフ UX が必要)。
- 数千ノードのハブを depth 3 で開くとき(爆発 — depth UI・上限が必須)。
- アクセシビリティだけではグラフが必須情報の場合(テキスト related を併用)。
よくある間違い
- BFS なしで 1 ホップだけハードコードし、「周辺知識」が浅く見える。
- draft 文書をノードに含め、非公開タイトルが露出。
- force-graph をページ上部に同期 import し LCP・TTI を悪化。
- 双方向エッジを source/target の順序だけ変えて 2 回レンダー。
- plain
next/linkでノードクリック — locale 喪失(i18n router を使用)。
関連概念
- hierarchical-document-navigation — テキスト一覧ナビ
- list-virtualization-windowing — 長い一覧はグラフではなく virtual list
- inverted-index-full-text-search — 全文検索インデックス(関係軸とは別)