曲対比機能 画面設計書
最終更新: 2026-09-25
1. 概要
曲対比機能(#474、MorningStatusApp#1633で手動作成方式へ再構築)で追加・変更される画面の設計。 新規 2 画面(対比一覧・対比詳細)と、既存 2 画面(トップ・曲詳細)へのセクション追加を定義する。 データ取得方式は 曲対比機能 データ設計書 を参照。本書は表示・操作仕様のみを扱う。
2. 画面一覧
| 画面名 | URL パターン | レンダリング方式 | 対応 Issue |
|---|---|---|---|
| 対比一覧 | /comparisons |
SSR(動的) | #474, morning-status-blume#148 |
| 対比詳細 | /comparisons/[id] |
SSR(動的) | #474, morning-status-blume#148 |
[id]はComparisonGroup.groupId(UUID)。既存画面への追加は §5・§6 を参照。
3. 対比一覧画面(/comparisons)
概要
全対比グループをリスト形式で一覧表示する画面。デスクトップモードでは新規作成の導線も提供する。
表示コンテンツ
| 要素 | 内容 |
|---|---|
| ナビゲーション | 「メンバー一覧に戻る」リンク(/ へ) |
| ページタイトル | 「対比一覧」 |
| グループ数 | 登録グループ件数(例: 12組) |
| 新規作成ボタン | デスクトップモードでのみ表示(§5.1参照) |
| グループ一覧 | ComparisonGroup.createdAt 降順(新しく作成したグループが先頭) |
リスト表示項目
| 項目 | 内容 |
|---|---|
| タイトル | ComparisonGroup.title(対比詳細画面へのリンク) |
| 曲数 | 所属 ComparisonGroupTrack 件数 |
データなし表示
グループが1件もない場合は「対比データがまだありません。」を表示する。
4. 対比詳細画面(/comparisons/[id])
概要
1 組の対比グループに含まれる曲を並べて表示する画面。 グループの各曲の YouTube 動画を横並びに表示し、オリジナルとリメイクを視覚的に比較できる。 デスクトップモードでは編集・削除の導線も提供する。
アクセス制御
| 条件 | 挙動 |
|---|---|
[id] に一致する ComparisonGroup が存在しない |
notFound() を返す |
表示コンテンツ
| 要素 | 内容 |
|---|---|
| ナビゲーション | 「前の画面に戻る」リンク(BackLink コンポーネント。フォールバック: /comparisons) |
| ページタイトル | "{title} 対比" |
| 編集・削除ボタン | デスクトップモードでのみ表示(§5.2参照) |
| 曲カードグリッド | 各曲を並列表示するグリッド(§4.1 参照)。ComparisonGroupTrack.addedAt 昇順(登録順) |
4.1 曲カード(1 曲分)
| 項目 | 内容 |
|---|---|
| 曲タイトル | Track.title |
| YouTube 動画 | YouTubePlayer コンポーネント(Track.links に type: 'youtube' のリンクがある場合) |
| 動画なし表示 | 該当リンクがない場合は「動画なし」プレースホルダー |
| 代表リリース | Track.release.title(Track.releaseId リンク付き、/releases/[id] へ) |
| 曲詳細リンク | Track.trackId リンク(/songs/[id] へ) |
4.2 グループ表示
グループ内のトラックを実際の Track.release.format でグルーピングし、single → album の順(候補データを§7でこの2フォーマットに限定しているため、現状はこの2種類のみが対象)で並べる。見出しラベルは lib/release-format.ts の FORMAT_LABEL(single → 「シングル」、album → 「アルバム」)から導出し、画面側で固定文字列として決め打ちしない。フォーマットが1種類のみであっても、そのフォーマットの見出しは省略せず表示する(「シングルのみの対比」「アルバムのみの対比」であることはトラックが持つ種別情報として画面上に残すべき情報のため)。
4.3 グリッドレイアウト
| 状況 | レイアウト |
|---|---|
| デスクトップ(2 曲) | 2 列横並び |
| デスクトップ(3 曲以上) | repeat(auto-fill, minmax(360px, 1fr)) でラップ |
| モバイル | 1 列縦積み |
5. デスクトップモードでの編集(対比グループの作成・編集・削除)(morning-status-blume#148)
アクセス制限: デスクトップモードでのみ編集UIを表示する。
5.1 新規作成(対比一覧画面)
UI構成: app/comparisons/page.tsx はServer Componentのまま残し、新規作成ボタン・作成フォームをClient Component(ComparisonGroupEditView 等)に切り出し、isDesktopMode をpropとして渡す(ライブ・フェス機能 画面設計書 §11と同じ理由。開発ノート UI/UX設計 #14)。
操作フロー:
- 「新規作成」ボタンを押すと、トラック検索・選択UI(§7)がインライン表示される
- 曲名検索でトラックを2件以上選択する
- 「作成」ボタンを押すと
POST /api/comparisonsに{ trackIds }を送信する - 成功時は作成された
groupIdの対比詳細画面(/comparisons/[groupId])へrouter.push()で遷移する - トラック選択が1件以下の場合、「作成」ボタンを非活性にする(クライアント側バリデーション。サーバー側でも
400で拒否する)
5.2 編集・削除(対比詳細画面)
UI構成: app/comparisons/[id]/page.tsx はServer Componentのまま残し、編集ボタン・削除ボタン・編集フォームをClient Component(ComparisonGroupEditView 等、§5.1と共通コンポーネント)に切り出し、isDesktopMode をpropとして渡す。
編集操作フロー:
- 「編集」ボタンを押すと、現在のトラック構成が編集可能なトラック検索・選択UI(§7)に切り替わる
- 曲名検索でトラックを追加、または既存トラックを削除する(最終的に2件以上を維持する必要がある)
- 「保存」ボタンを押すと
PUT /api/comparisons/[id]に{ trackIds }(編集後の全件、addedAt昇順ではなく編集UI上での並び順をそのまま送信)を送信する - 保存成功後は
router.refresh()でサーバー側データを再取得し、表示モードに戻る
削除操作フロー:
- 「削除」ボタンを押すと確認ダイアログ(
window.confirm等)を表示する - 確認後
DELETE /api/comparisons/[id]を送信する - 成功時は対比一覧画面(
/comparisons)へrouter.push()で遷移する
6. トップページ(/)変更
変更箇所
Topページ(app/page.tsx)のナビゲーションリンク群に「対比」リンクを追加する(変更なし、既存のまま)。
Topページのナビゲーションはその後の機能追加で大幅に増えており(メンバー・ユニット・関係性マップ・リリース・プレイリスト・ライブ・フェス・ラジオ・対比、デスクトップモード時は楽曲リンク修正・同期状況も追加)、詳細は screen-design.mdx の「Topページ(
/)」セクションを参照。
| 項目 | 内容 |
|---|---|
| アンカー文字列 | 対比 |
| リンク先 | /comparisons |
| スタイル | 他のナビゲーションリンクと同等 |
7. トラック検索・選択UI(ComparisonGroupEditView)
ライブ・フェス機能 画面設計書 §11「セットリスト画面」の SetlistEditView と同じパターンを踏襲する。現状「トラック一覧」専用画面は存在しないため、このUIが検索・選択の唯一の導線になる。
| 要素 | 内容 |
|---|---|
| 検索入力 | テキスト入力。曲タイトルの部分一致でクライアントサイドフィルタ(リリースタイトル・アーティスト名にはマッチしない。対比対象を探す検索であり、無関係な同名リリース収録曲を誤って拾わないため) |
| 検索結果 | チェックボックス付きリスト。各行に「リリースタイトル / アーティスト名 — 曲タイトル」を表示し、複数行を同時にチェック可能。最大30件に制限 |
| 追加操作 | チェックした複数トラックをまとめて「追加」ボタンでローカルの選択済リストへ追加 |
| 選択済リスト | <ol> で登録順に表示。曲タイトルにリリースタイトル・アーティスト名を併記する(同一曲名の異なるリリース収録トラックが並んだ場合に判別できるようにするため)。削除ボタンで個別に除去可能(並び替えは提供しない。表示順は登録順固定のため) |
| 候補データ | ページ側で全トラック候補({ trackId, title, releaseTitle, artist }[])を事前に取得し props として渡す(SetlistEditView の TrackOption に artist を加えた形。動的クエリではない)。候補は Release.format が single・album のリリースの収録曲に限定する(ライブ音源・コンピレーション等は対比対象として不適切なため除外)。並び順は single のリリースを album より前に配置する(§4のAPI設計で対比グループ名は trackIds[0] の曲名を採用する仕様のため、複数選択して追加する際にチェックした順序に関わらずシングルが優先的に trackIds[0] になるようにするため)。既に他の対比グループに所属済のトラックは候補から除外する(編集時は編集対象グループ自身の所属トラックは除外しない)。除外漏れがあっても曲対比機能 データ設計書 §4のAPI検証(事前の重複チェック)により409で拒否する。この事前チェックを他リクエストが競合してすり抜けた場合も、§3の@@unique([trackId])制約違反(Prisma P2002)を個別に検出し、同じ409を返す(役割分担: 409を実際に返すのはAPI検証・事前チェック側で、@@unique制約はその前提となる「1トラック1グループ」のデータ整合性をDBレベルで保証する) |
8. 曲詳細画面(/songs/[id])変更
変更箇所
「収録リリース一覧」セクションの下・「関連メンバー」セクションの上に「対比候補」セクションを追加する(変更なし、既存のまま)。
表示条件
該当 trackId を持つ ComparisonGroupTrack が存在する場合のみ表示する。
表示コンテンツ
| 項目 | 内容 |
|---|---|
| セクション見出し | 対比候補(既存セクション見出しと同スタイル) |
| リンク | "{title} 対比"(/comparisons/[groupId] へ) |
データ取得
曲対比機能 データ設計書 §5「曲詳細画面(app/songs/[id])の対比リンク」を参照。Prismaクエリの結果が空(該当なし)の場合はセクション非表示。
9. 更新履歴
| 版 | 更新日 | 変更内容 | 関連 Issue |
|---|---|---|---|
| 2.2 | 2026-09-25 | §7の候補データの記述を修正。「@@unique([trackId])制約と…API検証により409で拒否する」という並列表記が、409を実際に返す主体(API検証・事前チェック)と、その前提となるデータ整合性を保証する@@unique制約の役割を混同していたため、両者の役割分担が分かるよう書き分けた(レビューで検出) |
MorningStatusApp#1660 |
| 2.1 | 2026-09-24 | §7のトラック検索UIを改善。候補データをRelease.formatがsingle・albumのリリースの収録曲に限定(ライブ音源・コンピレーション等を除外)し、検索は曲タイトルにのみマッチするよう変更(リリースタイトル一致による無関係な曲の混入を防止)。検索結果をチェックボックス付きリストにして複数選択後に一括追加できるようにし、選択済リスト・検索結果の両方にリリースタイトルとアーティスト名を併記して同一曲名の判別を可能にした。§4.2のグループ表示見出しを、固定文字列(「シングル」「その他」)ではなく実際のトラックのreleaseFormatからFORMAT_LABELで導出する方式に変更し、フォーマットが1種類のみの場合も省略せず表示するよう修正。候補データの並び順をsingleがalbumより前に来るよう変更し、複数選択して追加する際に対比グループ名(trackIds[0]の曲名)が意図せずアルバム版になることを防止(ユーザーからの改善指摘) |
MorningStatusApp#1658 |
| 2.0 | 2026-09-22 | 対比機能の再構築(Neon DB化)に伴い全面改訂。対比一覧・対比詳細画面のデータ取得元をNeon DBに変更、デスクトップモードでの新規作成・編集・削除UI(§5)とトラック検索・選択UI(§7)を追加。§7の候補データから、既に他の対比グループに所属済のトラックを除外する仕様を追記(レビューで検出) | MorningStatusApp#1633, morning-status-blume#148 |
| 1.1 | 2026-03-29 | 対比一覧をカード形式からリスト形式に変更(#494) | #494 |
| 1.0 | 2026-03-29 | 初版作成 | #474 |