通知
Sandbox 透過既有的 TeamSync 通知中心(NotificationCenterType.SANDBOX_EVENT = "sandbox_event")寫入 inbox + FCM/MQTT。它們不能取代輪詢。GET run/build 狀態(terminal_at/terminal_class)仍是真相來源。
用既有通知 API 讀 inbox(不在 /private/module/sandbox 底下):
GET /private/notifications?type=sandbox_event每列是 UserNotificationResponse:id、type、title、body、metadata、source_type、source_id……。metadata.kind 是 sandbox_event。社群/LINE run 不會幫外部 client 建 inbox 列——會扇出給聊天室管理者(否則公司管理者)。把管理者 deep-link 到該 run。
Payload 只帶 id、status、error_code、標籤與 deep-link metadata。絕不包含腳本、secret、input/output/log 本體、ENV、capability token 或 URL(src/crud/sandbox/notifications.py 的 _FORBIDDEN_PAYLOAD_KEYS)。
事件目錄
event(SandboxNotificationEvent) | Deep-link 資源 | 典型收件人 |
|---|---|---|
run_terminal | run | 內部呼叫者本人;外部/社群呼叫者 → 聊天室管理者,否則公司管理者 |
run_content_expiring | run | 合格呼叫者,否則聊天室管理者 |
run_content_expired | run | 同上 |
build_ready | build_attempt | 環境 owner-scope 管理者 + 公司管理者(後端 #1149 起有 producer;與 attempt 終態同一交易寫入,以 attempt_id 冪等) |
build_failed | build_attempt | 同上——body 帶 error_code/error_detail |
build_cancelled | build_attempt | 同上 |
curated_environment_published | environment | 已釘住該 curated 環境任一版本的每家公司的公司管理者(不會廣播給所有租戶);後端 ≥ #1149 |
security_finding_discovered | finding | 提交者 + owner-scope 管理者 + 公司管理者 |
security_finding_resolved | finding | 同上 |
security_finding_reappeared | finding | 同上 |
security_finding_blocked | finding | 同上 |
security_remediation_deadline | finding | 同上 |
security_exception_granted | finding | 同上 |
security_exception_revoked | finding | 同上 |
security_exception_expired | finding | 同上 |
runner_replacement_available | environment | 環境擁有者 + 公司管理者 + 受影響房間管理者 |
runner_handoff_completed | environment | 同上 |
runner_handoff_expired | environment | 同上 |
runner_handoff_failed | environment | 同上 |
image_storage_renewal_blocked | company | 公司管理者 |
image_storage_cleanup_completed | company | 公司管理者 |
Inbox 冪等鍵是 (user_id, type, source_type, source_id)。source_type 例如:sandbox_run_terminal、sandbox_build_ready、sandbox_security_finding_discovered。run_terminal 的 source_id 是 run_id。
Dispatch payload(安全欄位)
FCM/通知中心的 dispatch_data 是字串化的,包含:
notification_type = "sandbox_event"
event = SandboxNotificationEvent
company_id
status
error_code
run_id (適用時)
build_attempt_id (適用時)
finding_id (適用時)
deep_link_resource_type = run | build_attempt | finding | environment | company
deep_link_resource_id用 deep-link 對去開既有的狀態頁,然後再 GET 該資源。不要只信推播上的 status。
run_terminal 文案(zh-TW)
run_terminal、三個 build_* 事件與 curated_environment_published 有專屬的繁體中文標題/內文(本部署的使用者語言;build/curated 文案自後端 #1149 起)。其他事件維持英文預設。
Run status | 標題 | 內文模式 |
|---|---|---|
completed | 沙盒任務執行完成 | 「{task}」已順利執行完成,點開查看結果。 |
cancelled | 沙盒任務已取消 | 「{task}」已被取消。 |
customer_failed / platform_failed | 沙盒任務執行失敗 | 「{task}」執行失敗(錯誤代碼:{error_code}),點開查看詳情。 |
| 其他 | 沙盒任務已結束 | 「{task}」已結束(狀態:…)。 |
目前每一則 run_terminal 的 {task} 都是 您的沙盒任務:唯一的生產端 record_run_terminal 不傳 task_label,metadata.task_label 也永遠是 null。要在通知裡顯示任務名,前端得用 metadata.task_id/run_id 自行查。
前端規則
- 走既有通知中心/FCM 客戶端訂閱。沒有 sandbox 專用 websocket。
- 尊重使用者通知偏好;後端已做
apply_notification_preferences。 - 沒收到通知 ≠ run 不存在。繼續輪詢。
- Deep-link 只開使用者本來就能
GET的 run/build。A-010 仍適用:擁有被分享的任務,不能因此打開 borrower 房間的 run。 - 不要把通知
data當成含有 log 或產出物來渲染。