Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
f9a7607
docs(plans): add implementation plan for #43 UX-A danger actions
poterpan Jul 31, 2026
55bc468
feat(worker): 新增 resendBillingOpenedNotice(只重貼開繳公告,不建帳單、不清 marker)
poterpan Jul 31, 2026
1c066ca
refactor(worker)!: initiateBillingOpened 移除 force、回報 createdPayments、…
poterpan Jul 31, 2026
8f3dbbd
refactor(worker)!: sendOverdueForPeriod 改回傳 OverdueResult 並支援 dry-run
poterpan Jul 31, 2026
9d91d8c
feat(worker): 重發需已開繳(否則 409)、開繳紀錄禁止單獨重置、通知動作支援 dry-run
poterpan Jul 31, 2026
9b05126
feat(worker): 發起繳費支援 dry-run 影響預覽(建立/改價筆數、定價 before→after、是否發通知)
poterpan Jul 31, 2026
01525af
fix(worker): web 上傳連結也要過開繳閘門;upload-link 驗證 period 格式
poterpan Jul 31, 2026
8f4f5e0
feat(discord): /發起繳費 可指定期別、預設對齊後台、方案 >5 明確拒絕
poterpan Jul 31, 2026
23da6d4
feat(worker): 記錄 Discord 指令註冊時間(供後台顯示持久狀態)
poterpan Jul 31, 2026
a0b094f
refactor(admin): 破壞性動作統一 btn--danger + ConfirmDanger,移除未定義的 --danger …
poterpan Jul 31, 2026
f64c6c6
feat(admin): 推播狀態改兩段式(重發開繳通知/催繳未繳成員/重置催繳發送紀錄),刪掉開繳重置與「✓ 完成」
poterpan Jul 31, 2026
3384e69
feat(admin): 發起繳費改兩段式影響預覽、誠實回報筆數;收回文案補齊;工具列顯示持久狀態
poterpan Jul 31, 2026
edecf76
fix(admin): 推播狀態讀不到時顯示「狀態不明」而非「未發送」,狀態未知就鎖住三顆推播鈕
poterpan Aug 2, 2026
c497295
docs(readme): 更新推播狀態與發起繳費的行為說明(issue #43)
poterpan Aug 2, 2026
fb87037
fix(notify): Discord 沒回 2xx 就不能算「已發送」;沒方案可公告時不先搶開繳名額
poterpan Aug 2, 2026
12b8e66
docs(readme): 測試數 300 → 349,補上發送失敗與送出時重驗的行為說明
poterpan Aug 2, 2026
0f86227
fix(admin): 舊版後端回應(沒有 outcome)不再讓推播 modal 空白,版本不符時改顯示警告並刷新卡片
poterpan Aug 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
![Cloudflare Workers](https://img.shields.io/badge/Cloudflare-Workers-F38020?logo=cloudflare&logoColor=white)
![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?logo=typescript&logoColor=white)
![React](https://img.shields.io/badge/React-18-61DAFB?logo=react&logoColor=black)
![Vitest](https://img.shields.io/badge/tests-300%20passing-0f6e63?logo=vitest&logoColor=white)
![Vitest](https://img.shields.io/badge/tests-349%20passing-0f6e63?logo=vitest&logoColor=white)
![Serverless](https://img.shields.io/badge/100%25-serverless-074340)

<br/>
Expand Down Expand Up @@ -70,7 +70,7 @@ pre-wired) and a multi-workspace-ready data model, so it generalizes well beyond
enforces screenshot retention — all deduped through `notification_logs`.
- 🛡️ **Access-gated admin** — the whole admin host sits behind Cloudflare Access (email OTP); the
SPA and its API are same-origin so the Access JWT reaches the Worker.
- 🧪 **Real-runtime tests** — 300 Vitest cases run against actual Miniflare D1 + R2 (FK constraints
- 🧪 **Real-runtime tests** — 349 Vitest cases run against actual Miniflare D1 + R2 (FK constraints
enforced), not mocks.

## How a payment flows
Expand Down Expand Up @@ -218,12 +218,23 @@ payment screenshots) and fill in `wrangler.toml` accordingly — `database_id`,
- **重新同步本期帳單** — on Payments, re-align the selected opened period's bills to the current
roster/price (add missing · remove de-subscribed · reprice pending · freeze settled), with a preview
before applying and an option to ping newly-added members with the pay button.
- **發起繳費** — confirm this period's per-plan amounts (any change becomes the plan's new price),
then post the billing-opened notice. Triggerable from the admin Settings or Discord's `/發起繳費`.
- **發起繳費** — confirm the selected period's per-plan amounts (any change becomes the plan's new
price), preview exactly which bills would be created/repriced and whether a notice goes out, then
apply. Defaults to the period being collected; pre-opening next month is an explicit opt-in.
Triggerable from the admin Settings or Discord's `/發起繳費` (which takes an optional 期別 and
refuses when a workspace has more than 5 active plans — re-checked on modal submit, not just when
it opens). A refused Discord send is reported as a failed notice, never as a delivered one: the
bills and the open state stay as they really are, and 重發開繳通知 is the way to re-post.
- **綁定按鈕** — Settings → 工具 → post a persistent public **綁定 Discord** button to the channel so
members self-link proactively (in addition to binding at first payment).
- **Push status** — the dashboard shows whether the billing-opened / overdue notices went out, with
**Resend now** (force) and **Reset** controls.
**重發開繳通知** (re-posts the notice only — never creates bills, never clears the open marker),
**催繳未繳成員** (@s every unpaid member regardless of 逾期天數, unlike the cron) and
**重置催繳發送紀錄**. The first two show the exact recipients before sending; all three take a
confirmation step and report the real counts — a non-2xx from Discord is reported as a failed
send, so the billing notice's `sent_at` is never moved forward and the overdue dedup slot is
released so the next run (cron included) can try again. Reopening/closing a period lives in 收回本期開繳 on
the payments page, not here.
- **Submission alerts** — set a Bark device key and/or a webhook (Discord / Google Chat / Slack) under
Settings → 繳費通知; each new submission then pushes you a notice that opens that member's whole
period for review (shared screenshot once, every row listed, 一鍵全部核准), phone-friendly. Both
Expand Down
18 changes: 13 additions & 5 deletions README.zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
![Cloudflare Workers](https://img.shields.io/badge/Cloudflare-Workers-F38020?logo=cloudflare&logoColor=white)
![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?logo=typescript&logoColor=white)
![React](https://img.shields.io/badge/React-18-61DAFB?logo=react&logoColor=black)
![Vitest](https://img.shields.io/badge/tests-300%20passing-0f6e63?logo=vitest&logoColor=white)
![Vitest](https://img.shields.io/badge/tests-349%20passing-0f6e63?logo=vitest&logoColor=white)
![Serverless](https://img.shields.io/badge/100%25-serverless-074340)

<br/>
Expand Down Expand Up @@ -64,7 +64,7 @@ ChipPot 解決的是一個很具體的痛點:社團大量採購 OpenAI / Anthr
`notification_logs` 去重。
- 🛡️ **Access 保護的後台** — 整個後台主機在 Cloudflare Access 後(email OTP);SPA 與其 API 同源,
Access JWT 因此能到達 Worker。
- 🧪 **真環境測試** — 300 個 Vitest 案例跑在真正的 Miniflare D1 + R2(強制 FK 約束),不是 mock。
- 🧪 **真環境測試** — 349 個 Vitest 案例跑在真正的 Miniflare D1 + R2(強制 FK 約束),不是 mock。

## 一筆繳費怎麼跑

Expand Down Expand Up @@ -206,11 +206,19 @@ pnpm --filter @chippot/worker register
- **重新同步本期帳單** — 在繳費審核頁,把目前篩選的**已開期別**帳單對齊現在的名單/價格
(補缺漏 · 移除已退訂 · 待繳改現價 · 已繳/已驗證凍結);先出差異預覽再套用,並可勾選用繳費按鈕
@ 通知新加進來的成員。選「全部期別」時按鈕停用。
- **發起繳費** — 確認本期各方案金額(任何更動就是該方案的新定價),再發出開繳通知。
可從後台「設定」或 Discord 的 `/發起繳費` 觸發。
- **發起繳費** — 確認所選期別各方案金額(任何更動就是該方案的新定價),先看「會建立/改價哪些帳單、
定價 before→after、是否會發通知」的預覽,確認後才送出。預設期別是**目前收款中的那一期**,
「預開下期」是要自己勾的次要選項。可從後台「設定」或 Discord 的 `/發起繳費` 觸發
(後者可帶 `期別`,方案超過 5 個時會直接請你改用後台——開表單與送出表單都會重驗一次)。
Discord 沒有回應成功時回報的是「通知發送失敗」而不是已發送:帳單與開繳狀態照實留著,可到推播狀態補送。
- **綁定按鈕** — 設定 → 工具 → 在帳單頻道張貼一則常駐的公開**綁定 Discord** 按鈕,讓成員主動綁
(第一次繳費時綁定仍然保留為 fallback)。
- **推播狀態** — 看板顯示開繳/逾期通知是否已發,並提供**立即重發**(force)與**重置**。
- **推播狀態** — 看板顯示開繳/逾期通知是否已發,並提供 **重發開繳通知**(只重貼公告,不建帳單、
不會讓期別短暫變回未開繳)、**催繳未繳成員**(@ 全部未繳者,與只 @ 逾期者的每日 cron 不同)
與 **重置催繳發送紀錄**。前兩者送出前會先列出實際名單,三者都要再確認一次,並回報真實筆數:
Discord 沒回成功就說發送失敗——開繳通知的 `sent_at` 不會被往前推,催繳也會把佔用的去重名額還回去,
下次(含每日 cron)才送得出去。
要把期別改回未開繳請用「繳費審核 → 收回本期開繳」。
- **繳費通知** — 在設定 → 繳費通知填 Bark 裝置金鑰和/或 webhook(Discord/Google Chat/Slack),
之後每筆新送出都會推你一則,點開就是該成員當期的合併審核(共用截圖一次、每筆列出、可一鍵核准),
手機上也好操作。存檔前可先按**送出測試**確認打得通。兩者都選填、best-effort(端點慢或掛掉都不會
Expand Down
Loading