From 3946724d3d25333ce24f1e23a615feffb1fe35a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=BF=E3=81=A6=E3=82=8B=E3=81=9E?= Date: Thu, 11 Jun 2026 21:06:06 +0900 Subject: [PATCH] =?UTF-8?q?=E5=AE=9F=E8=A3=85=E8=AA=AC=E6=98=8E=E6=9B=B8?= =?UTF-8?q?=20=E3=82=92=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...%9F%E8%A3%85%E8%AA%AC%E6%98%8E%E6%9B%B8.md | 653 ++++++++++++++---- 1 file changed, 501 insertions(+), 152 deletions(-) diff --git a/%E5%AE%9F%E8%A3%85%E8%AA%AC%E6%98%8E%E6%9B%B8.md b/%E5%AE%9F%E8%A3%85%E8%AA%AC%E6%98%8E%E6%9B%B8.md index 3be7aab..50307b2 100644 --- a/%E5%AE%9F%E8%A3%85%E8%AA%AC%E6%98%8E%E6%9B%B8.md +++ b/%E5%AE%9F%E8%A3%85%E8%AA%AC%E6%98%8E%E6%9B%B8.md @@ -1,6 +1,6 @@ --- title: 'BTRC Hub / タグ広場 現行実装仕様書' -subtitle: 'btrc-hub-main.zip / btrc-hub.wiki.zip / 2026-04-25 旧本番DBダンプ確認版' +subtitle: 'ソース / Wiki / 旧本番DB / 開発者ヒアリング / Gitea 課題一覧 反映版' date: '2026-06-11' lang: ja-JP toc: true @@ -10,9 +10,9 @@ numbersections: true # 本書の位置づけ -本書は、添付された `btrc-hub-main.zip` の現行ソース、`btrc-hub.wiki.zip` の Wiki、`btrc_hub_20260425時点本番DBデータ.zip` の旧本番 DB ダンプ、既存仕様書 `BTRC_Hub_現行実装仕様書_2026-05-10_ヒアリング反映版.md` を確認し、2026-06-11 時点のタグ広場の実装事実を再構成した仕様書である。 +本書は、添付された `btrc-hub-main.zip` の現行ソース、`btrc-hub.wiki.zip` の Wiki、`btrc_hub_20260425時点本番DBデータ.zip` の旧本番 DB ダンプ、既存仕様書 `BTRC_Hub_現行実装仕様書_2026-05-10_ヒアリング反映版.md`、開発者ヒアリング回答、添付 Gitea 課題一覧 JSON を確認し、2026-06-11 時点のタグ広場の実装事実と確定意図を再構成した仕様書である。 -本書は願望ではなく、まずコード・スキーマ・画面・テストに現れてゐる事実を書く。未確定の設計意図は `開発者ヒアリング` として分離し、回答後に仕様へ反映する。 +本書は願望ではなく、まずコード・スキーマ・画面・テストに現れてゐる事実を書く。その上で、開発者ヒアリング回答を仕様決定として本文へ反映する。実装が仕様決定に追いついてゐない箇所は `仕様決定済み・実装未反映` として明示する。 ## 確認対象 @@ -23,7 +23,7 @@ numbersections: true | Wiki | 開発 Wiki、テーブル定義書、環境構築手順 | | DB | 2026-04-25 旧本番 DB SQL ダンプ。現行 schema との差分あり | | 既存仕様 | 2026-05-10 版仕様書 | -| 課題一覧 | Gitea API 取得を試行したが、この実行環境では取得失敗。未反映 | +| 課題一覧 | 添付 Gitea issue JSON 50 件。全件 open。P1/P2/P3・status・area・type を集計して反映 | ## 表記ルール @@ -33,7 +33,27 @@ numbersections: true | 実装あり・UI薄い | API/モデルはあるが画面導線が弱い、または管理導線が薄い | | 未実装・残骸候補 | スキーマだけある、または途中の設計痕跡はあるが呼び出し実装が薄いもの | | 注意 | 仕様として固定するには危険な実装差・不整合・セキュリティ上の穴 | -| 開発者ヒアリング | コードだけでは判断不能。開発者確認が必要な事項 | +| 開発者ヒアリング | コードだけでは判断不能だったが、開発者回答により仕様確定した事項 | + +## 本版で確定した設計判断 + +開発者ヒアリングにより、次を仕様として確定する。 + +| ID | 決定事項 | 実装状態 | +| --- | --- | --- | +| H-001 | タグ親子関係は member 以上が編集可能。UI の親タグ欄は全員に表示し、変更操作は member 以上に限る。D&D だけ admin 専用だったのは履歴管理前の安全策であり、恒久方針ではない | 一部未反映。`TagChildrenController` は admin 限定のまま | +| H-002 | 素材作成は member 以上を原則とする。URL-only 素材だけ guest 許可の余地あり。file 素材は storage 圧迫防止のため guest 不可 | 未反映。現行 `POST /materials` は current_user のみ | +| H-003 | 初回閲覧で guest user を作る単純設計は継続。ただし bot/cookie なしアクセス対策は未定 | 現行通り。ただし users 肥大化が残る | +| H-004 | 投稿履歴には親投稿変更を必ず表示する。API は `parent_posts: [{ id, title }]` を返し、表示は現在 title に加へて当時 title を注記する方向 | 未反映。API が返してゐない | +| H-005 | 素材履歴は必要。snapshot 対象は tag、URL、file blob、更新者。parent は廃止予定 | テーブルあり、実装薄い | +| H-006 | Wiki asset は Wiki 内画像/添付として実装予定。`wiki_pages.next_asset_no` と連動し、バイト列 SHA256 をキー情報に使ふ | テーブルあり、導線未確認 | +| H-007 | Gekanator は恒久 admin 専用ではない。管理者側で学習・調整後、一般ユーザ向けに公表する | 現行は admin 専用 | +| H-008 | Gekanator AI は質問分類だけでなく、既存投稿への回答補完まで行ふ。初期モデルは低コスト structured output 対応モデルを環境変数で差し替へる | converter 未実装 | +| H-009 | 上映会 host 制御は、本来サーバ側で担ふ方向。現行の active watching user 自動 host は暫定色が強い | 現行は自動 host | +| H-010 | Preview API は guest 利用を直ちに禁止はしない。ただし private IP 拒否、redirect 検査、content length 上限等は必須。クリーンに守れないなら機能廃止も検討 | 未反映 | +| H-011 | issue は全件共有が望ましい。今回は添付 JSON 50 件を反映する | 反映済み | + +この表と本文が衝突する場合、本文の「確定仕様」節を優先する。現行実装との差分は、修正対象であって仕様の揺れではない。 ## 用語: 公開と公表 @@ -168,6 +188,7 @@ cd frontend && npm run test:run && npm run build && npm run lint | `/tos` | 利用規約 | | `/more` | その他 | + # 認証・ユーザ・BAN ## 認証方式 @@ -188,16 +209,50 @@ cd frontend && npm run test:run && npm run build && npm run lint 3. 無効またはコードなしなら `POST /users` で guest ユーザを作成。 4. 新規作成された `inheritance_code` を localStorage へ保存。 +## 確定仕様: guest 自動作成 + +初回閲覧で guest user を作る仕様は継続する。理由は、仕様分岐を増やさず単純に保つためである。 + +ただし、旧本番 DB で `users = 42805` 件あるため、bot または cookie/localStorage を保持しないアクセスにより users が肥大化してゐる可能性は高い。これは仕様として許容されたわけではなく、未決定の運用リスクである。 + +### bot / cookie なしアクセスへの推奨方針 + +現時点では次を推奨仕様とする。 + +| 層 | 方針 | +| --- | --- | +| フロント | localStorage が使へない環境では編集系 UI を出さず、`POST /users` を連打しない | +| API | `POST /users` に IP 単位・UA 単位の軽い rate limit を置く | +| DB | `users` に `last_seen_at`, `created_ip_address_id`, `user_agent_hash` の追加を検討する | +| 運用 | 一定期間一度も編集/投票/コメントしてゐない guest を掃除できる Rake task を用意する | +| bot 対策 | 明確な bot UA は user を作らず 403/204 に寄せる。検索エンジン等に guest ID を発行しない | + +初回閲覧 guest 自動作成を維持するなら、最低限 `POST /users` の rate limit と掃除 task は必要である。ここを放置すると、BAN・分析・バックアップが砂嵐になる。 + ## ロール | role | 意味 | | --- | --- | -| `guest` | 自動生成される通常閲覧者。閲覧中心 | +| `guest` | 自動生成される通常閲覧者。閲覧、閲覧済み、上映会在席、コメント、skip 投票など軽い参加行為の主体 | | `member` | 投稿・タグ・Wiki・素材等の編集者 | -| `admin` | 管理者。Gekanator、タグ親子 API 等も利用可能 | +| `admin` | 管理者。管理者専用調整機能や未公開ツールを利用可能 | `User#gte_member?` は `member` または `admin` を許可する。 +## 権限原則 + +| 操作 | 権限 | +| --- | --- | +| 投稿作成/更新 | member+ | +| タグ編集 | member+ | +| タグ親子編集 | member+。現行の D&D/admin 限定は暫定 | +| Wiki 作成/更新 | member+ | +| 素材作成 | member+。URL-only guest 許可は将来検討 | +| file 素材作成 | member+ 必須 | +| Gekanator 調整 | admin | +| Gekanator 公開プレイ | 将来 public 化予定 | +| Preview API | public/guest 相当を維持する可能性あり。ただし SSRF 対策必須 | + ## BAN `ApplicationController` の `before_action` は次の順序で動く。 @@ -217,7 +272,7 @@ IP は `IPAddr.new(request.remote_ip).hton` により binary 化して `ip_addre ### 注意 -`users.inheritance_code` はモデル上必須・64文字以内だが、現行 schema では一意 index が見当たらない。UUID なので衝突可能性は低いが、認証トークンに DB 一意制約がないのは設計として弱い。 +`users.inheritance_code` はモデル上必須・64文字以内だが、現行 schema では一意 index が見当たらない。UUID なので衝突可能性は低いが、認証トークンに DB 一意制約がないのは設計として弱い。DB 一意 index を追加すべきである。 # エラー応答 @@ -386,6 +441,7 @@ IP は `IPAddr.new(request.remote_ip).hton` により binary 化して `ip_addre `updated_at` sort は、投稿本体の `updated_at` と `post_tags.updated_at` の最大値を使ふ。 + ## 投稿履歴 `post_versions` は immutable snapshot である。 @@ -396,7 +452,7 @@ IP は `IPAddr.new(request.remote_ip).hton` により binary 化して `ip_addre | `version_no` | 投稿内連番 | | `event_type` | `create`, `update`, `discard`, `restore` | | `title`, `url`, `thumbnail_base` | 投稿本体 | -| `tags` | タグ名の空白区切り snapshot | +| `tags` | タグ名の空白区切り snapshot。将来 `tags_json` へ移行予定 | | `parent_post_ids` | 親投稿 ID の空白区切り snapshot | | `original_created_from/before` | 元日時範囲 | | `created_by_user_id` | 操作者 | @@ -408,9 +464,45 @@ IP は `IPAddr.new(request.remote_ip).hton` により binary 化して `ip_addre - 同一 snapshot の update は版を増やさない。 - 作成後、対象 record の `version_no` を更新する。 -### 注意: frontend 型と API のズレ +## 確定仕様: 親投稿変更履歴 -フロント `PostVersion` 型には `parentPosts` がある。しかし現行 `PostVersionsController#index` は `parent_post_ids` を select/serialize しておらず、`parentPosts` を返してゐない。これは履歴 UI の仕様不整合である。親投稿変更履歴を画面に出すつもりなら、API 実装が不足してゐる。 +投稿履歴画面では、親投稿の追加・削除を必ず表示する。現行 API が返してゐないのはバグである。 + +`GET /posts/versions` は各 version に少なくとも次を返すべきである。 + +```ts +parentPosts: Array<{ + id: number + title: string | null + historicalTitle?: string | null +}> +``` + +API の snake_case 原型は次を想定する。 + +```json +{ + "parent_posts": [ + { + "id": 123, + "title": "現在のタイトル", + "historical_title": "履歴作成当時のタイトル" + } + ] +} +``` + +表示仕様: + +- 通常表示は現在 title を使ふ。 +- 当時 title が現在 title と異なる場合、`(当時タイトル:{historical_title})` を付記する。 +- 対象投稿が削除済みまたは参照不能なら、`#123(現在参照不可)` のやぅに ID を残す。 + +タグ履歴についても同様に、現在名だけでなく当時の名前・カテゴリを表示できる形が望ましい。添付 issue #354 により、`post_versions.tags_json` を作り、旧 `post_versions.tags` を廃止する方向が課題化されてゐる。 + +### 実装差分 + +フロント `PostVersion` 型には `parentPosts` がある。しかし現行 `PostVersionsController#index` は `parent_post_ids` を select/serialize しておらず、`parentPosts` を返してゐない。これは仕様決定済みの実装バグである。 # タグ仕様 @@ -490,6 +582,7 @@ IP は `IPAddr.new(request.remote_ip).hton` により binary 化して `ip_addre タグ詳細の full update では、名称変更時に旧名が aliases に追加される。 + ## タグ親子 `tag_implications` は子タグから親タグへの関係を表す。 @@ -503,11 +596,27 @@ IP は `IPAddr.new(request.remote_ip).hton` により binary 化して `ip_addre - 自己親は禁止。 - 投稿側では、付与タグの親タグが再帰的に展開される。 -### 注意: 権限仕様が二重化してゐる +## 確定仕様: タグ親子編集権限 -`TagChildrenController` の親子追加/削除 API は admin 限定である。一方、`TagsController#update_all` は member 以上で `parent_tags` を更新できる。つまり、API とタグ編集フォームの設計意図がズレてゐる可能性が高い。 +タグ親子関係の編集は **member 以上** が可能である。 -ここは仕様として固定する前に開発者ヒアリングが必要である。 +UI 仕様: + +| ユーザ | 親タグ欄の表示 | 変更 | +| --- | --- | --- | +| guest | 表示する | 不可 | +| member | 表示する | 可 | +| admin | 表示する | 可 | + +現行の D&D 操作が admin 限定だった理由は、履歴管理がなかった時期に誤操作を避けるための安全策である。現在は履歴管理があるため、admin 限定を続ける必然性は薄い。 + +### 実装差分 + +`TagChildrenController` の親子追加/削除 API は admin 限定である。一方、`TagsController#update_all` は member 以上で `parent_tags` を更新できる。正しい仕様は member+ なので、専用 API 側の権限を揃へる必要がある。 + +### 追加制約 + +添付 issue #332 により、上位タグの循環登録禁止が P1 バグとして課題化されてゐる。タグ親子編集を member+ に開くなら、循環検出は必須である。 ## タグ一覧/検索 @@ -709,9 +818,33 @@ content revision 同士のみ差分対象。 `Wiki::Commit.redirect!` は現行では `raise '廃止しました.'` で無効化されてゐる。ただし schema と controller には redirect revision の痕跡がある。 -## 注意: wiki_assets -`wiki_assets` テーブルは schema に存在するが、現行ソースで明確な model/controller/画面導線は確認できない。Wiki 内画像/添付の将来設計または残骸候補である。 +## Wiki asset + +`wiki_assets` は Wiki 内画像/添付ファイルのための将来機能である。 + +確定仕様: + +- Wiki ページ内に画像または添付ファイルを持たせる。 +- `wiki_pages.next_asset_no` と連動し、ページ内 asset 番号を採番する。 +- `wiki_assets.sha256` は添付バイト列を SHA256 に通した値を保持する。 +- 同一バイト列の重複検出・再利用・整合性確認に `sha256` を使ふ。 +- 本体保存は Active Storage を前提にする。 + +推奨カラム意味: + +| カラム | 意味 | +| --- | --- | +| `wiki_page_id` | 所属 Wiki ページ | +| `no` | ページ内 asset 番号 | +| `sha256` | 添付バイト列の SHA256 | +| `filename` | 表示/ダウンロード用ファイル名 | +| `content_type` | MIME type | +| `byte_size` | サイズ | +| `created_by_user_id` | 追加者 | + +現行ソースでは明確な model/controller/画面導線は確認できない。したがって、schema は将来機能として正当化されたが、実装は未完である。 + # 素材仕様 @@ -724,7 +857,7 @@ content revision 同士のみ差分対象。 | `tag_id` | 必須・一意 | | `url` | 任意。file がなければ必須 | | `file` | Active Storage 添付。url がなければ必須 | -| `parent_id` | 親素材。任意 | +| `parent_id` | 親素材。任意だが廃止予定 | | `created_by_user_id` | 作成者 | | `updated_by_user_id` | 更新者 | | `discarded_at` | 論理削除 | @@ -735,25 +868,67 @@ content revision 同士のみ差分対象。 素材に紐づくタグは `character` または `material` カテゴリでなければならない。 -注意: バリデーション文言は「素材カテゴリのタグ」と言ってゐるが、実装上は `character` も許可してゐる。 +注意: バリデーション文言は「素材カテゴリのタグ」と言ってゐるが、実装上は `character` も許可してゐる。仕様としては **character も素材を持てる** で確定し、文言を直すべきである。 ## API -| API | 権限 | 内容 | -| --- | --- | --- | -| `GET /materials` | public | 素材一覧 | -| `GET /materials/:id` | public | 素材詳細。関連 Wiki 本文も返す | -| `POST /materials` | current_user 必須 | 素材作成 | -| `PUT/PATCH /materials/:id` | member+ | 素材更新 | -| `DELETE /materials/:id` | member+ | 論理削除 | +| API | 現行権限 | 確定仕様 | 内容 | +| --- | --- | --- | --- | +| `GET /materials` | public | public | 素材一覧 | +| `GET /materials/:id` | public | public | 素材詳細。関連 Wiki 本文も返す | +| `POST /materials` | current_user 必須 | member+ | 素材作成 | +| `PUT/PATCH /materials/:id` | member+ | member+ | 素材更新 | +| `DELETE /materials/:id` | member+ | member+ | 論理削除 | -### 注意: 作成権限が緩い +## 確定仕様: 素材作成権限 -`POST /materials` は `current_user` があれば通る。フロントは初回訪問者に guest を自動作成するため、実質的に guest でも素材作成可能である。`docs/roadmap.md` にも `Tighten material creation permission` があるため、ここは既知の弱点と見るべきである。 +素材作成は member 以上を原則とする。現行の guest 作成可能状態は設計意図ではなく実装バグとして扱ふ。 -### 注意: material_versions +ただし、URL-only 素材については guest への開放余地がある。理由は、file 付き素材と違ひ、オブジェクト・ストレージを直接圧迫しないためである。 + +推奨仕様: + +| 入力 | guest | member+ | 理由 | +| --- | --- | --- | --- | +| URL-only | 将来検討 | 可 | storage 圧迫がない。荒らし URL への moderation は別途必要 | +| file-only | 不可 | 可 | storage 圧迫・危険ファイル・著作権対応が重い | +| URL + file | 不可 | 可 | file を含むため member+ | + +現時点では単純に `POST /materials` を member+ へ制限するのが最優先である。URL-only guest 開放は、rate limit、通報/削除導線、URL preview の安全化後に検討する。 + +## 確定仕様: material_versions + +`material_versions` は必要なテーブルであり、残骸ではない。素材にも履歴を持たせる。 + +snapshot 対象: + +| 対象 | 必要性 | +| --- | --- | +| tag | 素材が何に紐づいてゐたかを復元するため必要 | +| URL | URL-only / 参照先変更履歴として必要 | +| file blob | 添付ファイル差替え履歴として必要 | +| 更新者 | 誰が変更したかを追跡するため必要 | +| parent | 廃止予定のため新仕様では対象外 | + +推奨 `material_versions` 返却形: + +```ts +interface MaterialVersion { + id: number + materialId: number + versionNo: number + eventType: 'create' | 'update' | 'discard' | 'restore' + tag: { id: number, name: string | null, category: string | null } | null + url: string | null + fileBlobId: number | null + fileUrl: string | null + createdByUser: { id: number, name: string | null } | null + createdAt: string +} +``` + +添付 issue #306 にも `material_versions` 実装が明記されてゐる。素材管理は UI だけでなく履歴まで含めて完了とみなすべきである。 -`material_versions` テーブルは schema にあるが、現行ソースで MaterialVersion model / recorder / controller 利用は確認できない。素材履歴は未実装または残骸候補である。 # 上映会仕様 @@ -788,13 +963,28 @@ content revision 同士のみ差分対象。 - `watching_users` - `skip_vote` -### 注意 +## 確定仕様: host 制御の方向性 -ホスト選出はかなり自動的で、悪意あるユーザが active host になる余地がある。公表後に荒らし耐性を考へるなら、host 権限の条件を仕様化する必要がある。 +現行の active watching user から自動で host を選ぶ仕様は暫定である。開発者意図としては、上映会の進行制御はできるだけサーバ側で担ひたい。 + +したがって、長期仕様では次を目標にする。 + +| 領域 | 方針 | +| --- | --- | +| 次投稿決定 | サーバが theatre 状態・番組表・skip イベント・重みを見て決定 | +| 再生不能検知 | クライアント通知は使ふが、最終判断はサーバ状態に集約 | +| host | 手動操作が必要な暫定制御者。恒久的な絶対権限者ではない | +| 荒らし耐性 | 公表前に host 乗っ取り・連続 next・skip 連打への制限を入れる | + +`skip 投票と next_post の権限を分離するか` という問いは、現時点では仕様語彙が曖昧だった。ここでは次の意味に定義する。 + +- skip 投票: 視聴者全員ができる意思表示。 +- next_post: 現行では host だけが実行できる即時進行操作。 +- 将来仕様: next_post も単なる host 命令ではなく、サーバの進行判断 API に寄せる。 ## 次投稿選択 -`PATCH /theatres/:id/next_post` は host のみ実行可能。 +`PATCH /theatres/:id/next_post` は現行 host のみ実行可能。 `TheatrePostSelector` は次の投稿を候補にする。 @@ -805,6 +995,8 @@ content revision 同士のみ差分対象。 `penalty` は、active user が過去に skip した投稿のタグに基づく。つまり、視聴者が嫌がったタグを持つ投稿ほど選ばれにくい。 +添付 issue #360 により、上映会で上位タグを持つタグが表示されないバグが P1 として課題化されてゐる。上映会はタグ継承・親タグ展開と強く結びつくため、タグ表示は単純な直接付与タグだけでは不足する。 + ## 番組表 `theatre_programmes` は再生履歴/番組表である。 @@ -863,7 +1055,7 @@ required_count = floor(active_watching_users_count / 2) + 1 - YouTube は `react-youtube`。 - ニコニコは `NicoViewer` による JS API `postMessage`。 -- duration が 0 以下など再生不能っぽい場合、host が次投稿へ進める。 +- duration が 0 以下など再生不能っぽい場合、現行では host が次投稿へ進める。 ## 埋め込み @@ -878,21 +1070,38 @@ required_count = floor(active_watching_users_count / 2) + 1 ニコニコ iframe の `loadComplete` timeout は 8000 ms。 + # Gekanator 仕様 ## 概要 -Gekanator は管理者専用の投稿当てゲームである。投稿群に関する質問を出し、回答から候補投稿を絞り、最終的に投稿を推測する。 +Gekanator は投稿当てゲームである。投稿群に関する質問を出し、回答から候補投稿を絞り、最終的に投稿を推測する。 用途はゲームだけではない。終了後の質問追加・回答保存により、投稿間類似や識別質問を蓄積する学習機構でもある。 -## 権限 +## 確定仕様: 公開範囲 + +Gekanator は恒久的な admin-only ツールではない。 + +段階: + +| 段階 | 公開範囲 | 目的 | +| --- | --- | --- | +| 現行 | admin のみ | 学習データ作成、質問品質確認、パラメータ調整 | +| 調整後 | member または限定ユーザ | 追加学習、UX 確認 | +| 公表版 | 一般ユーザ | おたのしみゲームとして公開 | + +公表版では、内部パラメータ・候補スコア・調整用情報は非表示にする。添付 issue #361 により「グカネータ公開」が課題化されてゐる。 + +## 現行権限 バックエンド API は `current_user&.admin?` でなければ 404 を返す。フロントも `/gekanator` は admin 以外 `NotFound` を表示する。 +これは現行実装であって最終仕様ではない。 + ## 投稿カタログ -`GET /gekanator/posts` は admin 専用。 +`GET /gekanator/posts` は現行 admin 専用。 返却投稿: @@ -903,7 +1112,7 @@ Gekanator は管理者専用の投稿当てゲームである。投稿群に関 ## 質問カタログ -`GET /gekanator/questions` は admin 専用。 +`GET /gekanator/questions` は現行 admin 専用。 質問 kind: @@ -963,9 +1172,15 @@ status: 候補が潰れる場合、高難度・非 unknown の過去回答を `0.35` に緩和して復旧を試みる。 +## 確定仕様: 質問数ルール + +通常は 25 問を経過するまで推測しない。「続けますか → はい」の流れでも 25 問ルールを維持する。 + +例外は、100% 近似に近い確信状態で、候補が実質的に一意になった場合のみである。ただし、この例外も最低質問数・2 位候補との差・誤答時の UX を見て慎重に扱ふ。 + ## ゲーム保存 -`POST /gekanator/games` は admin 専用。 +`POST /gekanator/games` は現行 admin 専用。 入力: @@ -984,7 +1199,7 @@ status: `POST /gekanator/question_suggestions`: -- admin 専用。 +- 現行 admin 専用。 - `game_id` - `question_text` 1000 文字以内。 - `answer` は enum。 @@ -998,11 +1213,40 @@ status: `POST /extra_question_answers` は、それらへの回答を `GekanatorQuestionExample` として保存する。 -## AI 変換 +## 確定仕様: AI 変換 `POST /gekanator/question_suggestions/:id/ai_convert` は存在するが、`Gekanator::QuestionSuggestionAiConverter` は現行 `NotImplementedError` を投げる。 -AI 予算: +AI は質問分類だけでなく、既存投稿への回答補完も行ふ。 + +担当範囲: + +| 処理 | 内容 | +| --- | --- | +| 質問分類 | ユーザ文を `tag`, `source`, `title`, `original_date`, `post_similarity` 等へ分類 | +| 正規化 | 曖昧な質問文をゲームで扱へる構造へ変換 | +| 回答補完 | 既存投稿群に対して yes/no/partial/probably_no/unknown を推定 | +| 信頼度 | AI 推定には confidence を持たせ、低信頼は pending に留める | +| 監査 | AI が作った質問・回答は `ai_generated` として追跡可能にする | + +## AI モデル選定 + +初期実装は OpenAI Responses API + Structured Outputs を前提とする。 + +推奨初期値: + +| 項目 | 値 | +| --- | --- | +| 環境変数 | `GEKANATOR_AI_MODEL` | +| 初期モデル | `gpt-5.4-mini` | +| 出力形式 | JSON Schema strict structured output | +| reasoning | `none` または `low` から開始 | +| 大量補完 | Batch API または夜間 Rake task | +| 予算 | 仮置き。半年 500 円程度を目標に、run 数・token 数・batch 割引で調整 | + +`gpt-5.4-mini` は価格と品質の妥協点としての初期値であり、固定ではない。分類だけなら将来 `gpt-5.4-nano` 等のさらに低価格モデルへ落とせるやぅに、モデル ID は必ず環境変数化する。 + +旧メモの AI 予算: | 項目 | 値 | | --- | --- | @@ -1010,7 +1254,8 @@ AI 予算: | 1 run 見積 | 5 円 | | 超過見込み | 402 `blocked_budget` | -現行では API 枠だけが先行してゐる。 +この見積は仮置きであり、確定予算ではない。現在の希望は「半年で 500 円くらゐ」であるため、1 run 5 円の設計は高すぎる。AI 補完は per game 即時実行ではなく、batch 化・cache 化・差分実行に寄せるべきである。 + # プレビュー API @@ -1036,9 +1281,41 @@ AI 予算: - 生成画像を MiniMagick で 180x180 に resize。 - PNG inline で返す。 -### 注意: SSRF/任意URLアクセスリスク +## 確定仕様: セキュリティ方針 -この API は current_user 必須だが、guest は自動作成されるため実質的に広く使へる。任意 URL をサーバから取得・Node screenshot するので、SSRF/内部ネットワーク到達/リソース消費のリスクがある。roadmap に `Harden preview API` があるのは妥当で、これは公表前の赤信号である。 +Preview API は guest 相当にも提供したい機能である。ただし、危険性は高い。クリーンに守れないなら機能廃止も検討対象である。 + +最低必須対策: + +| 対策 | 必須度 | 内容 | +| --- | --- | --- | +| scheme allowlist | 必須 | `http`, `https` のみ | +| DNS 解決後 IP 検査 | 必須 | private, loopback, link-local, multicast, metadata IP を拒否 | +| redirect 検査 | 必須 | redirect 先 URL も同じ検査を繰り返す | +| content length 上限 | 必須 | title HTML 取得、画像、screenshot 出力に上限 | +| timeout | 必須 | connect/read/browser 全て短めに制限 | +| concurrency 制限 | 必須 | screenshot は特に重いので同時実行数を絞る | +| rate limit | 必須 | IP + user + URL host 単位で制限 | +| user agent | 推奨 | 明示 UA を使ひ、必要なら deny されても落ちない UX にする | +| cache | 推奨 | 同一 URL の title/thumbnail を短時間 cache | + +## rate limit 推奨仕様 + +Preview API を guest に残すなら、Rails 単体の before_action ではなく、Rack middleware または reverse proxy で一次防衛するのがよい。 + +推奨値の初期案: + +| 単位 | `/preview/title` | `/preview/thumbnail` | +| --- | --- | --- | +| IP | 60 req / 10 min | 10 req / 10 min | +| user | 120 req / 10 min | 20 req / 10 min | +| URL host | 30 req / 10 min | 10 req / 10 min | + +thumbnail は headless browser を起動するため、title より厳しくする。 + +## 実装差分 + +現行 API は current_user 必須だが、guest は自動作成されるため実質的に広く使へる。任意 URL をサーバから取得・Node screenshot するので、SSRF/内部ネットワーク到達/リソース消費のリスクがある。これは公表前の赤信号である。 # 類似度計算 @@ -1171,190 +1448,262 @@ Vitest が導入され、かなり広範囲にテストがある。 2026-05-10 時点の「フロントテストなし」状態からは明確に改善してゐる。 + # 実装上の不整合・危険点 -この節は慰めではなく、仕様確定前に潰すべき箇所である。ここを曖昧にしたまま公表すると、後で設計負債が増える。 +この節は、仕様決定後も実装が追いついてゐない箇所を列挙する。ここを曖昧にしたまま公表すると、設計負債が増える。 ## P0: Preview API の SSRF/リソース消費リスク `/preview/title` と `/preview/thumbnail` はサーバから任意 URL へアクセスする。guest 自動生成により、事実上かなり広い入口である。 -必要な対策候補: +仕様としては guest 提供の余地を残すが、次は必須である。 - private IP / localhost / link-local / metadata IP の拒否。 - scheme allowlist を http/https に固定。 - redirect 先検査。 - content length 上限。 - screenshot queue/timeout/concurrency 制限。 -- member 以上へ制限するか、rate limit を置く。 +- IP + user + host rate limit。 + +守れないなら機能ごと廃止を検討する。便利さよりサーバ防衛が優先である。 ## P0: guest 自動作成による users 肥大化 旧 DB で `users = 42805`。実利用規模に比して異様に多い。bot が来るたび user を発行してゐる可能性が高い。 -機会費用: +guest 自動作成は継続するが、以下は未実装リスクとして残る。 -- BAN/権限/ユーザ管理がノイズで死ぬ。 -- 本物ユーザの分析ができない。 -- DB とバックアップが無駄に膨らむ。 - -少なくとも「閲覧だけの初回アクセスで user を作る」設計は再検討対象。 +- `POST /users` rate limit。 +- bot UA / localStorage 不可環境への抑制。 +- 編集実績のない guest 掃除 task。 +- user 分析用の `last_seen_at` 等。 ## P0: 素材作成権限が緩い `POST /materials` は current_user だけを要求する。guest 自動作成と合はせると、匿名同然で素材作成できる。 -roadmap にも `Tighten material creation permission` がある。これは既知の穴として扱ふべき。 +確定仕様は member+ 作成である。file 素材は storage を食ふため、ここは早めに閉じるべきである。 ## P1: タグ親子編集権限が二重化 - `TagChildrenController`: admin のみ。 - `TagsController#update_all`: member 以上で `parent_tags` 更新可。 -どちらを正とするか決める必要がある。現状は仕様が二枚舌。 +確定仕様は member+ なので、専用 API 側を修正する。あはせて issue #332 の循環登録禁止を入れないと、member 開放は危ない。 ## P1: `post_versions` の parent post 履歴 API が不足 -schema と snapshot には `parent_post_ids` があるが、`PostVersionsController` が返してゐない。フロント型には `parentPosts` がある。履歴画面で親投稿変更を出すなら API 追加が必要。 +schema と snapshot には `parent_post_ids` があるが、`PostVersionsController` が返してゐない。フロント型には `parentPosts` がある。 -## P1: `material_versions`, `wiki_assets` の幽霊テーブル +確定仕様として、親投稿変更履歴は表示必須である。`parent_posts` の返却を追加する。 -schema にあるが、現行導線が薄い/見当たらない。将来機能なら仕様化、残骸なら削除か凍結判断が必要。 +## P1: `material_versions`, `wiki_assets` は必要だが未実装 + +開発者回答により、どちらも将来機能として必要と確定した。 + +- `material_versions`: tag, URL, file blob, 更新者の履歴。 +- `wiki_assets`: Wiki 内画像/添付、`next_asset_no`、sha256 連動。 + +したがって「残骸として削除」ではなく「仕様化して実装」が正しい。 ## P1: inheritance_code の一意制約なし 認証トークンである以上、DB 一意 index を張るべき。UUID 衝突は現実的に低くても、仕様としては弱い。 -## P2: Material のバリデーション文言と許可カテゴリのズレ - -文言は「素材カテゴリ」だが、実装は `character` も許可する。仕様として `character` も素材を持てるなら文言を直すべき。 - -## P2: Gekanator AI 変換 API は未実装 - -API と予算 model はあるが converter は NotImplemented。画面から到達できるなら UX 上は「未実装」と明示した方がよい。 - -## P2: 上映会 host 乗っ取り耐性 +## P1: 上映会 host 乗っ取り耐性 active host が切れたら次の watching ユーザが host になる。小規模内輪ではよいが、公表後は荒らしが再生制御を握る可能性がある。 -# 開発者ヒアリング +長期方針はサーバ主導進行である。現行 host は暫定制御者と見るべきで、連続 next、短時間 host 交替、再生不能偽装への防御が必要である。 -以下は、仕様書へ確定反映する前に開発者確認が必要な事項である。回答を受けたら「回答済み」として本書の該当節へ反映する。 +## P2: Material のバリデーション文言と許可カテゴリのズレ -## H-001: タグ親子編集の正しい権限 +文言は「素材カテゴリ」だが、実装は `character` も許可する。仕様として `character` も素材を持てるため、文言を直すべきである。 -現状、タグ親子 API は admin 限定だが、タグ full update は member でも `parent_tags` を更新できる。 +## P2: Gekanator AI 変換 API は未実装 -質問: +API と予算 model はあるが converter は NotImplemented。公表版では質問構成 AI を稼動させる予定なので、未実装表示ではなく実装対象である。 -1. タグ親子関係の編集は admin 限定にしたいのか。 -2. それとも member にも許可したいのか。 -3. UI のタグ編集フォームで親タグ欄を出す対象は誰か。 +## P2: issue 管理との接続が手動 -## H-002: 素材作成権限 +今回の issue 一覧は添付 JSON で取り込んだ。継続的な同期手段は未確定である。全件共有方針は妥当だが、手動添付だけだと仕様書がすぐ腐る。 -`POST /materials` は current_user のみ要求してゐる。 -質問: +# 開発者ヒアリング反映結果 -1. guest に素材作成を許す意図か。 -2. member 以上に制限すべきか。 -3. URL-only 素材と file 素材で権限を分ける必要はあるか。 +本章は、前版で未確定だった H-001 から H-011 への回答を記録する。回答内容は本文へ反映済みである。 -## H-003: guest 自動作成の継続可否 +| ID | 状態 | 反映先 | +| --- | --- | --- | +| H-001 | 回答済み | タグ仕様 / タグ親子 | +| H-002 | 回答済み | 素材仕様 / 素材作成権限 | +| H-003 | 回答済み | 認証・ユーザ・BAN / guest 自動作成 | +| H-004 | 回答済み | 投稿仕様 / 投稿履歴 | +| H-005 | 回答済み | 素材仕様 / material_versions | +| H-006 | 回答済み | Wiki 仕様 / Wiki asset | +| H-007 | 回答済み | Gekanator 仕様 / 公開範囲 | +| H-008 | 回答済み | Gekanator 仕様 / AI 変換 | +| H-009 | 回答済み | 上映会仕様 / host 制御 | +| H-010 | 回答済み | Preview API / セキュリティ方針 | +| H-011 | 回答済み | Gitea 課題一覧反映 | -旧 DB で users が 42805 件ある。 +## 残る未決定事項 -質問: +回答後も、次はまだ設計決定が必要である。 -1. 初回閲覧だけで guest user を作る仕様を継続するか。 -2. 閲覧者には user を作らず、編集/投票/コメント時に初めて作る形へ変更するか。 -3. bot 判定や cookie/localStorage なしアクセスへの扱ひをどうするか。 +| 項目 | 未決定内容 | 推奨 | +| --- | --- | --- | +| guest bot 対策 | cookie/localStorage なしアクセス、bot UA、掃除 task の詳細 | `POST /users` rate limit と未使用 guest 掃除 task から着手 | +| URL-only 素材の guest 開放 | いつ・どの条件で許可するか | 当面は member+ に閉じる | +| Gekanator AI 予算 | 半年 500 円程度をどう守るか | batch 化、cache 化、差分実行、model env 化 | +| 上映会 host | 完全サーバ主導へどう移行するか | host を暫定権限に格下げし、server advancer を育てる | +| Preview API | 防御実装不能な場合の廃止判断 | SSRF 防御を実装できなければ thumbnail 生成から止める | +| issue 同期 | 今後どう ChatGPT と共有し続けるか | 当面は JSON 添付。将来は read-only token + 手元 export script | -## H-004: post_versions の親投稿履歴 +# Gitea 課題一覧反映 -`post_versions.parent_post_ids` は保存されるが、履歴 API が返してゐない。 +添付された Gitea issue JSON を取り込み、2026-06-11 時点の仕様書へ反映した。今回の添付には 50 件が含まれ、全件 `open` である。 -質問: +## 集計 -1. 投稿履歴画面で親投稿追加/削除を表示したいか。 -2. 表示するなら、当時の title snapshot が必要か、現在 title 参照でよいか。 -3. `parent_post_ids` だけでよいか、version API で `parentPosts` を返すべきか。 +### Priority -## H-005: material_versions の扱ひ +| priority | 件数 | +| --- | ---: | +| `P1` | 8 | +| `P2` | 26 | +| `P3` | 15 | +| `優先度なし` | 1 | -`material_versions` が schema に存在するが、利用実装が薄い。 +### Status -質問: +| status | 件数 | +| --- | ---: | +| `status/blocked` | 8 | +| `status/in-progress` | 1 | +| `status/ready` | 39 | +| `status/review` | 1 | +| `statusなし` | 1 | -1. 素材にも履歴を持たせる予定か。 -2. 予定があるなら snapshot 対象は URL、tag、parent、file blob、作成/更新者のどれか。 -3. 不要なら migration 残骸として扱ふか。 +### Area -## H-006: wiki_assets の扱ひ +| area | 件数 | +| --- | ---: | +| `area/backend` | 26 | +| `area/frontend` | 25 | -`wiki_assets` が存在する。 +### Type -質問: +| type | 件数 | +| --- | ---: | +| `type/bug` | 8 | +| `type/enhancement` | 24 | +| `type/task` | 17 | +| `typeなし` | 1 | -1. Wiki 内画像/添付ファイル機能を実装する予定か。 -2. `wiki_pages.next_asset_no` と連動する想定か。 -3. Active Storage と `wiki_assets.sha256` の関係はどう設計するか。 +## P1 課題 -## H-007: Gekanator の公開範囲 +P1 は公表前または主要 UX に直撃するものとして扱ふ。 -Gekanator は admin-only かつ非 admin には 404。 +| issue | title | status | area | type | +| --- | --- | --- | --- | --- | +| #360 | 上映会で上位タグを持つタグが表示されないバグ | status/ready | area/backend, area/frontend | type/bug | +| #356 | 天保暦対応 | status/ready | area/frontend | type/enhancement | +| #353 | 局所記載 (#351) | | | | +| #344 | 今後の課題整理 | status/ready | | type/task | +| #334 | posts.thumbnail_base を後からでも変更できるやぅにする | status/ready | area/backend, area/frontend | type/enhancement | +| #332 | 上位タグの循環を登録できないやぅにする | status/ready | area/backend | type/bug | +| #306 | 素材管理(#99 の続き) | status/ready | area/backend, area/frontend | type/enhancement | +| #170 | 別の投稿からタグ・インポート | status/ready | area/backend, area/frontend | type/enhancement | -質問: +## 仕様へ反映した主な issue -1. 今後も完全 admin ツールか。 -2. member へ開放する予定はあるか。 -3. 一般ユーザ向けゲームとして公表する可能性はあるか。 +| issue | 仕様上の扱ひ | +| --- | --- | +| #361 グカネータ公開 | Gekanator は恒久 admin-only ではなく、公表予定機能として定義した | +| #360 上映会で上位タグを持つタグが表示されないバグ | 上映会のタグ表示は親タグ/継承タグを含むべき既知バグとして記載した | +| #356 天保暦対応 | 日付表示/旧暦対応の未実装拡張として課題一覧に反映した | +| #354 `post_versions.tags_json` | 投稿履歴タグ snapshot の構造化予定として記載した | +| #353/#351 局所記載 | 投稿タグに対する sections 構造の未完機能として扱ふ | +| #337 Wiki 履歴 | Wiki 履歴は `wiki_versions` を根拠にする方針として課題一覧に反映した | +| #336 Wiki 本文検索 | Wiki 検索仕様の既知バグとして扱ふ | +| #334 `posts.thumbnail_base` 変更 | 投稿更新対象の拡張課題として扱ふ | +| #332 タグ親子循環禁止 | タグ親子 member 開放前の必須制約として記載した | +| #306 素材管理 | `material_versions` を必要機能として確定した根拠に含めた | +| #301 備考欄 | `post_remarks`, `post_remark_versions` の将来拡張として扱ふ | +| #227 限定公開 | 投稿閲覧権限モデルの将来拡張として扱ふ | +| #123 同定文字 | タグ正規化/検索同定の将来仕様として扱ふ | -## H-008: Gekanator AI 変換 +## 全 issue 一覧 -AI converter は未実装。 +| issue | kind | title | priority | status | type | area | milestone | due | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | +| #361 | Issue | 【おたのしみ】グカネータ公開 | `P3` | `status/ready` | `type/enhancement` | area/backend, area/frontend | | | +| #360 | Issue | 上映会で上位タグを持つタグが表示されないバグ | `P1` | `status/ready` | `type/bug` | area/backend, area/frontend | | | +| #356 | Issue | 天保暦対応 | `P1` | `status/ready` | `type/enhancement` | area/frontend | | | +| #354 | Issue | `post_versions.tags_json` の作成 → `post_versions.tags` を廃止 | `P2` | `status/ready` | `type/enhancement` | area/backend, area/frontend | | | +| #353 | PR | 局所記載 (#351) | `P1` | `` | `` | | | | +| #352 | Issue | サムネつきで手動投稿した際にエラーとなる | `P2` | `status/ready` | `type/bug` | area/backend | | | +| #351 | Issue | 局所記載のしくみ作り | `` | `status/review` | `type/enhancement` | area/backend, area/frontend | | | +| #344 | Issue | 今後の課題整理 | `P1` | `status/ready` | `type/task` | | | | +| #337 | Issue | Wiki 履歴,wiki_versions を根拠にする | `P2` | `status/ready` | `type/enhancement` | area/backend, area/frontend | | | +| #336 | Issue | Wiki 検索で本文が検索できないバグ | `P2` | `status/ready` | `type/bug` | area/backend | | | +| #335 | Issue | API の直発行をやめる | `P2` | `status/ready` | `type/task` | area/frontend | | | +| #334 | Issue | posts.thumbnail_base を後からでも変更できるやぅにする | `P1` | `status/ready` | `type/enhancement` | area/backend, area/frontend | | | +| #332 | Issue | 上位タグの循環を登録できないやぅにする | `P1` | `status/ready` | `type/bug` | area/backend | | | +| #322 | Issue | ニジラー情報の履歴管理 | `P2` | `status/ready` | `type/enhancement` | area/backend | | | +| #320 | Issue | ニコニコ連携画面の TextArea に対するタグ補完 | `P2` | `status/ready` | `type/enhancement` | area/frontend | | | +| #306 | Issue | 素材管理(#99 の続き) | `P1` | `status/ready` | `type/enhancement` | area/backend, area/frontend | | | +| #301 | Issue | 備考欄の作成 | `P2` | `status/ready` | `type/enhancement` | area/backend, area/frontend | | | +| #291 | Issue | “閲覧済” を押しても反映されないバグ | `P2` | `status/ready` | `type/bug` | area/frontend | | | +| #285 | Issue | モデルに対する Spec | `P3` | `status/ready` | `type/task` | area/backend | | | +| #283 | Issue | `deerjikists.tag_id` に外部キー制約 | `P2` | `status/ready` | `type/bug` | area/backend | | | +| #279 | Issue | 検索のワイルドカード | `P2` | `status/in-progress` | `type/enhancement` | area/backend | | | +| #273 | Issue | タグ補完コンポーネント共通化 | `P2` | `status/ready` | `type/task` | area/frontend | | | +| #272 | Issue | タグ補完,前方検索を優先表示するが,後方検索も行ふやぅにする(末尾に追記) | `P2` | `status/ready` | `type/enhancement` | area/backend | | | +| #270 | Issue | 個人用メモを作成可能に | `P2` | `status/ready` | `type/enhancement` | area/backend, area/frontend | | | +| #268 | Issue | タグのドラッグがスマホのスクロールと干渉する問題 | `P2` | `status/ready` | `type/bug` | area/frontend | | | +| #266 | Issue | Wiki 新規作成直後に内容表示されないバグ対応 | `P2` | `status/ready` | `type/bug` | area/frontend | | | +| #242 | Issue | `tags.post_count` にインデクス | `P2` | `status/ready` | `type/task` | area/backend | | | +| #235 | Issue | フロントのビルド軽量化 | `P2` | `status/ready` | `type/task` | area/frontend | | | +| #227 | Issue | 限定公開用のしくみ作り | `P3` | `status/ready` | `type/enhancement` | area/backend | | | +| #225 | Issue | GET /tag_names/name/:name により,タグや Wiki を含む情報を返す | `P2` | `status/ready` | `type/enhancement` | area/backend | | | +| #221 | Issue | Wiki 排他 | `P2` | `status/ready` | `type/enhancement` | area/backend, area/frontend | | | +| #213 | Issue | 広場追加の自動チェックボックス,ボタンにして押したタイミングでの取得にする | `P2` | `status/ready` | `type/enhancement` | area/frontend | | | +| #205 | Issue | 申請フォーム | `P2` | `status/ready` | `type/enhancement` | area/backend | | | +| #172 | Issue | 上位タグ設定画面 | `P3` | `status/ready` | `type/enhancement` | area/backend, area/frontend | | | +| #170 | Issue | 別の投稿からタグ・インポート | `P1` | `status/ready` | `type/enhancement` | area/backend, area/frontend | 一般公開 | | +| #164 | Issue | 【運用】bot 操作タグの投稿を 0 件までに減らす | `P3` | `status/blocked` | `type/task` | | 一般公開 | 2026-06-30 | +| #163 | Issue | 【運用】bot 操作タグの投稿を 100 件までに減らす | `P3` | `status/blocked` | `type/task` | | | 2026-06-15 | +| #162 | Issue | 【運用】bot 操作タグの投稿を 200 件までに減らす | `P3` | `status/blocked` | `type/task` | | | 2026-05-31 | +| #161 | Issue | 【運用】bot 操作タグの投稿を 300 件までに減らす | `P3` | `status/blocked` | `type/task` | | | 2026-05-15 | +| #160 | Issue | 【運用】bot 操作タグの投稿を 400 件までに減らす | `P3` | `status/blocked` | `type/task` | | | 2026-04-30 | +| #159 | Issue | 【運用】bot 操作タグの投稿を 500 件までに減らす | `P3` | `status/blocked` | `type/task` | | | 2026-04-15 | +| #158 | Issue | 【運用】bot 操作タグの投稿を 600 件までに減らす | `P3` | `status/blocked` | `type/task` | | | 2026-03-31 | +| #152 | Issue | Pixiv の埋込み | `P2` | `status/ready` | `type/enhancement` | area/frontend | | | +| #151 | Issue | ニジカ投稿局の埋込み | `P2` | `status/ready` | `type/enhancement` | area/frontend | | | +| #150 | Issue | bilibili の埋込み | `P2` | `status/ready` | `type/enhancement` | area/frontend | | | +| #149 | Issue | Tiktok の埋込み | `P2` | `status/ready` | `type/enhancement` | area/frontend | | | +| #147 | Issue | コントローラをサービスに分離 | `P3` | `status/ready` | `type/task` | area/backend | | | +| #138 | Issue | bot 操作タグのみに限定し,自動で楽曲に関するタグを付与するバッチ作成 | `P3` | `status/ready` | `type/task` | area/backend | | | +| #123 | Issue | 同定文字の制定 | `P3` | `status/ready` | `type/task` | | 一般公開 | | +| #122 | Issue | 【運用】bot 操作タグの投稿を 700 件までに減らす | `P3` | `status/blocked` | `type/task` | | | 2026-03-15 | -質問: - -1. 使用モデル/API は何を想定してゐるか。 -2. 月 450 円/1 run 5 円という予算は確定か仮置きか。 -3. AI は質問分類だけするのか、既存投稿への回答補完もするのか。 - -## H-009: 上映会 host 権限 - -host は active watching user から自動選出される。 - -質問: - -1. 公表後も誰でも host になれる仕様でよいか。 -2. theatre ごとに host 候補を member/admin に限定するか。 -3. skip 投票と next_post の権限を分離するか。 - -## H-010: Preview API の制限方針 - -Preview API は危険度が高い。 - -質問: - -1. preview は member 以上に制限してよいか。 -2. guest に許すなら rate limit はどこで実装するか。 -3. SSRF 対策として private IP 拒否・redirect 検査・content length 上限は必須でよいか。 - -## H-011: 課題一覧の取得方法 - -指定された Gitea API は、この実行環境では取得に失敗した。 - -質問: - -1. issue JSON をファイルとして渡す運用にするか。 -2. read:issue token 付きの安全な取得方法を用意するか。 -3. ChatGPT へ渡すべき issue は全件か、open + P0/P1 のみか。 # 次回更新方針 -1. 上記ヒアリング回答を反映する。 -2. Gitea issue 一覧を取得でき次第、仕様上の未実装/既知不具合/優先度と照合する。 -3. RSpec/Vitest/build/lint の実行結果を追記し、仕様ではなく検証報告として分離する。 +1. 本書を実装作業用に分解し、P0/P1 から Codex 向け issue prompt を作る。 +2. `POST /materials` 権限修正、`PostVersionsController` の `parent_posts` 返却、Preview API 防御を先に潰す。 +3. RSpec/Vitest/build/lint を実行し、仕様ではなく検証報告として別章へ追記する。 4. API レスポンス例を主要 endpoint ごとに追加する。 -5. DB ER 図またはテーブル関係図を別紙化する。 \ No newline at end of file +5. DB ER 図またはテーブル関係図を別紙化する。 +6. Gitea issue の次回添付または export script により、仕様書を腐らせない運用を決める。 + +# 外部参照 + +Gekanator AI モデル選定では、2026-06-11 時点の OpenAI 公式ドキュメントを参照した。モデル ID は変動し得るため、仕様では `GEKANATOR_AI_MODEL` による差し替へを必須とする。 + +- OpenAI Models: https://developers.openai.com/api/docs/models +- OpenAI Structured Outputs: https://developers.openai.com/api/docs/guides/structured-outputs +- OpenAI API Pricing: https://openai.com/api/pricing/ \ No newline at end of file