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

events テーブル定義書

最終更新: 2026-08-03 関連 Issue: #926(eventsテーブル実装)【v5.0.0 タイムライン機能】 / #1108(V2設計書整備), #1109(festival統合), #1110(タグシステム)【v7.0.0 タイムライン機能拡張(V2)】 / #1381(イベントテーブル拡張・time カラム追加) / #1472(タイムライン改善: 同日順序・プレースホルダー全文表示・ツアー時刻二重表示解消)


1. 目的

既存データ(Releases / Members / Lives / Radio / Manual Events)を時系列で横断的に扱うための統合イベントレイヤーを構築する。

  • 既存データは変更しない
  • events は「派生データ」として生成する
  • タイムライン UI は events のみを参照する

2. テーブル定義

テーブル名

events

スキーマ

カラム NOT NULL デフォルト 説明
id UUID —(Prisma がアプリ層で UUID 生成) PK
date DATE イベント発生日
time TIME(0) NULL イベント開始時刻。lives.time と同じ表現方式(秒精度なし)。時刻不明・未登録時は NULL
type TEXT イベント種別(後述)
title TEXT イベントタイトル
description TEXT NULL 補足説明
members TEXT[] '{}' 関連メンバー ID 配列(members.json の id と対応)
tags TEXT[] '{}' タグ配列(後述)
imageUrl TEXT NULL 表示画像の URL(Vercel Blob URL 等)
link TEXT NULL 関連リンク(MV / ニュース / radiko 等)
source TEXT 元データ種別(後述)
sourceId TEXT 元データの ID
createdAt TIMESTAMPTZ CURRENT_TIMESTAMP 作成日時
updatedAt TIMESTAMPTZ —(Prisma の @updatedAt で管理) 更新日時(更新時に自動更新)

3. type(イベント種別)

説明 元データ V1/V2
release シングル・アルバム発売 releases V1
live ライブ・ツアー lives V1
join メンバー加入 members.json V1
graduate メンバー卒業 members.json V1
media ラジオ・TV 出演 radio_episodes V1
topic その他の話題・発表 manual V1
festival 外部フェス出演 festivals V2追加予定

festival type の仕様(V2)

  • festivals テーブルからの派生データ
  • source = 'festival'sourceId = festival.festivalId
  • members フィールドは空配列(メンバー×フェス紐づけテーブルが存在しないため)
  • フェスが複数日にまたがる場合も dateEnd は持たない(セクション 3b 参照)。V2 時点では開始日のみ表示とし、期間表示が必要になった際に改めて検討する

3a. tags(タグ)仕様

tags フィールドは type とは別軸のイベント性質を表すラベル配列。フィルタリングやUIでの表示に使用する。

