iT邦幫忙

2026 iThome 鐵人賽

DAY 28
0
ChatGPT & Codex

這隻 LINE Bot 不是我寫的:30 天讓 Codex 從零幫我做到上線系列 第 28

Day 28 - 不是發起人按了截止,接下來呢?我修好 LINE Bot 裡消失的下一步

  • 分享至 

  • xImage
  •  

群組選時間功能完成後,我就直接在 LINE 裡開始操作。

這一次,我和 Codex 的開發沒有在程式寫完的那一刻結束。我把 Bot 當成真的群組成員來使用,只要有一個當下不知道怎麼往下走的時刻,就直接用白話把現象交給 Codex。

因此這篇不只是「我發現 bug,Codex 幫我改好」。更接近真實的過程是:我提供 LINE 畫面上看到的症狀,Codex 則從這句描述往後找到真正斷掉的程式路徑。

整個流程看起來很順:選好咖啡廳、加入時間、投票,最後截止。

但當我刻意讓「不是發起人的成員」去按截止時,Bot 雖然正確回答:

只有這次投票的發起人可以截止投票。

卻也就停在這裡了。

這句話沒有錯,權限也確實擋下了不該發生的操作,但群組裡的原發起人看到這則訊息後,卻沒有一個明顯的下一步可以接著做。

這是我這次最有感的發現:

錯誤訊息只說明「你不能做什麼」還不夠,它還應該讓「可以做的人」馬上接手。

問題一:權限阻擋成功了,整個群組卻被留在原地

在群組功能裡,一個人按下按鈕,回覆卻是給整個群組看的。

這和一對一聊天很不一樣。非發起人的誤觸雖然是個人行為,但 Bot 的下一則訊息會變成大家現在看到的最新狀態。

原本的做法只回覆一行權限提示:

非發起人按截止
        ↓
Bot 拒絕操作
        ↓
顯示「只有發起人可以截止」
        ↓
流程中斷

問題不在於原本的投票資料不見了,而是新訊息沒有把操作入口一起帶回來。原發起人可能要往上翻卡片,或者根本不知道要輸入什麼才能繼續。

技術上,原本所有群組投票錯誤會走進同一個通用處理:

catch (error) {
  reply(errorText(error));
}

forbidden 被正確翻譯成「只有發起人可以截止」,但這個 handler 不知道使用者剛才在做什麼,也不會去取得最新投票。

這讓我發現,有些錯誤適合只回文字,有些錯誤則必須保留「發生在哪個動作」的上下文。

我當時只告訴 Codex:「它說只有發起人可以,但發起人沒有下一步。」

Codex 先沿著 postback 進入點往下看,找到 finish 會呼叫截止投票的 function;接著看到非發起人被 store 拋出 forbidden;最後追到 handler 的 catch,發現所有錯誤最後都只被壓成一則純文字。

我看到的:發起人沒有按鈕
Codex 追到的:finish → forbidden → generic errorText

這是我覺得 Codex 很適合參與這種修正的地方。我不必先知道錯在哪個檔案,但要把當下的使用情境說清楚;它再負責把畫面症狀對回實際的程式流程。

https://ithelp.ithome.com.tw/upload/images/20260908/20183556WkWoJbK5Ju.jpg

修正後:提醒權限,也把接棒交給正確的人

現在,當非發起人按下截止時,Bot 不再只回一句話。

它會先說明:

🙋 只有原發起人可以截止投票。
我已重新顯示目前票數,
請原發起人按下方的「截止投票」。

緊接著重新顯示:

  • 目前所有候選。
  • 每個選項的最新票數。
  • 可用的「截止投票」按鈕。

流程因此變成:

非發起人按截止
        ↓
Bot 拒絕操作
        ↓
重新顯示最新投票與截止按鈕
        ↓
原發起人直接接手

這個修正同時放進了「咖啡廳投票」和「時間投票」。因為兩邊都有截止權限,也都可能遇到同一種群組斷點。

修正後,handler 會特別辨識「在 finish 動作遇到 forbidden」這個組合。概念上像這樣:

if (action === 'finish' && error.code === 'forbidden') {
  const latestVote = await getCurrentVote(groupId);

  reply([
    ownerRequiredMessage,
    ...createVoteMessages(latestVote)
  ]);
}

重點不是繞過權限,finalize 仍然會檢查操作者是不是發起人。這段新處理只會重新讀取最新狀態,然後用同一組產生投票卡片的 function,把票數和截止按鈕再畫一次。

https://ithelp.ithome.com.tw/upload/images/20260908/20183556ZBGiA1KWRo.jpg

問題二:明明能加 5 個時間,畫面卻在第 1 個就收工

接著我又遇到另一個很直覺的問題。

按下「接著一起選時間」後,我先加入一個日期時間。Bot 正確告訴我:

✅ 已加入候選時間(1/5)

但下方只剩一個選項:

查看並投票

這裡的矛盾很明顯:文字說還可以有 4 個,介面卻像在說「時間已經收集完了」。

