[] Add custom 404 page, language fallback banner, and feedback widget to docs site#263
Conversation
There was a problem hiding this comment.
🍊 Orange Codens レビュー
全体的に PRD の要件を満たした実装になっています。最も注意すべき問題は「ごフィードバックありがとうございます。」という誤った敬語表現で、実装とテスト両方に存在します。また next/navigation(App Router)と next/router(Pages Router)の API 混在は、Nextra の Pages Router 環境では usePathname() が常に null を返す可能性があり、フィードバックの path が空文字になるリスクがあります。テスト面では非 2xx レスポンスのサイレント失敗ケースと UntranslatedBanner の非表示条件が未検証です。
🔒 セキュリティ: 今回の diff はドキュメント UI のみの追加であり、直接的な認証 bypass・SQL injection・SSRF 等の重大脆弱性は検出されませんでした。主なリスクは FeedbackWidget が未検証の path / version をサーバーに送信する点と、CSRF トークン不在による偽フィードバック送信の懸念です。いずれも現時点では中〜低リスクですが、/api/docs/feedback エンドポイント実装時にレート制限・入力検証・CSRF 対策を確実に組み込むことを強く推奨します。
🟡 medium: 4 / 🔵 low: 5 / ⚪ info: 1
その他の指摘 (10 件)
- 🟡 [medium]
docs/components/FeedbackWidget.tsx:47— 「ごフィードバック」は誤った敬語表現 (confidence: 0.95,code.typo.honorific_prefix) - 🟡 [medium]
docs/__tests__/components/FeedbackWidget.test.tsx:35— テストの期待値も誤った敬語「ごフィードバック」を使用 (confidence: 0.95,code.typo.honorific_prefix_test) - 🟡 [medium]
docs/components/FeedbackWidget.tsx:41— 非 2xx レスポンス時にボタンが disabled のまま復帰しない (confidence: 0.65,code.logic.feedback_silent_failure_ux) - 🟡 [medium]
docs/components/FeedbackWidget.tsx:29— ユーザー制御の path 値が未検証のまま POST ボディに送信される (confidence: 0.55,sec.sast.injection.path_traversal) - 🔵 [low]
docs/__tests__/components/FeedbackWidget.test.tsx:40— 非 2xx レスポンス(fetch 成功・ok=false)のケースがテストされていない (confidence: 0.90,maintainability.test.missing_non2xx_case) - 🔵 [low]
docs/__tests__/components/UntranslatedBanner.test.tsx:1—UntranslatedBannerのテストに「表示されないべきケース」の検証がない (confidence: 0.90,maintainability.test.untranslated_banner_no_show_condition) - 🔵 [low]
docs/components/UntranslatedBanner.tsx:22—role="status"のバナーに dismiss ボタンがあると支援技術で混乱する可能性 (confidence: 0.70,maintainability.a11y.role_status_dismiss) - 🔵 [low]
docs/components/FeedbackWidget.tsx:28— フィードバック POST にフルパスと version が含まれ、情報漏洩になり得る (confidence: 0.60,sec.sast.info.verbose_path_exposure) - 🔵 [low]
docs/components/UntranslatedBanner.tsx:18— locale / pageLang が文字列比較のみで使われており、型チェック外の値が将来的に XSS につながる可能性 (confidence: 0.45,sec.sast.xss.unsafe_locale) - ⚪ [info]
docs/theme.config.tsx:11— Next.js Pages Router と App Router の API を混在使用 (confidence: 0.80,maintainability.routing.mixed_router_apis)
head: c8ad4a6 | Orange Codens (P1)
There was a problem hiding this comment.
🍊 Orange Codens レビュー
全体として PRD の要件を概ね満たした実装ですが、「ごフィードバック」という敬語の誤字が本番コードとテスト両方に存在しており(blocker 相当のユーザー可視バグ)、早期修正が必要です。また usePathname(App Router)と useRouter(Pages Router)の混在は Nextra v2 環境では path が常に空文字になりうる実動作上の問題です。その他は低優先度の改善点です。
🔒 セキュリティ: このPRはフロントエンドのみのUI追加(404ページ・翻訳バナー・フィードバックウィジェット)であり、バックエンドロジックを含まないため重大な脆弱性は見当たりません。主な懸念は FeedbackWidget が path および version をクライアント側で検証せずPOSTボディに含める点(CWE-20)と、CSRF トークン未付与(CWE-352)です。いずれも /api/docs/feedback エンドポイントの実装次第で影響度が変わるため、サーバー側でも入力を検証・サニタイズする実装を合わせて確認することを推奨します。
🟡 medium: 2 / 🔵 low: 6
その他の指摘 (8 件)
- 🟡 [medium]
docs/__tests__/components/FeedbackWidget.test.tsx:36— テスト期待値も「ごフィードバック」の誤字を引き継いでいる (confidence: 0.95,code.typo.honorific_prefix_test) - 🟡 [medium]
docs/components/FeedbackWidget.tsx:38— fetch 失敗後もボタンが無効化されたままになる可能性がある (confidence: 0.70,code.logic.fetch_failure_no_ui_update) - 🔵 [low]
docs/__tests__/components/UntranslatedBanner.test.tsx:1— バナーが表示されないケース(locale が en 以外、pageLang が ja 以外)のテストが欠落 (confidence: 0.88,maintainability.test.missing_case) - 🔵 [low]
docs/theme.config.tsx:3—usePathname(App Router)とuseRouter(Pages Router)を混在させている (confidence: 0.82,maintainability.router_mixing) - 🔵 [low]
docs/components/UntranslatedBanner.tsx:23—role="status"のバナーに dismiss ボタンがある組み合わせはrole="alert"またはrole="region"の方が適切 (confidence: 0.75,code.accessibility.role_status_dismiss) - 🔵 [low]
docs/components/FeedbackWidget.tsx:55— 全スタイルがインラインで記述されており、テーマとの一貫性・保守性が低い (confidence: 0.65,maintainability.inline_style) - 🔵 [low]
docs/components/FeedbackWidget.tsx:26— フィードバック送信 fetch に CSRF 対策トークンが含まれていない (confidence: 0.50,sec.sast.authz.csrf_missing) - 🔵 [low]
docs/pages/404.mdx:9— 404 ページのリンク先が絶対パス/docsのみでオープンリダイレクトリスクは低いが、クエリパラメータ由来リダイレクトへの拡張に注意 (confidence: 0.30,sec.sast.xss.open_redirect)
前回 run からの未解決 finding: 2 件
head: ca59c9e | Orange Codens (P1)
…dget to docs site
There was a problem hiding this comment.
🍊 Orange Codens レビュー
全体的に実装は PRD の仕様に沿っており、コンポーネント構造も適切です。ただし ごフィードバック(外来語への誤った「ご」付け) がコンポーネントとテスト両方に存在しており修正が必要です。また docs/theme.config.tsx で App Router 用の usePathname(next/navigation)と Pages Router 用の useRouter(next/router)を混用しており、Nextra 環境によっては pathname が正しく取れないリスクがあります。テストは dismiss フローと silent failure を押さえている一方、バナー非表示条件や 役に立たなかった ボタンのカバレッジが不足しています。
🔒 セキュリティ: 今回の diff はドキュメントサイトへの UI 追加が中心であり、重篤な認証 bypass や SQL injection は存在しません。主なリスクは FeedbackWidget が受け取る path および version の入力値を検証・サニタイズせずにバックエンドへ送信している点(CWE-20)と、POST リクエストに CSRF 対策が施されていない点(CWE-352)です。/api/docs/feedback バックエンドの実装がこのリポジトリの diff には含まれないため、サーバー側の影響度は確定できませんが、フロントエンド側での入力検証を追加することで防御層を設けることを推奨します。
🟡 medium: 3 / 🔵 low: 7
その他の指摘 (10 件)
- 🟡 [medium]
docs/components/FeedbackWidget.tsx:48— 謝辞メッセージの誤字:「ごフィードバック」→「フィードバック」 (confidence: 0.95,code.typo.japanese_honorific) - 🟡 [medium]
docs/components/FeedbackWidget.tsx:18— fetch 失敗時にボタンが押せたままになり、ユーザーが何度も送信を試みられる (confidence: 0.75,code.logic.feedback_silent_failure_ux) - 🟡 [medium]
docs/components/FeedbackWidget.tsx:28— ユーザー制御のpath値をサニタイズせずにリクエストボディに含めている (confidence: 0.70,sec.sast.injection.path_traversal) - 🔵 [low]
docs/__tests__/components/UntranslatedBanner.test.tsx:1—UntranslatedBannerテストに「英語以外のロケールでは表示しない」ケースが欠落 (confidence: 0.90,maintainability.test.missing_negative_case_banner) - 🔵 [low]
docs/__tests__/components/FeedbackWidget.test.tsx:1—FeedbackWidgetテストに「役に立たなかった」ボタンのケースが欠落 (confidence: 0.90,maintainability.test.feedback_unhelpful_button) - 🔵 [low]
docs/theme.config.tsx:3—usePathname(App Router)とuseRouter(Pages Router)を同一コンポーネントで混用 (confidence: 0.80,code.router.mixed_navigation_hooks) - 🔵 [low]
docs/components/UntranslatedBanner.tsx:22—role="status"はライブリージョンであり、バナーにはrole="alert"かrole="region"の方が適切 (confidence: 0.70,code.a11y.role_status_banner) - 🔵 [low]
docs/components/FeedbackWidget.tsx:26— フィードバック POST に CSRF 対策トークンが含まれていない (confidence: 0.60,sec.sast.authz.missing_csrf) - 🔵 [low]
.github/workflows/helm.yml:31—--generate-nameフラグ削除によりリリース名が固定化 (confidence: 0.55,maintainability.helm.generate_name_removed) - 🔵 [low]
docs/theme.config.tsx:14— frontMatter から取得したversion値が未検証のまま子コンポーネントに渡される (confidence: 0.55,sec.sast.injection.log_injection)
head: 9695e63 | Orange Codens (P1)
# Conflicts: # .github/workflows/helm.yml # docs/theme.config.tsx
There was a problem hiding this comment.
🍊 Orange Codens レビュー
404・未翻訳バナー・フィードバックウィジェットの PRD 要件は概ね満たされていますが、theme.config.tsx で next/router と next/navigation のフック混在は実行時リスクが高く、修正を推奨します。コンポーネントテストは主要 happy path はあるものの、非 2xx HTTP 応答や negative case のカバレッジが不足しています。
🔒 セキュリティ: 本 PR の diff は静的 404 ページ、翻訳未対応バナー、フィードバックウィジェット、およびテーマ設定の配線のみで、バックエンド API 実装は含まれていません。FeedbackWidget の fetch は固定の相対 URL /api/docs/feedback へ JSON POST するクライアント側処理であり、SSRF・SQL/コマンドインジェクション・認可漏れ・暗号誤用・認証 bypass 等の論理的脆弱性は diff 上確認できませんでした。path は usePathname() 由来で DOM に描画されず、JSON.stringify 経由のため XSS 面も限定的です。
🟠 high: 1 / 🟡 medium: 1 / 🔵 low: 2 / ⚪ info: 1
その他の指摘 (4 件)
- 🟡 [medium]
docs/__tests__/components/FeedbackWidget.test.tsx:41— HTTP 非 2xx(reject 以外)のサイレント失敗が未テスト (confidence: 0.88,maintainability.test.missing_non2xx) - 🔵 [low]
docs/__tests__/components/FeedbackWidget.test.tsx:10— 「役に立たなかった」送信パスが未テスト (confidence: 0.85,maintainability.test.missing_helpful_false) - 🔵 [low]
docs/__tests__/components/UntranslatedBanner.test.tsx:5— バナー非表示条件のテストが不足 (confidence: 0.80,maintainability.test.missing_negative_case) - ⚪ [info]
docs/pages/404.mdx:9— 404 ページに検索への導線リンクがない (confidence: 0.55,maintainability.prd.search_link)
head: 86f5b5e | Orange Codens (P1)
|
|
||
| function DocsMain({ children }: { children: ReactNode }) { | ||
| const { frontMatter } = useConfig(); | ||
| const pathname = usePathname(); |
There was a problem hiding this comment.
🟠 [high] Pages Router と App Router のフックを混在させている
locale 取得に next/router の useRouter を使いながら、パス取得に next/navigation の usePathname を使っており、Next.js 標準のルーティングモデルでは同一ツリー内で併用できません。locale を next/router から取っている時点で Pages Router 前提と読め、usePathname() は実行時エラーになるか、常に null となり path が空文字になる恐れがあります。
該当箇所:
import { usePathname } from 'next/navigation';
import { useRouter } from 'next/router';
...
const pathname = usePathname();
const { locale } = useRouter();フィードバック POST の path が空になると、分析用途のデータ品質も損なわれます。
@@ -3,2 +3,1 @@
-import { usePathname } from 'next/navigation';
import { useRouter } from 'next/router';
@@ -12,3 +11,3 @@
const { frontMatter } = useConfig();
- const pathname = usePathname();
- const { locale } = useRouter();
+ const { asPath, locale } = useRouter();
@@ -25,1 +24,1 @@
- <FeedbackWidget path={pathname ?? ''} version={version} />
+ <FeedbackWidget path={asPath} version={version} />code.router.mixed_hooks | confidence: 0.82
Summary
Type of Change
Testing
Checklist
Task Goal
Target Repository
Corevice/open-gitAll work for this task belongs in this repository. Do the implementation inside this repository's directory in the workspace; do not search or edit other repositories unless this task explicitly requires a cross-repo change.
Context
The PRD requires: a 404 page with search link, a translation-missing banner for untranslated en pages that falls back to ja content, and an optional feedback widget (Was this helpful? Yes/No). These are self-contained UI additions that do not depend on a backend API — the feedback widget can POST to
/api/docs/feedbackbut must degrade gracefully when that endpoint is absent.Steps
open-git/docs/pages/404.mdxwith frontmattertitle: ページが見つかりません; body: heading, explanation, link back to/docshomepage, and a search encouragementopen-git/docs/components/UntranslatedBanner.tsx: a yellow info banner that reads 'このページはまだ日本語のみ提供されています。' with a dismiss button (useState); shown whenlocale === 'en'and page haslang: 'ja'frontmatteropen-git/docs/theme.config.tsxto add amainwrapper component that conditionally rendersUntranslatedBannerbased on Nextra'suseConfig()frontmatter + current localeopen-git/docs/components/FeedbackWidget.tsx: renders two buttons '役に立った' and '役に立たなかった'; on clickfetchesPOST /api/docs/feedbackwith{ path, helpful, version }; shows thank-you message on 2xx; shows silent failure (no error UI) on non-2xx; entire widget isaria-labeledopen-git/docs/theme.config.tsxmainwrapper to also renderFeedbackWidgetat bottom of each doc page, readingpathfromusePathname()andversionfromuseConfig().frontMatter.version ?? 'latest'open-git/docs/__tests__/components/UntranslatedBanner.test.tsx: render withlocale='en'; assert banner text is visible; click dismiss button; assert banner disappearsopen-git/docs/__tests__/components/FeedbackWidget.test.tsxChanges Made
I'll
inspect
the
existing
docs
setup
and
theme .config .tsxso
the
new
components
match
current
patterns
.
Creating
the
docs
files
from
scratch
since
the
folder
doesn't
exist
yet
.
Implemented
the
docs
UI
additions
for
the
404
page
,
unt
rans
lated
banner
,
feedback
widget
,
theme
wiring
,
and
tests
.
Created
files
docs/pages/404.mdx— 404 page withtitle: ページが見つかりません, explanation, link to/docs, and searchencouragement.
docs/components/UntranslatedBanner.tsx— Yellow info banner with dismiss state; shown whenlocale === 'en'andpageLang === 'ja '.docs/components/FeedbackWidget.tsx— Yes/No buttons (役に立った/役に立たなかった); POSTs to/api/docs/ feedback; thank-you on 2xx; silent failure otherwise;aria-labelon the widget.docs/theme.config.tsx—
DocsMainwrapper usesuseConfig(),useRouter(), andusePathname()to renderUntranslatedBannerandFeedbackWidgetaround pagecontent.
Tests — Component tests for banner dismiss and feedback submission/failure; Node test for 404 MD
X frontmatter and
/docslink.[PURPLE-MODIFIED-FILES]
docs/pages/404.mdx
docs/components/UntranslatedBanner
.tsx
docs/components/FeedbackWidget.tsx
docs/theme.config.tsx
docs/tests/components/UntranslatedBanner.test.tsx
docs/tests/components/FeedbackWidget.test.tsx
docs/__
tests
__/
pages
/not
-found
.test
.ts
[/
P
UR
P
LE
-M
OD
IFIED
-F
ILES
]
Task ID:
019f0d7d-8813-773c-947c-6f895c67cd2bGenerated by Purple Codens