タグ値 説明 設定対象 type の例 付与方法
OG OG メンバーが関与するイベント 全 type 自動(assignTags
Birthday 誕生日関連イベント 全 type 自動(assignTags
Solo メンバーのソロ活動 topic, live, media 手動(manual-events.json)
Unit ユニット活動 release, live, topic 手動(manual-events.json)
Special 記念・特別イベント live, topic 手動(manual-events.json)
Collaboration 他アーティストとのコラボ release, topic 手動(manual-events.json)
  • タグは任意付与。付与なし(空配列)も有効
  • 1イベントに複数タグを付与可能
  • 自動付与タグ(OGBirthday)は sync-events.tsassignTags() 関数で付与される
    • OG: イベントに関与するメンバーのうち1名以上が status='OG'
    • Birthday: イベント日の UTC 月/日がいずれかの関与メンバーの profile.dob と一致
    • 全データソース(Releases / Members / Lives / Radio / Festivals / Manual)に適用される
  • data/inputs/manual-events.jsontags フィールドで任意タグを明示指定できる
    • tags省略した場合 → assignTags() が OG・Birthday を自動付与
    • tags明示指定した場合([] を含む)→ 明示値を優先し、assignTags() は適用されない

3b. dateEnd フィールドの要否

dateEnd(終了日)フィールドは当初 V2 設計として検討されたが、追加しないと判断した。

理由:

  • live 型はツアーの各公演を1レコードずつ持つ設計のため、期間を持つ概念がない
  • festival 型の元データ(festivals テーブル)は単日記録であり、終了日のデータソースがない
  • タイムライン UI での期間表示が必要になった時点で、データ供給方法と合わせて改めて検討する

4. source / source_id の意味

events は既存データの派生であるため、どのデータから生成されたかを保持する。

source 値 sourceId の意味
release Release.releaseId "release_001"
member Member.memberId(members.json の id) "nakazawa-yuko"
live Live.liveId "2026B001"
radio RadioEpisode.episodeId "morning-musume-radio-20240517"
manual 任意(手動入力時に付与) "topic-2024-01"
festival Festival.festivalId "summer-sonic-2025"

5. 変換ロジック仕様

変換レイヤーの実装は #927 で行う。本書には入力元フィールドのマッピング仕様のみを記載する。

5-1. Releases → events(release)

events カラム 元フィールド
date release.releaseDate
type "release"
title release.title
members releases.json のメンバー紐づけ
imageUrl Cover Art Archive から取得したジャケット画像 URL(後述)
link releases.json の MV URL
source "release"
sourceId release.releaseId(= MusicBrainz リリースグループ MBID)

5-2. Members → events(join / graduate)

加入(join)

events カラム 元フィールド
date member.joined(members.json)
type "join"
title "{期}期加入"
members [member.id]
imageUrl member.image(members.json)
source "member"
sourceId member.id

卒業(graduate)

events カラム 元フィールド
date member.graduated(members.json)
type "graduate"
title "{name} 卒業"
members [member.id]
imageUrl member.image(members.json)
source "member"
sourceId member.id

5-3. Lives → events(live)

events カラム 元フィールド
date live.date
time live.time(そのままコピー)
type "live"
title live.title(または tour.title
members MemberLive 経由の memberId 配列
source "live"
sourceId live.liveId

5-4. Radio → events(media)

events カラム 元フィールド
date radioEpisode.date
type "media"
title radioShow.name
members RadioMember 経由の memberId 配列
source "radio"
sourceId radioEpisode.episodeId

5-5. Manual → events(topic)

全フィールド手動入力。source = "manual"source_id は任意の識別子を付与する。

data/inputs/manual-events.jsontime フィールド("HH:MM" 形式の文字列、任意)を指定すると、time カラムに変換される。省略時は既存値を保持する(imageUrl と同じ undefined/null の使い分け。#1381)。

5-6. Festivals → events(festival)(V2追加予定)

events カラム 元フィールド
date festival.date
type "festival"
title festival.name
members [](メンバー×フェス紐づけなし)
source "festival"
sourceId festival.festivalId

6. imageUrl 管理方針

6-1. release イベントのジャケット画像(#1070)

source = 'release' のイベントは Cover Art Archive(CAA) からジャケット画像を取得して imageUrl に保存する。

データフロー

releases.releaseId
  = MusicBrainz リリースグループ MBID
    └─ https://coverartarchive.org/release-group/{MBID}/front
         → 307 リダイレクト → archive.org 上の実画像 URL
              → events.imageUrl に保存

取得タイミング

imageUrl の自動設定は行わず、以下のタイミングで手動実行する。

タイミング 手順
初回一括バックフィル bun run scripts/patch/fetch-release-images.ts を実行
新シングル発売後 MusicBrainz 登録・sync-discography・sync-events 完了後に同スクリプトを実行

詳細な手順は docs/operations/discography-operations.md の「新シングル発売時のカバーアート取得手順」を参照。

取得対象外

  • source = 'manual'manual- プレフィックス ID)の手動登録リリース→ MusicBrainz MBID を持たないため CAA 取得不可

6-2. release 以外のイベントの画像表示(#1070、プレースホルダー方式見直し #1472)

imageUrl = NULL かつ type ≠ release のイベントは、EventCard コンポーネントが種別に応じたプレースホルダーを動的生成する。DB への保存は不要。プレースホルダーは表示内容によって2方式に分かれる。

方式A: SVG テキストアートlivejoingraduateleader

タイトル文字列そのものではなく、種別ごとに合成した短い定型テキスト(開催年・JOIN/GRAD ラベル・メンバー名等)を固定サイズの viewBox に描画する。表示内容が短く定型のため、折り返しや省略は発生しない。

type SVG に表示する内容
live 開催年 + 季節(UTC 月から算出: 3〜5月→春、6〜8月→夏、9〜11月→秋、12〜2月→冬)
join 1行目: JOIN / 2行目: メンバー名(1行に収まる範囲、超過は省略)
graduate 1行目: GRAD / 2行目: メンバー名(1行に収まる範囲、超過は省略)
leader 1行目: 第X代 / 2行目: リーダー就任

方式B: HTML テキストブロックmediatopicfestival、#1472)

events.title をそのまま全文表示する種別。SVG の <text> は CSS の折り返し(white-space/overflow-wrap)に対応しておらず、行数を固定して溢れた分を で省略する方式だと、タイトル長が可変な限り必ず一部のケースで全文を表示できなくなる問題があった(#1472で発覚)。そのため、これらの type は <div> 等の HTML ブロック(overflow-wrap: break-word)で描画し、コンテナは固定の縦横比をやめて min-height のみを指定し、コンテンツ量に応じて高さが伸びる可変レイアウトにする。行数の上限は設けず、events.title を省略なく全文表示する。

type HTML ブロックに表示する内容
media 番組名(events.title、全文)
topic タイトル(events.title、全文)
festival フェス名(events.title、全文)

6-3. タイトル表示の重複回避(#1472)

EventCard は画像・プレースホルダー領域の下に <h3> でタイトルを別途表示するが、6-2 の方式Bはプレースホルダー自体に events.title の全文を表示するため、imageUrl 未設定時は <h3> と内容が完全に重複する。

  • imageUrl = NULL かつ 6-2 方式B対象の type(mediatopicfestival)の場合のみ、<h3> タイトルを非表示にする
  • 上記以外(imageUrl が設定されている場合、または方式A対象の type)は、プレースホルダー側がタイトル文字列自体を表示しないため、従来通り <h3> を表示する

7. インデックス

インデックス対象 インデックス種別 理由
date B-tree タイムライン表示(ORDER BY date)の主要クエリキー
type B-tree イベント種別フィルタリング
source, sourceId B-tree 元データからのルックアップ・重複排除
tags GIN タグ配列フィルタリング(@> ARRAY[...])(フィルタ機能実装時に追加予定)

8. タイムライン UI 表示仕様

8-1. 年別表示(#998)

  • タイムラインページは 1年分のイベントのみ を表示する
  • URL クエリパラメータ year(例: /timeline?year=2024)で表示年を指定する
  • 未指定・無効値の場合は最新年を表示する
  • ページ上部にすべての年のタブリンクを表示し、選択中の年をハイライトする

8-2. ライブイベントのグループ表示(#997)

同一ツアー(title が同じ type=live イベント群)は1グループとして折りたたんで表示する。

グループの公演数 表示方法
1件 通常のフルサイズカード(会場名を日付の後に表示)
2件 2枚のフルサイズカードを並列表示(会場名あり)
3件以上 初日・千秋楽をフルサイズカード、中間日をコンパクトリスト(日付 / 会場 / 開演時刻)で表示
  • 会場名・開演時刻は lives テーブルを sourceId(liveId)経由でジョインして取得する
  • 同日に複数公演がある場合は1行にまとめ、時刻を "14:00 / 18:00" 形式で列挙する
  • 開演時刻が 00:00(未設定)の場合は時刻を表示しない

8-3. EventCard の時刻表示(#1381)

ツアーグループ化されない単発イベント(EventCard で直接描画される全 type)は、events.time を日付の直後に表示する。

  • time が NULL または 00:00 の場合は表示しない(8-2 の Live 表示ルールと同じ判定関数 shouldShowTime/formatLiveTime を共通利用)
  • type=live のツアーグループ表示(8-2)は lives テーブルの時刻を別途取得して表示するため、events.time の表示とは独立している
  • 8-2 のツアーグループで会場欄に複数公演の時刻一覧("14:00 / 18:00")が含まれる代表カード(初日・千秋楽、または同日2件時の1枚カード)は、時刻が会場欄と二重表示にならないよう events.time 自体の表示を抑制する(#1472)

8-4. イベントの並び順(#1472)

タイムライン表示(年・週・日・年表の各ビュー)で events を取得するクエリは、date 昇順に加えて time を副次ソートキー として指定する(orderBy: [{ date: "asc" }, { time: "asc" }])。

  • date のみで ORDER BY すると、同日内のタイ(同値)の並び順は Postgres が保証しないため、物理的な行順(挿入順等)が表示順になり不安定になる(#1472で発覚)
  • time が NULL のイベントは Postgres の ASC デフォルト挙動(NULLS LAST)により末尾に並ぶ

改訂履歴

更新日 変更内容
2.3 2026-08-03 タイムライン改善(#1472): 同日イベントの並び順仕様(8-4)を追加、ツアーグループ代表カードの時刻二重表示回避仕様(8-3)を追加、media/topic/festival のプレースホルダーをSVG2行折り返しからHTML全文表示(可変高さ)に変更し6-2を更新、タイトル重複回避仕様(6-3)を追加
2.2 2026-07-20 time カラムを追加。Lives → events(live) の変換仕様・Manual の time 入力仕様・EventCard の時刻表示仕様(8-3)を追記(#1381)
2.1 2026-06-14 tags フィールドを実装済みに更新。OG・Birthday 自動タグ仕様を追記。手動タグ付与フローを追記(#1110)
2.0 2026-06-13 V2 拡張設計を追記(festival type・tags フィールド・dateEnd フィールド・GIN インデックス)。セクション番号重複を修正(#1108)
1.3 2026-06-05 imageUrl 管理方針を追加(CAA によるジャケット画像取得・SVG テキストアート)(#1070)
1.2 2026-05-29 タイムライン UI 表示仕様を追加(年別表示・ライブグループ表示)(#997, #998)
1.1 2026-05-24 カラム名を実際の DB カラム名(camelCase)に修正。id・updatedAt のデフォルト値記述を修正(#989)
1.0 2026-05-24 初版作成(#926)

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