メインコンテンツまでスキップ

データベーススキーマ

Subseek で使用する全テーブルの定義。ORM は Drizzle ORM、DB は Turso(SQLite)。

Better Auth が管理する users テーブルは FK 参照用に最小限のみ定義し、マイグレーション対象からは除外している。

ER図

テーブル定義

users(参照専用)

Better Auth が管理するテーブル。FK 参照に必要な id のみ定義。

カラム制約説明
idTEXTPK, NOT NULLユーザーID

channels

YouTube チャンネルのメタデータを管理する。

カラム制約デフォルト説明
idTEXTPK, NOT NULL-YouTube チャンネルID(UCxxxxxx)
titleTEXTNOT NULL-チャンネル名
handleTEXT--カスタムURL(@handle)
thumbnail_urlTEXT--サムネイル画像URL
subtitle_statusTEXTNOT NULL'pending'字幕取得状態: pending / processing / completed / failed
video_countINTEGERNOT NULL0動画数(YouTube API から取得)
created_atTEXTNOT NULLnew Date().toISOString()作成日時
updated_atTEXTNOT NULLnew Date().toISOString()更新日時

インデックス:

インデックス名カラム
idx_channels_titletitle
idx_channels_handlehandle
idx_channels_subtitle_statussubtitle_status

videos

動画メタデータ・字幕取得状態を管理する。

カラム制約デフォルト説明
idTEXTPK, NOT NULL-YouTube 動画ID(11文字)
channel_idTEXTNOT NULL, FK → channels.id-所属チャンネルID
titleTEXTNOT NULL-動画タイトル
thumbnail_urlTEXT--サムネイル画像URL
duration_secondsINTEGERNOT NULL-動画の長さ(秒)
published_atTEXTNOT NULL-公開日時(ISO 8601)
subtitle_statusTEXTNOT NULL'pending'字幕取得状態: pending / completed / failed / unavailable / deleted
created_atTEXTNOT NULLnew Date().toISOString()作成日時
updated_atTEXTNOT NULLnew Date().toISOString()更新日時

インデックス:

インデックス名カラム
idx_videos_channel_idchannel_id
idx_videos_published_atpublished_at
idx_videos_subtitle_statussubtitle_status
idx_videos_channel_subtitlechannel_id, subtitle_status

subtitle_status 状態遷移:

user_video_access

ユーザーの動画アクセス権(クレジット消費履歴)を管理する。

カラム制約説明
user_idTEXTPK, NOT NULL, FK → users.idユーザーID
video_idTEXTPK, NOT NULL, FK → videos.id動画ID
creditsINTEGERNOT NULL消費したクレジット数
created_atTEXTNOT NULL作成日時
updated_atTEXTNOT NULL更新日時
expires_atTEXTNOT NULLアクセス権の有効期限(created_at + 4週間)

主キー: (user_id, video_id) の複合主キー

billing_accounts

課金情報(プラン・クレジット残高・Stripe 顧客)を管理する(users と 1:1 関係)。

認証ユーザー情報とは別ドメインとして分離しており、独立した主キー id を持つ。将来 organization が所有者になった場合に所有者カラムを付け替えるだけで対応できる設計。user 削除時も billing レコードを残す運用を想定するため CASCADE しない。設計方針は ADR: organization 将来導入と billing 分離戦略 を参照。

カラム制約デフォルト説明
idTEXTPK, NOT NULLUUID v4 (crypto.randomUUID())billing アカウントID
user_idTEXTNOT NULL, UNIQUE, FK → users.id-ユーザーID(1 ユーザー 1 billing account)
stripe_customer_idTEXTUNIQUE, NULL 許容-Stripe Customer ID(未接続ユーザーは NULL)
planTEXTNOT NULL'free'プラン: free / plus / pro
credit_balanceINTEGERNOT NULL50クレジット残高(Free プランの上限値)
created_atTEXTNOT NULLnew Date().toISOString()作成日時
updated_atTEXTNOT NULLnew Date().toISOString()更新日時

ユニーク制約:

制約名カラム
uq_billing_accounts_user_iduser_id
uq_billing_accounts_stripe_customer_idstripe_customer_id

favorite_channels

ユーザーのお気に入りチャンネルを管理する。

カラム制約説明
user_idTEXTPK, NOT NULL, FK → users.id (CASCADE)ユーザーID
channel_idTEXTPK, NOT NULL, FK → channels.idチャンネルID
created_atTEXTNOT NULL作成日時

主キー: (user_id, channel_id) の複合主キー

インデックス:

インデックス名カラム
idx_favorite_channels_user_createduser_id, created_at

search_histories

ユーザーの検索履歴を管理する。同一検索条件(userId, query, channels, target, sort)に対してユニーク制約を持ち、重複する検索条件は searched_at を更新する。

カラム制約デフォルト説明
idINTEGERPK, NOT NULL, AUTOINCREMENT-検索履歴ID
user_idTEXTNOT NULL, FK → users.id (CASCADE)-ユーザーID
queryTEXTNOT NULL-検索キーワード
channelsTEXTNOT NULL''検索対象チャンネルID一覧(カンマ区切り。全チャンネル検索時は空文字)
targetTEXTNOT NULL'description,subtitle,title'検索対象(ソート済みカンマ区切り)
sortTEXTNOT NULL'relevance'並び順
searched_atTEXTNOT NULL-検索実行日時(ISO 8601)
created_atTEXTNOT NULLnew Date().toISOString()作成日時
updated_atTEXTNOT NULLnew Date().toISOString()更新日時

ユニーク制約:

制約名カラム
uq_search_histories_conditionuser_id, query, channels, target, sort

インデックス:

インデックス名カラム
idx_search_histories_user_searcheduser_id, searched_at

スキーマ定義ファイル

実装は packages/db/src/schema/schema.ts を参照。