Relay · 核心概念
Relay 核心概念
Relay 負責對話傳輸。Host product 提供身分與業務規則;Relay 儲存 channel、membership、message 與 delivery state,不需要理解 host 的 domain model。
Host product
└─ tenant
└─ channel
├─ members
├─ messages ordered by seq
└─ read cursors Tenant
Tenant 是資料隔離邊界。Relay 把每個 tenant 的對話資源存進獨立的 PostgreSQL schema,名稱為 tenant_<uuid>。
Host 決定何時建立 tenant,以及 tenant 如何對應自己的 account 或 organization。Relay 不推測這層關係。
User identity
Relay 從 host 簽發的 token 取得 user_id。登入、帳號狀態、角色,以及 business user 與 user_id 的對應,都由 host 負責。
Agent 或 bot 在 Relay 裡同樣是 user,與 human user 適用相同的 tenant 與 membership 檢查。
Channel 與 membership
一個 channel 保存一段有序對話,並維護 next_seq。Channel 也能透過 closed_at 進入關閉狀態。
Member 把一個 user_id 連到一個 channel。Membership 控制 message 存取。關閉 channel 後不能再寫入新訊息,但既有歷史不會因此消失。
Message
每則 message 包含兩個用途不同的識別值:
| 欄位 | 分配者 | 用途 |
|---|---|---|
nonce | Client | 識別跨 retry 的同一次邏輯傳送。在同一個 channel 內必須唯一。 |
seq | Relay | 定義 message 在 channel 內的順序。 |
Relay 在 message transaction 內透過資料庫分配 seq。Client time 不會決定 message order。
Message 也能包含 parent_message_id、mentions、reactions 與 attachments。這些能力沿用相同的 tenant、membership、ordering 與 idempotency boundary。
Read cursor
Relay 會記錄每位 member 在 channel 裡的 last_read_seq。Cursor 指向 server sequence,因此跨 reconnect 與 device 仍有一致意義。
Unread state 要如何呈現在產品中由 host 決定。Relay 提供 transport state,不負責 notification policy 或 UI behavior。
四項不變式
- REST 與 WebSocket send 使用同一條 message write path。
- Tenant resource 留在各自的 PostgreSQL schema 內。
- 資料庫在 message transaction 內分配 channel-local
seq。 - 重複使用
(channel_id, nonce)時,Relay 回傳原 message,不建立第二筆。
權責邊界
Relay 負責 conversation transport,包括 channel、member、message、reply、reaction、attachment、sequence、cursor 與 delivery behavior。
Host 負責 business identity、business authorization、workflow、notification policy,以及 conversation contract 以外的所有事實。Relay 不會呼叫 host application API。
下一步:驗證 Relay request。