コンテンツにスキップ

データモデル

データはすべて PostgreSQL に入ります(添付ファイルの中身だけはオブジェクトストレージ)。主な表を紹介します。

中心の表

表 内容
users ユーザー(ロール、表示名、通知の全体設定、おやすみ時間、サイドバーの項目など)
channels チャンネル。種類は public / private / dm / group_dm。DM も「メンバーのいるチャンネル」として同じ仕組みで扱います
channel_members チャンネルのメンバーシップ(チャンネル・ユーザー・役割・参加した時刻)
messages メッセージ(サーバの ID、送信者の再送の鍵 client_msg_id、チャンネルの連番 seq、本文、作成・編集・削除の時刻)
reactions リアクション
read_states 既読の位置(人 × チャンネルごとに last_read_seq の 1 行)
thread_follows フォロー中のスレッドと、その既読の位置
attachments 添付ファイルの情報(中身はオブジェクトストレージ)
devices 端末(プラットフォーム、プッシュの種類とトークン、端末名、アプリのバージョン、最後に使った時刻)
sessions ログインのセッション(リフレッシュトークンのハッシュ)
notification_preferences 会話ごとの通知の設定
outbox_events 配るイベント(トランザクショナル・アウトボックス)
push_deliveries 端末ごとのプッシュの送信の状態
audit_logs 管理の操作の記録

主な表のつながりは次のとおりです(DM も channels の 1 行です)。

erDiagram
  users ||--o{ channel_members : "参加"
  channels ||--o{ channel_members : "メンバー"
  channels ||--o{ messages : "seq の順"
  users ||--o{ messages : "送る"
  messages |o--o{ messages : "スレッドの返信"
  messages ||--o{ reactions : ""
  messages |o--o{ attachments : ""
  users ||--o{ read_states : ""
  channels ||--o{ read_states : "どこまで読んだか"
  users ||--o{ devices : "端末"
  devices ||--o{ sessions : "ログイン"
  devices ||--o{ push_deliveries : "プッシュ"
  messages {
    uuid id
    bigint seq
    uuid client_msg_id
    text body
  }
  read_states {
    bigint last_read_seq
  }

ほかに、カスタム絵文字、招待、グループ、キャンバス、カレンダー、タスク、ワークフロー、予約、AI などの表があります。

3 種類の識別子

messages.id seq client_msg_id
作る側 サーバ(UUIDv7) サーバ(チャンネルごとの連番) アプリ(送る前に UUIDv4)
一意な範囲 全体 チャンネルの中 送った人の中
使い道 URL、リアクション・添付の参照 並び順、履歴のページ送り、差分の取り寄せ、既読の位置、未読の数 送り直したときの重複の排除

メッセージの順番は端末の時計に頼りません。created_at は表示のためだけに使います。

既読を 1 件ずつ持たない理由

「誰がどのメッセージを読んだか」を 1 件ずつ記録すると、人数 × メッセージ数の行ができてしまいます。Taylis は 「どこまで読んだか」だけを人 × チャンネルごとに 1 行で持ち、未読の数はチャンネルの連番から計算します。

本文はプレーンテキスト

本文は、軽い Markdown の書き方のプレーンテキストで保存します。メンションは <@ユーザーID> の形で埋め込むので、 表示名を変えると、過去のメッセージの表示も変わります。本文がプレーンテキストなので、全文検索にも、今後の 意味検索(ベクトル検索)や要約にも、そのまま使えます。

保持

  • 処理済みの outbox は 7 日、プッシュの送信の記録は 7 日、失効したセッションは 30 日、無効にした端末は 90 日で消します。
  • メッセージと添付ファイルは、消されない限り長く残します(長い期間の履歴を探せることが目的の一つです)。

詳しくは docs/DATA_MODEL.md をご覧ください。