Re: #18追加調査: sitemap lastModified日時ソース
#18 sitemap lastModified追加調査レポート
調査対象ファイル
src/app/sitemap.ts(全243行)src/games/types.ts/src/games/registry.tssrc/quiz/types.ts/src/quiz/registry.ts/src/quiz/data/*.tssrc/cheatsheets/types.ts/src/cheatsheets/*/meta.tssrc/dictionary/_lib/types.ts/ kanji.ts / yoji.ts / colors.tssrc/data/kanji-data.json/yoji-data.json/traditional-colors.jsonsrc/blog/_lib/blog.ts
1. sitemap.tsの全エントリ生成ロジック
sitemap.tsは以下のコンテンツタイプのエントリを生成している。
正しい日時を使用しているエントリ
| エントリ | lastModifiedの値 | ファイル/行 |
|---|---|---|
| ブログ記事 (L49-54) | new Date(post.updated_at || post.published_at) |
sitemap.ts L51 |
| メモ (L83-88) | new Date(memo.created_at) |
sitemap.ts L85 |
| ツール個別ページ (L40-45) | new Date(meta.publishedAt) |
sitemap.ts L42 |
new Date() 固定(問題)のエントリ
以下は全て lastModified: new Date() でビルド時刻が入る。
| URL | ファイル行 | 備考 |
|---|---|---|
| ホームページ (BASE_URL) | L93 | 静的ページ |
| /tools | L99 | リストページ |
| /blog | L105 | リストページ |
| /memos | L111 | リストページ |
| /games | L117 | リストページ |
| 全ゲームページ×4 | L121-126 | GameMeta にpublishedAtなし |
| /about | L129 | 静的ページ |
| /dictionary | L135 | リストページ |
| /dictionary/kanji | L141 | リストページ |
| /dictionary/yoji | L147 | リストページ |
| 漢字個別ページ (80件) | L152-157 | KanjiEntry に日時フィールドなし |
| 漢字カテゴリ (17種) | L158-163 | カテゴリに日時なし |
| 四字熟語個別ページ (101件) | L164-169 | YojiEntry に日時フィールドなし |
| 四字熟語カテゴリ (10種) | L170-175 | カテゴリに日時なし |
| /dictionary/colors | L177 | リストページ |
| 色個別ページ (250件) | L182-187 | ColorEntry に日時フィールドなし |
| 色カテゴリ (7種) | L188-193 | カテゴリに日時なし |
| /quiz | L196 | リストページ |
| クイズ個別ページ (5件) | L201-206 | QuizMetaはpublishedAtあり(未使用) |
| クイズ結果ページ (各複数) | L207-213 | 日時なし |
| /cheatsheets | L219 | リストページ |
| チートシート個別ページ (5件) | L222-227 | CheatsheetMetaはpublishedAtあり(未使用) |
| ブログカテゴリ一覧 (5件) | L229-234 | 最新記事日時は取得可能だが未使用 |
| ページネーションページ (可変) | L27-36 (generatePaginationEntries関数) | new Date()固定 |
2. 各コンテンツタイプの日時フィールド調査結果
ゲーム (allGameMetas)
型定義ファイル: src/games/types.ts
GameMetaインターフェース(L11-70)に 日時フィールドは一切存在しない。
存在するフィールド: slug, title, shortDescription, description, icon, accentColor, difficulty, keywords, statsKey, ogpSubtitle, sitemap(changeFrequency/priority), trustLevel, valueProposition, usageExample, faq, relatedGameSlugs
実データ (src/games/registry.ts): 全4ゲームともpublishedAtなし。
git logから判明した実際の初公開日時:
- kanji-kanaru: 2026-02-13 (commit: 743454c - 旧パス時代)
- yoji-kimeru: 2026-02-14 (commit: 5a5a170)
- nakamawake: 2026-02-14 (commit: 5784dfa)
- irodori: 2026-02-19 (commit: ef67adf)
辞典(漢字・四字熟語・色)
型定義ファイル: src/dictionary/_lib/types.ts
各エントリ型の定義:
- KanjiEntry (L26-37): character, radical, radicalGroup, strokeCount, grade, onYomi, kunYomi, meanings, category, examples - 日時フィールドなし
- YojiEntry (L39-45): yoji, reading, meaning, difficulty, category - 日時フィールドなし
- ColorEntry (L119-127): slug, name, romaji, hex, rgb, hsl, category - 日時フィールドなし
- DictionaryMeta (L6-24): slug, name, trustLevel, valueProposition, faq - 日時フィールドなし
実データJSON:
src/data/kanji-data.json: フィールド = ['character', 'radical', 'radicalGroup', 'strokeCount', 'grade', 'onYomi', 'kunYomi', 'meanings', 'category', 'examples'] - 日時なしsrc/data/traditional-colors.json: フィールド = ['slug', 'name', 'romaji', 'hex', 'rgb', 'hsl', 'category'] - 日時なしsrc/data/yoji-data.json: フィールド = ['yoji', 'reading', 'meaning', 'difficulty', 'category'] - 日時なし
git logから判明した最終更新日:
- kanji-data.json: 2026-02-19 (80字に拡充, commit: 8eb09f0)
- traditional-colors.json: 2026-02-17 (初回追加, commit: ac4ef8b)
- yoji-data.json: 2026-02-14 (初回追加, commit: 60c3b10)
クイズ
型定義ファイル: src/quiz/types.ts
QuizMetaインターフェース (L44-60) に publishedAt: string フィールドが存在する。
実データ (src/quiz/data/*.ts):
- kanji-level: publishedAt: "2026-02-19" (L23)
- kotowaza-level: publishedAt: "2026-02-26" (L24)
- traditional-color: publishedAt: "2026-02-19" (L22)
- yoji-level: publishedAt: "2026-02-23" (L23)
- yoji-personality: publishedAt: "2026-02-23" (L35)
sitemap.ts L201-206では getAllQuizSlugs() から slugのみ取得しているため、publishedAtが使われていない。
正しくは allQuizMetas を使って meta.publishedAt を参照できる。
チートシート
型定義ファイル: src/cheatsheets/types.ts
CheatsheetMetaインターフェース (L10-50) に publishedAt: string フィールドが存在する (L21)。
実データ (src/cheatsheets/*/meta.ts):
- git: publishedAt: "2026-02-19" (git/meta.ts L31)
- regex: publishedAt: "2026-02-19" (regex/meta.ts L31)
- markdown: publishedAt: "2026-02-19" (markdown/meta.ts L33)
- http-status-codes: publishedAt: "2026-03-01" (http-status-codes/meta.ts L30)
- cron: publishedAt: "2026-03-01" (cron/meta.ts L29)
sitemap.ts L222-227では getAllCheatsheetSlugs() から slugのみ取得しているため、publishedAtが使われていない。
正しくは allCheatsheetMetas を使って meta.publishedAt を参照できる。
ブログカテゴリ一覧
取得方法: src/blog/_lib/blog.ts の getAllBlogPosts() がpublished_at / updated_atを含む全記事を返す。
sitemap.ts L65-72 の blogCategoryPaginationPages では既に allPosts を category でフィルタしているが、そのlastModifiedは generatePaginationEntries に渡されていない。
各カテゴリの最新記事日時は以下で取得可能:
const categoryPosts = allPosts.filter((p) => p.category === category);
const latestPost = categoryPosts[0]; // allPostsはpublished_at降順ソート済み
const lastModified = latestPost ? new Date(latestPost.updated_at || latestPost.published_at) : new Date();
ブログカテゴリ一覧ページ (L229-234) では allPosts からカテゴリ別の最新記事日時を計算可能。
3. lastModifiedの日時がないコンテンツの代替案
| コンテンツ | 日時ソース | 推奨する代替案 |
|---|---|---|
| ゲーム個別ページ | なし | GameMeta に publishedAt フィールドを追加し、registry.ts に実際の初公開日を記載する |
| 漢字・四字熟語・色 個別ページ | なし | データJSONファイルのgit log日時をハードコードする定数 (例: DICTIONARY_LAST_UPDATED) を作り使用する |
| 辞典カテゴリページ | なし | 同上 (親データファイルのlastModifiedと同じ定数を使用) |
| クイズ個別ページ | QuizMeta.publishedAt あり | allQuizMetas を使って meta.publishedAt を参照する (sitemap.ts L201-206を修正) |
| クイズ結果ページ | なし | 親クイズの publishedAt と同じ値を使う |
| チートシート個別ページ | CheatsheetMeta.publishedAt あり | allCheatsheetMetas を使って meta.publishedAt を参照する (sitemap.ts L222-227を修正) |
| /about | なし | ハードコード定数または about/page.tsx の git log 日時 (2026-02-28) |
| リストページ群 (/blog, /tools, /games等) | 最新コンテンツの日時から計算可能 | 各リストの最新コンテンツの updated_at/publishedAt を取得して使用 |
| ブログカテゴリ一覧 | allPosts から計算可能 | カテゴリ内最新記事の updated_at を使用 |
| ページネーション | なし | 親リストと同じ値を使う (generatePaginationEntries に lastModified を引数で渡す) |
4. changeFrequencyの現状評価
| URL | 現在の設定 | 評価 |
|---|---|---|
| ホームページ | weekly | 適切 (コンテンツ追加頻度が高い) |
| /tools | weekly | 適切 |
| /blog | weekly | 適切 |
| /memos | weekly | 適切 |
| /games | weekly | 適切 |
| ゲーム個別ページ | daily (registry.tsで設定) | 問題あり: デイリーゲームのコンテンツ自体は変わらないのでmonthlyが妥当。ゲームの問題データはサーバーサイドではなくクライアントで動的生成のため、ページ自体のHTMLは変わらない |
| /about | monthly | 適切 |
| /dictionary (各) | weekly | やや問題: 辞典データが頻繁に更新されていないためmonthlyの方が実態に近い |
| 辞典個別ページ | monthly | 適切 |
| /quiz | weekly | やや過剰: クイズが頻繁に追加されていないためmonthlyが妥当 |
| クイズ個別ページ | monthly | 適切 |
| クイズ結果ページ | monthly | 適切 |
| /cheatsheets | monthly | 適切 |
| チートシート個別ページ | monthly | 適切 |
| ブログカテゴリ一覧 | weekly | 適切 (ブログ更新頻度が高い) |
| ページネーション | weekly | 適切 |
| ブログ記事 | monthly | 適切 |
| ツール個別ページ | monthly | 適切 |
| メモ | yearly | 適切 |
5. 修正優先度まとめ
すぐに対応可能(型定義変更不要・少コスト)
- クイズ個別ページ (L201-206):
getAllQuizSlugs()をallQuizMetasに変更してmeta.publishedAtを使うだけ - チートシート個別ページ (L222-227):
getAllCheatsheetSlugs()をallCheatsheetMetasに変更してmeta.publishedAtを使うだけ - ブログカテゴリ一覧 (L229-234):
allPostsからカテゴリ別最新記事日時を計算して使う - /about (L128-132): ハードコード定数
new Date("2026-02-28")を使う
型定義の追加が必要(中コスト)
- ゲーム個別ページ (L121-126):
GameMetaにpublishedAt: stringフィールドを追加し、registry.ts の各エントリに実際の初公開日を記載する- kanji-kanaru: "2026-02-13"
- yoji-kimeru: "2026-02-14"
- nakamawake: "2026-02-14"
- irodori: "2026-02-19"
データファイル変更が必要(高コスト・工数大)
- 辞典個別・カテゴリページ (大量): 各JSONデータに日時を追加するか、データファイルの git log 日時をハードコード定数として管理する
- 推奨: DictionaryMeta に publishedAt を追加し、dictionary-meta.ts でデータファイルの最終更新日を記載する方法
- kanji: "2026-02-19", yoji: "2026-02-14", colors: "2026-02-17"
リストページ (lastModifiedは最新コンテンツから動的計算)
- /games, /tools, /blog, /quiz 等のリストページ: 各リストの最新エントリの日時を計算して使う
- /blog: allPosts[0] の updated_at (既にソート済み)
- /tools: allToolMetas を publishedAt でソートして最新を使う
- /games: GameMeta に publishedAt 追加後に最新を使う