@@ -0,0 +1,873 @@
|
|||||||
|
---
|
||||||
|
title: 'BTRC Hub 現行仕様書'
|
||||||
|
subtitle: 'ソースコード・Wiki・Issue スナップショットから再構成した仕様'
|
||||||
|
date: '2026-03-08'
|
||||||
|
lang: ja-JP
|
||||||
|
toc: true
|
||||||
|
toc-depth: 2
|
||||||
|
numbersections: true
|
||||||
|
documentclass: report
|
||||||
|
geometry:
|
||||||
|
- margin=22mm
|
||||||
|
fontsize: 10pt
|
||||||
|
mainfont: 'Noto Sans CJK JP'
|
||||||
|
header-includes:
|
||||||
|
- |
|
||||||
|
\usepackage{longtable}
|
||||||
|
\usepackage{booktabs}
|
||||||
|
\usepackage{array}
|
||||||
|
\usepackage{xcolor}
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\definecolor{linkcolor}{HTML}{0B5FFF}
|
||||||
|
\hypersetup{colorlinks=true,linkcolor=linkcolor,urlcolor=linkcolor}
|
||||||
|
---
|
||||||
|
|
||||||
|
# 本書の位置づけ
|
||||||
|
|
||||||
|
本書は、以下の情報源を突き合わせて **2026-03-08 時点の BTRC Hub の現行仕様** を再構成したものである。
|
||||||
|
|
||||||
|
1. バックエンド実装(Rails 8 API)
|
||||||
|
2. フロントエンド実装(React + Vite)
|
||||||
|
3. 開発 Wiki
|
||||||
|
4. Gitea issue 一覧
|
||||||
|
|
||||||
|
本書では、情報の優先順位を次の通りに置く。
|
||||||
|
|
||||||
|
- **第 1 優先**: 現在のソースコードと `db/schema.rb「
|
||||||
|
- **第 2 優先**: Wiki のテーブル定義・方針文書
|
||||||
|
- **第 3 優先**: issue の記述
|
||||||
|
|
||||||
|
理由は単純で、Wiki と issue は過去の設計意図や予定を含み、現実装とズレている箇所があるためである。よって、本書は「夢想」ではなく、**現に動いている仕様を基準にした仕様書** として読むこと。
|
||||||
|
|
||||||
|
# システム概要
|
||||||
|
|
||||||
|
## 目的
|
||||||
|
|
||||||
|
BTRC Hub は、ぼざろクリーチャーシリーズ関連コンテンツへのリンクを集約し、それらにタグを付与して横断的に検索・整理できるようにするリンク集システムである。対象はコンテンツ本体ではなく **リンク** であり、Danbooru 的なタグ付け・Wiki・関連付けの思想を継承しつつ、SNS 的な会話機能は極力持たせない方針である。
|
||||||
|
|
||||||
|
主目的は次の 3 点である。
|
||||||
|
|
||||||
|
- ニコニコ側のタグ数制限を補完すること
|
||||||
|
- 複数プラットフォーム上の関連コンテンツを横断管理すること
|
||||||
|
- タグ、Wiki、関連付けを通じて共同で知識を蓄積すること
|
||||||
|
|
||||||
|
## 非目的
|
||||||
|
|
||||||
|
現時点の方針上、次は中心機能ではない。
|
||||||
|
|
||||||
|
- コメント欄や掲示板のような強い SNS 機能
|
||||||
|
- コンテンツ本体の保存・転載
|
||||||
|
- 汎用 SNS 化
|
||||||
|
|
||||||
|
## 技術構成
|
||||||
|
|
||||||
|
| 層 | 現行構成 |
|
||||||
|
| --- | --- |
|
||||||
|
| バックエンド | Rails 8.0 API, MySQL 8, Active Storage |
|
||||||
|
| フロントエンド | React 19, Vite 6, TypeScript 5, TanStack Query 5 |
|
||||||
|
| UI | Tailwind CSS, Framer Motion |
|
||||||
|
| 補助ライブラリ | Nokogiri, MiniMagick, Discard, diff-lcs |
|
||||||
|
| バッチ | Rake task による同期・類似度計算 |
|
||||||
|
|
||||||
|
## 画面構成の大枠
|
||||||
|
|
||||||
|
現行フロントエンドに存在する主要画面は次の通り。
|
||||||
|
|
||||||
|
- 投稿一覧 」/posts「
|
||||||
|
- 投稿詳細 」/posts/:id「
|
||||||
|
- 投稿履歴 」/posts/changes「
|
||||||
|
- 新規投稿 」/posts/new「
|
||||||
|
- ニコニコ連携 」/tags/nico「
|
||||||
|
- Wiki 一覧・検索 」/wiki「
|
||||||
|
- Wiki 詳細 」/wiki/:title「
|
||||||
|
- Wiki 新規作成 」/wiki/new「
|
||||||
|
- Wiki 編集 」/wiki/:id/edit「
|
||||||
|
- Wiki 差分 」/wiki/:id/diff「
|
||||||
|
- Wiki 変更履歴 」/wiki/changes「
|
||||||
|
- 設定 」/users/settings「
|
||||||
|
|
||||||
|
# 仕様整理の結論
|
||||||
|
|
||||||
|
まず結論を先に書く。
|
||||||
|
|
||||||
|
1. **BTRC Hub の核は「投稿」「タグ」「Wiki」の 3 本柱** である。
|
||||||
|
2. タグは単なる文字列ではなく、**カテゴリ、別名、上位タグ、ニコタグ連携、ニジラー連携** を持つ。
|
||||||
|
3. Wiki は 1 タイトル 1 ページではあるが、内部的には **改訂履歴を持つバージョン管理対象** である。
|
||||||
|
4. 検索は現時点では主に **タグ AND 検索 / ANY 検索 / 補完検索** であり、OR / NOT は未実装である。
|
||||||
|
5. いくつかのテーブルやカラムは存在するが、**UI も API もまだ追いついていない箇所がある**。この点を曖昧にすると仕様書として腐る。
|
||||||
|
|
||||||
|
# 利用者と認可
|
||||||
|
|
||||||
|
## ユーザモデル
|
||||||
|
|
||||||
|
」users.role「 は文字列 enum であり、現行のロールは次の 3 種。
|
||||||
|
|
||||||
|
| ロール | 意味 |
|
||||||
|
| --- | --- |
|
||||||
|
| 」guest「 | 閲覧中心。編集系は不可 |
|
||||||
|
| 」member「 | 投稿・Wiki・タグ更新など通常の編集可 |
|
||||||
|
| 」admin「 | member 権限に加え、管理系操作可 |
|
||||||
|
|
||||||
|
## 認証方式
|
||||||
|
|
||||||
|
認証は一般的なログイン画面ではなく、**引継ぎコード** による軽量認証である。
|
||||||
|
|
||||||
|
- クライアントは 」localStorage「 に 」user_code「 を保存する。
|
||||||
|
- API 呼び出し時は 」X-Transfer-Code「 ヘッダで送信する。
|
||||||
|
- サーバは 」users.inheritance_code「 と照合して 」current_user「 を決定する。
|
||||||
|
|
||||||
|
## 初回利用フロー
|
||||||
|
|
||||||
|
1. フロント起動時に 」localStorage.user_code「 を確認する。
|
||||||
|
2. あれば 」/users/verify「 に送る。
|
||||||
|
3. 無効なら 」/users「 で guest ユーザを新規発行する。
|
||||||
|
4. 有効ならそのユーザを継続利用する。
|
||||||
|
|
||||||
|
## IP 紐づけ
|
||||||
|
|
||||||
|
」/users/verify「 実行時、リクエスト元 IP は 」ip_addresses「 と 」user_ips「 に記録される。よって、現行システムは匿名ではなく、**引継ぎコードと IP の対応を保持する設計** である。
|
||||||
|
|
||||||
|
## 注意点
|
||||||
|
|
||||||
|
- 」users.banned「 と 」ip_addresses.banned「 はスキーマ上存在する。
|
||||||
|
- しかし、現スナップショットでは **禁止フラグを認可処理で強制する実装は見当たらない**。
|
||||||
|
|
||||||
|
ここは「項目はあるが、運用ロジックは未実装または未接続」という理解が正しい。
|
||||||
|
|
||||||
|
# ドメインモデル
|
||||||
|
|
||||||
|
## 投稿 」posts「
|
||||||
|
|
||||||
|
投稿は「URL を中心にしたリンクオブジェクト」であり、タイトル、サムネイル、元コンテンツの作成日時範囲などを持つ。
|
||||||
|
|
||||||
|
主要属性は以下。
|
||||||
|
|
||||||
|
| 属性 | 概要 |
|
||||||
|
| --- | --- |
|
||||||
|
| 」url「 | 一意な参照先 URL |
|
||||||
|
| 」title「 | 表示用タイトル |
|
||||||
|
| 」thumbnail「 | Active Storage で保持する実サムネイル |
|
||||||
|
| 」thumbnail_base「 | 外部取得元のサムネイル URL |
|
||||||
|
| 」parent_id「 | 親投稿参照。現時点では本格機能化前 |
|
||||||
|
| 」uploaded_user_id「 | 投稿者。自動投稿時は NULL |
|
||||||
|
| 」original_created_from` / `original_created_before「 | 元コンテンツ作成日時の範囲 |
|
||||||
|
|
||||||
|
### 投稿に関する現行ルール
|
||||||
|
|
||||||
|
- URL は HTTP / HTTPS のみ許可。
|
||||||
|
- URL は正規化される。
|
||||||
|
- ホストは小文字化
|
||||||
|
- 末尾スラッシュは削除
|
||||||
|
- 」url「 は一意。
|
||||||
|
- 」original_created_from「 と 」original_created_before「 は、両方ある場合 」from < before「 が必須。
|
||||||
|
- サムネイル添付時は 180x180 にリサイズされる。
|
||||||
|
|
||||||
|
## タグ 」tags` + `tag_names「
|
||||||
|
|
||||||
|
タグは 2 層構造で管理される。
|
||||||
|
|
||||||
|
- 」tag_names「: 文字列名そのもの
|
||||||
|
- 」tags「: 実体タグ。カテゴリや件数を持つ
|
||||||
|
|
||||||
|
この分離によって、**別名タグ** を 」tag_names.canonical_id「 で実装している。
|
||||||
|
|
||||||
|
### カテゴリ
|
||||||
|
|
||||||
|
現行カテゴリは次の 7 種。
|
||||||
|
|
||||||
|
| カテゴリ | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| 」deerjikist「 | ニジラー |
|
||||||
|
| 」meme「 | 元ネタ |
|
||||||
|
| 」character「 | キャラクタ |
|
||||||
|
| 」general「 | 一般 |
|
||||||
|
| 」material「 | 素材 |
|
||||||
|
| 」nico「 | ニコニコタグ |
|
||||||
|
| 」meta「 | メタタグ |
|
||||||
|
|
||||||
|
### 別名タグのルール
|
||||||
|
|
||||||
|
- 」tag_names.canonical_id「 が NULL のものが実体名。
|
||||||
|
- NULL でないものは別名。
|
||||||
|
- 別名はさらに別名を指してはならない。
|
||||||
|
- 別名にはプレフィクス 」:「 を含めない。
|
||||||
|
- 」tag「 や 」wiki_page「 を持つ 」tag_name「 は別名化できない。
|
||||||
|
|
||||||
|
### タグ正規化ルール
|
||||||
|
|
||||||
|
投稿作成・更新時にタグ文字列は正規化される。
|
||||||
|
|
||||||
|
- 既知プレフィクスでカテゴリ判定する。
|
||||||
|
- 例: 」general:`, `gen:`, `deerjikist:`, `djk:`, `character:`, `chr:`, `material:`, `mtr:`, `meta:「
|
||||||
|
- プレフィクス除去後、別名なら canonical 名へ正規化する。
|
||||||
|
- 必要ならタグを自動生成する。
|
||||||
|
|
||||||
|
### 自動付与タグ
|
||||||
|
|
||||||
|
現行コード上、通常投稿のタグ処理には次の自動補完がある。
|
||||||
|
|
||||||
|
| 条件 | 自動付与 |
|
||||||
|
| --- | --- |
|
||||||
|
| 新規投稿でタグ数が 10 未満、かつ未付与 | 」タグ希望「 |
|
||||||
|
| ニジラー系タグが 1 つも無い | 」ニジラー情報不詳「 |
|
||||||
|
|
||||||
|
### ニコニコタグの扱い
|
||||||
|
|
||||||
|
」nico:「 プレフィクス付きタグは一般投稿入力から直接追加させない。
|
||||||
|
|
||||||
|
つまり、**ニコタグは通常の手入力タグとは別レーン** である。現在の設計思想は、ニコタグを別カテゴリ・別管理対象として扱うことにある。
|
||||||
|
|
||||||
|
## 投稿とタグの関係 」post_tags「
|
||||||
|
|
||||||
|
投稿とタグは多対多。リレーションは **論理削除** される。
|
||||||
|
|
||||||
|
- 削除は 」discarded_at「 に記録する。
|
||||||
|
- 作成者 」created_user_id「、削除者 」deleted_user_id「 を持つ。
|
||||||
|
- 現在有効な 」(post_id, tag_id)「 は一意。
|
||||||
|
- 論理削除時、」tags.post_count「 を減算する。
|
||||||
|
|
||||||
|
このため、現行システムでは「今そのタグが付いているか」だけでなく、**タグ変更履歴** も追跡可能である。
|
||||||
|
|
||||||
|
## 上位タグ 」tag_implications「
|
||||||
|
|
||||||
|
タグには親子関係を付与できる。
|
||||||
|
|
||||||
|
- 」tag_id「 が子
|
||||||
|
- 」parent_tag_id「 が親
|
||||||
|
- 自己参照は禁止
|
||||||
|
|
||||||
|
投稿保存時には 」Tag.expand_parent_tags「 が走り、**親タグが再帰的に自動付与** される。
|
||||||
|
|
||||||
|
## ニコニコタグ連携 」nico_tag_relations`
|
||||||
|
|
||||||
|
`nico「 カテゴリのタグと、それ以外の内部タグを関連付けるテーブル。
|
||||||
|
|
||||||
|
- 」nico_tag_id「 は 」nico「 カテゴリ必須
|
||||||
|
- 」tag_id「 は 」nico「 カテゴリ不可
|
||||||
|
|
||||||
|
ニコニコ同期時、新しく見つかった外部タグに対応する内部タグを自動付与するための基盤である。
|
||||||
|
|
||||||
|
## ニジラー 」deerjikists`
|
||||||
|
|
||||||
|
`deerjikists「 はプラットフォーム上の人物・投稿者識別子をタグに結びつけるテーブルである。
|
||||||
|
|
||||||
|
- 主キーは 」(platform, code)「 の複合主キー
|
||||||
|
- 」platform「 は現状 」nico` / `youtube「
|
||||||
|
- 参照先タグは 」deerjikist「 カテゴリ必須
|
||||||
|
|
||||||
|
## Wiki 」wiki_pages`, `wiki_revisions`, `wiki_lines`, `wiki_revision_lines「
|
||||||
|
|
||||||
|
Wiki は単なる本文持ちテーブルではない。**ページ本体と改訂履歴を分離した版管理システム** になっている。
|
||||||
|
|
||||||
|
### ページ単位
|
||||||
|
|
||||||
|
- 」wiki_pages.tag_name_id「 がページタイトルに対応する
|
||||||
|
- 1 タイトルにつき 1 ページ
|
||||||
|
- 」created_user_id`, `updated_user_id「 を持つ
|
||||||
|
|
||||||
|
### 改訂単位
|
||||||
|
|
||||||
|
- 」wiki_revisions.kind「 は 」content「 または 」redirect「
|
||||||
|
- 内容改訂は 」wiki_revision_lines「 を介して行単位で保持
|
||||||
|
- 各行は 」wiki_lines「 に SHA-256 で重複排除して保存
|
||||||
|
- 」base_revision_id「 により改訂チェーンを持つ
|
||||||
|
- 」message「 に編集メッセージを持てる
|
||||||
|
|
||||||
|
### Wiki の意味
|
||||||
|
|
||||||
|
要するに、現行 Wiki は **Git 的な差分・履歴志向をデータベースで再実装したもの** である。ここを単なる markdown カラムだと思うと仕様を読み違える。
|
||||||
|
|
||||||
|
## 閲覧済フラグ 」user_post_views「
|
||||||
|
|
||||||
|
ユーザ単位で投稿の閲覧済状態を持つ。
|
||||||
|
|
||||||
|
- 主キーは 」(user_id, post_id)「 の複合主キー
|
||||||
|
- 詳細画面から切替可能
|
||||||
|
|
||||||
|
## 類似度 」post_similarities`, `tag_similarities「
|
||||||
|
|
||||||
|
投稿とタグには事前計算された類似度テーブルが存在する。
|
||||||
|
|
||||||
|
- 」cos「 はコサイン類似度
|
||||||
|
- 投稿詳細では 」post.related「 として利用
|
||||||
|
- Rake task により再計算する構成
|
||||||
|
|
||||||
|
# 現行機能仕様
|
||||||
|
|
||||||
|
## 投稿一覧・検索
|
||||||
|
|
||||||
|
### 一覧表示
|
||||||
|
|
||||||
|
」GET /posts「 により投稿一覧を取得する。
|
||||||
|
|
||||||
|
- デフォルト件数は 20
|
||||||
|
- 」page` / `limit「 によるページネーションあり
|
||||||
|
- 」cursor「 を使ったカーソル取得にも対応
|
||||||
|
- ソート基準は概ね次の優先順
|
||||||
|
1. 」original_created_before - 1 秒`
|
||||||
|
2. `original_created_from`
|
||||||
|
3. `created_at「
|
||||||
|
|
||||||
|
### 検索条件
|
||||||
|
|
||||||
|
」tags「 クエリに空白区切りでタグ名を渡す。
|
||||||
|
|
||||||
|
- 」match=all「 または未指定: AND 検索
|
||||||
|
- 」match=any「: ANY 検索
|
||||||
|
|
||||||
|
タグ指定時は、検索前に 」TagName.canonicalise「 により別名が正規化される。よって、**別名で検索しても実体タグに吸収される**。
|
||||||
|
|
||||||
|
### 現時点で未実装の検索
|
||||||
|
|
||||||
|
issue 上は次が残っている。
|
||||||
|
|
||||||
|
- 投稿一覧の明示的なソート指定
|
||||||
|
- OR / NOT 検索
|
||||||
|
- 独立したタグ検索画面
|
||||||
|
|
||||||
|
つまり、現行検索はまだ完成形ではない。
|
||||||
|
|
||||||
|
## 投稿詳細
|
||||||
|
|
||||||
|
」GET /posts/:id「 で取得できる内容は次の通り。
|
||||||
|
|
||||||
|
- 投稿基本情報
|
||||||
|
- タグ木構造
|
||||||
|
- 関連投稿最大 20 件
|
||||||
|
- 閲覧済フラグ
|
||||||
|
|
||||||
|
### 埋め込み表示
|
||||||
|
|
||||||
|
現行の専用埋め込み対応は次の通り。
|
||||||
|
|
||||||
|
| サイト | 対応 |
|
||||||
|
| --- | --- |
|
||||||
|
| ニコニコ動画 | 専用 viewer |
|
||||||
|
| YouTube | 」react-youtube「 による埋め込み |
|
||||||
|
| Twitter / X | 専用埋め込み |
|
||||||
|
| その他 | 確認ダイアログ付き iframe |
|
||||||
|
|
||||||
|
未対応だが backlog にあるものは TikTok, bilibili, Pixiv など。
|
||||||
|
|
||||||
|
## 新規投稿
|
||||||
|
|
||||||
|
」POST /posts「 は member 以上のみ可能。
|
||||||
|
|
||||||
|
入力は概ね以下。
|
||||||
|
|
||||||
|
- URL
|
||||||
|
- タイトル
|
||||||
|
- サムネイル画像
|
||||||
|
- タグ文字列
|
||||||
|
- 元コンテンツ作成日時範囲
|
||||||
|
|
||||||
|
保存時の流れは次の通り。
|
||||||
|
|
||||||
|
1. 投稿保存
|
||||||
|
2. サムネイル縮小
|
||||||
|
3. タグ正規化
|
||||||
|
4. 親タグ展開
|
||||||
|
5. 」post_tags「 同期
|
||||||
|
|
||||||
|
## 投稿編集
|
||||||
|
|
||||||
|
」PUT /posts/:id「 は member 以上のみ可能。
|
||||||
|
|
||||||
|
現行仕様では次を更新できる。
|
||||||
|
|
||||||
|
- タイトル
|
||||||
|
- タグ
|
||||||
|
- 元コンテンツ作成日時範囲
|
||||||
|
|
||||||
|
編集時は既存の 」nico「 カテゴリタグを維持した上で、一般タグ側を再計算する。
|
||||||
|
|
||||||
|
### 制約
|
||||||
|
|
||||||
|
- 排他制御は未実装。issue #171 が未着手。
|
||||||
|
- 親投稿対応はスキーマ上の準備のみで、本格機能は未実装。
|
||||||
|
|
||||||
|
## 投稿履歴
|
||||||
|
|
||||||
|
」GET /posts/changes「 では 」post_tags「 の追加・削除をイベント列として返す。
|
||||||
|
|
||||||
|
- 追加は 」change_type = add「
|
||||||
|
- 削除は 」change_type = remove「
|
||||||
|
- ユーザが紐づく場合は操作者も返す
|
||||||
|
|
||||||
|
投稿そのものの編集履歴ではなく、**タグ変更履歴** である点に注意。
|
||||||
|
|
||||||
|
## タグ一覧・補完
|
||||||
|
|
||||||
|
### タグ取得
|
||||||
|
|
||||||
|
」GET /tags「
|
||||||
|
|
||||||
|
- 全タグを返す
|
||||||
|
- 」post「 パラメータ指定で特定投稿に付いたタグだけ返せる
|
||||||
|
|
||||||
|
### 補完検索
|
||||||
|
|
||||||
|
」GET /tags/autocomplete?q=...「
|
||||||
|
|
||||||
|
現行仕様はかなり実用寄りで、以下を同時にやっている。
|
||||||
|
|
||||||
|
- 前方一致検索
|
||||||
|
- 別名ヒット時の実体タグ返却
|
||||||
|
- 」matched_alias「 の返却
|
||||||
|
- 」present_only=true「 で件数 0 のタグを除外
|
||||||
|
- 」nico=true「 で 」nico:「 接頭辞側の候補も含める
|
||||||
|
- 」post_count DESC, tag_names.name「 で整列
|
||||||
|
|
||||||
|
### タグ詳細
|
||||||
|
|
||||||
|
- 」GET /tags/:id`
|
||||||
|
- `GET /tags/name/:name「
|
||||||
|
|
||||||
|
いずれも 」TagRepr「 による基本情報を返す。
|
||||||
|
|
||||||
|
## ニコニコ連携
|
||||||
|
|
||||||
|
### ニコタグ一覧
|
||||||
|
|
||||||
|
」GET /tags/nico`
|
||||||
|
|
||||||
|
- `updated_at DESC「 で取得
|
||||||
|
- カーソルページングあり
|
||||||
|
- 各ニコタグに対する 」linked_tags「 を返す
|
||||||
|
|
||||||
|
### ニコタグ更新
|
||||||
|
|
||||||
|
」PUT /tags/nico/:id「
|
||||||
|
|
||||||
|
- member 以上のみ
|
||||||
|
- 入力された内部タグ列を再正規化
|
||||||
|
- 」nico「 タグを連携先に指定することは禁止
|
||||||
|
|
||||||
|
### 日次同期バッチ
|
||||||
|
|
||||||
|
Rake task 」nico:sync「 により、外部のニコニコ DB から同期を行う。
|
||||||
|
|
||||||
|
現行コードから読み取れる同期仕様は次の通り。
|
||||||
|
|
||||||
|
- ニコニコ動画 URL 既存投稿を探索し、あれば更新、なければ新規作成
|
||||||
|
- 新規作成時は 」タグ希望`, 「bot操作」, 「ニコニコ」, 「動画」 を付与
|
||||||
|
- 外部ニコタグは `nico:「 接頭辞付きで内部タグ化
|
||||||
|
- 新規に付いたニコタグについてのみ、連携された内部タグを自動付与
|
||||||
|
- ニジラー対応が見つからなければ 」ニジラー情報不詳「 を補う
|
||||||
|
- 内部タグ構成が変化した場合は 」bot操作「 を付与
|
||||||
|
- タグ削除は 」post_tags「 の論理削除で反映
|
||||||
|
|
||||||
|
これは「単にニコタグを写す」のではなく、**外部タグを内部知識へ変換する ETL** に近い。
|
||||||
|
|
||||||
|
## ニジラー管理
|
||||||
|
|
||||||
|
### 個別参照
|
||||||
|
|
||||||
|
」GET /deerjikists/:platform/:code「
|
||||||
|
|
||||||
|
### 登録・更新
|
||||||
|
|
||||||
|
」PUT /deerjikists/:platform/:code「
|
||||||
|
|
||||||
|
- member 以上
|
||||||
|
- 対象タグは 」deerjikist「 カテゴリ必須
|
||||||
|
|
||||||
|
### 削除
|
||||||
|
|
||||||
|
」DELETE /deerjikists/:platform/:code「
|
||||||
|
|
||||||
|
- member 以上
|
||||||
|
|
||||||
|
## 上位タグ管理
|
||||||
|
|
||||||
|
」POST /tags/:parent_id/children/:child_id`
|
||||||
|
`DELETE /tags/:parent_id/children/:child_id「
|
||||||
|
|
||||||
|
- admin のみ
|
||||||
|
- 子タグに親タグを付ける / 外す
|
||||||
|
|
||||||
|
管理 UI はまだないが、API はある。
|
||||||
|
|
||||||
|
## Wiki
|
||||||
|
|
||||||
|
### 一覧・検索
|
||||||
|
|
||||||
|
- 」GET /wiki`
|
||||||
|
- `GET /wiki/search`
|
||||||
|
|
||||||
|
`title「 指定がなければ全件、あれば部分一致上位 20 件。
|
||||||
|
|
||||||
|
### 詳細表示
|
||||||
|
|
||||||
|
- 」GET /wiki/:id`
|
||||||
|
- `GET /wiki/title/:title「
|
||||||
|
|
||||||
|
現行の返却内容は次を含む。
|
||||||
|
|
||||||
|
- タイトル
|
||||||
|
- 本文
|
||||||
|
- 」revision_id「
|
||||||
|
- 前後改訂 ID (」pred`, `succ`)
|
||||||
|
- `updated_at「
|
||||||
|
|
||||||
|
### リダイレクト
|
||||||
|
|
||||||
|
改訂が 」redirect「 の場合、サーバは対象タイトルへ 301 リダイレクトを返す。
|
||||||
|
|
||||||
|
### 存在確認
|
||||||
|
|
||||||
|
- 」GET /wiki/:id/exists`
|
||||||
|
- `GET /wiki/title/:title/exists「
|
||||||
|
|
||||||
|
### 差分表示
|
||||||
|
|
||||||
|
」GET /wiki/:id/diff?from=...&to=...`
|
||||||
|
|
||||||
|
- `content「 改訂同士のみ比較可
|
||||||
|
- 差分は 」context`, `added`, `removed「 の列で返す
|
||||||
|
|
||||||
|
### 作成
|
||||||
|
|
||||||
|
」POST /wiki「
|
||||||
|
|
||||||
|
- member 以上
|
||||||
|
- 」title`, `body「 必須
|
||||||
|
- タイトルに対応する 」tag_name「 を作成または再利用
|
||||||
|
- 初回改訂を 」Wiki::Commit.content!「 で保存
|
||||||
|
|
||||||
|
### 更新
|
||||||
|
|
||||||
|
」PUT /wiki/:id「
|
||||||
|
|
||||||
|
- member 以上
|
||||||
|
- タイトル変更は受け付けない
|
||||||
|
- 本文を書き換えて新改訂を追加する
|
||||||
|
|
||||||
|
### 履歴
|
||||||
|
|
||||||
|
」GET /wiki/changes「
|
||||||
|
|
||||||
|
- 全体履歴または特定ページ履歴を返す
|
||||||
|
- 現行返却内容は revision 単位
|
||||||
|
|
||||||
|
### 編集競合
|
||||||
|
|
||||||
|
」Wiki::Commit「 には 」Conflict「 例外とページロックがあり、競合時は 409 を返す設計である。
|
||||||
|
|
||||||
|
ただし、現行の更新 API はクライアントからベース revision を明示送信させていない。したがって、**厳密な意味での楽観ロックが完成しているとは言い難い**。ここは仕様書で盛ると嘘になる。
|
||||||
|
|
||||||
|
## 設定・ユーザ管理
|
||||||
|
|
||||||
|
### 現行 UI でできること
|
||||||
|
|
||||||
|
設定画面 」/users/settings「 で現にできるのは次。
|
||||||
|
|
||||||
|
- 表示名更新
|
||||||
|
- 引継ぎコード表示
|
||||||
|
- ほかブラウザからの引継ぎ
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
- 」POST /users「 新規 guest 発行
|
||||||
|
- 」POST /users/verify「 引継ぎコード検証 + IP 紐づけ
|
||||||
|
- 」POST /users/code/renew「 引継ぎコード再発行
|
||||||
|
- 」GET /users/me?code=...「 ユーザ取得
|
||||||
|
- 」PUT /users/:id「 表示名更新
|
||||||
|
|
||||||
|
### 留意点
|
||||||
|
|
||||||
|
」settings「 テーブルは存在するが、現スナップショットでは **汎用ユーザ設定 API / 反映ロジックは未完成** である。issue #34, #35 がそのまま残っているため、このテーブルは将来拡張用の足場と見なすべきである。
|
||||||
|
|
||||||
|
## プレビュー取得
|
||||||
|
|
||||||
|
」/preview/title「 と 」/preview/thumbnail「 は member 権限ではなく **認証済ユーザなら利用可能** な補助 API である。
|
||||||
|
|
||||||
|
- title: 対象 URL の HTML title を取得
|
||||||
|
- thumbnail: Puppeteer スクリーンショット経由で 180x180 サムネイル生成
|
||||||
|
|
||||||
|
ただし TODO が残っており、既知サイト個別最適化は未実装。仕様としては **暫定ユーティリティ** の域を出ていない。
|
||||||
|
|
||||||
|
# 画面仕様の要約
|
||||||
|
|
||||||
|
## 投稿一覧画面
|
||||||
|
|
||||||
|
- 左または下部に TagSidebar を表示
|
||||||
|
- 検索欄でタグ入力 + 補完
|
||||||
|
- 単一タグ検索時は Wiki タブを併設
|
||||||
|
- ランダム遷移あり
|
||||||
|
- モバイルではタグ一覧を折りたたむ
|
||||||
|
|
||||||
|
## 投稿詳細画面
|
||||||
|
|
||||||
|
- 埋め込み表示
|
||||||
|
- 閲覧済トグル
|
||||||
|
- 関連投稿タブ
|
||||||
|
- member 以上なら編集タブ
|
||||||
|
- 詳細専用サイドバーあり
|
||||||
|
|
||||||
|
## Wiki 詳細画面
|
||||||
|
|
||||||
|
- 本文表示
|
||||||
|
- 版指定時は前後改訂移動リンク表示
|
||||||
|
- タグ対応ページであれば関連投稿タブ表示
|
||||||
|
|
||||||
|
## ニコニコ連携画面
|
||||||
|
|
||||||
|
- 無限追加読込に近い UI
|
||||||
|
- ニコタグごとの連携内部タグ列を編集可能
|
||||||
|
|
||||||
|
## 設定画面
|
||||||
|
|
||||||
|
- 名前変更
|
||||||
|
- 引継ぎコード表示
|
||||||
|
- 引継ぎダイアログ
|
||||||
|
|
||||||
|
# バッチ・運用仕様
|
||||||
|
|
||||||
|
## 類似度計算
|
||||||
|
|
||||||
|
| タスク | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 」post_similarity:calc「 | 投稿同士の類似度再計算 |
|
||||||
|
| 」tag_similarity:calc「 | タグ同士の類似度再計算 |
|
||||||
|
|
||||||
|
## Wiki 移行
|
||||||
|
|
||||||
|
」wiki:migrate「 は Gollum 管理の旧 Wiki を DB 版管理へ移行するタスクである。つまり、開発史としては **Gollum から DB 内版管理への移行** がすでに行われている。
|
||||||
|
|
||||||
|
## ニコニコ同期
|
||||||
|
|
||||||
|
」nico:sync「 は外部ニコニコ DB を入力にして投稿・タグを更新する中核バッチであり、日次同期を前提にした設計である。
|
||||||
|
|
||||||
|
# 非機能要件
|
||||||
|
|
||||||
|
現行ソースから読み取れる非機能面の要件を整理すると以下。
|
||||||
|
|
||||||
|
## 性能・可用性
|
||||||
|
|
||||||
|
- 投稿一覧は 20 件単位を基本とする
|
||||||
|
- 一部 API はカーソルページングあり
|
||||||
|
- 補完は上位 20 件まで
|
||||||
|
- フロントは React Query によるキャッシュとプリフェッチを使用
|
||||||
|
|
||||||
|
## データ整合性
|
||||||
|
|
||||||
|
- URL 一意制約
|
||||||
|
- タグ実体一意制約
|
||||||
|
- 別名正規化
|
||||||
|
- 有効 」post_tags「 一意制約
|
||||||
|
- Wiki 改訂チェーン保持
|
||||||
|
- 複合主キーでの閲覧・IP 紐づけ管理
|
||||||
|
|
||||||
|
## 監査性
|
||||||
|
|
||||||
|
- タグ追加者・削除者を保持
|
||||||
|
- Wiki 改訂者を保持
|
||||||
|
- タグ変更履歴 API あり
|
||||||
|
- Wiki 変更履歴 API あり
|
||||||
|
|
||||||
|
## セキュリティ
|
||||||
|
|
||||||
|
- 認証は引継ぎコード依存であり、一般的な ID / パスワード認証より軽量
|
||||||
|
- 埋め込み非対応サイトは確認ダイアログ経由
|
||||||
|
- ただし banned フラグの強制や厳密な管理 UI はまだ弱い
|
||||||
|
|
||||||
|
ここは率直に言って、**管理機能は発展途上** である。
|
||||||
|
|
||||||
|
# 計画中機能と未実装領域
|
||||||
|
|
||||||
|
issue のうち、現行仕様に直接関係する未完了項目を抽出すると次の通り。
|
||||||
|
|
||||||
|
## 検索系
|
||||||
|
|
||||||
|
- 投稿一覧ソート指定
|
||||||
|
- タグ検索専用画面
|
||||||
|
- OR / NOT 検索
|
||||||
|
- Wiki 検索自動補完
|
||||||
|
|
||||||
|
## Wiki 系
|
||||||
|
|
||||||
|
- 画像アップロード
|
||||||
|
- 保護機能
|
||||||
|
- サイドバー
|
||||||
|
- 下書き保持と離脱警告
|
||||||
|
- 議論ページ
|
||||||
|
|
||||||
|
## 投稿系
|
||||||
|
|
||||||
|
- 親投稿対応
|
||||||
|
- バリデーション表示改善
|
||||||
|
- 別投稿からのタグインポート
|
||||||
|
- 編集時排他制御
|
||||||
|
|
||||||
|
## 管理・ユーザ系
|
||||||
|
|
||||||
|
- 管理者画面
|
||||||
|
- 管理者用別名タグ作成画面
|
||||||
|
- ユーザ一覧・詳細画面
|
||||||
|
- 利用規約ページ
|
||||||
|
|
||||||
|
## 埋め込み・連携系
|
||||||
|
|
||||||
|
- TikTok
|
||||||
|
- bilibili
|
||||||
|
- Pixiv
|
||||||
|
- その他独自埋め込み
|
||||||
|
- 連携抑止
|
||||||
|
|
||||||
|
## 品質系
|
||||||
|
|
||||||
|
- コントローラのサービス分離
|
||||||
|
- Frontend テスト自動化
|
||||||
|
|
||||||
|
## 注意点
|
||||||
|
|
||||||
|
issue は backlog であって、そのまま確定仕様ではない。したがって、本書ではこれらを **「計画中」** として扱い、現行仕様には含めない。
|
||||||
|
|
||||||
|
# 情報源間のズレ
|
||||||
|
|
||||||
|
ここはかなり重要なので明記する。
|
||||||
|
|
||||||
|
## Wiki 定義書が古い箇所
|
||||||
|
|
||||||
|
### 1. 」users.last_login_at「
|
||||||
|
|
||||||
|
Wiki のテーブル定義にはあるが、現行 」db/schema.rb「 には存在しない。
|
||||||
|
|
||||||
|
### 2. 」posts.thumbnail「
|
||||||
|
|
||||||
|
Wiki では 」thumbnail「 列のように見えるが、現実装は **Active Storage** であり、RDB の 」posts「 テーブルにその列は無い。
|
||||||
|
|
||||||
|
### 3. 」deerjikists`, `user_ips`, `user_post_views「
|
||||||
|
|
||||||
|
Wiki では代理キー 」id「 がある体で書かれているが、現スキーマは **複合主キー** である。
|
||||||
|
|
||||||
|
### 4. Wiki 本文の保存方式
|
||||||
|
|
||||||
|
Wiki 定義書だけでは読み切れないが、現スキーマでは本文は 」wiki_pages「 直持ちではなく、」wiki_revisions「 と 」wiki_lines「 による版管理で保持される。
|
||||||
|
|
||||||
|
## 仕様書としての判断
|
||||||
|
|
||||||
|
このため、DB や API の設計判断をするときに Wiki の古い定義書だけを見るのは危険である。**現ソースを真実、Wiki を補助資料** とするのが正しい。
|
||||||
|
|
||||||
|
# 現時点の総括
|
||||||
|
|
||||||
|
BTRC Hub は、表面上は「タグ付きリンク集」だが、内部構造はもう少し重い。
|
||||||
|
|
||||||
|
- タグは別名・階層・外部連携を持つ
|
||||||
|
- 投稿は履歴志向のタグ付け対象である
|
||||||
|
- Wiki は改訂履歴付きの知識ベースである
|
||||||
|
- バッチは外部ニコニコ DB を内部知識へ変換する
|
||||||
|
|
||||||
|
つまり本システムの正体は、**リンク集 UI を持つ知識統合基盤** である。
|
||||||
|
|
||||||
|
逆に弱いのは次。
|
||||||
|
|
||||||
|
- 管理 UI
|
||||||
|
- 設定の汎用化
|
||||||
|
- 検索演算子の拡張
|
||||||
|
- 一部埋め込み対応
|
||||||
|
- フロントテスト
|
||||||
|
- ソース間の仕様同期
|
||||||
|
|
||||||
|
このあたりを曖昧にしたまま開発を続けると、仕様の主語が「今の実装」ではなく「昔のメモ」になって腐る。なので、今後は本書のように **現実装ベースで仕様を固定し、issue は差分として扱う** のが筋である。
|
||||||
|
|
||||||
|
# 付録 A: 現行 API 一覧
|
||||||
|
|
||||||
|
## 投稿系
|
||||||
|
|
||||||
|
- 」GET /posts`
|
||||||
|
- `GET /posts/random`
|
||||||
|
- `GET /posts/changes`
|
||||||
|
- `GET /posts/:id`
|
||||||
|
- `POST /posts`
|
||||||
|
- `PUT /posts/:id`
|
||||||
|
- `POST /posts/:id/viewed`
|
||||||
|
- `DELETE /posts/:id/viewed「
|
||||||
|
|
||||||
|
## タグ系
|
||||||
|
|
||||||
|
- 」GET /tags`
|
||||||
|
- `GET /tags/autocomplete`
|
||||||
|
- `GET /tags/:id`
|
||||||
|
- `PUT /tags/:id`
|
||||||
|
- `GET /tags/:id/deerjikists`
|
||||||
|
- `GET /tags/name/:name`
|
||||||
|
- `GET /tags/name/:name/deerjikists`
|
||||||
|
- `POST /tags/:parent_id/children/:child_id`
|
||||||
|
- `DELETE /tags/:parent_id/children/:child_id「
|
||||||
|
|
||||||
|
## ニコタグ系
|
||||||
|
|
||||||
|
- 」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「
|
||||||
|
|
||||||
|
## ユーザ系
|
||||||
|
|
||||||
|
- 」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「
|
||||||
|
|
||||||
|
# 付録 B: 主要永続データ一覧
|
||||||
|
|
||||||
|
| テーブル | 役割 |
|
||||||
|
| --- | --- |
|
||||||
|
| 」posts「 | 投稿リンク本体 |
|
||||||
|
| 」tags「 | 実体タグ |
|
||||||
|
| 」tag_names「 | タグ文字列と別名管理 |
|
||||||
|
| 」post_tags「 | 投稿とタグの関係、履歴含む |
|
||||||
|
| 」tag_implications「 | 上位タグ |
|
||||||
|
| 」nico_tag_relations「 | ニコタグと内部タグの連携 |
|
||||||
|
| 」deerjikists「 | 外部人物識別子とタグの対応 |
|
||||||
|
| 」wiki_pages「 | Wiki ページ本体 |
|
||||||
|
| 」wiki_revisions「 | Wiki 改訂 |
|
||||||
|
| 」wiki_lines「 | 行単位本文ストア |
|
||||||
|
| 」wiki_revision_lines「 | 改訂と行の対応 |
|
||||||
|
| 」users「 | ユーザ |
|
||||||
|
| 」ip_addresses「 | IP 記録 |
|
||||||
|
| 」user_ips「 | ユーザと IP の紐づけ |
|
||||||
|
| 」user_post_views「 | 閲覧済管理 |
|
||||||
|
| 」post_similarities「 | 投稿類似度 |
|
||||||
|
| 」tag_similarities「 | タグ類似度 |
|
||||||
|
| 」settings「 | 将来の設定拡張用テーブル |
|
||||||
|
|
||||||
|
# 付録 C: 参照した情報源
|
||||||
|
|
||||||
|
- 」backend/config/routes.rb`
|
||||||
|
- `backend/db/schema.rb`
|
||||||
|
- `backend/app/controllers/*`
|
||||||
|
- `backend/app/models/*`
|
||||||
|
- `backend/app/services/wiki/commit.rb`
|
||||||
|
- `backend/lib/tasks/*.rake`
|
||||||
|
- `frontend/src/App.tsx`
|
||||||
|
- `frontend/src/pages/*`
|
||||||
|
- `frontend/src/components/*`
|
||||||
|
- `frontend/src/lib/*`
|
||||||
|
- 開発 Wiki 一式
|
||||||
|
- Gitea issue ダンプ
|
||||||
新しい課題から参照
ユーザをブロックする