feat(#45): 通知 slot 底座 + 遷移危險修復 + 退回必發回條 (P0-5) - #50
Merged
Merged
Conversation
同一張帳單的退回與確認需要兩個 dedup slot,個別催繳需要自己的 type。 SQLite 無法 ALTER CHECK/UNIQUE,故以 0006 重建表。收回本期開繳時一併清掉 該期的 receipt/nudge slot。
該列不是送信紀錄,而是「本期已開繳」的定義;單獨刪除會讓待繳帳單留在 成員已無法繳費的期別裡(半套收回)。以 ReleasableKey 於編譯期擋掉, 並以 @ts-expect-error 測試釘住(tsconfig 涵蓋 test/,放寬即建置失敗)。
投遞走帳單頻道 @:adapter 只有 channel API,且既有的開繳/催繳/入職提醒 都在同一個頻道,成員的目光已經在那裡。未綁定者退回粗體姓名、不 ping。 回傳 boolean 而非計畫寫的 void,跟齊 #43 的 Notifier 契約:只有 Discord 真的 回 2xx 才算送達,呼叫端才有辦法在失敗時把 receipt 名額釋放掉。
rebase 到含 #48 的 main 之後: - 遷移改名 0007_notification_event.sql(原 0006 與已上線的 0006_overdue_daily 撞號) - **關鍵**:INSERT ... SELECT 的 event 改為原值傳遞(原本硬寫 '')。0006 已在正式環境 寫入逐日催繳 day-key,硬寫 '' 會靜默清空它們,使 #48 退化成每期一則且無任何錯誤。 已用 sqlite3 重放 0001→0007 驗證:day-key 保留;替換成 '' 作反證:確實被清空。 - 本次重建只擴充 type CHECK 加入 'nudge',不重新宣告已存在的 event 欄 - schema 測試補上 event 參與去重鍵、nudge type 與 (entity,event) 去重 - overdue-daily 測試的 Notifier 假件補 sendPaymentReceipt(介面已加寬)
成員送出繳費後被退回,過去完全收不到任何通知——這是 UX 健檢的 P0-5。 - 新增 core/receipt.ts 的 announcePaymentReceipt:以 (帳單, event) 為去重鍵, 退回與確認是兩個 slot;一位成員同期多筆合併成「一則」訊息而非 N 則 - 沒有頻道或 bot token 時不佔用 slot(同 cron 規則),之後設定好才不會撲空 - 送失敗把 slot 還回去,避免這張帳單的回條被永久靜音 - 接上 POST /admin/payments/:id/reject:退回已提交,Discord 失敗不轉成 500, 誠實回報 notified 筆數 - 成員重新送出時(settleUserPeriod)釋放該期回條 slot,下次審核是新事實要再講 測試 373 → 382
This was referenced Aug 29, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
UX 健檢批次 C(#45)的第一批:通知 slot 底座、遷移危險修復,以及 P0-5 的主軸「退回必發回條」。
本 PR 刻意不涵蓋 #45 的全部 16 項任務——這批本身完整且獨立,而且含有一個會破壞正式環境資料的修復,值得先落地讓
main穩定(#44 / #46 的 rebase 基準也才穩)。🚨 最重要的一項:修掉會靜默清空正式資料的遷移
本分支原有
0006_notification_event.sql,與已上線的 #480006_overdue_daily.sql撞號。更嚴重的是它的搬移語句把event硬寫成空字串:分支切出去時這是對的(那時
event欄還不存在),但 #48 已上線,正式環境的notification_logs.event現在存著逐日催繳的 day-key。照原樣套用會:''→ [Feature] 催繳邏輯改善 #48 的「每日催繳」退化成「每期一則」SELECT永遠碰不到測試列)修法:改名
0007_notification_event.sql、event改為原值傳遞、不重新宣告已存在的欄位,本次重建只把 type CHECK 擴充加入'nudge'。驗證方式(不是靠測試,因為測試根本測不到):用
sqlite3實際重放0001 → 0007,種一筆帶 day-key 的 overdue 列:0007event=2026-08-29✅ 保留'')event=''❌ 確實被清空這個限制已寫成註解留在
test/schema.test.ts,避免後人誤以為有測試保護。rebase:兩套語意都保留
分支基底是 #48 之前的 main,
core/notify.ts與core/billing.ts有實質衝突(非單純文字衝突)。已手工合併,兩邊都保留:claimNotificationSlot/releaseSlot/dayKey逐日去重releaseNotification/releaseReceiptSlots/receipt/nudgeP0-5:退回必發回條
成員送出繳費被退回後,過去完全收不到任何通知——這是 UX 健檢列為 P0 的死路。
core/receipt.ts的announcePaymentReceipt:以 (帳單, event) 為去重鍵,退回與確認是兩個 slotPOST /admin/payments/:id/reject:退回已提交,Discord 失敗不轉成 500,誠實回報notified筆數測試
382 passed / 53 files(main 基準 355)。
pnpm -r typecheck綠,admin + web build 皆綠。新增涵蓋:回條去重、跨 event 分離、多筆合併成一則、重送後可再發、送失敗還 slot、無投遞管道不佔 slot、路由層退回會記錄、Discord 失敗不 500。
尚未涵蓋(#45 後續 PR)
Task 4–16:確認回條開關、P0-6 錯誤中文化、C1–C9(金額收斂、三入口能力差異、
/我的帳單、綁錯名字、個別催繳、未綁定成員可見度等)。審查註記
Codex 跨引擎審查因額度用盡尚未執行,額度恢復後補送(owner 已知悉)。