6
実装説明書
みてるぞ edited this page 2026-05-10 13:28:13 +09:00
title, subtitle, date, lang, toc, toc-depth, numbersections
title subtitle date lang toc toc-depth numbersections
BTRC Hub / タグ広場 現行実装仕様書 現行ソース btrc-hub-main.zip に基づく実装事実ベース仕様(2026-05-10) 2026-05-10 ja-JP true 3 true

本書の位置づけ

本書は、2026-05-10 時点で添付された btrc-hub-main.zip の実装を確認し、タグ広場(BTRC Hub)の現行仕様を再構成した文書である。

既存の BTRC_Hub_仕様書_2026-03-23.md は有用な土台だが、現行実装とはすでに差分がある。したがって本書では、過去仕様書の記述よりも現行ソース・db/schema.rbroutes.rb・フロントエンドルーティング・主要コントローラ/モデルの実装を優先する。

本書の分類は次のとおり。

表記 意味
現行仕様 現在のソース・スキーマ・画面で確認できるもの
実装あり・UI薄い バックエンドやモデルは存在するが、画面や導線が不足しているもの
計画・未確定 ソースだけでは確定できず、開発者ヒアリングが必要なもの
注意 実装上の落とし穴、仕様として明文化すべき制約

本書は「願望」ではなく、コードにあるものをまず書く。曖昧な点は 開発者ヒアリング として末尾に隔離する。

用語: 公開と公表

本書では、以後 公開公表 を分ける。

用語 意味
公開 URL として到達可能であり、検索エンジン等にも拾われ得る状態。現時点のタグ広場はすでにこの状態である。
公表 ぼざクリ界隈等へ明示的に告知し、利用導線を出して、人を呼び込む状態。

したがって、旧来の「一般公開前」「公開前」という表現は、本書では原則として 公表前 と読み替える。すでにサービスは外部から到達可能であり、問題は「存在をどこまで告知し、利用を促すか」である。

公開と公表の用語整理

システム概要

目的

BTRC Hub は、ぼざろクリーチャー関連コンテンツへのリンクを収集し、タグ・Wiki・素材・外部同期・上映会機能を通じて、作品群や関連知識を整理・再発見しやすくするための共同編集型基盤である。

中核は次の 5 系統である。

  1. 投稿: 外部 URL を中心としたリンクデータ。
  2. タグ: カテゴリ、別名、親子関係、外部タグ連携、素材連携を持つ分類単位。
  3. Wiki: タグ名と結びつく説明ページ。行単位ストアと改訂履歴を持つ。
  4. 素材: キャラクター・素材タグに紐づくファイルまたは参考 URL。
  5. 上映会: 投稿を共同視聴し、コメント・在席・ホスト制御を行う実験的機能。

非目的

現行実装は次を主目的にしていない。

  • 汎用 SNS。
  • コメント掲示板。
  • 外部コンテンツ本体の転載保存サービス。
  • 高度な動画配信基盤。
  • 通常のメール/パスワード式アカウント管理。

ただし、上映会や素材投稿などにより、単純なリンク集より重い知識基盤へ寄っている。

技術構成

現行構成
バックエンド Ruby 3.2.2 / Rails 8.0.2 API
DB MySQL 8 / utf8mb4_0900_ai_ci
ファイル Active Storage。Cloudflare R2/S3 利用を想定する構成あり
フロントエンド React 19.1 / Vite 6.3 / TypeScript 5.8
通信 Axios + TanStack Query
UI Tailwind CSS / Framer Motion / shadcn 風 UI コンポーネント
Markdown react-markdown / react-markdown-editor-lite / remark-wiki-autolink
バッチ Rake task。Nico 同期、YouTube 同期、類似度計算など

認証・ユーザ・BAN

ユーザモデル

users は次の主要属性を持つ。

属性 意味
name 表示名
inheritance_code 引継ぎコード。認証トークンとして使う
role guest / member / admin
banned_at BAN 時刻。NULL なら有効ユーザ

ロールは文字列 enum である。

ロール 権限の概略
guest 閲覧中心。編集系は不可
member 投稿・Wiki・タグ・素材など通常編集が可能
admin member 権限に加え、タグ親子関係など管理系操作が可能

User#gte_member?member? || admin? を返す。

認証方式

認証は通常の ID / パスワードではなく、inheritance_code による軽量認証である。

  • フロントは localStorage.user_code にコードを保持する。
  • API 呼び出し時、X-Transfer-Code ヘッダにコードを付与する。
  • サーバは users.inheritance_code と照合し、current_user を決定する。

初回利用フロー

フロント起動時の流れは次である。

  1. localStorage.user_code を確認する。
  2. ある場合は POST /users/verify へ送る。
  3. 有効なら返却ユーザを採用する。
  4. 無効またはコード無しなら POST /users で guest ユーザを新規作成する。
  5. 新規作成時、返却された引継ぎコードを localStorage に保存する。

BAN 強制

過去仕様書との差分として重要。

現行 ApplicationController では、すべての API に対して次が before_action で走る。

  1. reject_banned_ip_address!
  2. authenticate_user
  3. reject_banned_user!

したがって現行実装では、BAN は保存されているだけではなく、API レベルで強制される

対象 判定
IP BAN ip_addresses.banned_at が存在すれば 403
User BAN users.banned_at が存在すれば 403

IP は request.remote_ipIPAddr#hton で 16 byte binary 化し、ip_addresses.ip_address に保存する。

IP 紐づけ

POST /usersPOST /users/verify のタイミングで、ユーザと IP が紐づけられる。

  • ip_addresses: IP アドレス本体。
  • user_ips: user と ip_address の複合主キー関係。

注意点として、request.remote_ip が不正・空になるケースへの明示的な救済は薄い。ここはプロキシ構成・Cloudflare 経由・bot アクセスで事故り得る。

主要ドメインモデル

投稿 posts

投稿は外部 URL を中心とするリンクデータである。

