コンテンツにスキップ
Documents for MorningStatusApp
Esc
移動開く⌘Jプレビュー
このページの内容

プレイリスト機能 データ設計書

最終更新: 2026-03-21

1. 概要

playlists.json にメンバーが選曲したプレイリストデータを管理するためのデータ設計。 プレイリスト一覧・詳細ページ(#332)、メンバー詳細画面への選曲セクション追加(#333)、 リリース詳細画面へのプレイリスト掲載情報追加(#334)の前提基盤となる。


2. 背景・目的

目的 詳細
メンバー選曲データの管理 各メンバーが選曲した楽曲をプレイリスト単位で管理する
楽曲とリリース・トラックの紐付け releaseId / trackId により releases.json の既存データと連携する
外部サービスリンクの集約 Spotify・Apple Music・YouTube Music 等の複数プラットフォームへのリンクを一元管理する

3. 型定義

ExternalLinkType の拡張

types/external-link.tsExternalLinkType は現在 Track 向けに 'youtube' | 'youtube-music' のみ定義されている。 プレイリスト機能(#330)の型定義実装時に、以下の音楽ストリーミングプラットフォームを追加した。

// types/external-link.ts(#330 で更新済み)
export type ExternalLinkType =
  | 'youtube'
  | 'youtube-music'
  | 'spotify'
  | 'apple-music'
  | 'line-music'
  | 'recochoku'
  | 'mora'
  | 'other';

Track レベルのリンク(Track.links)は引き続き 'youtube' | 'youtube-music' のみを想定する。 other は上記以外のプラットフォームへのリンクを登録するための汎用値。

PlaylistEntry インターフェース

export interface PlaylistEntry {
  /** 選曲したメンバーの ID(members.json の id フィールドと一致)。グループ曲プレイリスト等では省略可 */
  memberId?: string;
  /** 表示用の楽曲タイトル(trackId 未設定時も含め常に必須) */
  songTitle: string;
  /** releases.json の id フィールド(リリースが特定できる場合に付与。省略可) */
  releaseId?: string;
  /**
   * Release.tracks 内の Track.id(MusicBrainz recording UUID)。
   * releaseId と組み合わせて使用する。releaseId なしで trackId のみの指定は不正。
   * アルバム収録曲・シングルカップリングを明示したい場合に設定する。省略可。
   */
  trackId?: string;
}

v0.7.6 変更: links: ExternalLink[] フィールドを廃止。外部リンクは releases.jsonTrack.links[] に一元管理する。詳細は tracklist-data-design.md を参照。

Playlist インターフェース

export interface Playlist {
  /** プレイリストの識別子(kebab-case。例: fukumura-mizuki-playlist-2026) */
  id: string;
  /** プレイリスト名 */
  name: string;
  /** 説明文(省略可) */
  description?: string;
  /** 公開日(YYYY-MM-DD 形式) */
  publishedAt: string;
  /** 収録楽曲のリスト */
  entries: PlaylistEntry[];
}

4. songTitleTrack.title の関係

PlaylistEntry には songTitle(手動入力)と、trackId が設定されている場合に参照できる Track.title(releases.json の正規表記)の2種類の曲名が存在する。

状況 UI での表示 備考
trackId あり Track.title を優先して表示する releases.json から引いた正規表記を使用
trackId なし songTitle を表示する ライブ音源など releases.json に存在しない楽曲
trackId あり・Track.titlesongTitle が食い違う Track.title を表示する 表記揺れは Track.title 側に統一

songTitle の役割: playlists.json の手動入力データとして常に必須。trackId が設定されている場合でも、UI は Track.title を表示するが songTitle は検索・フォールバック用途に保持する。意図的な表記差が必要な場合は trackId を設定しないこと。


5. playlists.json 入力フォーマット仕様

フィールド一覧

フィールド 必須 制約・説明
playlists[].id string 必須 kebab-case。小文字英数字とハイフンのみ。プロジェクト内で一意
playlists[].name string 必須 プレイリスト名(表示用)
playlists[].description string 省略可 プレイリストの説明文
playlists[].publishedAt string 必須 YYYY-MM-DD 形式
playlists[].entries[] PlaylistEntry[] 必須 楽曲リスト(空配列も可)
entries[].memberId string 省略可 members.jsonid フィールドと一致させること。グループ曲プレイリスト等、個人に帰属しない場合は省略可
entries[].songTitle string 必須 表示用の楽曲タイトル
entries[].releaseId string 省略可 releases.jsonid フィールドと一致させること
entries[].trackId string 省略可 Track.id(recording UUID)。releaseId が設定されている場合のみ指定可

プラットフォーム列挙値

対応サービス URL 形式例
spotify Spotify https://open.spotify.com/track/{id}
apple-music Apple Music https://music.apple.com/jp/album/{title}/{id}?i={track_id}
youtube-music YouTube Music https://music.youtube.com/watch?v={id}
youtube YouTube https://www.youtube.com/watch?v={id}
line-music LINE MUSIC https://music.line.me/webapp/track/{id}
recochoku レコチョク https://recochoku.jp/song/{id}
mora mora https://mora.jp/package/{id}
other 上記以外 任意の URL

id 命名規則

  • 形式: {memberId}-{playlist-description}-{year} (例: fukumura-mizuki-morning-musume-fav-2026
  • kebab-case で記述し、大文字・スペース・記号(ハイフン以外)は使用しない
  • プロジェクト内で一意性を担保すること(重複がないか手動で確認する)

記入例

{
  "playlists": [
    {
      "id": "fukumura-mizuki-morning-musume-fav-2026",
      "name": "譜久村聖セレクション:モーニング娘。名曲集",
      "description": "譜久村聖が選ぶモーニング娘。の思い出の名曲",
      "publishedAt": "2026-01-15",
      "entries": [
        {
          "memberId": "fukumura-mizuki",
          "songTitle": "LOVEマシーン",
          "releaseId": "fcd58b7d-77c0-37db-9334-5f50d92b09f1",
          "trackId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
        },
        {
          "memberId": "fukumura-mizuki",
          "songTitle": "ザ☆ピ〜ス!",
          "releaseId": "another-release-id"
        },
        {
          "memberId": "fukumura-mizuki",
          "songTitle": "ライブ限定曲"
        }
      ]
    }
  ]
}

6. JSON スキーマと Vercel Blob 格納方針

ファイル配置

ファイル 用途 更新方法
data/inputs/playlists.json ビルド凍結用の静的データ(Git 管理) 手動編集
Vercel Blob(playlists.json 本番環境での読み取り元 bun run upload-playlists でアップロード
Vercel Blob(member-playlist-index.json メンバー詳細画面の選曲セクション用 bun run build-playlist-index で再生成
Vercel Blob(track-playlist-index.json 曲詳細画面のプレイリスト掲載情報用 bun run build-playlist-index で再生成

プレイリスト更新手順

data/inputs/playlists.json を編集した後、以下を実行する。upload-playlists は内部で build-playlist-index も実行するため、1コマンドで両方完結する。

bun run upload-playlists

編集内容をコミット・プッシュすると、GitHub Actions の sync-playlist-links.yml ワークフローが自動実行される。このワークフローは各エントリの trackId / releaseId をもとに Neon track_links テーブルの該当トラックに YouTube Music URL を付与し(YOUTUBE_API_KEY を使用)、その後 build-playlist-index による派生インデックスの再生成も行われる。

環境変数の準備: BLOB_READ_WRITE_TOKEN は Vercel ダッシュボード → Blob ストア → Tokens から取得する。 ローカルで実行する場合は .env.local に設定する。 PLAYLISTS_BLOB_URL も設定されている場合、upload-playlists は Blob の既存データとマージしてから上書きする。

派生インデックスの環境変数設定

bun run upload-playlists(または bun run build-playlist-index)を初めて実行すると、コンソールに以下の URL が出力される。

member-playlist-index.json URL: https://xxxx.public.blob.vercel-storage.com/member-playlist-index.json
  → MEMBER_PLAYLIST_INDEX_BLOB_URL 環境変数に設定すること
track-playlist-index.json URL: https://xxxx.public.blob.vercel-storage.com/track-playlist-index.json
  → TRACK_PLAYLIST_INDEX_BLOB_URL 環境変数に設定すること

出力された URL を以下の2か所に設定する。

.env.local(ローカル開発用)

MEMBER_PLAYLIST_INDEX_BLOB_URL=https://xxxx.public.blob.vercel-storage.com/member-playlist-index.json
TRACK_PLAYLIST_INDEX_BLOB_URL=https://xxxx.public.blob.vercel-storage.com/track-playlist-index.json

Vercel 環境変数(本番・プレビュー用)

Vercel ダッシュボード → プロジェクト設定 → Environment Variables に追加する。 設定時は Environments のチェックボックスで Production・Preview・Development すべてを有効にすること(特定の Environment のみに限定すると、その環境以外では未設定扱いになる)。

フェイルセーフ: 環境変数が未設定の場合、該当セクションは非表示になる(エラーにはならない)。

読み取り方針

  • 読み取り専用: プレイリストデータは編集 API(PUT)を持たない。data/inputs/playlists.json を直接編集して bun run upload-playlists でアップロードする運用とする
  • プレイリスト本体は fetch + cache: "no-store" で Vercel Blob から取得する(リリースは Neon fetchReleasesFromDB() / getReleases() 経由)

7. 派生集計 JSON

画面レンダリング時に毎回全走査を避けるため、事前集計した派生 JSON を生成する。

member-playlist-index.json

目的: メンバー詳細画面(/members/[id])の「選曲した楽曲」セクション表示用

構造:

{
  "fukumura-mizuki": [
    {
      "playlistId": "fukumura-mizuki-morning-musume-fav-2026",
      "playlistName": "譜久村聖セレクション:モーニング娘。名曲集",
      "songTitle": "LOVEマシーン",
      "releaseId": "fcd58b7d-77c0-37db-9334-5f50d92b09f1",
      "trackId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "links": [...]
    }
  ]
}

8. (将来的な拡張性)

生成タイミング: playlists.json 更新時(scripts/build-playlist-index.ts 実行時)

格納先: Vercel Blob(member-playlist-index.json

track-playlist-index.json

目的: 曲詳細画面(/songs/[id])の「プレイリスト掲載情報」セクション表示用

構造:

{
  "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx": [
    {
      "playlistId": "fukumura-mizuki-morning-musume-fav-2026",
      "playlistName": "譜久村聖セレクション:モーニング娘。名曲集",
      "memberId": "fukumura-mizuki",
      "memberName": "譜久村聖",
      "songTitle": "LOVEマシーン"
    }
  ]
}

生成タイミング: playlists.json 更新時(scripts/build-playlist-index.ts 実行時)

格納先: Vercel Blob(track-playlist-index.json


8. ER 図

docs/design/er-diagram.mdx を参照すること。

Playlist / PlaylistEntry エンティティの位置づけは ER 図の「v0.6.0 完成時点・全体」セクションに記載。


9. バージョン位置づけ

バージョン 機能 対応 Issue
v0.5.0 トラックリスト管理機能 #341(#338・#339・#340)
v0.6.0 プレイリスト管理機能 #336(#328〜#335・#349・#351)

10. 後続 Issue との関係

Issue 本設計書への依存内容
#330 Playlist / PlaylistEntry 型定義・playlists.json 基盤追加 §3 の型定義・§6 のファイル配置に基づいて実装
#331 派生集計 JSON 生成スクリプト追加 §7 の集計 JSON 構造に基づいて実装
#332 プレイリスト一覧・詳細ページ実装 型定義・Blob 読み取り方針(§6)に基づいて実装
#333 メンバー詳細画面への選曲楽曲一覧セクション追加 member-playlist-index.json(§7)に基づいて実装
#401 曲詳細画面へのプレイリスト掲載情報セクション追加 track-playlist-index.json(§7)に基づいて実装
#351 PlaylistEntry への YouTube Music URL 自動取得スクリプト追加 links フィールドの構造(§3)に基づいて実装
#364 PlaylistEntry への trackId フィールド追加 §3 の PlaylistEntry.trackId 仕様に基づいて実装

改訂履歴

更新日 変更内容
1.2 2026-03-27 派生集計 JSON セクションの構成説明を修正
1.1 2026-03-22 release-playlist-index.jsontrack-playlist-index.json(trackId キー)に変更(#402)。リリース詳細画面のプレイリスト掲載情報セクション削除(#400)。
1.0 2026-03-21 初版作成(#328)

このページは役に立ちましたか?