6
課題整理
みてるぞ edited this page 2026-05-08 18:42:20 +09:00

タグ広場 今後の Gitea Issue 草案

  • レビュー日: 2026-04-27
  • 対象: btrc-hub-feature_317.zip 静的レビュー、仕様書、既存 Gitea issue dump
  • 注意: この環境では bundlenode_modules が無く、RSpec / frontend build は実行できていない。よって「コード上の疑い」と「実装提案」を含む。

優先度の目安

  • P0: 公開前に塞がないと危険
  • P1: 中核機能・データ整合性・運用上かなり重要
  • P2: 早めに直すべき改善・機能
  • P3: 余力で育てるゼロイチ・快適化

既存 issue 棚卸しメモ

  • #164 タグ検索機能作成#171 OR/NOT 検索 は、現ソースでは概ね実装済みに見える。close するか、残作業に title/body を更新する。
  • #165 管理者用別名タグ作成画面#169/#170 ユーザ一覧/詳細#137 設定画面反映#150 Wiki画像アップロード#151 Wiki検索自動補完#180 タグサイドバー見切れ#237 同定文字 はまだ有効な核として扱う。
  • bot操作 削減系は似た issue が多いので、バッチ仕様 issue に統合してから残タスクへ分解した方がよい。

Issue 草案一覧(90 件)

2. [P0] preview API の SSRF 対策を入れる

種別: security

対象

  • backend/app/controllers/preview_controller.rb
  • backend/lib/screenshot.js

背景 / 問題 /preview/title と /preview/thumbnail が任意 URL を外部取得している。private IP、localhost、メタデータ IP、file:// 相当、巨大レスポンス、リダイレクト経由を遮断しないと SSRF の入口になる。

完了条件

  • http/https 以外を拒否する
  • private / loopback / link-local / metadata IP を拒否する
  • DNS 解決後 IP でも検査する
  • リダイレクト先も検査する
  • サイズ上限・タイムアウト・content-type 検査を追加する
  • 異常時に内部例外メッセージを返さない

5. [P0] GET /users/me を query code 依存から current_user 依存に直す

種別: security / design

対象

  • backend/app/controllers/users_controller.rb
  • frontend/src/App.tsx
  • frontend/src/lib/api.ts

背景 / 問題 UsersController#me が params[:code] でユーザを探し、inheritance_code まで返している。認証ヘッダを使う設計と不一致で、コードが URL やログに載る導線を残している。

完了条件

  • GET /users/me は X-Transfer-Code 由来の current_user を使う
  • query param の code を廃止する
  • 返却に inheritance_code を含める必要があるか再検討する
  • フロントの取得処理を合わせる

6. [P0] 一覧・履歴・コメント系 API に limit 上限を設ける

種別: performance / security

対象

  • backend/app/controllers/posts_controller.rb
  • backend/app/controllers/tags_controller.rb
  • backend/app/controllers/nico_tags_controller.rb
  • backend/app/controllers/materials_controller.rb
  • backend/app/controllers/theatre_comments_controller.rb

背景 / 問題 複数 API が limit をほぼ無制限に受け付ける。小さいサイトでも、公開直後に巨大 limit 一発で DB と JSON 生成が詰まる。

完了条件

  • 全 index 系 API に MAX_LIMIT を設定する
  • 既定値・最大値を API 仕様に明記する
  • limit 過大時は clamp か 400 のどちらかに統一する
  • request spec を追加する

7. [P0] 外部 iframe / Markdown リンクに CSP と sandbox 方針を入れる

種別: security