属性 意味
title 表示タイトル
url 投稿 URL。一意
thumbnail_base 外部サムネイル URL
uploaded_user_id 手動投稿者。同期投稿は NULL になり得る
original_created_from 元コンテンツ作成日時の下限
original_created_before 元コンテンツ作成日時の上限
thumbnail Active Storage 添付

URL 仕様

  • URL は必須。
  • URL は一意。
  • HTTP / HTTPS のみ許可。
  • 保存前に前後空白を除去する。
  • host は小文字化される。
  • path 末尾の / は除去される。

元コンテンツ日時

original_created_fromoriginal_created_before の両方がある場合、from < before が必須である。

YouTube/Nico 同期では、動画公開時刻を分単位の範囲として保持する実装がある。

サムネイル

手動投稿時に thumbnail が渡されると Active Storage に添付され、Post#resized_thumbnail! により 180x180 の JPEG へリサイズされる。

投稿親子関係 post_implications

現行実装では、投稿の親子関係は posts.parent_id ではない。

post_implications により、投稿と親投稿は多対多で表現される。

カラム 意味
post_id 子投稿
parent_post_id 親投稿

仕様:

  • 主キーは (post_id, parent_post_id)
  • 自己参照は禁止。
  • 投稿作成・更新 API では parent_post_ids が必須。
  • parent_post_ids は空白区切りの ID 文字列として解釈される。
  • 存在しない親 ID が含まれると 422。
  • 自分自身を親にすると 422。

この仕様は重要で、フロントや API クライアントは空でも parent_post_ids を送る必要がある。

投稿版 post_versions

投稿本体とタグ・親投稿構成のスナップショットは post_versions に保存される。

属性 意味
post_id 対象投稿
version_no 投稿内連番。1 以上
event_type create / update / discard / restore
title / url / thumbnail_base 投稿本体スナップショット
tags タグ名の空白区切りスナップショット
parent_post_ids 親投稿 ID の空白区切りスナップショット
original_created_from / before 元日時範囲
created_by_user_id 操作者

PostVersionRecorder は更新前スナップショットを保証し、変更がなければ update 版を増やさない。

タグ tags / tag_names

タグ名文字列とタグ実体は分離されている。

  • tag_names: 名前、別名関係、Wiki ページとの結合点。
  • tags: カテゴリ、投稿件数、タグ実体。

カテゴリ

現行カテゴリは次である。

category 用途
deerjikist ニジラー
meme ミーム・原作・ネタ元など
character キャラクター
general 一般
material 素材
nico ニコニコ外部タグ
meta メタタグ

別名

tag_names.canonical_id により別名を表現する。

  • canonical_id = NULL: 正規名。
  • canonical_id != NULL: 別名。
  • 別名の参照先も別名であってはならない。
  • 別名名に : を含められない。
  • タグまたは Wiki ページを持つ tag_name は別名化できない。

TagName.canonicalise は、既知の別名を正規名へ置換する。

タグサニタイズ tag_name_sanitisation_rules

タグ名には優先度付きのサニタイズ規則がある。

属性 意味
priority 主キー。適用順序
source_pattern 正規表現
replacement 置換後文字列
discarded_at 論理削除

TagName のバリデーションは、名前が TagNameSanitisationRule.sanitise(name) と一致することを要求する。

したがって、サニタイズ規則は「保存前に自動で直す」だけではなく、「規則に反する名前を拒否する」層でもある。

タグ正規化

投稿作成・更新時、タグ入力は Tag.normalise_tags! で正規化される。

カテゴリプレフィクス

入力接頭辞 category
general: / gen: general
deerjikist: / djk: deerjikist
meme: meme
character: / chr: character
material: / mtr: material
meta: meta

nico: は通常手入力では拒否される。

自動付与タグ

通常の正規化では次が自動付与される。

条件 自動付与
タグ数が 10 未満 タグ希望
deerjikist カテゴリが無い ニジラー情報不詳

投稿更新時は with_tagme: false のため、更新時に「タグ希望」を新規補完しない。

親タグ展開

Tag.expand_parent_tags により、入力タグの親タグを再帰的に追加する。

結果として投稿には、明示タグだけではなく、親カテゴリ的なタグも保存される。

投稿タグ post_tags

投稿とタグは多対多である。

属性 意味
post_id 投稿
tag_id タグ
created_user_id 付与者
deleted_user_id 削除者
discarded_at 論理削除時刻
active_unique_key 有効レコード一意制約用の生成列

現行有効な (post_id, tag_id) の重複は DB レベルで防がれている。

PostTag は論理削除されるため、タグ付与履歴としても使われる。

タグ親子 tag_implications

タグの親子関係は tag_implications で表す。

カラム 意味
tag_id 子タグ
parent_tag_id 親タグ

仕様:

  • 同一組み合わせは一意。
  • admin のみ API で作成・削除できる。
  • nico カテゴリタグは親子操作不可。
  • 投稿タグ保存時、親タグは自動展開される。

タグ版 tag_versions / nico_tag_versions

通常タグと nico タグは別テーブルで履歴を持つ。

tag_versions

属性 意味
tag_id 対象タグ
version_no タグ内連番
event_type create / update / discard / restore
name 名前スナップショット
category カテゴリ
aliases 別名リスト
parent_tag_ids 親タグ ID リスト
created_by_user_id 操作者

nico_tag_versions

属性 意味
tag_id nico タグ
version_no nico タグ内連番
event_type create / update / discard / restore
name nico タグ名
linked_tags 連携内部タグ名
created_by_user_id 操作者

ニコタグ連携 nico_tag_relations

nico_tag_relations は nico カテゴリタグと内部タグを結ぶ。

  • nico_tag_id: nico カテゴリ必須。
  • tag_id: nico カテゴリ禁止。

これは外部ニコニコタグを内部タグ体系へ変換するための関係である。

ニジラー deerjikists

外部プラットフォーム上の人物識別子と内部タグを結ぶ。

属性 意味
platform nico / youtube
code 外部識別子
tag_id deerjikist カテゴリのタグ

主キーは (platform, code)

YouTube の @handle は、更新 API 内でチャンネル ID UC... へ正規化を試みる。

素材 materials

現行実装で追加されている重要機能。

