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

events テーブル定義書

最終更新: 2026-08-30 関連 Issue: #926(eventsテーブル実装), #989(カラム名修正), #997・#998(タイムラインUI表示仕様追加), #1070(imageUrl管理方針追加)【v5.0.0 タイムライン機能】 / #1108(V2設計書整備), #1109(festival統合), #1110(タグシステム)【v7.0.0 タイムライン機能拡張(V2)】 / #1381(イベントテーブル拡張・time カラム追加) / #1472(タイムライン改善: 同日順序・プレースホルダー全文表示・ツアー時刻二重表示解消) / #1551(TO_CHAR()日付比較クエリのunstable_cache化) / MorningStatusApp #1528(イベント登録における属性拡張), morning-status-blume#67(手動イベント登録の会場・楽曲属性設計。venueIdカラム・event_songs/event_song_tracksテーブル追加)


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 等)
venueId VARCHAR(8) NULL 会場ID(venues.venue_id 参照、FK制約あり)。手動イベント(source='manual')で venueName を指定・解決できた場合のみ設定する(§5-5参照)。live 型等、他の source では現状未使用(NULL のまま)。オンライン開催等、物理会場を持たないイベントもあるため任意項目
source TEXT 元データ種別(後述)
sourceId TEXT 元データの ID
createdAt TIMESTAMPTZ CURRENT_TIMESTAMP 作成日時
updatedAt TIMESTAMPTZ —(Prisma の @updatedAt で管理) 更新日時(更新時に自動更新)

2a. event_songs(イベント楽曲)

手動イベントの songs 入力(seqsongTitle)を保持する。radio_onair_songssetlists と同じ「曲エンティティ自体のテーブル + トラック紐付け中間テーブル」の2階層構成を踏襲する(詳細はラジオオンエア データ設計書 §4-0参照)。イベント(LiveFestival)と同格に、曲情報を独立したレコードとして持たせる方針とする。

CREATE TABLE event_songs (
  event_song_id SERIAL        PRIMARY KEY,
  event_id      UUID          NOT NULL REFERENCES events(id) ON DELETE CASCADE,
  seq           INTEGER       NOT NULL,
  song_title    TEXT          NOT NULL,
  UNIQUE (event_id, seq)
);
カラム名 NOT NULL 説明
event_song_id SERIAL PK。radio_onair_songs.onairId と同じ代理キー方式(events.id が UUID のため、setlists.setlistId のような文字列組み立て PK ではなく独立した連番キーを持たせる)
event_id UUID FK → events(id)。イベント削除時に連動削除(CASCADE)
seq INTEGER イベント内での曲順(1始まり)。入力 JSON の seq をそのまま格納
song_title TEXT 曲名。入力 JSON の songTitle をそのまま格納

インデックス:

CREATE INDEX idx_event_songs_event_id ON event_songs (event_id);

備考:

  • (event_id, seq) の一意制約により、同一イベント内での seq 重複を防ぐ
  • トラックID への紐付けは本テーブルの列では持たず、§2b「event_song_tracks」の中間テーブルで管理する(1曲が複数トラック(CD盤・配信版シングル等)に正しく該当しうるため。ラジオオンエア・セットリストと同じ方針)
  • 曲名からトラックが1件も解決できなかった場合も、event_songs には曲名・seq が残る(event_song_tracks への行のみ作成されない)。これはラジオオンエア・セットリストの「不明な曲」パターンと同じ考え方であり、将来イベントタイムライン UI に曲情報を表示する際の受け皿になる。ただし本書の時点ではイベントタイムライン UI への曲情報表示自体は対象外(画面設計は別途検討)

2b. event_song_tracks(イベント楽曲 × トラック紐付け)

CREATE TABLE event_song_tracks (
  event_song_id INTEGER       NOT NULL REFERENCES event_songs(event_song_id) ON DELETE CASCADE,
  track_id      VARCHAR(255)  NOT NULL REFERENCES tracks(track_id),
  PRIMARY KEY (event_song_id, track_id)
);
CREATE INDEX idx_event_song_tracks_track_id ON event_song_tracks (track_id);
カラム名 NOT NULL 説明
event_song_id INTEGER FK → event_songs(event_song_id)。複合 PK の一部。曲削除時に連動削除(CASCADE)
track_id VARCHAR(255) FK → tracks(track_id)。複合 PK の一部

