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

複数の音楽グループ対応 データ設計書

最終更新: 2026-11-09 関連 Issue: MorningStatusApp#1803(親Issue)/ morning-status-blume#245(初版作成)/ MorningStatusApp#1808(実装)/ MorningStatusApp#1813(モーニング娘。の移行)

1. 概要

ハロー!プロジェクトの複数の音楽グループを扱うためのデータ設計。モーニング娘。を主とし、他の音楽グループの情報を、モーニング娘。の情報から紐づけて参照できるようにする。

参照できる情報は、次の4パターンである(画面設計 → morning-status-blume#246)。

  • イベントで共演したメンバー情報
  • ラジオでオンエアした楽曲情報
  • プレイリストに掲載した楽曲情報
  • 音楽グループを横断したユニット情報

最終形は、ハロー!プロジェクトの全音楽グループを切り替えて参照できることである。どの音楽グループも、モーニング娘。と同じ情報量を持てる構造にする。最初の実装では、この構造の一部だけを使う。

音楽グループとユニット

単位 意味 例
音楽グループ(MusicGroup) メンバーの本拠地。メンバーファイルの単位 モーニング娘。
ユニット(Unit) 音楽グループの内で、または音楽グループをまたいで結成される集団 ミニモニ。、ConChu!、DECA!BEAT
広義のユニット リリース・収録曲に紐づく単位。ユニットまたは音楽グループのいずれか 上の例のすべて

リリース・収録曲(Track.unitId 等)に紐づくのは、広義のユニットである。広義のユニットの id は、units.json(ユニット)または groups.json(音楽グループ)の id と対応する。ユニットが、どの音楽グループのものかを持つ必要はない。


2. 背景・目的

目的 詳細
他の音楽グループの登録 音楽グループを特定せず、どの音楽グループでも登録できる構造にする
モーニング娘。との紐づけ 共演メンバー・オンエア曲・プレイリストの曲・混成ユニットを通じて、モーニング娘。の情報から他の音楽グループの情報へ辿れるようにする
メンバーの記録の一元的な引き方 同じ人が複数の音楽グループに載る場合も、メンバーID(id)から、載っている音楽グループと、その音楽グループでの記録を引けるようにする
リリースとの紐づけ 音楽グループを、ユニットと並ぶ、リリース・収録曲と紐づく単位として扱う

対象範囲

  • 対象: 音楽グループの定義、音楽グループごとのメンバーファイル、メンバーの引き方、ユニット・リリースとの関係、SNSアカウントの登録
  • 対象外: §10 を参照

3. 型定義

音楽グループ(MusicGroup)(types/music-group.ts)

型は Zod スキーマ(MusicGroupSchema)から z.infer で導出する。

export const MusicGroupSchema = z.object({
  /** 音楽グループの識別子(kebab-case。例: morning-musume)。units.json の id と重ならない */
  id: z.string().min(1),
  /** 音楽グループ名 */
  name: z.string().min(1),
  /** メンバーファイルの Blob 相対パス */
  membersPath: z.string().min(1),
  /** 活動開始年(YYYY 形式) */
  activeFrom: z.string(),
  /** 活動終了年(YYYY 形式。活動中の場合は省略) */
  activeTo: z.string().optional(),
  /** MusicBrainz のアーティスト ID(MBID)。設定すると sync-discography のリリース取得対象になる */
  mbid: z.string().optional(),
  /** 関連リリースの ID 一覧(Release の id。sync-discography が自動集約して書き戻す) */
  releaseIds: z.array(z.string()).optional(),
});
export type MusicGroup = z.infer<typeof MusicGroupSchema>;

メンバーは、既存の Member(メンバー データ設計書 §3)をそのまま使う。音楽グループごとに別の型は持たない。


4. データファイル

groups.json(Vercel Blob)

  • 音楽グループの一覧(MusicGroup[])を管理する。Vercel Blob で管理し、相対パス groups.json で指定する(データ設計書(全体概要) §5)
  • モーニング娘。も、他の音楽グループと同じく1件として登録する。membersPath は members.json とする。モーニング娘。は音楽グループとして groups.json にだけ登録し、MBID は groups.json の morning-musume の mbid に持つ
  • 他の音楽グループの membersPath は、groups/{id}/members.json とする。groups/ を付けるのは、instagram/・ameba/・daily-digest/ 等の既存のフォルダと名前が重ならないようにするため
  • releaseIds は sync-discography が自動集約して書き戻す(§8)
  • 並び順を、画面での音楽グループの表示順とする

members.json と groups/{id}/members.json(Vercel Blob)

  • モーニング娘。のメンバーは、現在と同じ members.json に置く
  • 他の音楽グループのメンバーは、その音楽グループの membersPath のファイルに置く
  • どのファイルも、形式は { members: Member[] } で、メンバーの項目は メンバー データ設計書 §3 と同じである
  • メンバーが載っているファイルが、そのメンバーの本拠地の音楽グループを決める。Member に、音楽グループの項目は持たせない
  • メンバーの id は氏名に由来する。同じ人は、どの音楽グループのファイルでも同じ id で載る

サンプルデータ(groups.json)

[
  {
    "id": "morning-musume",
    "name": "モーニング娘。",
    "membersPath": "members.json",
    "activeFrom": "1997",
    "mbid": "00000000-0000-0000-0000-000000000000",
    "releaseIds": ["release-id-1", "release-id-2"]
  },
  {
    "id": "group-id-1",
    "name": "音楽グループ名",
    "membersPath": "groups/group-id-1/members.json",
    "activeFrom": "1999",
    "mbid": "11111111-1111-1111-1111-111111111111",
    "releaseIds": ["release-id-3"]
  }
]

5. フィールド詳細

フィールド 型 必須 説明
id string ✅ 音楽グループの識別子(kebab-case)。units.json の id と重ならない
name string ✅ 音楽グループ名
membersPath string ✅ メンバーファイルの Blob 相対パス。モーニング娘。は members.json、他の音楽グループは groups/{id}/members.json
activeFrom string ✅ 活動開始年(YYYY 形式)
activeTo string — 活動終了年(YYYY 形式)。活動中の音楽グループは省略
mbid string — MusicBrainz のアーティスト ID(MBID)。sync-discography がリリースを取得する対象と、トラックとの照合(§8-2)に使う
releaseIds string[] — 関連リリースの ID 一覧(Release の id と一致)。sync-discography が自動集約する

整合性ルール

ルール 内容
広義のユニットの id の一意性 groups.json の id は重複せず、units.json の id とも重ならない
モーニング娘。の登録 id が morning-musume の音楽グループが1件あり、membersPath は members.json であること
年の形式 activeFrom・activeTo は YYYY 形式で、activeTo は activeFrom 以降であること
ファイル内のメンバーID 1つのメンバーファイルの中で、id は重複しない
複数のファイルの同じメンバーID 複数のメンバーファイルに同じ id がある場合、同じ人であること。氏名(name)と生年月日(profile.dob)が一致する
ユニットのメンバーの実在 Unit.memberIds の各 id は、いずれかの音楽グループのメンバーファイルに存在すること

整合性ルールの検証は、Blob ファイル診断バッチ(バッチ設計書 W16)の対象とする。

groups.json の読み込みは、units.json と同じ方式とする。配列として読み込めた内容を、そのまま音楽グループの一覧として使う。取得に失敗した場合と、配列でない場合は、音楽グループを0件として扱う。


6. メンバーの引き方

6-1. メンバー索引

メンバーの id からそのメンバーが載っている音楽グループを引く索引を実行時に導出する。永続ファイルは持たない。

  • groups.json の各 membersPath のファイルを読み、id ごとに、載っている音楽グループの id を groups.json の並び順でまとめる
  • 同じ id が複数のファイルに載る場合(移籍・兼任したメンバー等)、その id は複数の音楽グループの id を持つ
  • 読み込みの結果は、members.json と同じ再検証間隔(3600秒)でキャッシュする。キャッシュのタグには、各ファイルの相対パスを付ける
  • メンバーファイルの読み込みに失敗した場合(未作成・取得失敗・形式不正)は、その音楽グループのメンバーを空として扱う。他の音楽グループの読み込みには影響しない
  • 索引は、メンバーファイルのみを情報源とする。メンバーを追加・削除したときに、索引のための項目を別に直す必要はない

6-2. 記録の選び方

同じ人が複数の音楽グループに載るとき、各ファイルのエントリは、その音楽グループでの記録(メンバーカラー・期・在籍状況等)である。どの記録を使うかは、引く場面で決まる。

引く場面 使う記録
音楽グループの画面(その音楽グループを表示する画面) その音楽グループの記録
上記以外(ユニットの memberIds から引く場合を含む) モーニング娘。の記録。載っていなければ、groups.json の並び順で最初の音楽グループの記録

引く場面ごとの記録の選び方は、共通の関数1つで行い、画面ごとに複製しない。

6-3. メンバー詳細での扱い

同じ id のメンバーが複数の音楽グループに載るとき、メンバー詳細(/members/{id})で記録をどう見せるかは、画面設計書(morning-status-blume#246)で定める。


7. ユニットとの関係

  • units.json は1ファイルとし、すべてのユニットを同じファイルに登録する。ユニットは、どの音楽グループのものかを項目として持たない(ユニット一覧機能 データ設計書)
  • ユニットの parentId は、units.json の id、または groups.json の id(音楽グループ)を指す。モーニング娘。の西暦年を含む名称のユニット(「モーニング娘。’14」〜「モーニング娘。’26」等。このアプリで、リリースの名義に対応づけるためにユニットとして定義したもの)は、parentId に音楽グループ morning-musume を指す
  • ユニットの memberIds には、どの音楽グループのメンバーの id も入れられる。音楽グループをまたいで結成されるユニット(DECA!BEAT、ConChu! 等)の所属メンバーは、複数の音楽グループのメンバーで構成できる。id から記録を引く方法は §6 に従う

8. リリースとの関係

  • リリース(Release)・収録曲(Track)は、Neon の既存のテーブルを共用する。音楽グループごとのテーブルは持たない
  • リリースに、音楽グループを表す項目は足さない
  • 収録曲の Track.unitId は、広義のユニットの id で、units.json(ユニット)または groups.json(音楽グループ)の id と対応する

リリースは、収録曲を通じて、広義のユニット(ユニット・音楽グループ)とソロアーティストに紐づく。1つのリリースに複数が紐づくことがある(リリース データ設計書 §4-5)。

紐づく相手 紐づけの持ち方
ユニット Unit.releaseIds
音楽グループ MusicGroup.releaseIds
ソロアーティスト SoloArtist.releaseIds

8-1. リリース取得対象の MBID

ユニットの mbid とソロアーティストの mbids に加えて、groups.json の mbid も、sync-discography(バッチ設計書 W2)のリリース取得対象に含める。重複排除は、合算後の一覧に対して行う。

8-2. 収録曲との照合と releaseIds の自動集約

  • 収録曲の主体(トラックリスト データ設計書 §4「名義の解釈」)は、units.json のユニットと groups.json の音楽グループの両方に対して、ユニットと同じ照合(ユニット一覧機能 データ設計書 §6)で照合し、一致した広義のユニットの id を Track.unitId にする
  • Track.unitId が音楽グループの id であるトラックを1曲以上含むリリースを、その音楽グループの releaseIds に自動追加する。既存の releaseIds は保持し、重複は除去する
  • 1つのリリースに複数の広義のユニットのトラックが含まれる場合は、それぞれの releaseIds に追加する
  • 自動集約の後、groups.json を Vercel Blob に書き戻す

8-3. Track 型は変更しない

収録曲の項目は増やさない。Track.unitId の対応先が、units.json と groups.json の2つになる。

8-4. モーニング娘。のリリース

「モーニング娘。のリリース」の判定(リリース データ設計書 §4-5)は、共通の関数1つで行う。モーニング娘。のユニットは、id が morning-musume の音楽グループと、parentId が morning-musume のユニットである。モーニング娘。のリリースを使う画面・機能は、すべてこの判定を通して選ぶ。

実装時に、モーニング娘。のリリースを使う画面・機能のうち、この判定を通さずにリリースを全件扱っている箇所がないかを確認する。


9. SNS

  • 他の音楽グループのメンバーのSNSアカウントは、そのメンバーのエントリ(officialSns・youtubeChannel・tiktokChannel)に登録する。項目は メンバー データ設計書 §3 と同じである
  • SNSの投稿の収集と近況の自動検索は、モーニング娘。の members.json のメンバーを対象とする。他の音楽グループのメンバーは、アカウントの登録だけを行う
  • 投稿データ(TikTokPost・YoutubePost)の項目は増えない
  • 公式アカウント一覧(tiktok-official-accounts.json・instagram-official-accounts.json)は、モーニング娘。の公式アカウントを収集するための設定である

10. 対象外

項目 内容
音楽グループの切り替え 音楽グループを切り替えて参照する機能の実装(置き場所の方針は画面設計書 morning-status-blume#246 で定める)
他の音楽グループのSNS収集 投稿の収集、同期状態と新着ウィンドウの音楽グループ単位での管理、新着表示の音楽グループでの絞り込み、他の音楽グループの公式アカウントの登録(SNS収集を始める段階で検討する)
他の音楽グループのシード 他の音楽グループのメンバー・SNSアカウント・ユニット・groups.json の登録データの作成(別途行う)
メンバーの編集画面 他の音楽グループのメンバーの編集(PUT /api/members の対象は、モーニング娘。の members.json のみ)
出身地照合用メンバー Neon の出身地照合用メンバー(Member、メンバー データ設計書 §6)の他の音楽グループへの対応

11. データ取得層の設計方針

Server Component での直接取得とするか、Route Handler(BFF)+ TanStack Query とするかの判定は、画面が決まる画面設計書(morning-status-blume#246)の作成後に行い、結果を統合フィードアイテム データ設計書の実績ログに追記する(判定の基準はデータ設計書(全体概要) §4)。


12. 関連設計書

設計書 本書との関係
メンバー データ設計書 音楽グループごとのメンバーファイルが使う Member の定義
ユニット一覧機能 データ設計書 ユニット(Unit)の定義と、収録曲との照合・releaseIds の自動集約
トラックリスト データ設計書 Track.unitId の対応先と、収録曲の主体
リリース データ設計書 リリースと、広義のユニット・ソロアーティストの紐づけ、モーニング娘。のリリースの判定
データ設計書(全体概要) データファイル一覧・エンティティ一覧への登録、Blob ファイルの指定方式
バッチ設計書 sync-discography・Blob ファイル診断バッチの処理

13. モーニング娘。の移行(units.json → groups.json)

units.json の morning-musume(ユニット)を、音楽グループとして groups.json に移す。一回限りのパッチ scripts/patch/migrate-morning-musume-to-groups.ts で行う(バッチ設計書 一回限りパッチ一覧)。

13-1. 移す内容

units.json の morning-musume から、groups.json の1件を次のとおり作る。

groups.json の項目 元
id morning-musume の id
name morning-musume の name
membersPath members.json(固定)
activeFrom morning-musume の activeFrom
activeTo morning-musume の activeTo(あれば)
mbid morning-musume の mbid
releaseIds morning-musume の releaseIds
  • 移す項目は、上の表の7項目である。ドライランは、morning-musume が持つ、この7項目以外の値(creditMbids 等)を表示する
  • parentId が morning-musume のユニット(西暦年を含む名称のユニット、派生ユニット)は変更しない。parentId は、移行後は groups.json の id(音楽グループ)を指す(§7)

13-2. 処理の順序

  1. units.json と groups.json を、キャッシュを通さずに読む。読み込みに失敗した場合と、配列でない場合は、何も書かずに中止する。units.json が見つからない場合も、中止する。groups.json がまだない場合は、空として扱う(最初の移行では、groups.json は未作成である)
  2. 書き込み後の groups.json と units.json を組み立て、id が重ならないことを検証する。重なる場合は、何も書かずに中止する
  3. 実行前の units.json の控えを data/work/ に、実行日時を付けたファイル名で出力し、出力先のパスを表示する。控えの出力先の確認は、書き込みより前に行う。確認の内容は、同名のファイルがないことと、出力先のディレクトリを使えることで、ドライランでも行う(本実行は、data/work/ がなければ作る。ドライランは、data/work/ がなければ作らず、既存の親ディレクトリに書き込めることを確認する)
  4. groups.json の末尾に morning-musume を追加する。groups.json の並び順は、画面での音楽グループの表示順である(§4)。13-3 の順序では、他の音楽グループの登録より前に本パッチを実行するため、morning-musume が先頭の1件になる
  5. units.json から morning-musume を外す
  6. 本番のキャッシュを破棄する
  • 手順2で、groups.json に同一内容の morning-musume がある場合は、手順4を省き、手順5から続ける。内容が異なる場合は、上書きせずに中止する。途中で止まった場合は、同じコマンドを再実行する
  • units.json に morning-musume がなく、groups.json に morning-musume がある場合は、移行済みとして、書き込みは行わず、キャッシュの破棄だけを行う(キャッシュの破棄だけが失敗した後の再実行で、破棄をやり直すため)
  • ドライランは、作る内容(releaseIds は件数)と外す内容を表示し、書き込みとキャッシュの破棄は行わない。移行済みの場合も、何も行わない

13-3. 本番データの切替順序

コードを、移行前後のどちらのデータでも既存のモーニング娘。の表示・動作が変わらない状態で、先にデプロイする。そのうえで、本番のデータを次の順序で切り替える。

手順 内容
1・2 本パッチを実行する(groups.json の作成と、units.json からの除去を続けて行う)
3 W2 の更新(groups.json の releaseIds の集約)をデプロイしてから、W2 を手動実行する。W16 の groups.json の検証は、groups.json の作成後に有効にする
4 他の音楽グループのメンバーを投入してから、ユニットの memberIds を追加する
5 リリースを取り込む

W2 は手動実行のみのため、本パッチの実行から、手順3の W2 の更新のデプロイまでの間は、手動実行しない(units.json から morning-musume が外れた状態で、更新前の W2 を実行しないため)。各手順の前にドライランで確認し、戻し方として、実行前の units.json の控え(13-2 の手順2)を用意する。


改訂履歴

版 更新日 変更内容
1.3 2026-11-09 【実装時に追記(MorningStatusApp#1813)】§13-2 に、移行済みの場合はキャッシュの破棄だけを行うこと(キャッシュの破棄だけが失敗した後の再実行のため)、ドライランは data/work/ を作らずに書き込めるかを確認すること、ドライランは releaseIds を件数で表示することを追記(MorningStatusApp#1825 のレビュー指摘)
1.2 2026-11-08 【実装時に追記(MorningStatusApp#1813)】§13 モーニング娘。の移行(units.json → groups.json)を追加(MorningStatusApp#1813)
1.1 2026-11-08 【実装時に追記(MorningStatusApp#1812)】groups.json の読み込み方式を、units.json と同じ(配列として読み込めた内容をそのまま使う)と明記。§5 の見出し「MusicGroup」を削除(ソロアーティスト データ設計書の構成に合わせた)。§6-1 に、メンバーファイルの読み込みに失敗した場合の扱いを追記
1.0 2026-11-07 【実装時に追記(MorningStatusApp#1808)】初版作成(MorningStatusApp#1803, morning-status-blume#245)

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