素材は、素材タグまたはキャラクタータグに紐づくファイル・参考 URL である。

重要なのは、charactermaterial は単純な上下カテゴリではない点である。現行運用では、character タグを素材集合の代表タグとし、関連する material タグを TagImplication によって子タグとしてぶら下げる。つまり、キャラクタータグは「そのキャラクターに関する素材タグ群の入口」として機能する。

タグ分けするほどではないが異なる素材差分については、将来的に 包摂素材 として単一 Material の配下へ複数保持できるようにする計画である。これは、立ち絵差分・音声差分・参考画像などを何でもタグ化してタグ空間を肥大化させるのを避けるための拡張である。

素材タグ運用: 現行の親子タグ + 将来の包摂素材

属性 意味
url 参考 URL。論理削除されていない場合は一意
parent_id 親素材。将来的な包摂素材表現の土台になる
tag_id 対応タグ。素材 1 件につき一意
created_by_user_id 作成者
updated_by_user_id 更新者
discarded_at 論理削除
file Active Storage 添付

制約

  • tag_id は必須かつ一意。
  • タグは material または character カテゴリのみ許可。
  • character は素材集合の代表タグとして許可される。
  • material は具体的な素材タグとして許可される。
  • url または file の少なくとも一方が必須。
  • discarded_at が NULL の場合だけ url 一意制約が効く。

現行運用上の意味

  • キャラクターに関連する複数素材は、現時点では TagImplication によって character 親タグと material 子タグに分解して扱う。
  • そのため、materials.tag_id が一意であっても、素材をタグ単位へ分ける限りは大きな問題は起きにくい。
  • ただし、タグを増やすほどではない素材差分を複数持ちたい場合は、現行設計だけでは表現力が足りない。
  • この不足分を埋める将来仕様が 包摂素材 である。

バージョン

material_versions が存在し、素材の URL・親素材・タグ・作成/更新者・discard 状態を履歴化する構造がある。

ただし、コントローラ上は素材の version API は確認できない。モデル・サービス側の実運用接続は追加確認が必要。

Wiki

Wiki はタグ名に紐づく説明ページである。

wiki_pages

属性 意味
tag_name_id Wiki タイトルに対応する tag_name
body 現行本文キャッシュ
created_user_id 作成者
updated_user_id 更新者
next_asset_no Wiki 画像/添付素材の採番用
discarded_at 論理削除

wiki_pages.tag_name_id は一意。

wiki_revisions / wiki_lines

Wiki は改訂と行ストアを分離する。

  • wiki_revisions: 改訂メタ情報。
  • wiki_revision_lines: 改訂内の行順序。
  • wiki_lines: 行本文を SHA-256 で重複排除保存。

wiki_revisions.kind は現行 enum で content / redirect を持つ。ただし Wiki::Commit#redirect! は現在 廃止しました. として例外を投げる。

wiki_versions

wiki_versions も存在し、Wiki ページの版管理スナップショットを保持する。

現行 Wiki::Commit.content!WikiVersionRecorder.record! を呼ぶため、行単位 revision と別に、通常の version 履歴も記録される。

Wiki 競合制御

Wiki::Commit.content!base_revision_id を受け取る。指定があり、現在の最大 revision id と一致しない場合は Wiki::Commit::Conflict を投げ、コントローラは 409 を返す。

現行 WikiPagesController#updateparams[:base_revision_id] を使う。したがって、過去仕様書にあった「クライアント送信値を使わないため競合検出が活きていない」という記述は、現行実装では修正済みである。

閲覧済 user_post_views

ユーザごとの投稿閲覧済み状態を保持する。

  • 主キーは (user_id, post_id)
  • POST /posts/:id/viewed で付与。
  • DELETE /posts/:id/viewed で解除。

類似度 post_similarities / tag_similarities

投稿類似度とタグ類似度は事前計算テーブルで保持される。

テーブル 単位 特徴量
post_similarities 投稿 → 関連投稿 投稿に付いたタグ集合
tag_similarities タグ → 関連タグ タグに属する投稿集合

上位 20 件のみ保存する設計。

上映会 theatres

上映会は共同視聴機能である。

属性 意味
name 会場名
opens_at / closes_at 開始/終了時刻
kind 種別。現行 UI では薄い
current_post_id 現在上映中投稿
current_post_started_at 現在投稿の開始時刻
next_comment_no コメント採番
host_user_id 現在ホスト
created_by_user_id 作成者
discarded_at 論理削除

API 仕様

投稿 API

GET /posts

投稿一覧を取得する。

パラメータ

パラメータ 意味
tags 空白区切りタグ検索
match all 相当または any
title タイトル部分一致
url URL 部分一致
original_created_from / original_created_to 元コンテンツ作成日時範囲
created_from / created_to 投稿作成日時範囲
updated_from / updated_to 投稿またはタグ更新日時範囲
page ページ。既定 1
limit 件数。既定 20
order field:direction

order の field は次。

  • title
  • url
  • original_created_at
  • created_at
  • updated_at

updated_atposts.updated_atpost_tags.updated_at の最大値を updated_at_all として使う。

タグ検索意味論

tags は空白区切り。各要素は TagName.canonicalise により別名解決される。

  • match=any: OR。
  • それ以外: AND。
  • not: 接頭辞: 否定条件。

注意: match=anynot: を混ぜると、SQL 的には「否定条件を OR する」ため、期待とズレる可能性がある。仕様として許すか、UI で制限するか要確認。

GET /posts/random

現在の tags / match 条件に合う投稿をランダムに 1 件返す。

GET /posts/:id

投稿詳細を取得する。

返却には次を含む。

  • 投稿基本情報。
  • タグ木構造。
  • 関連投稿最大 20 件。
  • 現在ユーザの閲覧済みフラグ。
  • 親投稿・子投稿・兄弟投稿情報。

POST /posts

投稿を作成する。member 以上必須。

入力:

パラメータ 必須 意味
title 任意 タイトル
url 必須 URL
thumbnail 任意 サムネイルファイル
tags 任意 空白区切りタグ
original_created_from 任意 元日時下限
original_created_before 任意 元日時上限
parent_post_ids 必須 空白区切り親投稿 ID

