Skip to content

後台危險動作一律先預覽再確認,並如實回報結果 (#43) - #47

Merged
poterpan merged 17 commits into
mainfrom
ux/43-danger-actions
Aug 3, 2026
Merged

poterpan merged 17 commits into
mainfrom
ux/43-danger-actions

Conversation

@poterpan

@poterpan poterpan commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Closes #43

後台所有「破壞性動作」改成先預覽、再確認、如實回報。這批只處理 issue #43(UX-A:危險動作)
列出的項目;行動版/a11y(#44)、成員回饋(#45)、用詞統一(#46)不在範圍內。

這批做了什麼

推播狀態(看板) —— PushStatus 從 Dashboard.tsx 抽成獨立的 views/PushStatus.tsx,三顆按鈕
都改成兩段式:

按鈕 行為
重發開繳通知… 只重貼一次公告。不建帳單、不改定價、不清開繳標記,期別全程維持已開繳。此期尚未開繳 → 直接說「無法重發」,不給確認鈕。
催繳未繳成員… 先列出實際會被 @ 的人與未繳總額(未綁定者標「(未綁定,@ 不到)」),再確認。
重置催繳發送紀錄… 只清催繳去重紀錄,不動帳單、不影響開繳狀態。

「✓ 完成」這種一律成功的假回報拿掉了,改成各 modal 回報真實筆數
(✓ 已在頻道催繳 N 位成員。/未發送:{中文原因})。推播狀態讀不到時顯示「狀態不明」並鎖住三顆鈕,
不再把未知當成「未發送」。

發起繳費 —— 後台與 Discord 都先出影響預覽:四張統計卡(新增帳單/改價/方案改價/保留已繳)、
定價 before→after、將建立與將改價的帳單清單、以及「這次會不會發通知」。期別預設值改成目前收款中的
那一期
(periodForBillingDay),要開下個月得自己勾「預開下期」。

其他 —— 收回本期開繳的 tooltip 與 modal 文案補齊(含「一次性上傳連結會立即失效」);設定→工具三列
加上「目前:已張貼/尚未張貼/已註冊…」狀態行;全站破壞性動作統一 btn--danger + ConfirmDanger,
移除未定義的 var(--danger, #c0392b) 與兩處 window.confirm;web 的一次性上傳連結補上開繳閘門
(期別未開繳 → 409)。

⚠️ 行為變更(部署後行為會不一樣,請先看完)

  1. 立即重發 → 重發開繳通知…,語意變了。 舊的「立即重發」會走完整的開繳流程:建帳單、
    delete-then-claim 通知標記(期別會短暫變回未開繳)。新的只重貼公告,不再建立或修改任何帳單。
    如果你以前是用「立即重發」來補建漏掉的帳單,改用繳費審核 → 重新同步本期帳單。
  2. 開繳通知的 重置 按鈕移除了。 後端 POST /admin/notifications/reset 收到
    type: "billing_opened" 一律回 409 —— 這是刻意的行為移除,不是漏改。單獨清掉開繳標記會讓
    期別狀態與帳單不一致(標記說沒開、帳單還在),要把期別改回未開繳請用
    繳費審核 → 收回本期開繳(會一併處理帳單與上傳連結)。overdue 的重置行為不變。
  3. 發起繳費 預設只做預覽。 後台按下去先看影響,要再按一次紅色的確認鈕才會真的送出。
  4. Discord /發起繳費 新增 optional 期別 選項(YYYY-MM,留空=目前收款中的期別),且啟用
    方案超過 5 個時會 ephemeral 拒絕
    (Discord 表單只有 5 欄,無法在那裡確認全部金額),請改用後台。

Breaking changes(API/函式簽名)

  • initiateBillingOpened 移除 opts.force。
  • sendOverdueForPeriod 改回傳 OverdueResult({ notified, outcome, overdue_days, people })。
  • POST /admin/billing/initiate 與 POST /admin/notifications/resend 的 dry_run 預設為 true。
    既有腳本若直接打這兩支 API,必須改帶 dry_run: false 才會實際執行,否則只會拿到預覽。
    (與既有的 /sync、/retract 一致。)
  • POST /admin/upload-link:period 格式錯誤 → 400。
  • POST /upload/:token:期別未開繳 → 409。
  • POST /admin/discord/register-commands:回傳新增 registered_at,並寫入
    settings.discord_commands_registered_at。

部署後必做

重新註冊 Discord 指令:後台 → 設定 → 工具 → 「註冊 Discord 指令」。
/發起繳費 新增了 期別 選項、指令描述也改了,不重新註冊的話 Discord 那邊看到的還是舊的。
(該列現在有「目前:已註冊(日期)」狀態行,可以確認有沒有跑到。)

驗證

  • pnpm -r typecheck 三個 package 全綠。
  • pnpm -r test:338 passed / 47 files(300 → 338,+38)。README 徽章已同步。
  • VITE_API_BASE=… pnpm -r build 全綠。
  • 殘留樣式掃描:window.confirm( 呼叫 0 筆、var(--danger 0 筆、billing.ts 的 force: true 0 筆、
    adapters 的 nextBillingPeriod 0 筆;Dashboard.tsx 內舊的 重置/立即重發/✓ 完成 全數 0 筆。

Merge 方式

本分支含一個中間 commit(f64c6c6)在當下 typecheck 是紅的(後續 commit 修好,分支 tip 全綠)。
建議 squash merge(也是本 repo 的慣例)。

poterpan added 17 commits July 31, 2026 15:21
催繳不再只回一個數字:outcome 講清楚「沒送出」到底是 no_channel /
no_bot_token / none_due / already_sent,並帶回 overdue_days 與名單,
讓後台能在按下去之前先預覽會 @ 到誰、也能說明這份名單為何與 cron 不同。

同時收下 review 路由過來的三件事:
- POST /admin/notifications/resend 的稽核記下 outcome(原本只有 sent:false,
  看不出原因)
- 補 billing_opened 重發的路由層測試:成功/no_bot_token/no_plans,
  含 sent_at 前後比對與「重發不建帳單」
- test/core/billing-resend.test.ts 補上 sent_at 由舊變新的斷言(Task 1 遺留)

順手修掉兩處說 sendOverdueForPeriod「returns 0」的過時註解。
順帶把測試數 badge 從 300 更新為 338(兩份 README)。
Notifier 契約改為回傳「頻道確認收下」的布林值(createChannelMessage 回
{ ok, id },且不再因為 body 解析或連線錯誤丟例外)。三條發送路徑各自決定
失敗語意:

- 發起繳費:marker 已經搶下、帳單已建立 → 回 sent:false + notify_reason
  send_failed,不回收 marker(回收會讓帳單卡在不能繳的期別=半套收回),
  補救路徑是「重發開繳通知」。
- 重發開繳通知:outcome send_failed,sent_at 不往前推。
- 催繳:outcome send_failed,並把剛搶下的 overdue 名額還回去 —— 這列不代表
  「期別已開」,留著會讓本期永遠不再被催繳(含每日 cron),與收回本期開繳
  釋放同一列是同一個理由。
- cron 的 billing_opened 維持先搶名額(step 1 已建帳單且不會回頭重跑),
  只有確認送出才計入 summary;差異已在程式碼註解說明。

同時修掉 apply/preview 不對盤:發起繳費改成「先算出公告名單、再決定要不要
搶 marker」,沒有任何啟用方案時照 preview 的 no_plans 拒發,不留下「已開繳
卻從沒通知過」的期別;帳單照樣建立(preview.create 答應了什麼就做什麼)。
apply 現在把 notify_reason 一路帶回後台與 Discord 回覆,不再拿 preview 的
預測當結果講。/發起繳費 modal 送出時重驗方案數上限與啟用方案集合。

新增 502 模擬測試涵蓋三條路徑(band 9860)與零公告方案的 apply/preview
對照(band 9870),共 349 個測試。
@poterpan
poterpan merged commit 8c02705 into main Aug 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[UX-A] 危險動作與期別安全

1 participant