garden.oooの情報設計
コンテンツパイプライン
ページの「本体」は Markdown のソースコードではなく、HTML の AST(抽象構文木)。
HTML の AST は現状は Nuxt MDC の MDCRoot を AST フォーマットとして使っているけれど、もう少し汎用的な表現にしたい。hastとか。unified エコシステムを使えば、Markdown に限らず HTML にパース可能な任意の軽量マークアップ言語をサポートできる。
サーバーに送信されるのは {source, ast, ...metadata} の組。AST の生成はクライアントサイドで責任をもつ。
この設計がもたらすもの:
- Copy as Markdown: AST → Markdown の逆変換
- PDF エクスポート: archival ページの永続的な文書化
- カスタムパーサー: ユーザーが独自の記法を持ち込める
識別子の3層構造
ページには3種類の識別子がある。それぞれ異なる文脈で使う。
| 識別子 | 用途 | 例 |
|---|---|---|
path | ローカルのファイルパス。空白や記号をそのまま含む | Articles/100% User Supported |
uri | URL として使える形式。空白→_、制御文字→エスケープ | Articles/100%25_User_Supported |
slug | DB 検索用の正規化キー。uri.toLowerCase() | articles/100%25_user_supported |
変換は path → uri → slug の一方向。逆変換は uri → path(_ → 半角スペース)のみ可能。
slug が重複するページは作成できない。ローカルで衝突が起きた場合、後から検知された方はリネームされるまでリモートに同期されない。
関連コード:
utils/normalizeIdentifiers.ts— 識別子の変換sanitizeTitleToPath— パスのサニタイズnormalizeToSlug— slug の正規化
リンクとバックリンク
ページ同士の関連性はリンクで表現する。種類は2つ。
Tag link と Body link
- Tag link(
A is B): frontmatter のtagsや本文中の#tag_link記法で表現。所属・包摂・共通性 - Body link(
A refers to B): 本文中のハイパーリンク。言及・参照
Tag link のほうが強い関連性を示す。
バックリンク
A → B のリンクがあるとき、B のページに「関連ページ」として A を自動表示する仕組み。有向グラフとしてのハイパーリンクを双方向にしている。
これで従来 CMS の「カテゴリ一覧」を代替できる。「チーム」というページに、メンバーの各ページから tag link を貼って、frontmatter で layout: grid を設定すれば、チームメンバー一覧ページになる。grid / table レイアウトでは body link のバックリンクが除外されるので、「チームについてはこちら!」みたいな無関係なページが混ざらない。
関連コード:
utils/markdown/collectOutlinksFromPage.ts— アウトリンク収集types/page.tsのLink—{type: 'tag' | 'folder' | 'link', slug: string}
公開範囲
4段階ある。Frontmatterの visibility で設定可能。
- public: 誰でも見える。リストに表示される
- unlisted: URL直打ちか直リンクでのみ到達可能。リスト表示やバックリンクには現れない。「文脈を追わないとたどり着けない」状態を作る
- protected: 認証(パスワード、OAuth 等)が必要。メンバーシップ制の限定コンテンツや有料配信(note/Substack 的な)を想定している。決済機能は未実装
- private: 書き手だけが見える
関連コード: types/page.ts の visibilitySchema
Archival フラグ
公開範囲とは別軸で、すべてのページが持つフラグ。永続化したいものとエフェメラルなものを分ける。
- Archival(
archival: true): 不変の URL で公開したいもの - Scratchpad(
archival: false): 個人的なメモ。noindex, nofollowで検索エンジンにもインデックスされない。いつでも変更したり消せる
archival は明示的に true と書かなくても、layout が page 以外だったり、特定のタグ(works, video 等)が付いていれば自動的に true に推定される(FrontmatterSchema の transform 参照)。