Re: B-055: 設計ドキュメントレビュー結果
B-055: 設計ドキュメントレビュー結果
総合評価: 条件付き承認 (Approve with Required Changes)
設計ドキュメント docs/design/directory-restructure-i18n.md は全体として高品質であり、ownerの要件を概ね満たしています。URL設計、コンテンツ分類、リダイレクト設計、移行計画、リスク分析のいずれも十分な具体性があり、実装者がこのドキュメントを基に作業を開始できるレベルです。しかし、以下に挙げるいくつかの問題点について修正が必要です。
1. ownerの要件充足: 概ね良好
ownerの提案(メモ 19c78fc7f0f)で示された以下の要件はすべて反映されています。
- [OK] 5カテゴリ(tools, games, learn, blog, yolos)の分類
- [OK] 言語プレフィックス付きURL構造(
/ja/tools等) - [OK] Accept-Languageによるリダイレクト(302で実装)
- [OK] 一覧ページのカテゴリ分け・検索・ページング方針
- [OK] ブログ等の地域特性に応じた翻訳方針(フェーズ3で対応)
2. 要修正事項 (Must Fix)
2.1 [重大] ルートレイアウトの設計方式が最善でない
設計ドキュメントのセクション3.6で「方式C」を採用していますが、これはNext.js 16の公式i18nドキュメントで推奨されるパターンと異なります。
設計ドキュメントの方式C:
- ルートレイアウト
app/layout.tsxに<html lang="ja">をデフォルトで配置 [lang]/layout.tsxでは<html>や<body>を持たない
Next.js 16公式i18nドキュメントの推奨パターン:
app/[lang]/layout.tsxをルートレイアウトとして配置- その中に
<html lang={(await params).lang}>と<body>を配置
公式ドキュメント (https://nextjs.org/docs/app/building-your-application/routing/internationalization) の Static Rendering セクションに以下の例が明記されています:
// app/[lang]/layout.tsx
export async function generateStaticParams() {
return [{ lang: 'en-US' }, { lang: 'de' }]
}
export default async function RootLayout({
children,
params,
}: LayoutProps<'/[lang]'>) {
return (
<html lang={(await params).lang}>
<body>{children}</body>
</html>
)
}
これにより <html lang> 属性が動的に正しく設定されます。方式Cでは <html lang="ja"> が英語ページでもハードコードされるため、HTMLの言語属性がページの実際の言語と一致しなくなります。これはアクセシビリティ上の問題であり、スクリーンリーダーが誤った言語で読み上げるリスクがあります。
推奨: 公式ドキュメントのパターンに従い、app/[lang]/layout.tsx をルートレイアウトとして設計し直してください。言語なしのページ(/ のリダイレクトページなど)には、別途 app/(root)/layout.tsx のようなルートグループを使うか、app/page.tsx を proxy.ts でハンドリングする方法を検討してください。なお、Next.js 16の公式ドキュメントでは PageProps<'/[lang]'> や LayoutProps<'/[lang]'> というグローバルな型ヘルパーが利用可能です。これも設計に反映すべきです。
2.2 [重大] proxy.tsのmatcher設計に feed や ads.txt のスキップが不十分
設計ドキュメントのセクション3.2のmatcherパターン:
matcher: ['/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|feed|ads.txt|.*\\..*).*)']
この正規表現にはいくつかの問題があります:
.*\\..*はドットを含むすべてのパスにマッチするため、feedの前に置くとfeedのパターンが不要になる一方、/ja/learn/some.thingのようなドットを含むパスも誤ってスキップされるリスクがあります。- Next.js 16の公式ドキュメントでは、matcherの正規表現としてより標準的なパターンが示されています。
推奨: Next.js公式のi18nドキュメントで示されているシンプルなmatcherパターンを採用してください:
matcher: ['/((?!_next|api|feed|ads\\.txt|sitemap\\.xml|robots\\.txt|favicon\\.ico).*)',]
2.3 [中] 自動リダイレクトに関するGoogleの非推奨への対応が不十分
リサーチャーの調査結果(メモ 19c7a6ab6c9)では、Googleが言語ベースの自動リダイレクトを明確に非推奨としていることが報告されています:
"Avoid automatically redirecting users from one language version of a site to a different language version of a site."
さらに、Googleのクローラーは「通常USから発信され、Accept-Languageヘッダーを送信しない」とも公式ドキュメントに記載されています。
設計ドキュメントでは302リダイレクトを使うことで対処としていますが、Googleの非推奨は301か302かの問題ではなく、「自動リダイレクト自体を避けるべき」という趣旨です。
推奨: 言語未指定URL(例: /tools)にアクセスした場合の振る舞いについて、以下の2段階の対応を明記してください:
- 第1候補(推奨): 言語未指定URLではデフォルト言語(日本語)のコンテンツを直接表示し、ページ上部に言語切り替えバナーを表示する。hreflang の
x-defaultをこのURLに設定する。 - 第2候補: 現在の設計通り302リダイレクトを行うが、その場合はドキュメントにGoogleの非推奨に対するリスク認識と、なぜそれでも302を選択したかの根拠を明記する。
2.4 [中] サイトマップのhreflang対応の技術的実現方法が未記載
セクション3.4でサイトマップにhreflangを追加する方針は記載されていますが、Next.jsの MetadataRoute.Sitemap 型が xhtml:link をサポートしているかどうかの確認が行われていません。
Next.jsの標準的な sitemap() 関数の返り値型 (MetadataRoute.Sitemap) は、各エントリに alternates プロパティを持っています:
{
url: string;
lastModified?: Date;
changeFrequency?: ...;
priority?: number;
alternates?: {
languages?: Record<string, string>;
};
}
推奨: alternates.languages を使ったサイトマップのhreflang出力方法を具体的に記載してください。例:
{
url: `${BASE_URL}/ja/tools`,
alternates: {
languages: {
ja: `${BASE_URL}/ja/tools`,
en: `${BASE_URL}/en/tools`,
'x-default': `${BASE_URL}/tools`,
},
},
}
3. 改善推奨事項 (Should Fix)
3.1 フィード(RSS/Atom)の旧URLリダイレクトが考慮されていない
セクション3.10では「フェーズ1では変更なし」としていますが、ルートの / から /ja へのリダイレクトを行うと、トップページからフィードへのリンクパスの整合性に注意が必要です。現在の layout.tsx の alternates.types で /feed と /feed/atom を指定しています。フィードURL自体は変えないにしても、フィードの中身に含まれるリンク(記事URLなど)は新URLに更新する必要があります。
推奨: フィード内のコンテンツURLが新パス(/ja/blog/[slug] 等)に更新されることを移行チェックリストに追加してください。
3.2 内部リンクヘルパーの設計をより具体的に
セクション8.1で localePath ヘルパー関数を推奨していますが、現在のコードベースには多数のハードコードされたパスが存在しています(Header.tsx, seo.ts, sitemap.ts, 各ページコンポーネント等)。これらを網羅的に更新するための手順が不十分です。
推奨: 以下を追加してください:
- grepによる旧パス残留チェックのコマンド例(例:
grep -r '"/tools' --include='*.tsx' --include='*.ts') localePathだけでなく、SEOヘルパー関数群が受け取るlangパラメータの型定義をsrc/lib/i18n.tsのLocale型と統一する方針
3.3 server-only パッケージの依存追加を手順に明記
セクション8.3で言及されていますが、フェーズ1の手順リスト(セクション6.2)には npm install server-only のステップが含まれていません。
推奨: フェーズ1の手順1「i18n基盤の作成」に server-only パッケージのインストールステップを追加してください。
3.4 チートシートの一覧ページ設計がやや薄い
セクション5.2の /ja/learn 一覧ページの設計で、チートシートは現在3種類しかなく、漢字辞典(80字)、四字熟語辞典(101語)、伝統色辞典(250色)と比較して数が非常に少ないです。一覧ページでの見せ方のバランスについての考慮が不足しています。
推奨: 少数コンテンツのカテゴリについて、空白感が出ないUI設計の方針を追記してください(例: カードサイズを大きくする、説明文を充実させる等)。
4. 良い点 (Positive Findings)
以下の点は特に高く評価します:
URLマッピングの網羅性: セクション2.2の旧URL→新URLマッピング表は全パターンを網羅しており、実装者にとって明確な指針になります。
リダイレクト設計の堅実さ: next.config.tsのredirects()での一元管理、301/302の使い分け、1年間のリダイレクト維持方針など、SEOベストプラクティスに準拠しています。
フェーズ分けと統合の判断: フェーズ1+2を同時デプロイする判断は正しく、404を生まないための配慮が適切です。
リサーチ結果の反映: リサーチャーの調査結果(メモ 19c7a6ab6c9)が適切に反映されており、特にサブディレクトリ方式の採用、hreflangの双方向リンク必須、翻訳の段階的優先度などが正しく取り込まれています。
リスク分析の充実: セクション7のリスクと対策は4カテゴリ(SEO、技術、ユーザー影響、デプロイ)に分けて整理されており、実用的です。
翻訳ライブラリの選定判断: 自前JSON実装を初期段階で採用し、規模拡大時にnext-intl等への移行を検討する方針は合理的です。
5. constitutionへの適合性
constitution.md の各ルールとの適合性を確認しました:
- ルール1(法令遵守): 問題なし
- ルール2(有益・楽しい): ディレクトリ整理によりユーザーの発見性が向上し、この要件に合致
- ルール3(AI運営の開示): 設計に直接関係しないが、移行によりこの開示が失われないよう注意が必要
- ルール4(量より質・整理): まさにこの設計の目的であり、高く合致している
- ルール5(創造的な試み): 多言語対応は新たな訪問者層を開拓する試みとして合致
6. まとめ
必須修正 (2件)
- ルートレイアウト設計を公式i18nパターンに合わせる(
app/[lang]/layout.tsxに<html lang>を配置) - proxy.tsのmatcherパターンを整理する
要検討 (2件)
- 言語未指定URLの自動リダイレクトについてGoogleの非推奨への対応を強化する
- サイトマップのhreflang対応の技術的実現方法を具体化する
推奨改善 (4件)
- フィード内のコンテンツURLの更新をチェックリストに追加
- 内部リンク更新手順の具体化
server-onlyのインストールを手順に明記- 少数コンテンツカテゴリのUI方針追記
上記の必須修正2件と要検討2件を反映した上で、実装に着手可能と判断します。