保存フロー:

  1. 投稿を保存。
  2. タグを正規化。
  3. 関連タグのバージョンスナップショットを確保。
  4. 親タグを展開。
  5. post_tags を同期。
  6. 親投稿関係を同期。
  7. サムネイルをリサイズ。
  8. post_versions に create 版を記録。

PUT /posts/:id

投稿を更新する。member 以上必須。

更新対象:

  • title
  • original_created_from
  • original_created_before
  • tags
  • parent_post_ids

注意:

  • URL の更新は現行 API では行わない。
  • nico カテゴリタグは既存分を維持したまま、手入力側タグを再計算する。
  • parent_post_ids は更新時も必須。
  • 投稿の optimistic locking 用 version_no は posts テーブルにまだ無い。履歴はあるが、投稿更新 API で base version を照合する仕様は未実装。

POST /posts/:id/viewed / DELETE /posts/:id/viewed

ログイン済みユーザの閲覧済み状態を付与・解除する。

GET /posts/changes

投稿タグ付与履歴を取得する。

パラメータ 意味
id 投稿 ID 絞り込み
tag タグ ID 絞り込み
page / limit ページング

返却されるのは、投稿本体履歴ではなく post_tags の add/remove イベントである。

GET /posts/versions

投稿本体スナップショット履歴を取得する。

パラメータ 意味
post 投稿 ID 絞り込み
tag タグ ID 絞り込み
page / limit ページング

前版との差分として、title / url / thumbnail_base / tags / parent_post_ids / original_created_from / original_created_before などを返す。

タグ API

GET /tags

タグ一覧・検索を取得する。

パラメータ 意味
post 指定投稿に付いたタグだけに絞る
name 名前部分一致
category カテゴリ一致
post_count_gte / post_count_lte 投稿件数範囲
created_from / created_to 作成日時範囲
updated_from / updated_to 更新日時範囲
page / limit ページング
order field:direction

order の field は name / category / post_count / created_at / updated_at。

category 並びは独自順序。

  1. deerjikist
  2. meme
  3. character
  4. general
  5. material
  6. meta
  7. nico

注意: countq.size を返しており、ページング後/前の扱いが ActiveRecord の状態に依存しうる。厳密な総件数仕様としては弱い。

GET /tags/with-depth

階層表示用タグを取得する。

パラメータ 意味
parent 親タグ ID。無ければルートタグ

対象カテゴリは meme / character / material に限定される。

返却タグには has_children が付く。

GET /tags/autocomplete

タグ補完。

パラメータ 既定 意味
q 前方一致検索語
nico true nico 候補を含める
present true post_count > 0 に限定

挙動:

  • q 先頭の not: は除去する。
  • canonical 名前方一致を検索する。
  • 別名前方一致も拾い、正規タグを返す。
  • 別名ヒット時は matched_alias を返す。
  • 最大 20 件。

GET /tags/:id / GET /tags/name/:name

タグ詳細を取得する。

/tags/name/:name は exact name であり、別名から正規タグへ自動解決しない。

PUT /tags/:id

タグ全体更新。member 以上必須。

現行実装では以下を受ける。

  • name
  • category
  • aliases
  • parents

仕様:

  • nico タグの編集は禁止。
  • nico カテゴリへの変更は禁止。
  • 特殊タグの改名は禁止。
  • name 変更時は、対応 Wiki があれば Wiki 版も更新記録される。
  • aliases 更新時は対象・影響タグの snapshot を確保する。
  • parents 更新時は親タグを再正規化し、既存親関係を全置換する。

PATCH /tags/:id

狭いタグ更新。member 以上必須。詳細は update_all と分担があり、実装確認継続対象。

GET /tags/versions

タグ履歴を取得する。

パラメータ 意味
id タグ ID 絞り込み
page / limit ページング

前版との差分として、name / category / aliases / parent_tags を返す。

POST /tags/:parent_id/children/:child_id

タグ親子関係を追加する。admin のみ。

  • nico タグは不可。
  • 子タグの snapshot を確保してから関係追加。
  • tag_versions に update を記録。

DELETE /tags/:parent_id/children/:child_id

タグ親子関係を削除する。admin のみ。

ニコタグ API

GET /tags/nico

nico カテゴリタグ一覧を取得する。

パラメータ 意味
limit 件数。既定 20
cursor ISO8601 時刻。updated_at < cursor

linked_tags を含む。

PUT /tags/nico/:id

nico タグと内部タグの連携を更新する。member 以上必須。

  • 対象タグは nico カテゴリ必須。
  • 入力 tags を通常タグとして正規化する。
  • 連携先に nico カテゴリが含まれると 400。
  • nico_tag_versions に update が記録される。

ニジラー API

GET /deerjikists/:platform/:code

外部識別子からニジラー対応タグを取得する。

PUT /deerjikists/:platform/:code

ニジラー対応を作成・更新する。member 以上必須。

入力:

  • tag_id

DELETE /deerjikists/:platform/:code

ニジラー対応を削除する。member 以上必須。

素材 API

GET /materials

素材一覧を取得する。

パラメータ 意味
page / limit ページング
tag_id 紐づくタグで絞る
parent_id 親素材で絞る

返却は materialscount

GET /materials/:id

素材詳細を取得する。

返却には素材本体に加え、素材タグに対応する Wiki 本文 wiki_page_body が含まれる。

POST /materials

素材を作成する。現行実装ではログイン必須。

計画仕様としては member 以上に制限する。当初は guest 作成可能の意図があったが、ファイルアップロードを伴うため、オブジェクトストレージへの大量投入・違法ファイル混入・容量爆撃のリスクを避ける。

入力:

パラメータ 必須 意味
tag 必須 対応タグ名
file file または url の一方必須 素材ファイル
url file または url の一方必須 参考 URL

タグが存在しない場合は material カテゴリで作成される。

PUT /materials/:id

素材を更新する。member 以上必須。

  • tag
  • file
  • url

file が渡されない場合は既存ファイルを purge する。

