離開之後還走得回來,那段關係就沒有分成兩章

約 3 分鐘

離開群組做完之後,我以為章節已經把兩個人分開了。然後我看到 createInvite 的簽名。

export async function createInvite(groupId: string): Promise<string>

它替你傳來的那個帳本鑄一張七天的邀請。整條路上只確認你登入了。沒有一行問你是不是這個帳本的成員。

前任還記得那串 group id。它不是秘密,他人還在的時候,每次打開帳本都會出現在頁面資料裡。人走了,帳本回到一個人,他仍可以拿著舊的 id 鑄一張邀請給自己,再自己接受。他就回來了。當前這一章的帳、愛物裡的地址和車牌,一起回來。而留下來的那個人沒有一條「把人趕出去」的路。

陪伴若擋不住走掉的人自行走回來,上一章就沒有真的結束。


修法看起來就一行。登入之後再叫一次 requireGroupMember(groupId, user.id)。這樣能補上這個洞。我沒有這樣做。

我把參數拿掉了。邀請只能從「現在這個登入者自己的帳本」反查,呼叫端沒有 id 可以傳。

export async function createInvite(): Promise<string> {
  const { user, group } = await requireViewerGroup()
  // ...
}

多一個檢查,是在拜託下一個寫程式的人——多半是模型——記得呼叫它。這個 bug 本身就是有人忘了。把參數刪掉之後,錯誤的呼叫在結構上寫不出來。三個原本傳自己 group id 的地方跟著變短,兩個因此用不到的 prop 也刪了。

接受邀請的那一端再補一層。鑄造者若已經不是成員,邀請作廢,錯誤碼是 inviter_not_member。就算哪天又有人把 id 加回去,進來的門還會再問一次:鑄這張邀請的人,現在還在不在。

離開要留得下來,不能靠每個人都記得多寫一行檢查。

收尾

教科書上的修法是加 guard。我比較怕的是下一次生成的程式碼又會傳進一個 id,然後信任那個 guard 還在。沒有參數,就沒有東西好漏。

先不說了,我得去翻還有哪個 server action 在收一個它不該收的 id。

這件事發生於 2026 年 9 月,文章整理於 2026 年 10 月。