機能仕様書
ページ一覧
| パス | ページ名 | 認証 |
|---|---|---|
/ | トップページ | 不要 |
/search | 検索結果ページ | 不要 |
/videos/:id | 動画詳細ページ | 不要 |
/pricing | 料金プランページ | 不要 |
/profile | プロフィールページ | 必要 |
/contact | お問い合わせページ | 必要 |
/privacy | プライバシーポリシー | 不要 |
/terms | 利用規約 | 不要 |
トップページ (/)
- サービスの概要説明(キャッチコピー、主要機能のハイライト)
- CTA: 検索を試すボタン、ログインボタン
- 使い方の簡単な説明
- クレジットの仕組み説明: 「一度クレジットを消費した動画は、1ヶ月間クレジットを消費せずに何度でも閲覧できます」という旨を明示的に記載する(アイコン付きで視覚的にわかりやすく)
検索UI
- キーワード入力は 必須
- チャンネル選択は 必須。Combobox 形式(検索・選択可能なドロップダウン)
- プレースホルダー: 「チャンネルを選択またはURLを入力」
- チャンネルURLの直接入力にも対応
ボット対策(Cloudflare Turnstile)
/api/search エンドポイントは Cloudflare Turnstile によるボット対策で保護されている。主目的は YouTube Data API の無料クォータ(1 日 10,000 ユニット)を自動スクレイパから守ること。
- 配置: 検索系ページ(
/[locale]/search/**)の layout に<TurnstileProvider>を 1 つ常駐させる - 表示モード: invisible(
appearance: "interaction-only"+execution: "execute")。ユーザーにはウィジェットが見えず、裏で token を事前取得する - トークンの流れ: Provider が取得した token を
useTurnstileToken()フック経由でfetchSearchに渡し、x-turnstile-tokenヘッダに乗せて送信。送信完了後はrefreshToken()で次の検索用 token を先行取得するためユーザーに待ち時間は発生しない - API 側: Hono middleware (
apps/api/src/middleware/turnstile-middleware/) がchallenges.cloudflare.com/turnstile/v0/siteverifyで検証し、失敗時はTURNSTILE_REQUIRED/TURNSTILE_INVALID/TURNSTILE_UPSTREAM_ERRORを返す - 適用範囲: 現在は
/api/searchのみに適用。/api/contactはauthMiddleware(Google OAuth 必須)で保護されているため Turnstile は不要
環境変数:
CLOUDFLARE_TURNSTILE_SECRET_KEY(API)とNEXT_PUBLIC_TURNSTILE_SITE_KEY(Web)を参照。本番は Cloudflare ダッシュボードで発行、Preview / ローカルは Cloudflare 公式テストキーを使用する。詳細は 環境変数 を参照。
検索対象フィルター
- 検索対象を タイトル・説明文・動画内(字幕) から選択できる(チェックボックス)
- デフォルトは 3つすべて選択 された状態
- チェックを外した項目は検索対象から除外される(例: タイトルのチェックを外すと説明文・動画内のみで検索)
セマンティック検索(意味で検索)
キーワードの完全一致だけでなく、意味的に近い結果も検索できる機能。MeilisearchのHybrid Search(semanticRatio)を利用する。
UI構成
- スイッチ: 検索フォーム内に「意味で検索」トグルスイッチを配置
- OFF(デフォルト): キーワード検索のみ(従来通り)
- ON: キーワード検索 + セマンティック検索のハイブリッド
- Infoアイコン: スイッチの横に
(i)アイコンを配置- クリックするとダイアログが表示される
説明ダイアログの内容
- タイトル: 「意味で検索とは?」
- 本文:
- 通常の検索は入力したキーワードと一致する字幕を検索します
- 「意味で検索」をONにすると、キーワードと意味が近い表現も検索結果に含まれるようになります
- 例: 「最高」で検索 →「素晴らしい」「すごい」「感動的」なども検索結果に表示
- ボタン: 「閉じる」
プリセット選択
スイッチをONにした場合、検索の意味重視度を3段階から選択できる(全プラン共通)。
| プリセット | semanticRatio | 説明 |
|---|---|---|
| 弱 | 0.3 | キーワード重視。意味が近い結果も少し含む |
| 中(デフォルト) | 0.5 | キーワードと意味のバランス |
| 強 | 0.8 | 意味重視。幅広い表現を検索結果に含む |
URLクエリパラメータ
| パラメータ | 必須 | デフォルト | 説明 | 例 |
|---|---|---|---|---|
semantic | No | false | セマンティック検索ON/OFF | semantic=true |
sr | No | 0.5 | semanticRatio(semantic=true時のみ有効) | sr=0.3 |
URLクエリパラメータ連動
- 検索実行時にクエリパラメータをURLに反映する(
pushStateによるリロードなしのURL更新) - URLを直接入力/共有リンクでアクセスした場合、パラメータからフォームの状態を復元する
検索結果ページ (/search)
URLクエリパラメータ設計
検索結果はURLのクエリパラメータで状態を保持する。これにより検索結果のブックマーク・共有・ブラウザバックが可能になる。
ベースURL:
/search?q=キーワード&channel=チャンネルID&target=title,description,subtitle&sort=relevance&page=1
パラメータ一覧:
| パラメータ | 必須 | デフォルト | 説明 | 例 |
|---|---|---|---|---|
q | Yes | — | 検索キーワード | q=ゲーム実況 |
channel | Yes | — | チャンネルID | channel=UC... |
target | No | title,description,subtitle | 検索対象(カンマ区切り) | target=title,subtitle |
sort | No | relevance | 並び順(relevance / published_desc / published_asc) | sort=published_desc |
page | No | 1 | ページ番号 | page=3 |
semantic | No | false | セマンティック検索ON/OFF | semantic=true |
sr | No | 0.5 | semanticRatio(semantic=true時のみ有効) | sr=0.3 |
ルール:
qまたはchannelが空の場合は検索を実行しない(バリデーションエラー)targetはデフォルト値(全選択)の場合はURLから省略可能sort,pageもデフォルト値の場合は省略可能- フォーム操作時にURLを
pushStateで同期更新する(リロードなしでURL変更) - URLを直接入力/共有リンクでアクセスした場合、パラメータからフォームの状態を復元する
URL例:
# 最小(キーワード + チャンネル)
/search?q=ゲーム実況&channel=UCxxxxx
# 字幕のみ検索、新着順、2ページ目
/search?q=ゲーム実況&channel=UCxxxxx&target=subtitle&sort=published_desc&page=2
# タイトルと説明文のみ
/search?q=ゲーム実況&channel=UCxxxxx&target=title,description
# セマンティック検索ON(デフォルト精度)
/search?q=ゲーム実況&channel=UCxxxxx&semantic=true
# セマンティック検索ON + 精度調整(Proプラン)
/search?q=ゲーム実況&channel=UCxxxxx&semantic=true&sr=0.8
チャンネル初回取得時のUX
指定されたチャンネルがMeilisearchに未登録の場合、字幕の初回取得を行う。取得フローの詳細は データ保存戦略 の「チャンネル字幕の初回取得フロー」を参照。
- 「このチャンネルの字幕を初めて取得しています。しばらくお待ちください。」メッセージを表示
- プログレスバー: 取得済み動画数 / 全動画数、推定残り時間を表示
- 「次回以降の検索は高速に行えます」の案内メッセージ
- 取得が進むにつれ、インデックス済み動画の検索結果が順次表示される
- 全動画取得完了時に「取得完了」のトースト通知を表示
差分取得時のUX
検索時に前回取得から24時間以上経過しており、新規動画が見つかった場合の表示。差分取得フローの詳細は データ保存戦略 の「差分取得(検索トリガー)での利用」を参照。
- 差分取得が発生した場合:
- 既存のインデックス済み動画で即座に検索結果を表示
- 画面上部に「新しい動画の字幕を取得中です(○件)」のバナーを表示
- 差分取得完了後、検索結果を自動更新し「新しい動画が追加されました」トースト通知
- 差分チェックで新規動画がない場合: 通常の検索結果を表示(バナーなし)
検索結果のグリッド表示
- デフォルト: 4列 × 5行 = 20件/ページ
- 列数変更可能: 3, 4, 5
- 行数変更可能: 5, 10, 20
検索結果の表示
各動画カードには以下を表示する:
- 常に表示(無料): 動画タイトル、サムネイル、ヒット箇所のタイムスタンプ
- クレジット消費後に表示: ヒット箇所の字幕テキスト(前後5秒)
- 検索ワードを Bold で強調表示する