複数の音楽グループ対応 データ設計書
最終更新: 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. 処理の順序
units.jsonとgroups.jsonを、キャッシュを通さずに読む。読み込みに失敗した場合と、配列でない場合は、何も書かずに中止する。units.jsonが見つからない場合も、中止する。groups.jsonがまだない場合は、空として扱う(最初の移行では、groups.jsonは未作成である)- 書き込み後の
groups.jsonとunits.jsonを組み立て、idが重ならないことを検証する。重なる場合は、何も書かずに中止する - 実行前の
units.jsonの控えをdata/work/に、実行日時を付けたファイル名で出力し、出力先のパスを表示する。控えの出力先の確認は、書き込みより前に行う。確認の内容は、同名のファイルがないことと、出力先のディレクトリを使えることで、ドライランでも行う(本実行は、data/work/がなければ作る。ドライランは、data/work/がなければ作らず、既存の親ディレクトリに書き込めることを確認する) groups.jsonの末尾にmorning-musumeを追加する。groups.jsonの並び順は、画面での音楽グループの表示順である(§4)。13-3 の順序では、他の音楽グループの登録より前に本パッチを実行するため、morning-musumeが先頭の1件になるunits.jsonからmorning-musumeを外す- 本番のキャッシュを破棄する
- 手順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) |