このサイトの仕組みを、
ER図で読む。
fujikawa.com はデータベースを使っていません。記事や教材の情報は、JSON ファイルと Python の設定に書かれています。 それでも、データの種類とつながりを箱と線で描くと、どこを直せば何が変わるかが一目で分かります。 このページでは、このサイト自身を例に、ER図の読み方と描き方を説明します。
ER図とは
ER図(実体関連図)とは、システムが扱うデータの種類と、それらのつながりを箱と線で表した図です。 E は Entity(エンティティ=データの種類)、R は Relationship(リレーションシップ=つながり)の頭文字です。 箱の中にはそのデータが持つ項目を書き、線の両端には「相手が何個つながるか」を記号で書きます。
ER図はふつう、データベースの設計に使われます。しかし、データベースがなくても描けます。
このサイトでは、記事の一覧は posts.json、教材の一覧は data/lab_catalog.json、公開するページの一覧は site_meta.py という、ファイルそのものが「表」の役目をしています。
表同士は、記事の slug やページの path(URL)といった共通の値でつながっています。
2026年9月18日に、このサイトのソースコード(公開していないリポジトリ)を AI(Claude Code)に読ませて図を作り、件数はファイルを数えて確かめました。 件数はこのページを追加した時点のもので、記事や教材が増えると変わります。
図の読み方
覚えることは3つです。箱の見出し、箱の中の鍵、線の端の記号です。
箱の見出し
1行目がデータの名前、2行目がその実物の置き場所と件数です。例えば「記事 / posts.json / 21件」は、記事の情報が posts.json に21件書かれているという意味です。
PK と FK
- PK(主キー):その箱の中で1件を見分けるための値です。記事なら
slug(URL の末尾の文字列)が PK で、同じ slug の記事は2本存在できません。 - FK(外部キー):別の箱の PK を指している値です。記事の
content_fileは、本文ファイルの名前を指しています。
線の端の記号
線の端の記号は、その端につながる箱が「何個つながるか」を表します。この書き方はカラスの足に似ていることから「カラスの足記法」と呼ばれます。
全体の見取り図
ER図に入る前に、ページが表示されるまでの流れを見ておきます。これは ER図ではなく、処理の順番を表した図です。
このサイトは Vercel(ウェブサイトを置いて配信するサービス)で動いています。
読者が URL を開くと、Vercel は設定ファイル vercel.json の規則を見て、行き先を2つに振り分けます。
- 決まったファイル(
sitemap.xml、llms.txt、画像、フォントなど):static/フォルダにあるファイルを、そのまま返します。 - それ以外:Flask(Python でウェブアプリを作るための道具)で書いたアプリ
app.pyに渡します。アプリは記事や台帳のデータを読み、テンプレート(HTML の型)に流し込んでページを組み立てます。
以降の ER図は、この図の下段にある「データ」の中身を描いたものです。
記事のデータ
ブログ記事(/blog)に関わるデータは5種類です。中心は posts.json です。
記事と本文は、別のファイルに分かれている
posts.json には、タイトル・日付・タグ・要約などの「記事についての情報」だけが入っています。本文の HTML は content/ フォルダに1記事1ファイルで置き、content_file の値でつなぎます。
この分け方により、一覧ページやタグのページは本文を読まずに作れます。
タグは、記事から作られる
タグには専用のファイルがありません。アプリが全記事の tags を集めて、その場でタグの一覧を作ります。URL 用の文字列(slug)も、タグ名から決まった規則で変換します。
1本の記事は複数のタグを持ち、1つのタグは複数の記事に付くので、記事とタグは「多対多」です。関連記事は、タグが1つでも共通する記事を新しい順に3本選んでいます。
表紙画像は、記事の情報から生成する
SNS で共有したときに表示される表紙画像(OG 画像)は、og_cover_title と最初のタグから、生成用のプログラムが作ります。
画像ごとに材料の指紋(ハッシュ値)を記録しておき、記事の情報が変わったのに画像を作り直していない状態を検査で見つけます。
URL を変えた記事は、転送表で古い URL を残す
記事を統合して URL が変わったときは、古い slug と新しい slug の対応をアプリの中に書いておきます。古い URL を開いた人は、新しい記事へ自動で転送されます。
教材(LAB)のデータ
このページのような教材やツールは「FUJIKAWA LAB」の作品として管理しています。記事より箱の数が多く、つながりも複雑です。
「公開する登録」と「作品としての台帳」は別
site_meta.py の STATIC_PAGES は、URL とテンプレートの対応を並べた「公開する登録」です。ここに書いたページが URL として登録され、サイトマップにも載ります。
一方 data/lab_catalog.json は、作品としてのタイトル・説明・種類・確認記録を並べた「台帳」です。
台帳の1件は、必ず登録の1件と path で対応します。登録にはあっても台帳にないページ(章ページや /start など)もあります。
作品番号は変えない
台帳の PK は number(標本番号)です。一度付けた番号は、内容を大きく書き直しても変えません。各ページには「SPECIMEN 番号 / 総数」の形で表示されます。
章に分かれた教材
複数の章ページから成る教材は、related_prefixes に URL の先頭部分を書いて、章ページを親の作品に結び付けます。章ページは、親の対象環境と確認記録を引き継ぎます。
確認記録と出典
教材には、対象とする環境と、公式情報と照合した日を記録します。照合していない教材は日付を空にしておき、ページには「未記録」と表示します。ツールやゲームは確認記録を持たないので、この線は「0か1つ」です。
検索用の設定は、LAB のページが持つ
LAB の作品ページと章ページ(合わせて67ページ)は、検索結果や SNS に出すタイトルと説明文を FUJIKAWA_LAB_PAGE_SEO に登録します。
表紙画像の URL と、画像の代わりに読み上げる説明文(代替テキスト)は、親の作品の「表紙の文言」から自動で補われます。LAB 以外のページ(/start など)は、この設定を持ちません。
生成して置くファイル
ER図の箱には、人が書くデータと、プログラムがデータから作るファイルがあります。作るファイルは、作り直すのを忘れると古いまま公開されます。
次の表は、元のデータから作られるファイルと、作られる時点をまとめたものです。「手元で生成」は、手元でコマンドを実行して作ったファイルを、変更として記録してから公開します。「表示のたび」は、読者が開くたびにアプリが作るので、作り直しの手間はありません。
| 作られるもの | 元のデータ | 作る道具 | 作られる時点 |
|---|---|---|---|
サイトマップ(sitemap.xml) | 記事・公開ページの登録・タグ | generate_sitemap.py | 手元で生成 |
AI 向けの案内(llms.txt) | 記事と本文・教材の台帳・検索用の設定 | generate_llms_txt.py | 手元で生成 |
| フォントの部分集合 | 記事・テンプレート・台帳で使う文字 | generate_fonts.py | 手元で生成 |
| 記事の表紙画像 | 記事の表紙の文字と最初のタグ | generate_og_images.py | 手元で生成 |
| 教材の表紙画像 | 表紙の文言・作品番号と総数 | generate_lab_og_images.py | 手元で生成 |
RSS フィード(/feed.xml) | 記事と本文 | app.py | 表示のたび |
| 記事一覧・タグのページ | 記事 | app.py | 表示のたび |
日本語のフォントは、全部の文字を含めると1ファイルが数 MB になります。このサイトでは実際に使っている文字だけを切り出して、読み込みを軽くしています。その代わり、新しい文字を含むページを足したら作り直しが必要です。
1件足すと動くもの
ER図の使い道の1つは、変更の影響範囲を先に数えられることです。線をたどると、1件の追加で触るファイルが分かります。
| 作業 | 記事を1本足す | 教材を1件足す |
|---|---|---|
| 人が書く | posts.json に1件、content/ に本文1ファイル | テンプレート1ファイル、STATIC_PAGES と台帳に1件ずつ、表紙の文言と図柄、検索用の設定 |
| 作り直す | サイトマップ、llms.txt、新しい文字があればフォント | サイトマップ、llms.txt、フォント |
| 表紙画像 | 全記事分を作り直す | 全作品分を作り直す |
| 手で合わせる | なし | 表紙の図柄を描く関数、テストが期待する総数、フォントの指紋(SHA-256) |
| 自動で変わる | 記事一覧、タグのページ、RSS、関連記事 | トップと LAB の作品一覧 |
1件足すと、表紙画像が全部変わる理由
記事の表紙には、新しい順で何番目かを示す番号が入っています。新しい記事が1本入ると、既存の記事はすべて1つずつ後ろにずれるので、全部の表紙を作り直すことになります。 教材の表紙には「SPECIMEN 番号 / 総数」が入っているため、1件足すと総数が変わり、やはり全部の表紙が変わります。
ER図で言えば、表紙画像の箱は1件のデータだけでなく「全体の件数」にもつながっている、ということです。図に描いてある線だけでなく、こうした隠れたつながりを見つけて書き添えておくと、図の価値が上がります。
壊れないための検査
データベースには、つながりが壊れないように守る仕組みがあります。ファイルで管理するこのサイトでは、その役目を自動テストが担っています。
データベースは、存在しない相手を指す FK を登録しようとすると拒否します。JSON ファイルにはその仕組みがないので、このサイトでは、変更を公開する前に自動テスト(プログラムの正しさを確かめるプログラム)を実行して、つながりの食い違いを見つけています。テストのファイルは21本あり、例えば次のことを確かめます。
- 台帳の作品番号が 1 から総数まで欠けなく並び、各作品が公開ページの登録にちょうど1回ずつあること
- 各教材ページに正しい「SPECIMEN 番号 / 総数」が表示され、表紙画像が作品数と同じ枚数あること
- 記事の表紙画像が、今の記事の情報から作られたものであること
- ページが読み込む外部のファイルが、サイトの安全設定(CSP:読み込んでよい外部の場所を限定する設定)で許可されていること
- すべての公開ページが表示でき、エラーにならないこと
変更を GitHub に送ると、GitHub 上でも同じテストが実行されます。ただし、このテストは公開を止める関門ではありません。Vercel は同時に新しい版を公開するので、公開と並行して行う確認という位置づけです。そのため、手元でテストを通してから送ることを決まりにしています。
テストが確かめる「総数」は、テストの中に数字で書いてあります。教材を1件足したら、この数字も手で1つ増やします。数字が合っていないとテストが失敗するので、足し忘れや登録漏れに気づけます。
自分のサイトで描く
自分のサイトやツールでも、同じ手順で ER図を描けます。データベースを使っていなくてもかまいません。
- 表を探す:同じ形の情報が並んでいるファイルや一覧を探します。JSON、CSV、スプレッドシートのシート、設定ファイルの中の一覧などです。
- PK を決める:各一覧で、1件を見分ける値を1つ選びます。ID、URL、ファイル名などです。
- FK を探す:別の一覧の PK と同じ値を持っている項目を探します。それが線になります。
- 線の端を決める:「相手は必ずいるか」「相手は1つか複数か」を両側から確かめて、記号を付けます。
- 作られるものを足す:データから自動で作られるファイルも箱として描き、「作り直しが要るか」を書き添えます。
AI に頼む場合は、ソースコードを読ませたうえで「データの置き場所ごとに箱を作り、各箱の主キーとほかの箱を指す項目を挙げて、Mermaid の erDiagram で書いて」と指示すると、下書きが得られます。Mermaid は、文字で書いた図の指定から図を描く道具です。件数やつながりは、実際のファイルで確かめてください。
描けたかどうかのチェックリスト
用語集
- ER図
- データの種類(エンティティ)と、そのつながり(リレーションシップ)を箱と線で表した図。
- エンティティ
- 図の箱1つ。記事、タグ、教材など、同じ形の情報の集まり。
- 主キー(PK)
- 箱の中で1件を見分けるための値。重複してはいけない。
- 外部キー(FK)
- 別の箱の主キーを指す値。線の元になる。
- 多対多
- 両側とも複数がつながる関係。記事とタグがこれに当たる。
- JSON
- データを文字で書くための決まった形式。
{ }と[ ]で項目と一覧を表す。 - テンプレート
- HTML の型。空欄にデータを流し込んでページを作る。
- サイトマップ
- サイト内のページの URL を並べたファイル。検索エンジンがページを見つけるのに使う。
- llms.txt
- AI 向けに、サイトの概要と主なページを文章でまとめたファイル。
- OG 画像
- SNS などでリンクを共有したときに表示される画像。