Telegram 內的審批詳情卡(Mini App)
完整說明、模擬後果與剩餘倒數一次看完,直接在 Telegram 裡按下同意或拒絕。
解決什麼問題
Section titled “解決什麼問題”高風險動作要人同意時,DuDuClaw 會把一張卡片推到 Telegram,上面兩顆按鈕:同意、拒絕。按鈕夠用,但卡片裝不下判斷需要的東西:完整的動作說明、模擬出來的後果、還剩多久會自動拒絕。以前這些只能到儀表板看,於是「在手機上決定」變成「先切到瀏覽器、先登入、再找到那一筆」。
這一頁講的功能把那三樣東西搬進 Telegram 裡:卡片多一顆「🔎 查看詳情」,按下去在對話上方展開一個小畫面,看完直接按同意或拒絕,整段過程沒有離開 Telegram。
這是試作(spike)功能,預設關閉。 範圍只有審批詳情這一張卡:目標是先驗證「把介面塞進通道」這條路可不可行,再決定要不要推廣到任務、花費、狀態等其他畫面。
高風險動作等待人類同意 | v卡片推到你與 bot 的一對一私訊 [同意] [拒絕] [🔎 查看詳情] | 按下第三顆按鈕 vMini App 在對話上方展開 | Telegram 附上簽好章的 initData vGateway 重算 HMAC 驗簽 | 相符 --> 詳情經 POST 送達 v完整說明+模擬後果+每秒更新的倒數 | 同意 / 拒絕 v畫面自動關閉,對話裡那張卡片就地收斂成一行結果打開之後看到什麼
Section titled “打開之後看到什麼”- 這是哪一類決定:與卡片同一行的標籤(「⚠️ 高風險動作需要你同意」)。
- 誰要做什麼:AI 員工名稱、動作的白話說明(「執行高風險工具」「安裝新技能/工具」…)。
- 內容:完整說明,不像聊天氣泡那樣被截斷。
- 如果同意,接下來會發生什麼:系統事先模擬出來的一到三步後果。沒有模擬結果的審批就不顯示這一段,不會硬編。
- 剩餘時間:每秒更新的倒數,剩不到三分之一時轉紅。逾時未回覆一律自動拒絕。
- 兩顆大按鈕:同意這個動作/拒絕這個動作。按下去送出,成功後畫面自動關閉,回到對話。
畫面配色跟著 Telegram 的佈景走(深色模式、淺色模式、自訂主題都會套用),不會在深色聊天室裡刺出一片白。
開啟條件(三個都要滿足)
Section titled “開啟條件(三個都要滿足)”| 條件 | 怎麼設定 | 不滿足會怎樣 |
|---|---|---|
| 功能開關 | config.toml 加上 [miniapp] enabled = true |
端點回 404,卡片維持原本兩顆按鈕 |
| 對外網址是 https | config.toml [dashboard] public_url = "https://你的網域" |
不附詳情按鈕(Telegram 硬性規定 Mini App 只吃 https) |
| 卡片送到一對一私訊 | 由推播目的地決定 | 不附詳情按鈕(Telegram 規定 web_app 按鈕只能在私訊出現) |
[miniapp]enabled = true
[dashboard]public_url = "https://ai.example.com"改完重開 gateway。三個條件任何一個沒過,卡片就跟開啟這個功能之前一模一樣,不會少一顆按鈕,也不會送不出去。
http://localhost:18789 這種本機網址是有效的儀表板位置,但不是有效的 Mini App 位置。沒有對外 https 網域的部署(大多數本機安裝屬於這類)不需要做任何事,這個功能對它們是靜默的。
身分怎麼證明
Section titled “身分怎麼證明”Telegram 開啟 Mini App 時會附一段簽好章的 initData,內容包含使用者 id 與開啟時間,簽章的金鑰是你自己的 bot token。DuDuClaw 收到後照官方文件重算一次:
data_check_string = 除了 hash 以外的所有欄位,依字母排序,用 \n 串起來secret_key = HMAC_SHA256(<bot_token>, "WebAppData")hash = hex(HMAC_SHA256(data_check_string, secret_key))算出來的值與 Telegram 附的 hash 用定值時間比對。對不上就什麼都不回:連這筆審批存不存在都不透露,也不會退回任何精簡版內容。
除了簽章,還有三道:
auth_date超過 1 小時視為過期(畫面開太久要回對話重開);時間戳離譜地指向未來也一樣擋掉。user欄位必須含數字 id,否則拒絕。- 端點有每 IP 每分鐘的請求上限。
網址上的 ?id=<編號> 不是憑證。知道編號不會讓任何人看到內容,因為頁面本身不帶資料,資料一律走驗簽後的 POST 才拿得到。
沒有第二套權限。 Mini App 認出來的 Telegram 使用者 id,跟按下卡片按鈕時回報的是同一個 id,所以決定送出後走的是與按鈕完全相同的那一條路:
- 儀表板裡有已驗證綁定且身分是管理員/主管的人,可以決定;
- 一般員工帳號不行(就算他是收件人也不行,這是職責分離);
- 完全還沒有人綁定通道帳號的部署,只有「卡片送達的那個帳號本人」可以決定。
看詳情套用的是同一組判斷,不會比較寬鬆:不能決定的人也看不到內容。
bot token 只當作 HMAC 的金鑰材料用,不寫日誌、不回應、不進到頁面裡。頁面本身沒有任何後端細節,錯誤訊息一律是「請回到對話重新開啟」這種給人看的話。
- 群組收不到這顆按鈕。 Telegram 規定
web_app按鈕只在使用者與 bot 的私訊出現。卡片推到群組時只會有原本的同意/拒絕兩顆。這是刻意的:硬塞會讓整則訊息送不出去。 - 一定要 https。 這是 Telegram 的規定,不是本專案的選擇。
- 只有審批這一張卡。 任務、花費、狀態卡都還是走既有的按鈕與儀表板深連結。
- 只有 Telegram。 LINE LIFF、Teams Dialog、飛書 Web App 都具備對等能力,但這次沒做;Slack、WhatsApp、Google Chat、Discord 沒有對等機制,未來也只會走「卡片按鈕+原生表單」那一軌。
- 頁面會向 telegram.org 取得平台 SDK。 這是取得
Telegram.WebApp(initData、佈景參數、關閉視窗)的唯一受支援方式。SDK 取不到時頁面不會壞,會改從網址片段(tgWebAppData)讀同一份資料,只是少了自動關閉視窗。除此之外頁面沒有任何外部資源:CSS、JS 全部內嵌,沒有 CDN、沒有字型、沒有圖片。
真機驗收怎麼做
Section titled “真機驗收怎麼做”本機沒有對外 https,webview 開不起來,所以下面這段要在有公網部署的環境上跑:
- 設好
[miniapp] enabled = true與 https 的[dashboard] public_url,重開 gateway。 - 用瀏覽器打開
https://你的網域/miniapp/approval?id=test— 應該看到「請從對話中開啟」,這代表頁面活著而且沒有身分就不給資料。 - 觸發一筆需要人核可的動作,讓卡片推到你與 bot 的私訊。
- 卡片上應該出現第三顆按鈕「🔎 查看詳情」,點開後看到完整內容與倒數。
- 在畫面裡按同意或拒絕 → 對話裡原本那張卡片會就地收斂成一行結果(與按按鈕的行為一致)。
- 反面測試:把同一個網址傳給一個沒有決定權限的人,他打開應該只看到「您沒有查看這筆決定的權限」。