DELETE /materials/:id

素材を論理削除する。member 以上必須。

Wiki API

GET /wiki

Wiki 一覧・タイトル検索。

パラメータ 意味
title タイトル部分一致。空なら全件

本文検索は現行 index では行わない。

GET /wiki/search

現行では index と同じ処理。

GET /wiki/:id / GET /wiki/title/:title

Wiki 詳細を取得する。

パラメータ 意味
version revision id を指定して過去版取得

返却:

  • id
  • title
  • body
  • revision_id
  • pred
  • succ
  • updated_at

GET /wiki/:id/exists / GET /wiki/title/:title/exists

存在すれば 204、無ければ 404。

GET /wiki/:id/diff

Wiki 差分を取得する。

パラメータ 意味
from 古い revision id。省略時は空本文相当
to 新しい revision id。省略時は現行 revision

content revision 同士のみ比較可能。

POST /wiki

Wiki を作成する。member 以上必須。

入力:

  • title
  • body
  • message 任意

処理:

  1. title に対応する tag_name を取得または作成。
  2. Wiki::Commit.create_content! で page と revision を生成。
  3. wiki_versions に create 記録。

PUT /wiki/:id

Wiki を更新する。member 以上必須。

入力:

  • title
  • body
  • message 任意
  • base_revision_id 任意

現行では タイトル変更も受け付ける。タグがその tag_name を参照している場合、タグ版も更新記録される。

base_revision_id が現行最大 revision id と一致しない場合、409 conflict。

GET /wiki/changes

Wiki 改訂履歴を最大 200 件返す。

パラメータ 意味
id Wiki ページ ID 絞り込み

プレビュー API

GET /preview/title

指定 URL の HTML を取得し、<title> を読む。

GET /preview/thumbnail

Node スクリプトで対象 URL のスクリーンショットを取得し、縮小サムネイルを返す。

注意:

  • SSRF 対策、許可ドメイン、タイムアウト、サイズ上限などは仕様として明文化不足。
  • 外部ページ表示・プレビュー取得は公表前または利用拡大前に安全化必須。

上映会 API

GET /theatres/:id

会場情報を取得する。

返却は TheatreRepr.base。現行では会場作成・一覧 API は無い。

PUT /theatres/:id/watching

ログイン必須。heartbeat と会場状態取得を兼ねる。

処理:

  1. theatre_watching_usersexpires_at を現在 + 30 秒へ更新。
  2. host が空、または host が在席していなければ現在ユーザを host にする。
  3. host_flg, post_id, post_started_at, watching_users を返す。

PATCH /theatres/:id/next_post

ログイン必須かつ現在 host のみ。

  • nicovideo.jp または youtube.com を含む投稿から RAND() で 1 件選ぶ。
  • current_post_idcurrent_post_started_at を更新する。

GET /theatres/:theatre_id/comments

コメントを取得する。

パラメータ 意味
no_gt 指定番号より後のコメント

注意: 現行実装は order(no: :desc) で返す。過去仕様書の「no ASC」は現行と異なる。

POST /theatres/:theatre_id/comments

コメント投稿。ログイン必須。

  • 空本文は 422。
  • theatre.next_comment_nowith_lock で採番する。

フロントエンド画面仕様

ルーティング

現行フロントの主要ルートは次。

パス 画面
/ /posts へリダイレクト
/posts 投稿一覧
/posts/new 投稿作成
/posts/search 投稿詳細検索
/posts/:id 投稿詳細
/posts/changes 投稿タグ変更履歴
/tags タグ一覧
/tags/:id タグ詳細
/tags/:id/deerjikists ニジラー紐づけ管理
/tags/nico ニコタグ連携
/tags/changes タグ履歴
/theatres/:id 上映会
/materials 素材一覧
/materials/new 素材追加
/materials/:id 素材詳細
/wiki Wiki 検索
/wiki/:title Wiki 詳細
/wiki/new Wiki 作成
/wiki/:id/edit Wiki 編集
/wiki/:id/diff Wiki 差分
/wiki/changes Wiki 履歴
/users/settings ユーザ設定
/settings /users/settings へリダイレクト
/tos 利用規約 MDX
/more その他ページ

投稿一覧画面

  • 投稿一覧を表示する。
  • TagSidebar が表示される。
  • サイドバーは、現在表示中の投稿に出てくるタグを最大 25 件まで拾い、カテゴリ順・名前順で出す。
  • モバイルではタグ一覧が折りたたみ表示になる。
  • 関連導線としてランダム投稿リンクがある。

Danbooru 風サイドバーの現行仕様

サイドバーのタグ一覧は、全体 DB の人気順ではない。

現行実装では、現在表示中の投稿配列を先頭から舐め、出現したタグを最大 25 件までカテゴリ別に集め、各カテゴリ内を名前順に並べる

したがって、表示順は次に依存する。

  1. 投稿一覧の現在ページ・並び順。
  2. 各投稿に含まれるタグ。
  3. カテゴリ順。
  4. カテゴリ内名前順。

投稿詳細画面

投稿詳細では埋め込み表示を行う。

URL 専用表示
nicovideo.jp/watch/... NicoViewer
youtube.com/watch?v=... react-youtube
twitter.com / x.com の status URL TwitterEmbed
その他 確認後 iframe

注意:

  • youtu.be は現行 PostEmbed の専用 YouTube 対応外。
  • YouTube Shorts も現行専用判定外の可能性が高い。
  • その他 URL は confirm 後に iframe 表示するため、X-Frame-Options 等で表示不能なサイトがある。

タグ画面

  • /tags は検索・一覧画面。
  • /tags/:id はタグ詳細。
  • /tags/:id/deerjikists は外部ニジラー対応編集画面。
  • /tags/nico は nico タグ連携画面。
  • /tags/changes はタグ版履歴。

素材画面

素材機能は現行フロントにルートがある。

  • /materials: 素材一覧。
  • /materials/new: 素材追加。
  • /materials/:id: 素材詳細。

素材追加画面では、タグ、ファイル、参考 URL を入力する。ファイルは image / video / audio のプレビューに対応する。

