Relay · Channels
Channel、membership 與權限
Relay 提供一套精簡的 transport permission model。它隔離 tenant,要求 conversation write 必須具備 membership,並把 business authorization 留給 host。
目前的 read policy 比 write policy 寬。以下矩陣描述現在的 public behavior,不能視為 private-channel RBAC system。
建立 channel
任何已驗證的 tenant user 都能建立 channel:
POST /api/channels
Authorization: Bearer <jwt>
Content-Type: application/json
{
"metadata": {
"name": "support"
}
} Relay 回傳 201 Created,並自動為建立 channel 的 user 建立 membership。
Channel metadata 是由 host 定義的 JSON,encoded size 上限為 4096 bytes。Relay 負責儲存,但不替其中的 key 定義 business meaning。
目前的 permission matrix
| Operation | 目前條件 |
|---|---|
| 列出 tenant 內的 channel | 該 tenant 內任何 authenticated user |
| 取得單一 channel | 該 tenant 內任何 authenticated user |
| 列出 channel member | 該 tenant 內任何 authenticated user |
| Join WebSocket topic | Channel member |
| 傳送 message | Channel member,且 channel 尚未關閉 |
| 列出 message | Non-member 目前收到 empty list,不是 403 |
| 新增 member | 既有 channel member |
| 移除 membership | User 只能移除自己的 membership |
| 關閉 channel | Channel member |
| 修改 channel metadata | Channel agent member 或 tenant admin |
| Mute notification event | 目前的 member 本人 |
前三項 tenant-wide read 不會依 channel membership 過濾。同一 tenant 內持有 token 的 user 之間,channel existence、metadata 與 member list 不能視為機密資料。
Non-member 讀取 message 時的 empty-list behavior 來自目前的 policy filter。它不是可靠的 authorization signal,未來的 contract 可能會收緊這項行為。
新增 member
既有 member 可以透過 user_id 加入另一位 host user:
POST /api/channels/{channel_id}/members
Authorization: Bearer <jwt>
Content-Type: application/json
{
"user_id": "user-uuid"
} 建立 membership 時回傳 201 Created。同一 user 重複加入會回傳 422 validation response,因為 (channel_id, user_id) 必須唯一。
這個 endpoint 不判斷 host role、team、subscription 或 case ownership。Host 必須在 request 前決定是否應加入該 user。
離開 channel
Delete endpoint 接受 membership ID,不是 user ID:
DELETE /api/channels/{channel_id}/members/{member_id}
Authorization: Bearer <jwt> User 只能刪除自己的 membership。成功時回傳 204 No Content。移除其他 user 的 membership 會回傳 403;membership 不存在時回傳 404。
目前沒有讓 member 或 moderator 移除其他 member 的 endpoint。Admin surface 提供 tenant-wide user offboarding,但那不是 channel moderation。
關閉 channel
任何 member 都能關閉 open channel:
POST /api/channels/{channel_id}/close
Authorization: Bearer <jwt> Close 是 idempotent operation。重複 request 會回傳已關閉的 channel,不會改變原本的 closed_at。
Closed channel 保留 history,但新 message 會收到 422 validation response。目前的 public API 沒有 reopen 或 channel delete endpoint。
修改 metadata
Ordinary user member 不能修改 channel metadata。Kind 為 agent 的 channel member,或 tenant admin,可以使用以下兩種 operation:
PATCH /api/channels/{channel_id}/metadata
PUT /api/channels/{channel_id}/metadata PATCH 只 shallow merge top-level key。Nested map 會被取代,不會 deep merge。PUT 會取代完整 metadata map。Metadata 無效或超過大小限制時回傳 422。
Admin request 必須明確指定 tenant。Agent request 從 signed token 取得 tenant,且仍需具備 channel membership。
Mute notification event
目前的 member 可以 mute 或 unmute Relay 產生的 notification webhook event:
POST /api/channels/{channel_id}/notification_mute
DELETE /api/channels/{channel_id}/notification_mute Mute 會修改 member.muted_at,但不阻止 message read、write 或 WebSocket fan-out。Host 是否傳送 email、mobile push 或 in-product badge,不由 Relay 決定。
Product boundary
Relay 負責 tenant isolation 與 coarse conversation membership。Business role,以及是否建立 channel、加入 member 或公開 Relay token,都由 host 決定。
目前的 tenant API 不提供 private channel discovery、owner 或 moderator role、移除其他 member,以及重新開啟 channel。需要這些 guarantee 的 product,必須先補上 Relay contract;把 host role 寫進 channel metadata 不會產生 authorization。
下一步:上傳並綁定 attachment。