画面設計書
概要
MorningStatusApp は Next.js App Router をベースとした Web アプリケーション。 以下の35画面で構成される。
画面一覧
| 画面名 | URL パターン | レンダリング方式 | 追加バージョン |
|---|---|---|---|
| Topページ | / |
SSR(動的) | v0.1.0〜 |
| メンバー一覧 | /members |
SSR(動的) | v0.1.0〜 |
| メンバー詳細 | /members/[id] |
SSR(動的) | v0.1.0〜 |
| リリース一覧 | /releases |
SSR(動的) | v0.2.0〜 |
| リリース詳細 | /releases/[id] |
SSR(動的) | v0.2.0〜 |
| 曲詳細 | /songs/[id] |
SSR(動的) | v0.6.0 |
| プレイリスト一覧 | /playlists |
SSR(動的) | v0.7.0 |
| プレイリスト詳細 | /playlists/[id] |
SSR(動的) | v0.7.0 |
| 曲検索 | /search |
SSR(動的) | v1.0.0 |
| 対比一覧 | /comparisons |
SSR(動的) | v1.1.0 |
| 対比詳細 | /comparisons/[id] |
SSR(動的) | v1.1.0 |
| ユニット一覧 | /units |
SSR(動的) | v1.5.0 |
| ユニット詳細 | /units/[id] |
SSR(動的) | v1.5.0 |
| ライブ一覧 | /lives |
SSR(動的) | v3.0.0 |
| ライブ詳細 | /lives/[id] |
SSR(動的) | v3.0.0 |
| 地域ブロックマップ | /lives/map |
SSR(動的) | v3.0.0 |
| 都道府県別公演 | /lives/prefecture/[code] |
SSR(動的) | v3.0.0 |
| 同期状況 | /sync-status |
SSR(動的) | v3.3.0〜(デスクトップ専用) |
| 楽曲リンク修正 | /link-editor |
SSR(動的) | v5.5.0〜(デスクトップ専用) |
| YouTube投稿一覧 | /youtube |
SSR(動的) | v6.5.0 |
| YouTube公式チャンネル | /youtube/official |
SSR(動的) | v6.5.0 |
| YouTube OGチャンネル | /youtube/og/[memberId] |
SSR(動的) | v6.5.0 |
| フェス一覧 | /festivals |
SSR(動的) | v3.9.0 |
| フェス詳細 | /festivals/[id] |
SSR(動的) | v3.9.0 |
| セットリスト | /setlists/[id] |
SSR(動的) | v4.0.0 |
| ラジオ番組一覧 | /radio |
SSR(動的) | v4.3.0 |
| 番組別放送回一覧 | /radio/[show_id] |
SSR(動的) | v4.3.0 |
| 放送回詳細 | /radio/episodes/[episode_id] |
SSR(動的) | v4.3.0 |
| Instagram投稿一覧 | /instagram |
SSR(動的) | v4.5.0 |
| Instagramアカウント別 | /instagram/[accountId] |
SSR(動的) | v7.6.0 |
| TikTok投稿一覧 | /tiktok |
SSR(動的) | v4.2.0 |
| Amebaブログ一覧 | /ameba |
SSR(動的) | v4.5.0 |
| タイムライン | /timeline |
SSR(動的) | v5.0.0 |
| メンバー関係性マップ | /member-map |
SSR(動的) | v8.0.0 |
| レーダーチャート | /member-map/radar |
SSR(動的) | v9.0.0 |
機能別の詳細設計書:
- プレイリスト画面
- 曲対比画面
- ユニット画面
- ライブ機能画面
- YouTube投稿一覧画面
- タイムライン画面
- メンバー関係性マップ画面
- メンバー関係性マップ レーダーチャート画面
- ラジオオンエア収集(UI設計セクションあり)
- Amebaブログ機能(UI設計セクションあり)
画面遷移図
Topページが全ドメインのハブとなり1枚の図に収まらないため(#1435)、「TOP画面内遷移図」「外部遷移図(タイムライン・年表・関係性マップ系列)」「外部遷移図(リリース・ライブ・ラジオ等イベント系列)」の3図に分割する。
TOP画面内遷移図
Topページから各セクション一覧への一次遷移のみを示す。各セクション内部の詳細な遷移は後続の外部遷移図を参照。
外部遷移図(タイムライン・年表・関係性マップ系列)
外部遷移図(リリース・ライブ・ラジオ等イベント系列)
音楽コンテンツ・ライブ/フェス・ラジオ・SNS投稿の4クラスタに分けて表示する。クラスタをまたぐ遷移(例: ライブ詳細→メンバー詳細)も存在する。
既知の制約: メンバー詳細(曲詳細も一部)が他クラスタと相互に繋がる実質的なハブになっているため、1枚の図にまとめるとMermaidのレイアウトエンジンが4クラスタを横に並べて配置し、図全体の実寸幅が広くなりすぎて何を見ているか把握しづらくなる(#1435, #30)。クラスタ単位、さらにクラスタ内でも関連の薄いグループ単位で図を分割し、他グループへの遷移先は接続先ノード(メンバー詳細・曲詳細等)のみを示す形にすることで、1図あたりのサイズを読める範囲に抑えている。接続先ノードの内部遷移は、そのノードが属する図を参照。
音楽コンテンツ
メンバー・リリース・曲・ユニット
プレイリスト・対比
ライブ・フェス
ライブ
フェス
ラジオ
SNS投稿
TikTok・Ameba
YouTube
各画面の設計
1. Topページ(/)
概要: ナビゲーション・新着投稿ダイジェストを表示するトップ画面。メンバーカード一覧は「2. メンバー一覧画面(/members)」に分離されている。
表示コンテンツ
| 要素 | 内容 |
|---|---|
| タイトル | “Hello! Project History” |
| サブテキスト | アプリの説明文(歴代メンバー数・対象年を含む) |
| バージョン・更新日 | `v{version} |
| ナビゲーションリンク | メンバー・ユニット・関係性マップ・リリース・プレイリスト・ライブ・フェス・ラジオ・対比(横並び。デスクトップモード時は楽曲リンク修正・同期状況も追加) |
| 曲検索・タイムラインリンク | グローバルヘッダー(全画面共通)。クリックでそれぞれ /search・/timeline に遷移 |
| 新着投稿セクション | Ameba・Instagram・TikTok・YouTubeの新着をまとめて表示(後述、各SNSの一覧画面へのリンクは新着0件でも常時表示) |
| 過去のこの日セクション | 参照日と月日が一致するメンバーの記念日(誕生日・加入日・卒業日)に加え、過去複数年にわたるリリース・ライブ・メディア(ラジオ)出演・トピック等の出来事を年ごとに一覧表示(OnThisDaySection) |
新着投稿セクション
- 表示条件: 各SNSセクション(見出し・一覧画面へのリンク)は新着の有無に関わらず常時表示する。新着が0件のSNSは中身を「本日の新着投稿はありません」に差し替える(#1404: 以前は0件のSNSはリンクごと非表示になり、全SNSが0件の日はセクション全体が非表示だったため、一覧画面への導線が失われる不具合があった)
- 参照日ヘッダー:
{参照日の JST 日付} の新着投稿(詳細は後述の「参照日ヘッダー」を参照) - 著作権表記: 「(Instagram/TikTok/YouTubeの各画像は参考表示:権利はすべて投稿者に帰属しています)」。TikTok画像の参考表示期限切れ時はリンクのみの表示になる旨を併記
- 表示順: Instagram → TikTok → YouTube → Ameba
| SNS | 新着ありの場合の内容 | 0件時の表示 | 一覧へのリンク | 備考 |
|---|---|---|---|---|
| 当日新規取得の投稿(サムネイル/Live) | 「本日の新着投稿はありません」 | /instagram |
サムネイル正方形グリッド。Reel/Live投稿は専用ラベル表示 | |
| TikTok | 直近の収集日(capturedAt)の投稿 |
「本日の新着投稿はありません」 | /tiktok |
サムネイル有効期限切れの投稿はキャプションのみのカードリンクで表示(#1408: 投稿日時基準から収集日時基準に変更) |
| YouTube | 直近の収集日(capturedAt)の投稿 |
「本日の新着投稿はありません」 | /youtube |
公式チャンネルを優先してソート表示(#1408: 投稿日時基準から収集日時基準に変更) |
| Ameba | 公式Amebaブログ登録済みメンバーの、新着ウィンドウ(前々回の定期同期時刻〜直近の同期時刻)内の投稿 | 「本日の新着投稿はありません」 | /ameba |
メンバー名+投稿タイトル(statusHistory各エントリのcontent先頭行)のリストで表示。1メンバーが同ウィンドウ内に複数件投稿している場合は全件表示。詳細は Amebaブログ機能 データ設計書 を参照(#1387) |
参照日ヘッダー
- 表示条件: 新着投稿の参照日(当日の新着日時、なければメンバーデータの最終更新日時)が取得できる場合に表示。新着が全SNSで0件の日も、メンバーデータの最終更新日を参照日として表示する
- 日付ラベル:
{参照日の JST 日付} の新着投稿 - 出来事表示: 参照日と月日が一致するメンバーの記念日を表示
| 種別 | 集約単位 | 表示形式 |
|---|---|---|
| 誕生日 | 個別(1人1エントリ) | {name} 誕生日 |
| 加入日 | 同年グループ(同じ年に加入した複数名を1エントリに集約。異なる年は別エントリ) | {name1}・{name2} 加入日 |
| 卒業日 | 同年グループ(同じ年に卒業した複数名を1エントリに集約。異なる年は別エントリ) | {name1}・{name2} 卒業日 |
2. メンバー一覧画面(/members)
概要: 全メンバーのカードを現役・OG に分けて表示する一覧画面。
表示コンテンツ
| 要素 | 内容 |
|---|---|
| 見出し | 「メンバー一覧」 |
| メンバー選択 | 現役・OGをoptgroupで分けたドロップダウン(MemberSelect)。選択すると対象メンバーの詳細画面(/members/{id})に直接遷移する(検索・絞り込みではない) |
| セクションリンク | 「現役メンバー」「OGメンバー」(見出し行の下に横並び、各セクションへのアンカー) |
| 現役メンバーセクション | status === 'Active' のメンバーカード一覧(MemberCard グリッド、人数表示付き) |
| OGメンバーセクション | status === 'OG' のメンバーカード一覧(MemberCard グリッド、人数表示付き) |
MemberCard の表示内容
| 要素 | 内容 |
|---|---|
| 世代バッジ | {generation}期 |
| メンバー名 | 漢字氏名(name)+ルビ(ruby) |
| ステータスバッジ | 現役 または OG |
| SNSステータスバッジ | SNS更新あり・SNS更新なし・SNS取得エラーの状態表示。公式SNS未設定(skipped/unknown)のメンバーは非表示 |
| 更新日時 | {投稿 or 更新}: {YYYY-MM-DD}。公式SNSソースと一致する場合は「投稿」、それ以外は「更新」と表示。公式SNS未設定のメンバーは非表示 |
| SNS確認日時 | SNS確認: {YYYY-MM-DD}(未確認の場合は「未確認」)。公式SNS未設定のメンバーは非表示 |
| カードリンク | クリックで /members/{id} に遷移 |
SNSステータスバッジの状態
| 状態 | 表示色 | 条件 |
|---|---|---|
| SNS更新あり | 緑 | status === 'ok' && hasRecentUpdate === true |
| SNS更新なし | 灰 | status === 'ok' && hasRecentUpdate === false |
| SNS取得エラー | 赤 | status === 'error' |
| (非表示) | — | status === 'skipped' または 'unknown'(公式SNS未設定) |
3. メンバー詳細画面(/members/[id])
概要: 特定メンバーのプロフィール・近況・ディスコグラフィーを表示し、データ編集もできる画面。
動的レンダリング: generateStaticParams() でルートを定義し、リクエスト時に Vercel Blob から最新データを取得する(getMembersFromBlob() が cache: "no-store" でフェッチするため SSR として動作)。
表示コンテンツ
| 要素 | 内容 |
|---|---|
| ナビゲーション | 「メンバー一覧に戻る」+「前のメンバー / 次のメンバー」 |
| プロフィールヘッダ | 氏名・読み・世代バッジ・ステータスバッジ |
| 編集ボタン | 「編集」ボタンはプロフィールヘッダ内のステータスバッジの左に配置。クリックで編集モードに切り替え |
| 基本情報 | 生年月日・出身地(設定時のみ表示)・加入日・卒業日・家族構成 |
| 公式 SNS | アクティブな SNS URL のリンク一覧(inactive は打ち消し線表示) |
| ページ内リンク | 最新の近況以下の各セクションへのリンク |
| SNS チェック結果 | SNS の最終確認日時・更新状態(snsCheck の値を表示)。公式SNS未設定のメンバーは非表示 |
| 最新の近況 | latestStatus.content。情報ソースが1件(ブログ投稿等)のときは本文自体をソースURLへのアンカーにし、URL一覧は表示しない。2件以上(Exa検索結果)のときは従来通り情報ソース URL 一覧を表示(#1496) |
| 検索注記 | ※Exa検索の結果をを表示していることを注記 |
| 近況履歴 | statusHistory の折りたたみ一覧(最新順:直近30日以内 かつ 100件以内(早い方を適用)) |
| Instagram 投稿 | 最新12件の投稿グリッド(3カラム)。officialSns に Instagram URL が未登録または active: false のメンバーはセクション非表示(詳細は Instagram 投稿セクション参照) |
| YouTube 動画 | 公式チャンネル動画のうち、タイトルにメンバーのフルネームが含まれる動画のグリッド表示。マッチが0件の場合はセクション非表示(詳細は YouTube 動画セクション参照) |
| 所属ユニット | このメンバーが所属するユニット一覧(詳細は unit-screen-design.mdx §5.1) |
| 関連リリース | 在籍期間に紐づくモーニング娘。リリース一覧(サブユニット専用リリースを除く。リリース詳細へのリンク) |
| 選曲した楽曲 | プレイリスト掲載情報の抜粋表示(プレイリスト一覧リンクをラベル直下に配置) |
| 関連ライブ | 出演した公演の一覧(詳細は live-screen-design.mdx §8.1) |
編集モード
| 要素 | 内容 |
|---|---|
| 近況テキスト入力 | latestStatus.content の編集(required バリデーション) |
| 情報ソース入力 | latestStatus.sources の URL 追加・削除 |
| YouTubeチャンネル名入力 | youtubeChannel.handle(@〜 形式・空欄可)の編集。保存時にサーバー側が YouTube Data API でプレイリストIDに変換する(#1105) |
| 保存ボタン | PUT /api/members で Vercel Blob に保存し statusHistory へ蓄積 |
| キャンセルボタン | 編集内容を破棄して表示モードに戻る |
前/次ナビゲーション順序: 世代・加入日昇順でソートしたメンバーリストの前後インデックス。
Instagram 投稿セクション
- 表示条件:
officialSnsにinstagram.comを含むactive: trueの URL が登録されているメンバーのみ表示。条件を満たさない場合はセクション自体を非表示にする - 表示位置: 関連ライブの下(メンバー詳細ページの最下部)
- データソース: Vercel Blob の
instagram/{memberId}/posts.json(InstagramPost[]型) - 表示件数: 最新12件(
capturedAt降順) - レイアウト: 3カラムグリッド
| 要素 | 内容 |
|---|---|
| 投稿画像 | imageBlobUrl(レガシー)または thumbnailUrl(外部参照)の正方形画像(アスペクト比 1)。imageBlobUrl を優先し、なければ thumbnailUrl を使用する |
| Reelラベル | isReel: true の投稿は画像左下に「Reel」ラベルを表示する |
| キャプション | ホバー時に画像上にオーバーレイ表示(caption が空文字の場合は非表示) |
| クリック動作 | postUrl(元の Instagram 投稿 URL)を新しいタブで開く |
| 画像エラー時 | 投稿削除済み等で画像ロード失敗した場合はグレーのプレースホルダーを表示 |
- データ未取得時: Instagram URL は登録されているが Blob に
posts.jsonが存在しない場合は「まだ投稿データが取得されていません」を表示する(セクションは表示する)
YouTube 動画セクション(#9)
- 表示条件: 公式チャンネル動画のタイトルにメンバーのフルネームが一致する動画が1件以上ある場合のみ表示する。
officialSnsの登録有無やメンバー自身のYouTubeチャンネル登録有無は問わない(言及ベースの表示のため) - 表示位置: TikTok投稿セクションの直後
- データソース: Neon
youtube_posts(channelType = 'official')をgetAllOfficialYoutubePosts()で取得し、attributeYoutubeVideoToMembers()でフィルタする(詳細は youtube-data-design.md §6.1) - 表示件数: 上限なし(マッチした全件)
- レイアウト: グリッド(TikTok投稿セクションと同様のパターン)
| 要素 | 内容 |
|---|---|
| サムネイル | https://i.ytimg.com/vi/{videoId}/hqdefault.jpg(16) |
| タイトル | 動画タイトル(2行 clamp) |
| クリック動作 | https://www.youtube.com/watch?v={videoId} を新しいタブで開く |
- 判定結果の保存: DBには保存せず、表示のたびに都度計算する(詳細は youtube-data-design.md §6.1)
4. リリース一覧画面(/releases)
概要: モーニング娘。(年号付き含む)のディスコグラフィーをフォーマット別(シングル・アルバム・EP・その他)に分けて表示する画面。サブユニット専用リリース(タンポポ・ミニモニ。・W 等の Unit.releaseIds に含まれるもの)は除外する。
表示コンテンツ
| 要素 | 内容 |
|---|---|
| アンカーナビゲーション | 存在するフォーマット(single / album / ep / live / soundtrack / compilation / other)へのリンク。各リンクの先頭に ReleaseBadge を表示 |
| フォーマット別セクション | リリース日降順のリリースタイトル一覧(リリース詳細へのリンク) |
| データなし表示 | リリースデータが空の場合は「同期ジョブ実行後に表示」メッセージ |
フォーマットラベル(ReleaseBadge)
| フォーマット | ラベル | バッジ色 |
|---|---|---|
| single | シングル | 青 (#2563eb) |
| album | アルバム | 緑 (#16a34a) |
| ep | EP | 紫 (#7c3aed) |
| live | ライブアルバム | オレンジ (#ea580c) |
| soundtrack | サウンドトラック | 黄 (#ca8a04) |
| compilation | コンピレーション | シアン (#0891b2) |
| other | その他 | グレー (#6b7280) |
5. リリース詳細画面(/releases/[id])
概要: 特定リリースの詳細情報とメンバーを表示する画面。
表示コンテンツ
| 要素 | 内容 |
|---|---|
| 前後ナビゲーション | 「前の画面に戻る」(BackLink によりブラウザ履歴がある場合は router.back()、なければ /releases にフォールバック)+ 「← 前のリリース / 次のリリース →」(同フォーマット内でリリース日降順・同日はタイトル昇順) |
| フォーマットバッジ | FORMAT_LABEL[format] のラベル |
| タイトル | リリースタイトル |
| ユニット名 | releaseIds に当該リリース ID を含むユニット名(ユニット詳細へのリンク)。詳細は unit-screen-design.mdx §5.2 |
| リリース日 | YYYY-MM-DD 形式(不明の場合は「日付不明」) |
| ソース URL | MusicBrainz 等の情報ソースリンク(有効 URL のみ表示) |
| YouTube MV | links に youtube タイプのエントリが設定されている場合のみ表示。新しいタブで YouTube を開くリンクボタン(#348, #425) |
| 収録曲一覧 | トラックリスト(#339 完了後に表示。未取得時は非表示) |
| メンバー | 在籍期間が重なるメンバー一覧(メンバー詳細へのリンク) |
収録曲一覧セクション
- 配置場所: ソース URL とメンバーの間に配置する
- 表示項目:
| 項目 | 内容 |
|---|---|
| トラック番号 | Track.trackNumber(ディスク内での連番) |
| 曲名 | Track.title |
| 再生時間 | Track.length をミリ秒から M:SS 形式に変換して表示。未登録の場合は非表示 |
- ゼロ件時:
tracksフィールドが存在しない、または空配列の場合はセクション自体を非表示にする(「収録曲なし」等のメッセージは表示しない) - マルチディスク構成:
Track.discNumberが複数値を持つ場合は、ディスク番号ごとにグループ化して見出し(「Disc 1」「Disc 2」等)を表示する。全曲が同一ディスクの場合はグループ見出しを省略する - ソート順:
discNumber ASC, trackNumber ASC(discNumberが省略された場合は1として扱う)
6. 曲詳細画面(/songs/[id])
概要: 特定楽曲(recording)の詳細情報・収録リリース・外部リンク・プレイリスト掲載情報を表示する画面。
URL パラメータ: [id] = Track.id(MusicBrainz recording UUID)
データソース: Neon DB(releases / tracks テーブル)を全走査し、Track.id が一致するトラックを特定する。同一 recording UUID は複数リリースに存在し得る(例: シングル収録後にアルバムにも収録)。
動的レンダリング: force-dynamic で Neon DB から最新データを取得する(getMembersFromBlob() / getReleases() を使用)。
表示コンテンツ
| 要素 | 内容 |
|---|---|
| ナビゲーション | 「前の画面に戻る」(ブラウザ履歴を1つ戻る。リリース詳細・ユニット詳細・プレイリスト詳細のどちらから遷移しても対応。直接アクセス時のフォールバック: リリース詳細) |
| 曲タイトル | Track.title |
| 再生時間 | Track.length をミリ秒から M:SS 形式に変換して表示。未登録の場合は非表示 |
| アーティスト | 再生時間の右にユニット名をリンク表示。トラックの releaseId をキーに units.json を逆引きして特定(#538 で実装。詳細は unit-screen-design.mdx §5.3) |
| 動画(MV / YouTube Shorts) | Track.links に youtube または youtube-short タイプが存在する場合、アーティストの直下に VideoSelector でインライン iframe(16)表示。MV のみの場合はそのまま埋め込み、Shorts も存在する場合はドロップダウンで切り替え可能(#452, #774, #828) |
| YouTube リンク編集 | デスクトップモード(DESKTOP_MODE=1)のみ表示。現在の YouTube URL を確認・削除・URL 変更できる(#696)。DELETE /api/tracks/[id]/youtube-link / PUT /api/tracks/[id]/youtube-link を使用 |
| YouTube Shorts 編集 | デスクトップモード(DESKTOP_MODE=1)のみ表示。既存 Shorts リンクの個別削除と「次回バッチで再取得する」チェックボックス(Track.shortsRefetchRequested フラグ)を提供(#824)。DELETE /api/tracks/[id]/youtube-shorts / PATCH /api/tracks/[id]/youtube-shorts を使用 |
| 外部リンクセクション | Track.links の YouTube Music 等リンク(youtube・youtube-short・genius 以外のみ表示) |
| 収録リリース一覧 | この recording を収録しているリリース一覧(/releases/[id] へのリンク。リリース日昇順) |
| 対比候補 | trackComparisonMap に一致するペア情報がある場合のみ表示(/comparisons/[pairId] へのリンク) |
| プレイリスト掲載情報 | PlaylistEntry.trackId === track.id のプレイリスト一覧(詳細は playlist-screen-design.mdx §5.2) |
収録リリース一覧セクション
| 項目 | 内容 |
|---|---|
| リリースタイトル | Release.title(リリース詳細画面へのリンク) |
| フォーマット | FORMAT_LABEL[release.format] のラベル(バッジ表示) |
| リリース日 | Release.releaseDate(不明の場合は「発売日不明」) |
| トラック情報 | Disc {discNumber} / Track {trackNumber}(マルチディスクの場合のみ Disc 番号を表示) |
- 収録リリースが複数ある場合はリリース日昇順(古い順)で表示する
- 収録リリースが必ず1件以上存在することを前提とする(
Track.idに一致するリリースが見つからない場合はnotFound()を返す)
外部リンクセクション
| リンク種別 | 表示形式 |
|---|---|
| YouTube Music | 「♪ YouTube Music で聴く」ボタン(新しいタブで開く) |
- YouTube MV・YouTube Shorts はインライン表示のためこのセクションには含めない
youtube・youtube-short・genius以外のリンクが存在する場合のみセクションを表示するTrack.linksが空またはフィールド自体が存在しない場合はセクション自体を非表示にする
対比候補セクション
| 項目 | 内容 |
|---|---|
| 対比候補リンク | trackComparisonMap[track.id] のペアタイトル(/comparisons/[pairId] へのリンク) |
trackComparisonMapに当該track.idが存在する場合のみセクションを表示する- 存在しない場合はセクション自体を非表示にする
プレイリスト掲載情報セクション(#366 完了後に実装)
| 項目 | 内容 |
|---|---|
| プレイリスト名 | プレイリスト詳細画面(/playlists/[id])へのリンク |
| 選曲メンバー | プレイリストを作成したメンバーの名前(メンバー詳細画面へのリンク) |
- このトラックを選曲しているプレイリストが存在しない場合はセクション自体を非表示にする
リリース詳細画面からのリンク仕様
- リリース詳細画面(
/releases/[id])の収録曲一覧に表示される各曲名を、/songs/[Track.id]へのリンクにする Track.idが空文字列の場合はリンクなしでテキストのみ表示する(後方互換)- リンクはインラインリンク(
<Link>)で同一タブ遷移
7. 同期状況画面(/sync-status)
概要: 各種バッチ同期ジョブの最終実行状況・取得進捗をまとめて確認するデスクトップ専用画面。
アクセス制限: DESKTOP_MODE 環境変数が設定されている場合(DESKTOP_MODE=1)のみ表示。未設定時は notFound() を返す。
データソース
| セクション | データソース |
|---|---|
| 近況同期 | Vercel Blob の members.json(resolveSnsCheck で各メンバーのステータスを集計) |
| Instagram同期 | Vercel Blob の instagram-sync-status.json |
| Genius リンク同期 | Vercel Blob の genius-links-status.json |
| ディスコグラフィー同期 | Vercel Blob の discography-status.json |
表示コンテンツ(共通)
| 要素 | 内容 |
|---|---|
| ナビゲーション | 「← メンバー一覧に戻る」(/ へのリンク) |
| ページタイトル | 「同期状況」 |
近況同期セクション
| 項目 | 内容 |
|---|---|
| 最終バッチ実行 | 全メンバーの snsCheck.lastCheckedAt の最大値を JST 表示(未確認の場合は「未確認」) |
| 成功 | snsCheck.status === 'ok' のメンバー数 |
| エラー | snsCheck.status === 'error' のメンバー数 |
| 未確認 | snsCheck.status === 'unknown' または 'skipped' のメンバー数 |
Instagram同期セクション
データが存在しない場合は「データがありません。Instagram同期を実行後に表示されます。」を表示。
| 項目 | 内容 |
|---|---|
| 最終同期 | instagramSyncStatus.lastSyncedAt を JST 表示 |
| セッション状態 | sessionStatus === 'valid' → 「有効」(緑)、それ以外 → 「失効」(赤) |
| メンバー取得率 | capturedMembersCount / totalTargetMembersCount * 100(%表示)+ N / M 人表示 + プログレスバー |
Genius リンク同期セクション
データが存在しない場合は「データがありません。Genius リンク同期を実行後に表示されます。」を表示。
| 項目 | 内容 |
|---|---|
| 最終同期 | geniusLinksStatus.lastSyncedAt を JST 表示 |
| 最新状況 | 最新スナップショットの取得率(%)・取得済み / 対象曲数・残り曲数・プログレスバー |
| 棒グラフ | GeniusLinksStatusChart(履歴 1 件以上の場合に表示)。過去 N 日分の取得済 / 未取得をスタック棒グラフで表示 |
ディスコグラフィー同期セクション
データが存在しない場合は「データがありません。ディスコグラフィー同期を実行後に表示されます。」を表示。
| 項目 | 内容 |
|---|---|
| 最終同期 | discographyStatus.lastSyncedAt を JST 表示 |
| YouTube リンク取得率 | youtubeFetchedTracks / youtubeTargetTracks * 100(%表示)・N / M 曲・リリース N 件・プログレスバー |
| Shorts リンク取得率 | shortsFetchedTracks / shortsTargetTracks * 100(%表示)・N / M 曲・残り N 曲・プログレスバー。shortsTargetTracks が undefined の場合は非表示 |
| 棒グラフ | DiscographyStatusChart(履歴 1 件以上の場合に表示)。過去 N 日分の YouTube 取得済 / 未取得(緑)をスタック棒グラフで表示。shortsTargetTracks を持つ履歴が存在する場合は Shorts 取得済 / 未取得(ピンク)の系列を並列表示(#832) |
DiscographyStatusChart 仕様
| 系列名 | 色 | stackId | 条件 |
|---|---|---|---|
| 取得済 | #4ade80(緑) |
youtube |
常時 |
| 未取得 | rgba(255,255,255,0.2) |
youtube |
常時 |
| Shorts取得済 | #f472b6(ピンク) |
shorts |
履歴に shortsTargetTracks が存在する場合のみ |
| Shorts未取得 | rgba(255,255,255,0.15) |
shorts |
履歴に shortsTargetTracks が存在する場合のみ |
- Shorts 系列が表示される場合、棒の幅は 24px に縮小(非表示時は 40px)
- チャート上部の説明文: Shorts 系列あり → “YouTube / Shorts 取得進捗(過去 N 日分)”、なし → “YouTube リンク取得進捗(過去 N 日分)”(#836)
8. 楽曲リンク修正画面(/link-editor)
概要: シングル曲トラックの TikTok・YouTube・Genius リンクを手動で確認・編集するデスクトップ専用画面。
アクセス制限: DESKTOP_MODE 環境変数が設定されている場合(DESKTOP_MODE=1)のみ表示。未設定時は notFound() を返す。
データソース
| セクション | データソース |
|---|---|
| トラック選択肢 | Release(format: 'single'、releaseDate 降順)+ 各リリースの Track(Prisma、trackNumber 昇順) |
| リンク済みURL | TrackLink(type が tiktok / youtube / genius) |
| TikTok候補投稿 | TikTokPost(トラックタイトルのトークンマッチ、またはリンク済みURL) |
表示コンテンツ(共通)
| 要素 | 内容 |
|---|---|
| ナビゲーション | 「← トップ」(/ へのリンク) |
| ページタイトル | 「楽曲リンク修正」 |
| トラック選択 | シングル曲トラックのセレクトボックス(リリースタイトル — 曲タイトル 形式) |
| サービスタブ | TikTok / YouTube / Genius の3タブ切り替え |
トラック選択肢の絞り込み(isVersionTrack)
Instrumental・カラオケ等のバージョン違い楽曲を選択肢から除外する。以下のいずれかに該当するトラックは対象外:
- タイトル末尾が角括弧(
< >/< >)で終わる - タイトル末尾の丸括弧(
( )/( ))内に既知のバージョンキーワード(instrumental/off vocal/インスト/カラオケ/tv mix等)を含む
TikTokタブ
| 項目 | 内容 |
|---|---|
| 候補投稿の抽出 | 選択中トラックのタイトルをトークン分解(tokenizeTitle。バージョン表記除去 → 記号区切りで分割 → 2文字以上のトークンのみ)し、TikTokPost.caption にいずれかのトークンを含む投稿を候補として抽出。このトラックに既にリンク済みの投稿はトークン不一致でも必ず候補に含める |
| キーワード追加検索 | 検索欄にキーワードを入力すると caption の部分一致(大小文字を区別しない)で追加検索し、既存候補にマージ(重複除去) |
| リンク済み/未リンクの表示分け | 「リンク済み(N件)」「未リンク(N件)」の2セクションに分け、チェックボックス一覧で表示 |
| 他トラックへのリンク除外 | 他のトラックに既にリンク済み(DB上)の投稿URLは「未リンク」候補から除外する(1投稿は1トラックにのみリンクする前提) |
| キャプション表示 | 80文字を超える場合は末尾を … で省略表示 |
YouTube/Geniusタブ
| 項目 | 内容 |
|---|---|
| リンク一覧 | リンク済みURLをチェックボックス一覧表示(チェックを外すと削除対象になる) |
| URL追加 | 入力欄にURLを入力し「追加」ボタンまたは Enter キーで一覧に追加(保存前はクライアント側の状態のみ) |
保存
- 追加・削除いずれかの変更がある場合のみ「保存」ボタンが活性化する
PATCH /api/link-editorに{ trackId, type, addUrls, removeUrls }を送信し、TrackLinkを差分更新する(removeUrlsをdeleteManyした後、addUrlsをcreate)- 保存成功後は
router.refresh()でサーバー側データを再取得する - TikTok / YouTube / Genius の各タブは独立した保存状態(
idle/saving/success/error)を持つ
API エンドポイント
| メソッド | パス | 概要 |
|---|---|---|
| GET | /api/members |
Vercel Blob から全メンバーデータを JSON で返す |
| PUT | /api/members |
メンバーデータを更新し Vercel Blob に保存する |
PUT リクエストボディ
{
"id": "string",
"latestStatus": {
"content": "string",
"lastUpdated": "YYYY-MM-DD",
"sources": ["url"]
}
}
PUT 成功時: statusHistory に新エントリを蓄積(最大 100 件)、revalidatePath でキャッシュを無効化。
youtubeChannel の解決(#1105): youtubeChannel.handle が空・未指定の場合はフィールドを削除、既存と同一の場合は解決済み playlistId を引き継ぎ(API 呼び出しなし)、新規・変更時は YouTube Data API(fetchPlaylistId)でプレイリストIDに変換して保存する。変換できない場合は 422 を返し保存を中断する。
改訂履歴
| 版 | 更新日 | 変更内容 |
|---|---|---|
| 3.17 | 2026-08-14 | §2 メンバー詳細「最新の近況」「近況履歴」の表示仕様を変更。情報ソースが1件(ブログ投稿)のときは本文をアンカー化し生URL表示を省略、2件以上(Exa検索結果)は従来通りURL一覧を表示(#1496) |
| 3.16 | 2026-07-29 | §2 メンバー詳細に YouTube 動画セクション(公式チャンネル動画のフルネーム一致によるメンバー判定)の設計を追加(#9) |
| 3.15 | 2026-07-24 | §1 新着投稿セクションのTikTok・YouTubeの新着判定基準を投稿日時から収集日時(capturedAt)に変更。収集が遅延した投稿が投稿日時基準では新着ウィンドウから漏れる不具合を修正(#1408) |
| 3.14 | 2026-07-24 | §1 新着投稿セクションの表示条件を変更。各SNSの一覧画面へのリンクを新着0件でも常時表示し、0件時は「本日の新着投稿はありません」を表示するよう修正(#1404) |
| 3.13 | 2026-07-22 | §2 メンバー詳細 Instagram投稿セクションにReelラベルの表示仕様を追記(#1373) |
| 3.12 | 2026-07-22 | /link-editor 画面を画面一覧・画面遷移図に追加(除外対象から解除)、§8 楽曲リンク修正画面の設計を新規追加(#1368) |
| 3.11 | 2026-07-20 | §1 新着投稿セクションのAmeba表示条件を、当日の暦日一致から新着ウィンドウ(前々回の定期同期時刻〜直近の同期時刻)判定に変更。1メンバー複数件表示に対応(#1387) |
| 3.10 | 2026-07-19 | /ameba 画面を画面一覧・画面遷移図に追加(除外対象から解除)。機能別詳細設計書に Amebaブログ機能 を追加(#1367) |
| 3.9 | 2026-06-23 | §1 新着投稿セクション参照日ヘッダーの出来事表示仕様を追加(加入日・卒業日は同年グループで集約、異なる年は別エントリ)(#1216) |
| 3.8 | 2026-06-22 | メンバー詳細画面の近況履歴セクションの表示件数を明記(直近30日以内 かつ 100件以内(早い方を適用))(#1206) |
| 3.7 | 2026-06-12 | §2 編集モードに YouTubeチャンネル名入力を追加、API エンドポイントに youtubeChannel 解決仕様を追記(#1105) |
| 3.6 | 2026-06-12 | 画面一覧に YouTube 関連3画面を追加、詳細設計書リンクを箇条書きに整理し youtube-screen-design.mdx を追加(#1106) |
| 3.5 | 2026-05-08 | §6 DiscographyStatusChart の説明文切り替え仕様を追記(#836) |
| 3.4 | 2026-05-07 | §6 同期状況画面の設計を新規追加。DiscographyStatusChart に Shorts 系列追加仕様を記載(#832) |
| 3.3 | 2026-05-06 | §5 曲詳細画面の動画セレクターをボタンからドロップダウンに変更(#828) |
| 3.2 | 2026-05-06 | §5 曲詳細画面に YouTube Shorts 編集セクションを追加(個別削除・再取得フラグ)(#824) |
| 3.1 | 2026-05-06 | §5 曲詳細画面の YouTube MV 行を動画セレクター(MV / Shorts 切り替え)に更新し、外部リンクセクションの除外条件に youtube-short を追加(#774) |
| 3.0 | 2026-05-01 | §1 新着Instagram投稿セクションのタイトルを capturedAt JST 日付に動的変更(フォールバック: 「本日の」)(#733) |
| 2.9 | 2026-04-30 | §1 トップ画面に新着Instagram投稿セクションを追加、§2 メンバー詳細の投稿画像ソース記述を更新(thumbnailUrl 対応)(#721, #751, #754) |
| 2.8 | 2026-04-26 | §2 メンバー詳細に Instagram 投稿セクションを追加(#716) |
| 2.7 | 2026-04-11 | §2 メンバー詳細のセクション順を「所属ユニット→関連リリース→選曲した楽曲→関連ライブ」に変更(#523) |
| 2.6 | 2026-04-11 | 画面一覧・遷移図にライブ関連4画面を追加、live-screen-design.mdx への参照を追加(#523) |
| 2.5 | 2026-04-05 | §1 一覧ページリンクに「ユニット一覧」を追加(#576) |
| 2.4 | 2026-04-05 | §4 収録ユニットセクション行を削除・「関連メンバー」→「メンバー」に訂正(Figmaデザインと同期) |
| 2.3 | 2026-04-04 | §2 編集ボタンの位置明記・SNSチェック結果追加・近況→最新の近況・Instagram投稿履歴削除・所属ユニット追加(#567)。§4 ユニット名行追加(#568)。§5 アーティストの配置を再生時間の右と明記・対比候補サブセクション追加(#569) |
| 2.2 | 2026-04-04 | §5 表示コンテンツ表のアーティストと YouTube MV の順序を入れ替え(アーティスト→YouTube MV に統一)(#565) |
| 2.1 | 2026-04-04 | §4 前後ナビ追加・プレイリスト掲載情報削除(#400 反映)・収録ユニット行追加(#563)。§5 アーティスト・対比候補追加、セクション順を実装と整合(#554) |
| 2.0 | 2026-03-30 | 画面一覧・遷移図にユニット一覧・詳細を追加、unit-screen-design.mdx への参照を追加(#533) |
| 1.9 | 2026-03-28 | メンバー詳細画面に Instagram 投稿履歴セクションの設計を追加(#475) |
| 1.8 | 2026-03-28 | 遷移図に曲検索画面への入口矢印を追加、メンバー一覧の一覧ページリンクに対比一覧・曲検索アイコンを追記(#492) |
| 1.7 | 2026-03-28 | 画面一覧・遷移図に曲検索(v1.0.0)・対比一覧・対比詳細(v1.1.0)を追加(#489) |
| 1.6 | 2026-03-27 | メンバー詳細の「選曲した楽曲」セクションのレイアウト調整(プレイリスト一覧リンクの移動) |
| 1.5 | 2026-03-25 | 曲詳細画面の YouTube MV 表示をインライン iframe に変更(#452)、メンバー詳細のソートトグルボタンスタイルをリファクタリング(#454) |
| 1.4 | 2026-03-22 | メンバー一覧のナビゲーション構成変更(プレイリスト一覧リンク追加・配置調整)、曲詳細の戻るリンクをブラウザ履歴ベースに変更(#393 #394) |
| 1.3 | 2026-03-21 | 画面一覧にプレイリスト一覧・詳細を追加、画面遷移図にプレイリスト関連遷移を追加 |
| 1.2 | 2026-03-19 | 曲詳細画面(/songs/[id])の設計を追加 |
| 1.1 | 2026-03-19 | リリース詳細画面に収録曲一覧・プレイリスト掲載情報セクションを追加 |
| 1.0 | — | 初版作成(メンバー一覧・詳細・リリース一覧・詳細) |