MaterialSearchPage は存在するが、ルートはコメントアウトされており、現行導線からは未使用。

Wiki 画面

  • Wiki 検索。
  • Wiki 詳細。
  • Wiki 新規作成。
  • Wiki 編集。
  • Wiki 差分。
  • Wiki 履歴。

Markdown 表示には Wiki 自動リンク用 remark が組み込まれている。

ユーザ設定画面

/users/settings では以下を扱う。

  • 表示名更新。
  • 引継ぎコード表示。
  • 引継ぎコード更新。
  • 他ブラウザへの引継ぎ。

settings テーブルを使った汎用設定 UI は現行では未確認。

外部同期・バッチ

Nico 同期

Nico 同期は、ニコニコ動画の情報を投稿・タグへ反映する ETL 的機能である。

主な処理:

  1. 外部情報から動画 URL・タイトル・投稿日時・サムネイルを取得。
  2. 既存投稿を URL で探索し、無ければ作成。
  3. nico タグを nico: 接頭辞付きの nico カテゴリタグとして取り込む。
  4. nico_tag_relations に基づき内部タグへ展開する。
  5. タグ希望bot操作ニコニコ動画 等のメタタグを付与する。
  6. ニジラー対応がなければ ニジラー情報不詳 を補う。

YouTube 同期

YouTube 同期は Youtube::Sync に実装されている。

主な処理:

  1. 検索語および playlist id から動画 ID を収集する。
  2. YouTube Data API の videos で詳細を取得する。
  3. 既存投稿は YouTube URL 正規表現で探索する。
  4. タイトル・公開日時・サムネイル URL を反映する。
  5. 新規投稿には タグ希望bot操作YouTube動画 を付与する。
  6. チャンネル ID と deerjikists の対応があれば、ニジラータグを付与する。

YOUTUBE_API_KEY が環境変数として必須。

類似度計算

Rake task により投稿・タグの類似度を再計算する。

  • 投稿類似度: タグ集合ベース。
  • タグ類似度: 投稿集合ベース。
  • 上位 20 件保存。

非機能・運用仕様

整合性

  • URL は posts で一意。
  • post_tags の現行有効関係は生成列で一意。
  • materials の有効 URL は生成列で一意。
  • タグ名は一意。
  • Wiki ページは tag_name ごとに一意。
  • 投稿親子は複合主キーで重複不可。
  • 投稿親子の自己参照は禁止。

監査性

現行で保存される履歴:

対象 履歴
投稿本体 post_versions
投稿タグ付与 post_tags の created/deleted/discarded
タグ tag_versions
nico タグ連携 nico_tag_versions
Wiki wiki_revisions / wiki_versions
素材 material_versions。ただし API 接続状況は要追加確認

セキュリティ上の注意

公表前または利用拡大前に仕様として潰すべき箇所。

  1. preview API の SSRF 対策
    • private IP 禁止、localhost 禁止、リダイレクト制御、サイズ上限、タイムアウト、Content-Type 制限が仕様化されていない。
  2. iframe 外部表示
    • confirm はあるが、許可ドメインや CSP の明確仕様が無い。
  3. 引継ぎコード認証
    • 簡便だが漏洩時の被害が大きい。コード更新導線はあるが、セッション管理は薄い。
  4. 素材作成権限
    • 現行では guest でもログイン済みなら POST /materials できる。意図的か確認が必要。
  5. IP BAN の remote_ip 前提
    • 本番プロキシ設定がズレると、全員同一 IP 扱いになる危険がある。

パフォーマンス上の注意

  1. 投稿一覧はタグ・素材・Wiki を preload しているため、ページサイズやタグ数が増えると重くなる。
  2. タグサイドバーはクライアントで投稿配列からタグを収集する。1ページ件数増加時に効く。
  3. order('RAND()') は投稿数増加時に重くなる。
  4. Theatre の次動画選定も RAND() で、投稿数増加に弱い。
  5. TagsController#index の count は q.size であり、総件数計算として不安定。
  6. Wiki 本文検索は未実装であり、実装時には全文検索インデックス設計が必要。

過去仕様書からの主要差分

項目 2026-03-23 仕様書 2026-05-10 現行実装
BAN 未接続と記述 ApplicationController で IP / User BAN 強制済み
投稿親子 parent_id 前提の記述あり post_implications 多対多
投稿履歴 タグ履歴中心 post_versions API あり
タグ更新 name/category 中心 aliases / parents / deerjikists 更新も実装
Wiki 更新 title 変更不可と記述 title 変更可。tag version も記録
Wiki 競合制御 活用されていないと記述 base_revision_id を受け取り 409 を返す
素材 旧仕様書では薄い/無し materials / material_versions / 画面あり
Theatre コメント順 no ASC と記述 現行 API は no DESC
YouTube 一部計画寄り Youtube::Sync 実装あり
利用規約 計画 /tos MDX ルートあり。ただし内容精査は別途必要

現行で「ある」と言ってよいもの

  • 引継ぎコード認証。
  • guest / member / admin ロール。
  • IP BAN / User BAN の API 強制。
  • 投稿 CRUD のうち作成・参照・更新。
  • 投稿タグ検索、AND / OR / NOT、別名 canonicalise。
  • 投稿親子多対多。
  • 投稿本体バージョン履歴。
  • 投稿タグ付与履歴。
  • タグ一覧・検索・補完。
  • タグ別名・親タグ更新 API。
  • タグ履歴。
  • Nico タグ連携。
  • YouTube 同期。
  • ニジラー対応管理。
  • Wiki 作成・参照・更新・差分・履歴。
  • Wiki 競合検出。
  • 素材一覧・作成・更新・削除。
  • 上映会表示・在席・次投稿・コメント。
  • ユーザ設定の一部。
  • 利用規約ページのルート。

