硬鎖定與明確解鎖
問題
一筆單據被「確認」之後,還能不能改?
這題沒有共識就上線,一定會吵一次。常見的三種答案:
| 做法 | 問題 |
|---|---|
| 完全不能改 | 打錯字也不能改,使用者只好開一張沖銷單 |
| 能改,改了自動解除確認 | 最危險:使用者不知道自己剛剛把已核准的東西打回未核准 |
| 能改,但要明確解鎖 | ← 本模式 |
做法
確認 = 資料凍結。要改,必須先明確解除確認。
未確認 ──確認──→ 已確認(凍結)
│
└──明確「取消確認」──→ 未確認(可改)
三個層次的守衛,缺一不可:
1. 資料層守衛(權威)
所有寫入操作在資料層檢查鎖定狀態,已鎖定就直接 no-op。 不是回傳錯誤,是什麼都不做——因為到這一層才擋,代表 UI 已經漏了, 這時候最重要的是資料不能壞。
2. UI 預攔
按下去之前就擋,並且說清楚原因與解法:「此筆已確認,需先取消確認才能修改」。
3. 視覺標示
鎖定的欄位顯示鎖頭,而且仍然可以聚焦——螢幕報讀器要唸得到為什麼不能改。
取捨
代價:多一個步驟。 使用者要改已確認的資料時,得先解鎖。
這個代價是故意的。它把「我要改一筆已經核准的東西」這件事變成一個 需要刻意做的決定,而不是一次不小心的點擊。
反例
✅ 這樣做
解鎖是一個明確動作,而且會被記錄下來(誰、何時、為什麼解鎖)。
🚫 不要這樣
「編輯自動解除確認」。使用者只是想看看能不能改, 點了一下,整筆單據就退回未確認狀態——而且沒有任何提示。 下游流程(結案、請款)跟著全部回捲。
✅ 這樣做
解除確認時連帶處理衍生資料(例如刪掉當期的凍結快照), 重新確認時再重建。
🚫 不要這樣
不要只改狀態旗標。留著舊快照的話,會出現「狀態是未確認、 但報表還是舊數字」的鬼故事。
實作提示
- 鎖定判定寫成一個函式(
isLocked(period)),資料層與 UI 共用同一份邏輯 - 所有 mutation 開頭第一行就是這個守衛,不要散在各處
- 寫一個測試:對已鎖定的資料呼叫每一個 mutation,斷言狀態完全不變