東京五日遊 🇯🇵
預設幣別:JPY機票、住宿、築地市場與迪士尼門票共同分攤
各幣別淨餘額與最佳結算建議
依幣別獨立結算至小數點後兩位,演算法自動最小化轉帳次數
成員淨餘額 (應收 + / 應付 -)
最少交易結算路徑 (建議還款方式)
消費明細記錄 目前視角:陳冠宇
預設僅顯示您個人的收付金額;點擊「展開所有人清單」可檢視全體分攤明細與 R2 收據圖片
機票、住宿、築地市場與迪士尼門票共同分攤
依幣別獨立結算至小數點後兩位,演算法自動最小化轉帳次數
預設僅顯示您個人的收付金額;點擊「展開所有人清單」可檢視全體分攤明細與 R2 收據圖片
後端採用 Cloudflare Workers 搭配 D1 (SQLite) 與 R2 Object Storage 儲存收據圖片,前端透過 HTML5 Canvas 先將圖片剪裁並壓縮至數百 KB 後再上傳至 R2。
前往 Google Cloud Console > Credentials 建立「OAuth 2.0 用戶端 ID (Web 應用程式)」,在「已授權的 JavaScript 來源 (Authorized JavaScript origins)」加入小寫網址:https://nojjbook.7j0.uk、https://nojjbook.cj0.uk 與 http://localhost:8787,將 Client ID 填入 wrangler.toml。
執行 npx wrangler d1 create nojjbook-db 建立 SQLite 資料庫(將輸出的 database_id 貼回 wrangler.toml),並執行 npx wrangler r2 bucket create nojjbook-receipts 建立存放收據圖片的 R2 儲存桶。
執行 npm run db:init:local 建立本地資料表,再執行 npm run dev 即可在 http://localhost:8787 完整測試權重均分、已知成員選單與全螢幕手勢圖片裁切。
1. 分攤明細 JSON 內嵌化 (expenses.splits_json):將每筆消費的成員分攤明細直接以 JSON 存於 expenses 單一欄位中,廢除傳統多表關聯的 N+1 子查詢;新增或修改一筆 5 人拆帳消費從寫入 6 行降至僅寫入 1 行 (省下 83% 寫入額度)!
2. 讀寫連動邊緣快取 (Read-Through & Write-Invalidate Cache):GET /api/groups 查詢結果自動快取於 Worker 記憶體與 caches.default;只要期間沒有新增或修改帳務,重複打開網頁或重新整理皆為 0 次 D1 讀取,直到有寫入操作才自動更新快取。
3. 單次 db.batch() 合併查詢 + 複合索引:消除迴圈查詢,以 WHERE group_id = ? 搭配複合索引 idx_expenses_group_date 精準定位,0 全表掃描。
4. 按需自動建表 (On-Error Lazy Schema Init):僅在首次捕捉到 no such table 時執行一次建表,平時請求 0 系統表檢查開銷。
1. 網域綁定方式:同一網域名稱無法同時指向 Worker 與 R2,已將 Worker 主程式綁定至 nojjbook.7j0.uk 與 nojjbook.cj0.uk,並將 R2 儲存桶綁定至 nojjbook-r2.7j0.uk 與 nojjbook-r2.cj0.uk(完全獨立不衝突,自動簽發 SSL 憑證)。
2. 365天 Immutable 強快取 + caches.default:Worker 寫入與讀取 R2 圖檔時皆強制設定 Cache-Control: public, max-age=31536000, immutable 並寫入 Cloudflare Edge Cache,快取命中時 0 次 R2 讀取計費。
3. 404 負向快取 + 忽略惡意參數:自動剝除圖片網址後的隨機參數(如 ?v=123),且若攻擊者掃描不存在的圖檔,系統會將 404 結果快取 10 分鐘,絕不重複查詢 R2。
4. 防盜連 (Referer 白名單) + 單 IP 速率限制:僅允許來自 nojjbook.7j0.uk 與 nojjbook.cj0.uk 的請求存取圖片,並限制單一 IP 每分鐘上傳/未命中讀取次數。
wrangler.toml 已預先寫好 nojjbook.7j0.uk 與 nojjbook.cj0.uk 的 custom_domain = true 路由。執行 npm run db:init:remote 與 npm run deploy 後,Cloudflare 會自動建立 DNS 紀錄與 HTTPS 憑證!
# 1. 解壓縮 nojjbook-cloudflare-worker.zip 後,安裝依賴並登入註冊了 7j0.uk 與 cj0.uk 的 Cloudflare 帳號 npm install npx wrangler login # 2. 建立 D1 SQLite 資料庫與 R2 收據圖片儲存桶 (將輸出的 database_id 更新至 wrangler.toml) npx wrangler d1 create nojjbook-db npx wrangler r2 bucket create nojjbook-receipts # 3. 建立本地與遠端 D1 資料表結構 npm run db:init:local npm run db:init:remote # 4. 本地開發預覽測試 (http://localhost:8787) npm run dev # 5. 設定正式環境 JWT Secret 並一鍵部署至 https://nojjbook.7j0.uk 與 https://nojjbook.cj0.uk npx wrangler secret put JWT_SECRET npm run deploy