現行で「あるつもり」は危険なもの

  • 通常のアカウント登録/ログイン。
  • 管理画面。
  • user / IP BAN の UI。
  • 投稿削除 API。
  • 素材 version 表示 API。
  • Theatre 一覧・作成・編集 API。
  • Wiki 本文検索。
  • Wiki 画像添付の画面導線。
  • Wiki redirect 作成機能。
  • 投稿更新の optimistic locking。
  • settings テーブルを使った汎用ユーザ設定。
  • youtu.be / Shorts / Bluesky / Pixiv 専用埋め込み。
  • preview API の安全仕様。
  • ゲスト編集の公表後運用。

開発者ヒアリング反映結果

以下は、仕様書作成時に確認した開発者回答と、それを受けた仕様上の扱いである。

H-001: 素材作成権限

現行 POST /materialscurrent_user があれば許可され、gte_member? を要求していない。

開発者回答: 当初の意図どおり guest でも素材作成可能にしていたが、オブジェクトストレージへ大量投入されるリスクがあるため、耕作員(member)以上で制限する方向 とする。

仕様反映: 計画仕様として、素材作成は member 以上へ引き上げる。現行コードとの差分として明記する。

H-002: 投稿作成・更新で parent_post_ids 必須

現行 parse_parent_post_idsparams.key?(:parent_post_ids) が無いと例外にする。

開発者回答: 親投稿が無い投稿でも、API クライアントは必ず parent_post_ids: '' を送る仕様で確定。未指定によって誤って初期化されるのを防ぐためである。「変更なし」とする挙動は冪等性に反するため避ける。

仕様反映: POST /posts および PUT /posts/:id は、親投稿が無い場合でも parent_post_ids を必須入力とする。空文字は「親投稿なし」を意味する。未指定は不正リクエストである。

補足: これは PUT を部分更新ではなく完全置換寄りの API として扱う設計である。外部 API 化する場合も、この思想を明記しなければ事故る。

H-003: 投稿更新の排他制御

post_versions はあるが、posts.version_no は現行 schema に無く、PUT /posts/:idbase_version_no を受け取らない。

開発者回答: 投稿更新に base_version_no を入れる計画を仕様に含める。

仕様反映: 計画仕様として、投稿更新には optimistic locking を導入する。詳細画面で取得した version_no を更新時に base_version_no として送信し、サーバ側の現行版と一致しない場合は競合として扱う。

H-004: Wiki redirect の扱い

wiki_revisions.kind = redirect は残っているが、Wiki::Commit#redirect! は廃止例外になっている。

開発者回答: Wiki redirect は今後廃止し、タグ別名へ一本化する。過去に使われた歴史もない。

仕様反映: Wiki redirect は現行スキーマ上の残存要素として扱い、将来仕様では採用しない。別名・表記揺れ・旧名からの到達は tag_names.canonical_id によるタグ別名機能へ集約する。

H-005: Wiki title 変更

現行 PUT /wiki/:id は title 変更を受け付け、対応 tag_name を rename する。

開発者回答: Wiki 編集画面からのタイトル変更を正式仕様として許可する。ただし、紐づくタグが存在しない場合はタグ詳細画面からの変更を促したい。

仕様反映: Wiki title 変更は正式仕様である。ただし、タグ名と Wiki title は同一知識ノードを指すため、Wiki title rename は実質的に tag rename である。権限・履歴・衝突処理では「Wiki の表題変更」ではなく「タグ名変更」として扱う。

H-006: Theatre コメント順

現行 GET /theatres/:theatre_id/commentsno DESC で返す。

開発者回答: DESC で確定。

仕様反映: Theatre コメント一覧は no DESC を正式仕様とする。差分取得・画面表示では、クライアント側が必要に応じて並び替える。

H-007: TagSidebar のタグ順

現行サイドバーは「表示中投稿に出現したタグ最大 25 件」をカテゴリ別・名前順で表示する。

開発者回答: 理想は Danbooru を踏襲したい。

仕様反映: 現行仕様はカテゴリ別・名前順表示である。計画仕様として、Danbooru 風に現在の検索結果内での出現頻度・関連度を重視した順序へ寄せる。

H-008: settings テーブル

settings はあるが、汎用設定 API と UI は未確認。

開発者回答: テーマ、タグ色、ミュートタグ、埋め込み自動再生などを settings に集約する方針で概ねよい。ただし、見た目にしか関係しない設定は localStorage にすることも検討中。

仕様反映: サーバ側で永続化すべき設定と、端末ごとの表示設定を分ける。ミュートタグ・非表示タグなどユーザ体験に本質的な影響を与えるものは settings 候補、純粋な見た目は localStorage 候補とする。

H-009: 素材と material / character カテゴリ

現行 Material#tag_must_be_material_categorycharacter または material を許可する。

開発者回答: character タグに直接素材を 1 件だけ紐づける仕様でよい。現時点では TagImplication によって character を親タグ、関連する material を子タグとする運用をしており、大きな問題は生じていない。キャラクタータグは実質素材タグの集合代表である。ただし、タグ分けするほどでもないが異なる素材については、包摂素材 として複数持たせたい。

仕様反映: 現行仕様として、character は素材集合の代表タグ、material は具体素材タグとして扱う。複数素材は原則 TagImplication による子 material タグ化で表現する。計画仕様として、タグ分けするほどではない差分素材を単一 Material 配下へ複数保持する「包摂素材」を追加検討する。

H-010: 利用規約ページ

/tos ルートはある。

開発者回答: 現行 TOSPage.mdx は現時点で有効な利用規約である。ただし草案の域を脱していないのも事実であり、基本はこれを踏襲する。

仕様反映: /tos は現行の有効な利用規約ページとして扱う。ただし、公表に向けて文面精査が必要な草案ベースの利用規約であることも併記する。

H-011: preview API 安全仕様

現行 preview は便利だが、公開サービスとしては SSRF 対策の仕様化が必要である。

開発者回答: サムネ取得に関してはかなり危うい。対案を後ほど議論する。

仕様反映: preview API の安全仕様は未確定とする。ただし、既にサービスは公開状態であるため、これは「公表前の理想論」ではなく、現行公開サービスのリスクとして扱う。

H-012: YouTube 同期対象

Youtube::Sync は検索語と playlist id から動画 ID を集める。