當下的我當然還知道自己想測什麼,但真正的群組成員不會知道背後還支援 5 個候選。

如果畫面沒有按鈕,對使用者來說,那個能力幾乎等於不存在。

https://ithelp.ithome.com.tw/upload/images/20260908/20183556gR86ErWJSW.png

修正後:未滿 5 個以前,一直保留「提出候選時間」

現在每次加入新時間後,Bot 會同時留下兩個入口:

[提出候選時間] [查看並投票]

因此:

  • 原本的人可以繼續加第二個時間。
  • 群組裡下一個人也可以接著提案。
  • 想先看票數的人仍然可以直接進入投票。

當候選達到 5/5 時,「提出候選時間」才會消失,畫面只保留「查看並投票」。

這樣畫面表達的規則,才和 Bot 真正支援的功能一致。

實作上,Quick Reply 不再是寫死只有一個「查看」按鈕,而是依目前候選數量組出來:

const items = [
  ...(options.length < 5 ? [createDatetimePicker()] : []),
  createViewAndVoteAction()
];

這段判斷很短,卻將介面和原本的上限規則接在一起:還有名額就繼續邀請提案,滿了才把大家導向投票。

這一題也是同樣的協作方式。我沒有說「請修改 createGroupScheduleOptionAddedMessage」,而只是告訴 Codex:「我選了一個時間,怎麼只剩查看並投票?」

Codex 先確認後端真的支援 5 個候選,才去找「新增時間後那則回覆」是在哪裡產生。它發現問題不在 Datetime Picker,也不在 Firestore,而是成功訊息的 Quick Reply 從頭到尾只放了「查看並投票」。

因此我們不是無條件多放一個按鈕,而是讓 Codex 把介面接回已經存在的業務規則:候選數量小於 5 才顯示 Datetime Picker,到達上限就自動收起。

https://ithelp.ithome.com.tw/upload/images/20260908/20183556Q0kezU8tg3.png

這兩個問題的共同點:Bot 知道規則,但沒有幫人走完

這次的兩個問題,後端其實都有正確處理:

  • 它知道非發起人不能截止。
  • 它知道最多可以收集 5 個時間。

但光是「系統知道」還不夠。

如果介面只說你做錯了,卻沒有把正確動作放回來,那是一條死路。

如果系統允許再新增 4 個時間,畫面卻沒有入口,那則是被藏起來的功能。

所以我這次給自己留下一個很實用的檢查方法:

每當 Bot 回覆完,畫面上還有沒有一個很明顯的下一步?

這個問題對群組 Bot 特別重要,因為前一個人的操作,常常正是下一個人的起點。

我和 Codex 是在實際對話裡把流程補完的

這兩個問題都不是我一開始寫需求時想到的。

我是真的在 LINE 群組裡點了按鈕,才發現自己不知道接下來要做什麼。

我把當下看到的情況直接告訴 Codex:

不是發起人按截止後,
雖然有提示,但發起人沒有下一步。

以及:

我選了一個時間後,
怎麼只剩下查看並投票?

Codex 沒有只改那句錯誤文字,而是往前後查看整條互動:是誰觸發、回覆後還留下哪些按鈕,以及下一個應該行動的人是誰。

它還把第一個問題從時間投票往前檢查,發現咖啡廳投票也有相同的截止權限斷點。所以修正不只照著我看到的單一畫面打補丁,而是同時讓選店和選時間使用同一種「拒絕後重新交棒」流程。

第二個問題則反過來,讓 Codex 查看除了成功訊息之外,其他時間投票卡片是不是仍然有「提出候選時間」。這樣才能確定修正後的入口不會在下一則訊息又消失。

最後修的不是一個按鈕的文字,而是兩條斷掉的使用路徑。而我也從這個過程學到,和 Codex 合作時不一定要先猜技術解法;把「我做了什麼、看到什麼、期待下一步是什麼」說完整,往往更有幫助。

功能完成,不代表使用者完成了任務

如果只看功能清單,這個 Bot 原本已經能做到:

新增多個候選時間
限制發起人才能截止

但第一版介面並沒有讓人順利完成這兩件事。

真正修完後,我對「功能做完了」的定義也有點不一樣:

不是程式裡有這個能力,而是使用者不需要猜,就能一步一步走到結果。

這次加上的只是幾個按鈕和重新顯示的訊息,卻讓群組時間投票從「應該可以用」,變成真的有人能接著用完。

完整程式碼與參考資料

GitHub:
https://github.com/zonawang/line-cafe-group-scheduler

LINE Messaging API — Quick reply:
https://developers.line.biz/en/docs/messaging-api/using-quick-reply/

LINE Messaging API — Postback action:
https://developers.line.biz/en/reference/messaging-api/#postback-action


上一篇
Day 27 - 咖啡廳選好了,大家還是約不成:我讓 LINE Bot 繼續幫群組選時間
系列文
這隻 LINE Bot 不是我寫的:30 天讓 Codex 從零幫我做到上線28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言