セットリスト側にも同じパターンの中間テーブル(setlist_tracks)があり、詳細はライブ・フェス機能 テーブル設計書 §2-9を参照。


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)。

会場(venueNamevenueId

data/inputs/manual-events.json に任意項目 venueName(会場名の文字列)を指定すると、events.venueId に変換される。物理会場を持たないイベント(オンライン開催等)も扱えるよう venueName は省略可能とする。venueName を省略した場合、既存の venueId を保持する(time と同じ undefined 時保持パターン)。

解決手順は register-tour-festival.tsライブ・フェス機能 テーブル設計書)の会場登録ロジックをそのまま流用する。

  1. 既存 venues.name と完全一致する会場があれば、その venueId を再利用する
  2. 一致しない場合、Google Maps Geocoding API(環境変数 GEOCODING_API_KEY)で venueName をそのままクエリとして緯度経度・都道府県名を取得する(region=jp に加え language=ja を指定し、都道府県名の表記言語を日本語に固定する。#1520)
  3. 都道府県コードへの変換に失敗した場合、または API 呼び出し自体が失敗した場合は、当該会場名を警告ログに出力し、そのイベントの venueId は更新しない(既存値があればそれを保持、なければ NULL のまま。他のイベントの処理は継続する。グレースフルな失敗処理)
  4. 新規解決できた会場は都道府県コード + 連番3桁で venueId を新規採番し、venues へ登録する

GEOCODING_API_KEY が未設定の場合、会場解決自体をスキップする(venueName 指定イベントは venueId を更新せず同期される。Releases / Lives / Radio 等、会場を伴わない他のイベント同期には影響しない)。

本仕様は会場の「登録・変更」のみを扱う。venueName に明示的な「未設定に戻す」値(null 等)は用意しない。一度 venueId が設定されたイベントについて、venueName を省略しても venueId は変更されない(前述の undefined 時保持)ため、会場を後から解除したい場合は本仕様の対象外(必要になった時点で別途検討する)。

楽曲(songsevent_songs / event_song_tracks

data/inputs/manual-events.json に任意項目 songsSongEntrySchema の配列。scripts/lib/song-entry-schema.tsseqsongTitle を持つ。ラジオオンエア・セットリストの入力と共通のスキーマ。詳細はラジオオンエア データ設計書 §4-0参照)を指定すると、§2a「event_songs」・§2b「event_song_tracks」に変換される。

同期は seq をキーにした差分方式。 events 本体が sourcesourceId をキーに差分upsert(upsertEvent()。既存レコードは id を保持したままUPDATE、新規のみINSERT)する既存設計と対称に揃える。event_songs.event_idevents(id) への FK のため、event_songsevent_song_tracks への書き込みは upsertEvent() で対象イベントの id が確定したに行う(新規の手動イベントは events 行の INSERT より前に曲を書き込むことはできない。処理順序の詳細はバッチ設計書 W6参照)。songs を省略した場合、既存の event_songsevent_song_tracks を保持する(変更しない)。songs を明示指定した場合([] を含む)は、そのイベントの既存 event_songsseq で識別)と入力 songs を突き合わせ、以下のように処理を分ける。