開発者回答: 現行はコード固定であるが、いずれは DB 管理に移行したい。汎用基盤化が夢である。

仕様反映: 現行仕様では YouTube 同期対象はコード固定。計画仕様として、検索語・playlist ID を DB 管理へ移行し、外部同期を汎用基盤化する余地を残す。

H-013: 管理画面の最小範囲

管理 API / UI はまだ薄い。

開発者回答: 管理画面は公表後に追従して実装する。現時点では、Rails Console を管理ツールとして使用している。なお、サービス自体は既に公開済みであり、ここでいう「一般公開」は「公表」の意味である。

仕様反映: 現行管理運用は Rails Console ベースとする。管理画面は未実装の計画機能であり、公表後に追従実装する。ただし、BAN / 差し戻し / 最近の更新確認などは、利用者増加時に早期に必要となる。

実装優先度メモ

現行仕様を踏まえると、公表前または利用拡大前に優先すべき順は次。

  1. 投稿更新の排他制御
    • Wiki は 409 を返せる。投稿も合わせるべき。
  2. 素材権限の確認・修正
    • guest 作成可は危険。
  3. 管理画面 MVP
    • 現行運用は Rails Console ベース。少人数運用では成立するが、利用者が増えると UI が無い状態は運用負荷になる。
  4. preview API 安全化
    • SSRF は利用拡大後に燃える種類の穴。
  5. Wiki 本文検索
    • タグ整理基盤として価値に直結。
  6. TagSidebar の並び順改善
    • 現行は「たまたま表示された投稿の先着タグ」で、検索支援として弱い。
  7. Theatre コメント順・会場管理
    • 周辺機能なので中核より後。

付録 A: 現行 API 一覧

投稿

  • GET /posts
  • GET /posts/random
  • GET /posts/changes
  • GET /posts/versions
  • GET /posts/:id
  • POST /posts
  • PUT /posts/:id
  • POST /posts/:id/viewed
  • DELETE /posts/:id/viewed

タグ

  • GET /tags
  • GET /tags/autocomplete
  • GET /tags/with-depth
  • GET /tags/versions
  • GET /tags/:id
  • PUT /tags/:id
  • PATCH /tags/:id
  • GET /tags/:id/deerjikists
  • PUT /tags/:id/deerjikists
  • GET /tags/name/:name
  • GET /tags/name/:name/deerjikists
  • GET /tags/name/:name/materials
  • POST /tags/:parent_id/children/:child_id
  • DELETE /tags/:parent_id/children/:child_id

Nico タグ

  • GET /tags/nico
  • PUT /tags/nico/:id

Wiki

  • GET /wiki
  • GET /wiki/search
  • GET /wiki/changes
  • GET /wiki/:id
  • PUT /wiki/:id
  • GET /wiki/:id/exists
  • GET /wiki/:id/diff
  • GET /wiki/title/:title
  • GET /wiki/title/:title/exists
  • POST /wiki

素材

  • GET /materials
  • GET /materials/:id
  • POST /materials
  • PUT /materials/:id
  • DELETE /materials/:id

ユーザ

  • POST /users
  • POST /users/verify
  • GET /users/me
  • POST /users/code/renew
  • PUT /users/:id

ニジラー

  • GET /deerjikists/:platform/:code
  • PUT /deerjikists/:platform/:code
  • DELETE /deerjikists/:platform/:code

プレビュー

  • GET /preview/title
  • GET /preview/thumbnail

上映会

  • GET /theatres/:id
  • PUT /theatres/:id/watching
  • PATCH /theatres/:id/next_post
  • GET /theatres/:theatre_id/comments
  • POST /theatres/:theatre_id/comments

付録 B: 主要テーブル一覧

テーブル 役割
posts 投稿リンク本体
post_implications 投稿親子関係
post_tags 投稿タグ関係と付与履歴
post_versions 投稿本体・タグ・親投稿構成の版
tags タグ実体
tag_names タグ名と別名
tag_implications タグ親子関係
tag_versions 通常タグ履歴
nico_tag_versions nico タグ連携履歴
tag_name_sanitisation_rules タグ名サニタイズ規則
nico_tag_relations nico タグと内部タグの対応
deerjikists 外部人物識別子とタグの対応
materials 素材
material_versions 素材履歴
wiki_pages Wiki ページ
wiki_revisions Wiki 改訂
wiki_lines Wiki 行本文ストア
wiki_revision_lines Wiki 改訂と行の対応
wiki_versions Wiki スナップショット履歴
wiki_assets Wiki 添付資産
users ユーザ
ip_addresses IP 記録と IP BAN
user_ips ユーザと IP の対応
user_post_views 閲覧済み
post_similarities 投稿類似度
tag_similarities タグ類似度
theatres 上映会
theatre_comments 上映会コメント
theatre_watching_users 上映会在席
settings 汎用設定候補

付録 C: 確認した主要ソース

  • backend/config/routes.rb
  • backend/db/schema.rb
  • backend/app/controllers/application_controller.rb
  • backend/app/controllers/posts_controller.rb
  • backend/app/controllers/tags_controller.rb
  • backend/app/controllers/nico_tags_controller.rb
  • backend/app/controllers/post_versions_controller.rb
  • backend/app/controllers/tag_versions_controller.rb
  • backend/app/controllers/wiki_pages_controller.rb
  • backend/app/controllers/materials_controller.rb
  • backend/app/controllers/theatres_controller.rb
  • backend/app/controllers/theatre_comments_controller.rb
  • backend/app/controllers/users_controller.rb
  • backend/app/models/post.rb
  • backend/app/models/tag.rb
  • backend/app/models/tag_name.rb
  • backend/app/models/material.rb
  • backend/app/models/wiki_page.rb
  • backend/app/models/wiki_revision.rb
  • backend/app/models/user.rb
  • backend/app/models/ip_address.rb
  • backend/app/services/wiki/commit.rb
  • backend/app/services/youtube/sync.rb
  • frontend/src/App.tsx
  • frontend/src/components/PostEmbed.tsx
  • frontend/src/components/TagSidebar.tsx
  • frontend/src/pages/materials/*