対象

  • frontend/src/components/PostEmbed.tsx
  • frontend/src/components/WikiBody.tsx
  • backend/config/initializers/*

背景 / 問題 投稿埋め込みや Wiki Markdown は外部 URL と強く結びつく。公開するなら CSP、iframe sandbox、許可ドメイン、クリックジャック対策を明示しないと XSS 周辺の事故面積が広い。

完了条件

  • CSP を設定する
  • iframe sandbox 属性を設計する
  • 許可する埋め込み先を定義する
  • 未知サイト iframe は警告または opt-in にする

14. [P1] WikiHistoryPage の null user クラッシュを防ぐ

種別: bug

対象

  • frontend/src/pages/wiki/WikiHistoryPage.tsx
  • backend/app/controllers/wiki_pages_controller.rb

背景 / 問題 バックエンドは user が nil の履歴を返しうるが、フロントは change.user.id を直参照している。bot 操作や古い移行データで落ちる。

完了条件

  • user が nil の場合は「bot操作」等を表示する
  • 型定義を User | null にする
  • 回帰テストまたは Story を追加する

15. [P1] React Hooks の条件付き呼び出しを修正する

種別: bug / frontend

対象

  • frontend/src/pages/posts/PostHistoryPage.tsx
  • frontend/src/pages/wiki/WikiNewPage.tsx
  • frontend/src/pages/wiki/WikiEditPage.tsx

背景 / 問題 tagId ? useQuery(...) : ... のような条件付き hook と、権限分岐 return の前後で hook 数が変わる箇所がある。React の基本契約違反で、状態破壊の地雷。

完了条件

  • すべての hook を無条件に呼ぶ
  • enabled オプションで条件制御する
  • eslint-plugin-react-hooks を CI で必須化する

17. [P1] タグ補完の stale state バグを直す

種別: bug / UX

対象

  • frontend/src/components/TagSearch.tsx
  • frontend/src/components/common/TagInput.tsx
  • frontend/src/components/PostFormTagsArea.tsx

背景 / 問題 setSuggestions(data) の直後に古い suggestions.length を見て visible を決める箇所がある。初回補完が表示されない等の微妙な挙動になる。

完了条件

  • visible 判定を data.length で行う
  • 候補 0 件時の表示を統一する
  • タグ入力の手動テストケースを追加する

18. [P1] タグ名を URL に入れる箇所で encodeURIComponent を徹底する

種別: bug

対象

  • frontend/src/lib/tags.ts
  • frontend/src/components/TagLink.tsx
  • frontend/src/lib/prefetchers.ts
  • frontend/src/components/TopNav.tsx

背景 / 問題 fetchTagByName などでタグ名をそのまま URL に入れている。スラッシュ、空白、?、#、日本語正規化絡みで route が壊れる。

完了条件

  • タグ名 path segment は必ず encodeURIComponent する
  • サーバ側も decode 後の扱いを統一する
  • 特殊文字タグの request/frontend テストを追加する

19. [P1] TanStack Query key の id/name 衝突を分離する

種別: bug / frontend

対象

  • frontend/src/lib/queryKeys.ts
  • frontend/src/lib/tags.ts
  • frontend/src/lib/wiki.ts

背景 / 問題 tagsKeys.show が ID と名前の両方に使われている。名前が数字のタグや、Wiki の id/title でもキャッシュ衝突が起こりうる。

完了条件

  • showById と showByName の query key を分ける
  • Wiki も showById / showByTitle を分ける
  • prefetcher と各ページを追従させる

20. [P1] TagsController#index の count で Relation 全体をロードしない

種別: performance

対象

  • backend/app/controllers/tags_controller.rb

背景 / 問題 count に q.size を使うと、includes 済み relation のロード状況次第で全件メモリ展開になる。タグ数が増えるほど鈍い毒になる。

完了条件

  • count は q.except(:limit, :offset, :order).count 等にする
  • includes と count を分離する
  • 大量タグでの性能 spec または benchmark を残す

26. [P2] 投稿編集で URL とサムネイルを扱えるようにするか、非対応を UI に明記する

種別: feature / UX

対象

  • backend/app/controllers/posts_controller.rb
  • frontend/src/components/PostEditForm.tsx

背景 / 問題 投稿作成では URL/thumbnail を扱うが、更新では URL/thumbnail 更新がない。実運用ではリンク修正とサムネ更新が必ず出る。

完了条件

  • URL 更新可否を決める
  • thumbnail / thumbnail_base 更新可否を決める
  • 履歴に URL/thumbnail 変更を残す
  • UI の項目と API を一致させる

32. [P1] Material 更新時に file 未指定で既存ファイルを purge しない

種別: bug

対象

  • backend/app/controllers/materials_controller.rb

背景 / 問題 MaterialsController#update は file が無いと既存 file を purge する。タグ名や URL だけ編集したつもりでファイルが消える。

完了条件

  • file 未指定なら既存ファイル維持
  • 削除は remove_file=true 等の明示操作にする
  • URL-only / file-only / 両方ありの spec を追加する

33. [P2] Material 作成時の nil attach を避ける

種別: bug

対象

  • backend/app/controllers/materials_controller.rb

背景 / 問題 URL のみ素材でも material.file.attach(file) が呼ばれる。nil attach が環境差で例外化する可能性がある。

完了条件

  • file.present? の時だけ attach する
  • URL-only create の request spec を追加する

36. [P1] Theatre コメントに件数上限・長さ上限・削除を入れる

種別: moderation / performance

対象

  • backend/app/controllers/theatre_comments_controller.rb
  • backend/app/models/theatre_comment.rb
  • frontend/src/pages/theatres/TheatreDetailPage.tsx

背景 / 問題 コメント index は no_gt 以降を上限なしで返し、投稿内容の長さ制限も弱い。荒らしと巨大レスポンスに弱い。

完了条件

  • index に limit 上限を入れる
  • content 最大長を定義する
  • コメント削除/非表示 API を追加する
  • 削除履歴を残す

44. [P2] タグ統合 UI/API を作る

種別: feature

対象

  • backend/app/models/tag.rb
  • backend/app/controllers/tags_controller.rb
  • frontend/src/pages/tags/*

背景 / 問題 Tag.merge_tags! は存在するが、運用 UI/API がない。タグ整理基盤を名乗るなら、統合は中核作業になる。

完了条件

  • 統合元/統合先を確認する UI を作る
  • 影響投稿数・Wiki 有無・nico 制約を事前表示する
  • dry-run と実行を分ける
  • 統合履歴を残す

52. [P1] 御意見番フォームを実装する

種別: feature / ops

対象

  • frontend/src/pages/*
  • backend/app/controllers/*
  • backend/db/migrate

背景 / 問題 公開後の不具合報告導線として、操作ログ・画面 URL・環境情報・スクリーンショット添付を持つフォームが必要。単なる問い合わせより再現性を重視する。

完了条件

  • 意見テーブルを作る
  • URL/画面名/直前操作ログ/UA を保存する
  • スクリーンショット添付の有無を決める
  • 管理画面で一覧・対応済みにできる

57. [P1] アップロードファイルの content-type / サイズ制限を入れる

種別: security / ops

対象

  • backend/app/controllers/posts_controller.rb
  • backend/app/controllers/materials_controller.rb
  • backend/app/models/material.rb

背景 / 問題 thumbnail / material file は ActiveStorage に入るが、サイズや種類の上限が明確でない。R2/ストレージ費用と危険ファイル対策の両面で必要。

完了条件

  • 用途ごとの最大サイズを決める
  • 許可 MIME type を決める
  • 画像なら寸法上限も見る
  • エラーを UI に出す

59. [P2] フロントの role guard を共通化する

種別: frontend / refactor

対象

  • frontend/src/pages/wiki/WikiNewPage.tsx
  • frontend/src/pages/wiki/WikiEditPage.tsx
  • frontend/src/pages/tags/TagDetailPage.tsx
  • frontend/src/components/*

背景 / 問題 各ページで user?.role を直接見て分岐している。権限表示、hook 順序、guest 体験がばらつく。

完了条件

  • RequireRole コンポーネントまたは useCan helper を作る
  • server 権限と同じ表を使う
  • 権限不足時の表示を統一する

60. [P2] TypeScript の型を API 実態に合わせて null 許容を増やす

種別: bug / frontend

対象

  • frontend/src/types.ts
  • frontend/src/pages/*
  • frontend/src/components/*

背景 / 問題 uploadedUser / createdByUser / Wiki history user など、bot 操作や移行データで null になりうる値がある。型が嘘をつくと UI が落ちる。

完了条件

  • API レスポンスを洗い出す
  • null 許容型に直す
  • 表示側に fallback を入れる

65. [P3] preview API を OpenGraph / oEmbed 対応に寄せる

種別: feature

対象

  • backend/app/controllers/preview_controller.rb

背景 / 問題 現在は title と screenshot 中心の暫定実装。外部サイトごとのタイトル/サムネ取得は OG/oEmbed をまず見る方が安定する。

完了条件

  • og:title / og:image / twitter card を読む
  • 既知サイトの抽出器を追加できる構造にする
  • スクリーンショットは最後の手段にする

71. [P1] RSpec にセキュリティ回帰テスト群を追加する

種別: test

対象

  • backend/spec/requests/*

背景 / 問題 BAN、SSRF、権限、limit、system tag 保護は一度壊れると公開事故になる。仕様より spec で縛るべき。

完了条件

  • BAN/IP BAN spec
  • preview SSRF rejection spec
  • guest material create forbidden spec
  • system tag PATCH forbidden spec
  • limit clamp spec を追加する

73. [P3] Gemfile の未使用 gem を棚卸しする

種別: maintenance

対象

  • backend/Gemfile
  • backend/Gemfile.lock

背景 / 問題 jwt や gollum 等、現行コードで使っているか怪しい gem がある。依存は攻撃面積と更新負荷になる。

完了条件

  • 未使用 gem を rg で確認する
  • 不要なら削除する
  • 必要なら用途を README に書く

76. [P2] Post / Tag / Wiki の操作ログを共通 AuditLog に寄せる

種別: architecture / audit

対象

  • backend/app/models/*_version.rb
  • backend/app/controllers/*

背景 / 問題 各 version table は便利だが、管理画面で「このユーザが何をしたか」を横断表示するには共通ログが欲しい。

完了条件

  • AuditLog テーブルの要否を判断する
  • 対象種別・対象 ID・操作・ユーザ・IP を保存する
  • 管理画面で横断検索できる

86. [P3] Wiki 下書き保存を実装する

種別: feature / UX

対象

  • frontend/src/pages/wiki/WikiEditPage.tsx
  • backend/app/controllers/wiki_pages_controller.rb

背景 / 問題 Wiki 編集が長文化すると、ブラウザ落ちや競合で書きかけが消える。公開後の編集体験に効く。

完了条件

  • local draft と server draft のどちらにするか決める
  • ページ/ユーザ単位で下書きを保存する
  • 復元 UI を出す

88. [P2] WikiDiffPage の query 変更時再取得と key 不足を直す

種別: bug / frontend

対象

  • frontend/src/pages/wiki/WikiDiffPage.tsx

背景 / 問題 diff 取得 useEffect の依存配列が空で、id/from/to が変わっても再取得されない。map の key も不足している。

完了条件

  • 依存配列に id/from/to を入れる
  • diff 行に安定 key を付ける
  • ローディング/エラー状態を出す