ケース 処理
既存に同じ seq があり songTitle も同じ event_songs 行は変更しない(event_song_id を保持)
既存に同じ seq があるが songTitle が異なる 該当行の songTitle のみ UPDATE(event_song_id は保持)
既存にない seq 新規 INSERT(新しい event_song_id を採番)
入力 songs に含まれない既存 seq 該当行を DELETE(event_song_tracks は CASCADE で連動削除)
  • 本仕様は「楽曲の登録・追加・削除・全削除」のいずれも扱う。 入力 songs 配列に曲を足せば追加、配列から曲を除けば削除、配列を [] にすれば全削除になる
  • event_song_id は、対応する seq の曲が存在し続ける限り再同期をまたいで保持される。内容に変更がない曲について event_songs 行を毎回 delete→re-create することはしない
  • 一方 event_song_tracks(トラック紐付け)は、songs に含まれる全曲について毎回 buildTrackCandidatesMapFromPrisma で再解決し、該当 event_song_id の既存リンクを削除してから書き直す。event_song_tracks は複合PK(event_song_idtrack_id)のみで独自の代理キーを持たないため、event_songs と異なり洗い替えても ID の再採番は発生しない。この再解決を毎回行う理由は、曲名からtrackIdが1件も解決できなかった曲(発表当初はTrack未登録の新曲等)が、後日 Track が正式登録された時点で自動的に紐付くようにするため(追加の再解決バッチを別途用意せずに済む)
  1. songs 内の各曲について、lib/track-match.tsbuildTrackCandidatesMapFromPrisma で曲名から該当する全 trackId 候補を解決する(1曲が複数トラック(CD盤・配信版シングル等)に正しく該当しうるケースへの対応。ラジオオンエア・セットリストと同じロジックを再利用する)
  2. 上記の差分ルールに従って event_songs を INSERT/UPDATE/DELETE する
  3. 各曲(event_song_id が確定したもの全て)について、既存の event_song_tracks を削除し、解決できた trackId を全件登録し直す(lib/track-match.tsbuildTrackJunctionRows を再利用)
  4. 該当トラックが1件も見つからない曲は、event_songs には登録するが(曲名・seq は残る)、event_song_tracks への登録は行わない。該当曲名を警告ログに出力する(register-tour-festival.tsunresolvedSongTitles と同じ扱い)

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[...])(フィルタ機能実装時に追加予定)

7-1. TO_CHAR(date, ...) による日付比較クエリのキャッシュ方針(#1551)

「過去のこの日」(トップページ)・タイムラインの年一覧取得は、date の月日・年だけを取り出して比較するため TO_CHAR() を使った生SQLクエリになっている。TO_CHAR()date カラムに関数をかけてから比較する形になり、7. の date への B-tree インデックスが使えず全件スキャンになる。

関数 用途 クエリ内容
lib/on-this-day.ts getOnThisDayEvents(monthDay) トップページ「過去のこの日」セクション WHERE TO_CHAR(date, 'MM-DD') = ${monthDay}
lib/timeline.ts getTimelineYears() タイムラインページの年タブ一覧 SELECT DISTINCT TO_CHAR(date, 'YYYY') AS year FROM events

いずれも unstable_cache(revalidate: 3600秒)でラップし、DBへのクエリ発行自体を最大1時間に1回へ抑える(lib/youtube.ts と同パターン)。全件スキャンそのものを解消する関数インデックスの追加は本番DBへのマイグレーションを伴うため別Issue(#1554)で扱う。

備考: 以前は getOnThisDayEvents() にキャッシュがなく、アクセスの度にNeon DBへ生クエリを発行していた。同じトップページ内の「新着投稿」セクション(キャッシュ経由でほぼ即時に返る)とは別々の Suspense で並行ストリーミングされるため、データ取得が先に完了した方から画面に反映される仕様と相まって、app/page.tsx 上でのセクション配置順(過去のこの日が先)と実際の表示順が逆転する不具合が発生していた(#1551で修正)。


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.5 2026-08-30 手動イベント登録に「会場」「楽曲」属性を追加する設計を追記。events.venueId カラム、event_songsevent_song_tracks テーブル(§2a・§2b)を新設。§5-5 に venueNamevenueId の解決手順(register-tour-festival.ts の会場登録ロジックを流用)と songsevent_songs/event_song_tracks の変換手順(ラジオオンエア・セットリストと共通の SongEntrySchemabuildTrackCandidatesMapFromPrisma を再利用)を追加。実装は別Issueで対応(MorningStatusApp #1528, morning-status-blume#67)
2.4 2026-08-23 7-1. TO_CHAR(date, ...) を使う日付比較クエリ(getOnThisDayEventsgetTimelineYears)の unstable_cache 化を追記。全件スキャン解消(関数インデックス追加)は別Issue(#1554)に切り出したことを明記(#1551)
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)

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