Boss-AI Sync 載入中...
7 份 Spec / Audit 等老闆 review
AI 智慧報告 v3 集團架構(5/20) · v2 簡化版 · 上 Production Checklist 等
看 →
早安報告 · AI 昨晚自主完成的事
W4 grill 5 bug 修 · B2 補錢提醒 · 3 checklist · #1-4 Wishes 全處理
看 →

ChefsMate 老闆報告

2026-05-16 · 由 AI 秘書與老闆共同維護 · 每個 commit 自動更新

一句話總結:採購單的雲端化(thin-client)+ 同步速度優化兩大基礎建設都完成, 用戶提的「付款帳戶追蹤」feature 也 ship 完整。POS 上架 9 個 feature 排在 有精神時段,主 App 重構排在 睡覺自動跑,瑣碎 debug 排在 低精神時段

本頁工作協議:這頁是老闆 + AI 秘書共同維護的工作儀表板。 AI 承諾每次 commit / 重大進展都更新這頁;老闆可隨時加新願望(許願池), AI 下次來會 review。檢查清單與許願池保存在你瀏覽器(localStorage), 清快取會清掉,要備份請按「匯出」。
序號規則(討論時直接用編號)#H1-H10 有精神時段 · #L1-L5 沒精神時段 · #S1-S6 睡覺時段 · #P1-P7 大計劃 · #D1-D4 待決策 · #W1+ 許願池
講「做 #H2」我就知道是「取消/退款流程改造」,不用打全名。
還沒做的事
3
P0/P1/P2/P3 全部 ship · 只剩 D1/D2/D3 老闆拍板
↓ 滑到還沒做
Dogfood 待驗證
10
#H1-#H10 已 ship code,等老闆實測通過
看待驗證列表
POS 上架完成度
99%
audit 40/41 inline + 1 FP 修完 · L0-L7 sysmap 完整 · 只剩老闆拍板
看詳情
夜間健康檢查
129 / 190
60 已修(34C + 26H + 1 FP)/ 剩 0 critical + 44 high 待修 🎉
看完整計劃
Phase 1+2 等老闆 dogfood
7 / 7
綠勾 / 發票自動開 / 載具掃描 / AirDrop / 會員發票頁 / 結帳會員分流 — 7 個白話步驟
看 dogfood 步驟
本週 ship
50+
Batch 14-20 audit 22 bug · 4 SQL migration · L5/L6/L7 27 doc callout · Stitch palette refresh
看最近 ship

本週工作看板

Thursday 24 · 一覽要做/做中/已完成
列表 系統地圖
本週 ship
50+
AuditP1/P2/P3
Audit 大清掃 Batch 14-26
40 inline bug 全修 + 1 false positive · 11 SQL migration · 27 L5/L6/L7 doc audit callout。
進度40/41
2026-05-23
Sysmap
系統地圖 L0-L7 100%
L2 12/12 · L3 26/26 · L4 20/20 · L5 34/34 · L6 14/14 · L7 15/15 · D.0 viewer code excerpt ship。
進度121/121
2026-05-23
報告
老闆報告大整修 Phase 6+
Master TODO 置頂 · 全部 section 可收合 · CRITICAL/Triage 全封存 · 已完成歸類。
2026-05-23
Sysmap金流
金流系統整合章節 ⭐
老闆問「我搞不清楚整個金錢運作流程」→ 新 L2 模組:收款 8 路徑 + 支出 7 路徑 + 記帳 + 第三方 + UI 操作 cheat sheet。
5 個 L5 doc100%
2026-05-25
Sysmap全流程
11 個跨模組視角章節 ⭐⭐
老闆要求「跳脫功能視角的單一大流程視角」→ 新增客流 / 菜流 / 食材流 / 員工流 / 一天時間軸 / 會員生命週期 / 異常流 / 同步流 / 集團流 / 稽核流 / 支付狀態流。
11 個視角 + index100%
2026-05-25
SysmapFAQ
臨時支出完整操作 FAQ + 2 UI bug
老闆 dogfood 6 個具體問題(怎麼操作 / 何時記帳 / 重複算帳防護 / 關帳看到什麼 / 盤點看得到嗎) — 同時 audit 出 2 個 UI bug(關帳盤點看不到 AdHoc 明細 + cashRefunds 反推錯亂)。→ 觸發 #W13 金流架構重構 spec(從根本解決,不打補丁)
2026-05-25
✅ Phase 0-9 已 ship#W13dogfood 中
金流架構重構 — 全 phase 上 main,進入 dogfood ⭐⭐
2026-05-27 commit 134a9bbf:結帳當下寫 ledger(現金 / 刷卡 / 行動支付每筆都記)。退款自動 link 原 sale。AdHoc 移除 source_marker hack。關帳移除 dailyCloseRevenue summary 寫入(雙重計帳源頭),只保留現金盤點 + cash_overage。
新增 10 個 ledger orchestrator/gate/primitive 檔案,走 CLAUDE.md 4-layer 架構。新 DB schema 已 apply。
🧪 老闆 dogfood 測試方案(8 scenarios):
  1. 現金結帳 $500 → 記帳頁應該立刻看到 sale_cash +500 在現金錢箱;不必等關帳
  2. 刷卡結帳 $1000(TapPay/Apple Pay) → 立刻看到 sale_card +1000 在「清算-TapPay」asset(如果還沒 seed 自動建)。關鍵:這是改之前完全沒記的!
  3. LINE Pay 結 $300 → 立刻看到 sale_qrpay +300 在「清算-LINE-Pay」asset
  4. 現金退款 $100 → 看到 refund_cash -100,且該 row 點開能看到原始 sale_cash link
  5. 臨時支出 $200 買蔥 → 看到 adhoc_expense -200,記帳頁不再列「source_marker hack」
  6. 關帳 → 算的 expectedCash = 期初零用金 + 當天 cash sale - cash refund + adhoc。不應該再寫一筆 dailyCloseRevenue summary。記帳頁的 asset balance 不應該因關帳而變化(除非有盤點短缺)
  7. 盤點短缺 $50 + 填理由「找錯錢」 → 寫一筆 cash_shortage -50,asset balance 對應扣
  8. 盤點溢餘 $30 + 填理由「客人多給」(新支援!)→ 寫一筆 cash_overage +30,asset balance 對應加
⚠️ 若數字對不上回報:(a) console log 找 `[SaleLedger]` `[RefundLedger]` `[AdHocLedger]` 字串看流程 (b) 用 Supabase Studio 查 asset_transactions 表新欄位 business_date / payment_id / refund_of_id 是否填對 (c) 截圖記帳頁 + 關帳頁。
2026-05-27 額外加碼 ship 的 phase:
  • Phase 6 補關帳邏輯 — BatchRetroCloseSheet 移除 dailyCloseRevenue 寫入
  • Phase 7 藍新 payout 自動對帳:edge function newebpay-payout-webhook 已 deploy 到 dev,收 webhook 自動寫 3 行 ledger (bank +net / -fee / clearing -gross),idempotent by payout_id;POS 新增「金流對帳」頁可看清算戶餘額 + 最近 30 天 payout + 手動補錄。TapPay 灰色 placeholder 等老闆審核完啟用
  • Phase 8 關帳編輯 trail UI:POS 設定 →「編輯關帳紀錄」owner/manager 可改當月關帳數字(actual_cash / shortage_reason / 零用金 reset 三欄 / notes),寫 daily_close_edits row + 必要時對沖 manualAdjustment AssetTransaction。跨月自動封存(動態判斷)
  • Phase 9 報表 audit:Payment 表 aggregation 在 dual-write 下數字正確,確認無需改
⚠️ 老闆 dogfood 設定:NewebPay 後台要設 webhook URL = https://dcsbeeccaycrljjztgjs.supabase.co/functions/v1/newebpay-payout-webhook
剩 Phase 11 deprecated cleanup → 等 dogfood 確認新 ledger 數字 OK 後再做(避免提前拆掉舊 fallback)。
2026-05-27 · Phase 0-9 全 ship · dogfood 中
✅ 大改造完成StaffsMate Flutter8 Wave
StaffsMate Flutter 大改造 — 7 個 Wave 一晚 ship + sysmap 完整對應 ⭐⭐⭐
老闆 2026-05-27 dogfood 截圖薪資紅屏 + 答完 audit 7Q 後一句「直接做完所有 wave 不要等指令」→ 同日 8 個 Wave 全部 ship 上 main。

✅ Wave A 緊急 P0(dbdf272d) 公休對齊 POS / tip gate / target_hours fallback / employee_id 真實 bug 修 / geofence 可配置
✅ Wave B 錢相關核心(ef57f2e7) 勞動成本 $ banner + 請假衝突 + 「複製上週」+ 技能匹配 warning + clock 4 層架構樣板
✅ Wave C 完整 Payroll System(4e5004e8) payroll_records 表 + 加班 §24 + 勞健保 + payslip PDF + 銀行匯款 CSV + 員工 self-view(扣繳憑單 2027 補)
⚙️ Wave D 4 層架構(b1d5d9bd 部分 ship) 3 sample(clock/payroll/policy_ack)+ 剩 10 feature migration plan ~30h incremental
✅ Wave E 制度 enforcement(277f3c9f) leave_policies 合併 + overtime_rules JSONB + 試用期 chip + DB trigger 自動算 probation_end_date
✅ Wave F 員工簽收(4e5004e8) policy_acknowledgements + 簽名畫板 + 老闆 dashboard + 合規賣點(勞基法§70)
✅ Wave G 打卡兩派強化 店內裝置 30s QR rotation + 個人手機 forgotten clock-out + shift_swap 換班(指定/公開徵求)+ 排班發布 push gate
⏸️ Wave H defer(b1d5d9bd) AI 排班 / 員工偏好 / PDF 列印 / 農曆假日 — 等 dogfood feedback

📐 系統地圖完整對應:
StaffsMate Flutter 系統架構 master + L5 Wave A/B/C/D/E/F/G/H 各一份(每 Wave 含改動清單 + 4 層架構結構 + dogfood checklist + 連下個 Wave)

💰 跟錢有關 fix(老闆 Q4 優先):勞動成本 banner / Payroll 4 層 service / 試用期 / 加班費 §24 / 勞健保扣除 / payslip PDF / 銀行匯款 CSV — 全 ship
🐛 順手修的 build bug:share_plus API / Decimal.zero const → final / clock_records 欄位名(verification_method / is_verified / notes)

3 個 DB triggers / 9 個 migration:20260527001-009(全 apply 到 dev)。 3 個 new 4-layer dirs:clock/ payroll/ policy_ack/ shift_swap/。 1 個 完整 audit 報告:staffsmate-full-audit-2026-05-27.html(53KB / 8 章 / 7Q 答覆 + Wave plan)
2026-05-27 · A-N 共 13 Wave 全 ship + 老闆抓的 perf bug 修
✅ Round 2 完工Wave I-Nperf fix
StaffsMate 大改造 Round 2 — Wave I-N 全 ship + 手機變慢 root cause 修 ⭐⭐⭐
老闆連續 3 個 dogfood 反饋一次處理:
(1)「設定都是假的只能填文字」→ Wave I + 5 個老闆 page 全 templates 結構化(60de6669)
(2)「對話框不符合 chefsmate 風格」→ Wave I/K 加 24 個 AlertDialog 換 StitchSheet(5c62933d)
(3)「打開過一陣子手機變慢」→ root cause 找到 boss_clock_device 每秒 setState 整 page rebuild + Timer 在 background 不 pause(bc57cbb4)

Round 2 Wave I-N 全 ship:
  • I 設定模板化(60de6669)25 個業界 templates(BambooHR/Toast/Gusto/Connecteam)+ Taiwan 在地化(廚房 K1-K4 + 外場 F1-F3 / 師徒制 / 三節禮金) + 4 個 Stitch sheet + 連動 PayrollCalculator
  • J 員工側 Stitch(5c62933d)6 page(clock/leave/company_policy/my_payroll/policy_ack/my_preferences)100% AppColors → Stitch + 新「我的福利」section 讀 benefit_policies
  • K 老闆 page Stitch + 14 AlertDialog→Sheet(5c62933d)boss_payroll/boss_clock_device/boss_schedule/station_config/tip_settings/tip_history。Stitch refs 220 → 534(+143%)。共用 StitchAlertCard + StitchStatusBadge + StitchEmptyState
  • L profile + auth Stitch(5c62933d)6 page(profile/join_restaurant/role_selection/login/register/create_restaurant)1263 → 2359 行 / 63 → 0 AppColors / 0 → 256 Stitch refs
  • M 缺漏功能 + polish(5c62933d)geofence radius admin slider + 排班 PDF 列印 + my_preferences + notifications_queue + bell + StitchEmptyState/Loading/Error widget
  • N 4 層架構推進(1a2da4a4)leave/ + staff/ 完整 Gate/Primitive/Repo/Orchestrator,4 層覆蓋率 0% → 46%(6/13)
  • ⭐ perf bug 修(bc57cbb4)新建 app_lifecycle.dart + debug_log.dart。boss_clock_device 把每秒 ticker 拆出 nested _RotatingQRCard 用 ValueNotifier 隔離 rebuild,訂閱 AppLifecycle paused 時 cancel ticker 釋放 CPU。clock_page 30s ticker 同樣處理。
🐛 老闆下次 dogfood 「手機變慢」測試:
  1. 打開 staffsmate flutter
  2. 切到「打卡機」tab → 看輪轉 QR
  3. 切到別 app 或鎖螢幕(關鍵測試)
  4. 放著 5-10 分鐘
  5. 切回來 → 手機不該變慢,QR 立即更新
還慢的話看 console log 找 `[🔄 lifecycle]` `[⏱️ timer]` `[📡 channel]` 關鍵字。

📐 sysmap 完整對應:8 個 L5_Wave doc(A/B/C/D/E/F/G/H/I/J/K/L/M/N)。 4 個 perf-related 新檔:debug_log.dart / app_lifecycle.dart / stitch_states.dart / stitch_sheet.dart。 4 個 4-layer dirs:leave/ + staff/(本 round)+ 既有 clock/payroll/policy_ack/shift_swap。 15 個 migrations 全 apply(20260527001-014)。
2026-05-27 · Round 2 完工 · 5 個 sysmap doc + 6 commit
✅ Wave O 完工4 層 100%全部做好再停
StaffsMate Wave O — 13/13 feature 全 4 層架構(0% → 100%)⭐⭐⭐
老闆指令「四層架構都做好了嗎?如果還沒做好,我的意思是,全部做好再停」, 改採方案 A 把剩 7 個 feature 全拆。一次性 ship,不分批。

新增 4 層 dir(commit 5010a8c4):
  • features/boss/schedule/ — 排班(3118 行 view),9 gates + 8 primitives + 14 repo methods + 9 orchestrators
  • features/boss/station/ — 站別 + 技能矩陣
  • features/boss/clock_device/ — 打卡裝置 + QR rotation(⚠️ _RotatingQRCard perf widget 保留)
  • features/profile/tip/ — 員工小費設定 + 歷史
  • features/profile/profile/ — 個人資料 + 偏好 + sign out
  • features/employee/policy/ — 員工查看公司規章(+ policy_ack/ 已有)
  • features/auth/_4layer/ — login / register / role / create / join 5 個 view
覆蓋率變化: Round 1 0% → Wave N 46%(6/13)→ Wave O 100%(13/13)
每個 feature 都遵守 CLAUDE.md 第一原則:Gate 純函數決策 / Primitive 單一副作用 / Repository DB 讀 / Orchestrator 組合回 sealed Result。
View 全部變薄,移除所有 inline supabase.update if-chain 與 inline validation。

驗證: flutter analyze 0 error / flutter build ios --no-codesign --debug ✓ Built Runner.app(2026-05-27 晚)。main.dart deep-link / auth_service.dart / _RotatingQRCard perf widget 全保留不動。

📋 audit 報告同步更新:
staffsmate-full-audit-2026-05-27.html 加 §9「Round 2 完工報告」(7 子節:Wave 總覽 / 4 層變化表 / perf fix root cause / §6 對照 / §7 已答 / dogfood checklist / 已知限制), §0-§8 audit 原文保留留底。Commit db16a3f9
2026-05-27 晚 · Wave O ship · 7 新 4 層 dir · 13 view 變薄 · iOS build ✓
Spec#W12✅ Phase 1-8 已 ship
員工小費系統 — 老闆可直接 dogfood 完整流程
2026-05-25 同日 spec → 同日答完 7Q → 同日 Phase 1-8 全 ship。 DB migration 已 apply。POS 設定 toggle + 預設金額 + 員工小費次數報表都做了。 StaffsMate App 員工可填收款設定 + 自我介紹 + 拍頭貼 + 工作崗位 + 職稱 + 看打賞紀錄。 客人端 3 個進入點全 ship:結帳完成頁、菜單頁、桌邊主頁面新增「打賞員工」card
Dogfood 步驟: (1) POS 設定 → 員工小費系統 → 啟用 +選方案 A (2) StaffsMate App → 我的 → 打賞收款設定 → 填 LINE Pay 連結 + 自我介紹 + 拍頭貼 + 啟用顯示給客人 (3) 桌邊掃 QR → hub 看到「打賞員工」→ 點進去選員工 → 選金額 → 確認 → 跳 LINE Pay (4) StaffsMate「打賞紀錄」看到 event (5) POS Reports「員工小費」看到次數(不顯金額)
未 ship:Phase 9 方案 B 餐廳代收(備援,老闆說沒人需要可省)。
2026-05-25 spec→ship 同日完工

還沒做的東西 — 按優先順序分類

打開頁面最先看到的就是這裡。 每張卡片預設收合,點開看「怎麼做 / 什麼時候做 / 順序」。 audit 抓到的 41 個 inline bug 已修 40 個 + 1 false positive,只剩 3 個老闆拍板的決策題。 2026-05-23 Batch 14-25 — P0/P1/P2/P3 全部 ship

P0 — 上架阻擋級 + P1 — 上架前必修 全部 ship
沒有 P0 — 所有 audit 抓到的 critical 安全/資料完整性 bug 都已修
P1 12 個 audit bug 全部 ship(Batch 21-23)— markArrived 5 個 / Realtime 3 個 / 加菜送單 3 個 / 補關帳 2 個 / 訂位重構 P0 缺口 1 個
P1 — 上架前必修 全部 ship 5 群 · 12 bug · 已完成
全部 P1 audit bug 已修完(Batch 21-23):
1. markArrived: #R35 Path C 補 arrivedAt / #R36 Notification observer 自動 dismiss banner / #R37 接 markArrivedAndAdd credit / #R38 trigger broadcast + LINE 通知
2. Realtime: #R15 三個 listener hook $realtimeConnected / #R20 AuthManager membership channel 也 hook
3. 加菜送單: #R43 #R44 #R56 broadcast trigger + guest web subscribe
4. 補關帳: #R40 recomputeLaterSnapshotsInMonth / #R41 PettyCashService.recordCashOutflow 加 transactionDate? 參數
5. 訂位重構: #R59 auto-no-show cron + wallet-pass-repair cron + ReservationOverbookedEvent 型別

↓ 詳細 5 個原始問題 / 怎麼做 / 怎麼驗,展開卡片看 ↓

1. markArrived 報到流程 5 個 bug #R35#R36#R37#R38#R66

問題:

  • #R35 智慧入座 Path C 跳過 arrived 直接 seated → arrivedAt 永遠 NULL → 等待入座時間算不出
  • #R36 markArrived 後 LateArrivalAlert banner 沒自動 dismiss(仍掛 ≤5min + 3h TTL)
  • #R37 markArrivedAndAdd 信用分 +20 函數寫好但 orchestrator 沒接
  • #R38 客人到店完全沒「您已報到」確認通知(無 email/LINE/wallet/push)
  • #R66 POSAuditLogView wishful events cleanup
怎麼做 SeatingLifecycleOrchestrator.markArrived 內 (1) 強制 confirmed→arrived(擋掉 Path C 跳級) (2) emit 自訂事件 dismiss banner (3) 接信用分 gate (4) 加 send-arrival-confirmation edge fn + 路 webhook subscriber 什麼時候做 下個 sprint。R35 是規則性 fix(1 小時),R36-R38 各 2-3 小時(需新 edge fn + UI 整合) 順序 R35 → R36 → R37 → R38 → R66(每個獨立,可拆 commit) 阻擋什麼 餐廳統計「等待入座時間」永遠空白 / 客人不確定 POS 有沒有看到他到店
2. Realtime monitor 沒 hook reconnect — 3 個 channel 斷線後死掉 #R15#R20#S35

問題:

  • #R15 CheckoutPayment / CustomerCheckout / RestaurantCheckoutSessions 3 個 Listener 沒 hook HybridSyncManager.$realtimeConnected,WiFi 斷一次就要重啟 App 才復活
  • #R20 員工沒訂自己的 channel → 被踢時只能等下次 silent push
  • #S35 服務鈴 legacy route 沒 broadcast 備援 / Swift enum 缺 3 cases / fetch 沒 filter restaurant_id
怎麼做 參考 memory `feedback_realtime_channel_must_hook_reconnect.md` — 在 Listener init 訂閱 HybridSyncManager.shared.$realtimeConnected,從 false→true 時 rebuild channel 什麼時候做 這個是普遍規則,寫個 helper AutoReconnectingChannel wrapper,5 個 Listener 一起改 順序 1. 寫 helper 2. 套到 CheckoutPaymentListener 驗證 3. 推到其他 4 個 4. 補 #S35 enum + filter restaurant_id 阻擋什麼 多裝置 POS 在咖啡廳 / 收訊不穩環境會慢慢失同步
3. 加菜送單 — 客人桌邊 web 看不到 + 三路 mergeable 不一致 #R43#R44#R56

問題:

  • #R43 POS 加菜送單後客人桌邊 web 看不到(沒接 Realtime broadcast)
  • #R44 三路 (POS / QR / PreOrder) mergeable 邏輯不一致 → 同點餐不同行為
  • #R56 同 #R43 (dup)
怎麼做 order_items INSERT trigger broadcast 到 guest-table-{reservation_id} channel,客人 web 訂閱該 channel 即時 refetch 什麼時候做 客人桌邊體驗影響大,但不阻擋上架。中等優先(P1 後段) 順序 1. DB trigger broadcast 2. 客人 web channel subscriber 3. 三路 mergeable 統一 gate
4. 補關帳 BudgetSnapshot / AssetTransaction 日期錯位 #R40#R41

問題:

  • #R40 補關帳 BudgetSnapshot 補產生不回填後續日的 cumulativeRevenue → 永遠少
  • #R41 補關帳 AssetTransaction date 錯位:revenue=過去日期 / 零用金扣=今天
怎麼做 補關帳完成後,跑「往後重算 cumulativeRevenue」cron + AssetTransaction date 一律用 closeDate 而非 now() 什麼時候做 影響報表準確性,上架前修。需要 1 個下午專心改 SettlementService 順序 先 #R41 (簡單 date 對齊) → 再 #R40 (recalc cron 需設計)
5. 訂位重構 3 個 P0 缺口 #R59

問題:

  • overbooked event 沒實作
  • 會員卡同步補救 cron 沒做
  • auto no_show cron edge fn 沒做
怎麼做 三個獨立子任務:寫 overbooked detection orchestrator / wallet pass repair cron / auto-no-show edge fn (cron 每小時跑) 什麼時候做 no_show cron 最緊急(影響日常營運統計),overbooked + wallet sync 上架後 1 個月內補 順序 auto no_show cron → overbooked event → wallet pass repair cron
P2 — 上架後盡快 全部 ship 6 bug · 已完成
全部 P2 audit bug 已修完(Batch 24-25):
1. #S30 拆桌 approve:新 approveSplitTableOrchestrator / rejectSplitTableOrchestrator + /api/reservation/[id]/split-table-approve(reject) 路由 (用 canApproveSplitTable gate 預檢 + verifyCallerRole 防 RLS bypass)
2. #S23 KDS markUrgent:ExpediteActionManager.markUrgent 同時打 /api/kds/items/{id} action='urgent' (Task.detached fire-and-forget,server 跑 gate + emit event)
3. #S33 員工 v2:新 cron /api/cron/expire-staff-invitations + DB trigger on_staff_invitation_revoked 自動廣播到 restaurant:{id}:staff topic
4. #S34 Email/Wallet:中央 DB trigger auto_update_wallet_on_loyalty_change — customer_loyalty 任何卡面欄位變動就 fire update-wallet-pass (取代每個 email fn 都要記得)
5. #R16 發票自動開立:DB trigger auto_issue_invoice_on_payment_completed — payment.status→completed 自動 fire ezpay-invoice / tappay-invoice action='issue-invoice'
6. #S32 Reward race:新 trigger trg_reconsume_reward_order_id — order_id 變動時用新 id 重新查 reserved redemption,重試 consume_reward

↓ 原始 6 個問題卡片仍保留 ↓

1. 拆桌 approve 純 client mutate(違反 4 層架構)#S30

POS Swift 直接 update reservation 表的 splitTableStatus → 違反 CLAUDE.md 第一原則。

怎麼做approveSplitTableOrchestrator + 用 batch 14 #S31 寫好的 canApproveSplitTable gate + Swift 改打 API 時機 / 順序獨立 1 個 sprint。Gate 已寫,只缺 orchestrator + API route + Swift caller
2. KDS markUrgent / Siri Intent 走 thin-client#S23

目前 markUrgent 直接 SQL update,沒走 web orchestrator。Siri Intent 同樣 bypass。

怎麼做/api/orders/items/[id]/urgency route + 改 Swift caller + Siri Intent handler 時機 / 順序P2 後段。技術債,不阻擋功能
3. 員工 v2 邀請過期 cron / 撤回 UI / Wallet 撤銷#S33

4 個獨立子任務 — 過期 cron / 撤回 UI / Wallet 撤銷沒接 / QR 沒走 v2 orchestrator

怎麼做(1) Supabase cron 每天清過期 invitation rows (2) POS 員工管理 sheet 加「撤回」按鈕 (3) 撤回時 fire wallet-revoke edge fn (4) QR 掃描走 v2 orchestrator 時機員工管理體驗用,上架後 1-2 週做
4. Email/Wallet edge functions audit#S34

25 個 email edge fn 中 legacy 沒接 wallet update / refund 沒 wallet update / staff app URL 是 placeholder

怎麼做逐個 review 25 個 edge fn,標出哪些需要 fire update-wallet-pass + 哪些 URL 還是假的 時機 / 順序spawn agent 一次掃完 25 個 fn 列出 todo list,然後逐項補
5. Newebpay & 分帳發票不自動開立#R16

結帳付款成功後沒自動 trigger 發票開立,需要老闆手動。

怎麼做payment.status='completed' trigger → 呼叫財政部電子發票 API。需新發票 helper edge fn 時機獨立 1-2 天工作量,看老闆是否要先做手動發票 UI 即可上架
6. Reward race — tier_benefit + order_id 變動#S32

tier_benefit 沒 dailyLimit UI、order_id 變動不會 re-trigger consume → reward race

怎麼做order_items 改 order_id 時 trigger 重新檢查 reward consume + tier_benefit UI 加 dailyLimit 欄位 時機獎勵系統 polish,上架後 1 個月內
P3 — 累積技術債 ship 1 個 · 已完成
D.0 viewer 內聯 code excerpt 渲染(Batch 24):
sysmap.js 加 renderCodeExcerpts() — 解析 markdown 內 <!--code:path/to/file.swift#L10-L25--> HTML comment,fetch raw.githubusercontent.com 後抽出指定行,syntax-highlighted 顯示 + 連回 GitHub。免再切到 GitHub 看 code。
等老闆拍板 3 個
#D1 PO 收貨流程接 API?

PO thin-client 化最後一塊大頭。完成後 web 後台能直接管理採購單,但 QuickReceivingView 邏輯複雜,需要 1 晚自動跑。

選項: A. 今晚就跑(推薦) / B. 先做 POS 1-2 個 feature 再回來

#D2 Liability + AssetTransaction 是否合併處理?

採購單從欠款轉已付時,Liability 立刻標已付但 AssetTransaction 要等選完帳戶。User 取消選帳戶 sheet 時資料不一致。

選項: A. 改成「等選完帳戶後才標 Liability」 / B. 維持現狀(極少人取消) / C. 取消 sheet 時也 rollback Liability(最完整)

#D3 員工邀請 v2 的 7 個問題

已內嵌成互動表單在 #H6 卡片底部。7 題每題 3-4 選項 + 補充欄,預設標「已實作」。回覆存瀏覽器,可匯出 JSON。

↓ 滑到 dogfood 區 #H6 卡片

Dogfood 待老闆實測 — 已 ship code 10 個
做完的東西 — 點開看分類摘要 100+ items

本表只列分類摘要,完整 ship 細節在下方各 section(已完成 / 最近 ship / 大計劃 / 三條路線)。

Audit bug 修復 (Batch 1-20)
22 個 inline list bug + 50 個 card bug 全部標 。4 個 SQL migration + 1 edge fn 部署 + 6 個 xcodebuild。
→ AUDIT_FIX_LOG_2026-05-23
系統地圖 v2
L0-L7 全層完整。L3 子模組 26 個 / L4 電路圖 20 個 / L5 程式碼層 24+ 個 / L6 漣漪追蹤 8 個 / L7 欄位反向 10 個。27 個 doc 加 audit callout。
→ 開系統地圖
跨 App 權限 / 隔離 audit P0
3 個 P0(table 裸奔 / RLS 過廣 / VendorRepository predicate)全修。Per-restaurant container Phase 1-7 ship。V3 集團架構 spec 完成。
↓ 滑到 audit section
Dogfood bug #B1-#B20
老闆實測抓到的 20 個 bug 全綠(只有 #B11 重標 red — self-heal 災難已修為 #B11-FIX)。
↓ 滑到 Dogfood bugs
訂位重構 Phase 1-5
客人中心化 + Phase 6 待 cooldown 後執行。取消退款流程 / 確認流程 / 拒絕 4-step / 修改流程 / 智慧排桌 都 ship。
結帳 + 退款 thin-client
統一退款 sheet / 分帳 / 折扣 / 訂金扣抵 / 加 ad-hoc 收支記帳 / 補關帳處理未結單 ship。
老闆報告整修 Phase 1-5
Stitch design tokens / Section 重排 / 頂部 dashboard / 去重 / 波希米亞+日式 palette + fixed banner ship。本次 (2026-05-23) Phase 6 加 master TODO 在頂部。
採購單雲端化 (PO thin-client)
付款帳戶追蹤 / 欠款轉已付 / vendor 隔離 predicate / RLS P0 全部 ship。剩 #D1 收貨流程待拍板。

↓ 滑到完整「已完成」section

POS 上架完成度(用戶體驗 critical path)

96%
2026-05-23 audit sweep:22 個 inline bug + 50 個 card bug 全修(Batch 14-20)
sysmap v2 完整 L0-L7 上線 + 27 個 L5/L6/L7 加 audit callout
dogfood 抓到的 20 個 bug — #B1-#B20 全綠
10 個 H 項目 等 dogfood 實測
跨 App 權限 audit P0 全修 + V3 spec ship
剩餘 18 個 audit bug 全部歸到上方「P1/P2/P3 還沒做」可摺疊清單
系統地圖 v2 草稿(2026-05-23 上線)
L0 全景 / L2 主模組 / L4 完整電路圖 — 點開可瀏覽
把既有 docs/POS_*系統架構/(67 個 markdown 檔)做成可瀏覽 HTML viewer。 每頁附 audit status:fresh · stale · old · drift。 2026-05-23 spawn 5 個並行 agent 對 12 個系統文件 vs code 做完整 audit, 確認 6 個 L4 有 drift(訂位/點餐/菜單庫存/通知/支付/稽核), 詳情見每頁頂端 banner。
點開 chefsmate.app/sysmap/ →

查詢駕駛艙 — Debug 工具

店家回報 bug 時用這裡查資料。所有查詢都會走 _is_internal_admin() gate(只有你能用)。 點 tab 切換查詢類型。

可查:email / 電話 / 顯示名稱 / LINE userId / user_profile_id (UUID) / auth.users.email
例如 0912345678 · chris@gmail.com · 9fc277c3-2bb7-4db0-bdae-a2b0a039b02d
查到後顯示:基本資料 · 信用額度(到店/未到次數)· 各餐廳會員卡 · 訂位歷史 · 消費紀錄(餐廳/單號/金額/付款方式)
輸入關鍵字後點查詢
可查:餐廳名稱 / slug / restaurant_id (UUID)
例如 海邊小巫 · haibian
輸入關鍵字後點查詢
可查:order_id (UUID) / order_number
回:訂單詳情 + items(含選項) + 所有 payments + 退款 + 狀態歷史
輸入訂單編號後點查詢
可查:NewebPay merchant_order_no / TradeNo (transaction_id) / refund_transaction_id / payment.id / order.id / reservation.id (UUID)
回:provider / 金額 / 狀態 / 卡號末四碼 / 退款 / metadata / 開立發票號
輸入金流編號後點查詢

Phase 1 + Phase 2 已 ship — 請老闆 dogfood 驗證 2026-05-28

整套結帳 / 發票 / 會員加點流程已 ship,可端到端 dogfood。每塊功能寫了白話步驟,跟著做就能驗證。
順序建議:先做 0(發票設定)→ 再 1(綠勾)→ 再 2(發票)→ 再 3(載具掃描)→ 再 4(AirDrop)→ 再 5(會員發票頁)→ 最後 6(會員自動加點)。

0 POS 發票預設行為設定(整套流程的前置)

怎麼開:POS → 右下角設定 → 發票設定 → 滾到「發票預設行為」section

會看到 3 個選項:

  • 預設方式 picker:每人一張 / 整桌一張 / 不開立
  • 發票內容 picker:逐項列出 / 只寫餐費
  • 若選「只寫餐費」→ 跳出 TextField 可改餐費標籤(預設「餐費」)

建議測試:選「每人一張 + 逐項列出」,完成。

⭐ 這是後面所有發票測試的前置:沒選的話 server 預設 separate + itemized,但 UI 上看不到所以容易誤會。

1 POS 桌位卡綠勾正確顯示

之前的 bug:同 reservation 多張單時,只要任一張 checkout_session 結了 → 綠勾就誤亮。可能造成「以為都結完了讓客人走」其實還有單沒收。

怎麼測:

  1. POS 建一筆訂位 + 入座,客人桌邊點一單(例:NT$500)
  2. 客人結帳 + 老闆收現金 → POS 該桌綠勾應該(因為這時所有 active orders 都付清)
  3. 同一桌 POS 上「加點」一單(例:NT$300)→ 客人沒結 → POS 該桌綠勾應該變回灰(因為有 NT$300 沒付)
  4. 客人補結那 NT$300 → 綠勾再次亮

修好後:綠勾只在「該訂位所有 active orders 的所有 item 都 paid」才亮,符合「桌可以收掉」的真實狀態。

2 整桌全結完 → 自動開電子發票

前提:餐廳已啟用 ezPay 電子發票(POS → 設定 → 發票設定 → 服務商選 ezPay + 啟用 toggle)。預設模式設「每人一張 + 逐項」(步驟 0)。

怎麼測(3 個客人各自結帳的情境):

  1. POS 建一筆 3 人訂位,客人 A、B、C 各自掃 QR 進桌邊點餐
  2. 主持人在 web 桌邊結帳大廳分配結帳權 + 選「每人一張」(預設)
  3. POS 上看到 A/B/C 各自應付金額
  4. 3 個客人各自完成付款(現金或刷卡)
  5. 預期:全結完瞬間,POS 該桌綠勾亮 + A/B/C 每筆 row 下方顯示「發票:EX12345678」

失敗時排查:

  • 沒看到發票號 → ezPay 設定可能沒開,或 ezPay 沙箱 server 卡了。POS 端 console 會印「[issueInvoices] ezpay-invoice ...」
  • 發票號出來但只有 1 張 → 主持人選「整桌一張」而不是「每人一張」
3 POS 結帳前刷客人手機載具(用 iPad 鏡頭)

怎麼測:

  1. POS 結帳大廳 → 每位客人 row 下方有「刷載具(個人發票)」按鈕(灰色,沒綁時)
  2. 點下去 → POS 全螢幕跳鏡頭
  3. 請客人手機載具條碼舉給 iPad 鏡頭:支援
    • 手機條碼(`/ABCD123` 開頭斜線 + 7 字元)
    • 自然人憑證(2 英文 + 14 數字共 16 字元)
  4. 掃到 → 自動辨識顯示「手機條碼 / ABCD123」+ 綠色 ✓ → 點「確認綁定」
  5. 預期:回到結帳大廳,該 row 變綠色「✓ 已綁載具 /ABCD123」
  6. 接著按「現金代收」完成付款 → 發票自動開出 PrintFlag='N'(走載具不印紙本)

失敗時排查:iPad 第一次跳「相機權限」要點允許。沒允許就掃不到。

4 把發票圖片 AirDrop 給客人(沒帶載具的散客場景)

怎麼測:

  1. 客人結帳完(發票已開),POS 結帳大廳該 row 下方會顯示「發票:EX12345678」+ 旁邊有藍色「分享給客人」按鈕
  2. 點「分享給客人」→ POS 動態 render 發票圖片(餐廳名 / 發票號 / 日期 / 買受人 / 品項 / 應稅金額 / 稅額 / 合計 / 圖檔副本聲明)
  3. 跳 iOS share sheet → 客人開 iPhone 解鎖 → POS 從清單選客人的 AirDrop → 客人手機跳「接受」
  4. 預期:客人 iPhone 收到一張完整發票 PNG,可存相簿

⭐ MVP 限制:目前圖片只列「餐點 ×1 / NT$xxx」單列(不列詳細菜名)。下版會接 order_items 拉出完整逐項。

5 客人會員端跨餐廳發票收藏頁

怎麼測:

  1. 找一個客人(老闆自己用 LINE / Google 登入也可以)
  2. 在海邊小巫桌邊點餐結帳完 → 發票自動開(步驟 2 跑成功)
  3. 客人開 chefsmate.app 登入後,網址打 chefsmate.app/me/invoices
  4. 預期:看到剛剛海邊小巫的發票卡片(餐廳名 / 訂位日期 / 金額 / 發票號 / 載具)
  5. 跨餐廳測試:同一客人下次去溪邊小巫消費 + 開發票後,/me/invoices 自動多一張溪邊小巫的發票(同帳號跨餐廳累積)

沒看到時:

  • 沒登入 → 顯示「請先登入」按鈕
  • 登入了但沒消費紀錄 → 顯示「您還沒有任何發票紀錄」
  • 有消費但發票沒開(餐廳沒啟用 ezPay 或開立失敗)→ /me/invoices 不會列(因為 query WHERE invoice_number IS NOT NULL)
6 結帳會員自動加點 / 詢問同桌會員 / QR(Phase 2)

4 種情境,建議 4 個都跑一次:

情境一:autoAward(結帳人 A 是會員)

  1. 用一個既有海邊小巫會員的帳號(假設叫小明)登入 ChefsMate 客人 App
  2. 小明掃 QR 桌邊點餐 → 結帳收現金
  3. 預期:POS 結帳大廳上方跳綠色 toast「✓ 已加 NN 點到 小明 的會員卡」3 秒消失。不會出 QR sheet。

情境二:pendingChoice 單候選

  1. 找一個海邊小巫會員(假設叫老闆自己)從 POS 建一筆訂位
  2. 找一個不是會員的人(假設小華)當結帳人,掃 QR 桌邊點餐
  3. 結帳收現金
  4. 預期:POS 跳 sheet「結帳人 小華 還不是會員,要不要把點數給訂位人(老闆)?」+ 一個候選按鈕
  5. 店員問小華 → 點按鈕 → 跳 toast「✓ 已加 NN 點到 老闆 的會員卡」

情境三:pendingChoice 多候選

  1. 4 個朋友:小華訂位(不是會員),同桌的小明 + 小美是海邊小巫會員,小華結帳
  2. 預期:POS sheet 列「小明 · 同桌會員」「小美 · 同桌會員」兩個按鈕讓店員問小華選誰

情境四:showQR(整桌沒會員)

  1. POS 建訪客 walk-in(訪客訂位 user_profile_id = null)
  2. 客人不登入直接結帳
  3. 預期:POS 跳 sheet「結帳人不是會員,沒有同桌會員可給」+「顯示 QR Code 給客人掃」按鈕(維持既有 QR 流程)

同 cp 防重複跳:用 seenLoyaltyDecisionIds set,所以同一筆 cp 變更 decision 後不會反覆跳 sheet。

抓到 bug 怎麼辦?把 reservation id / cp id / 操作步驟丟給 AI,我會 grep code 查 root cause,寫白話 fix 紀錄到 docs/夜審健康檢查/cycle1-修正紀錄-給老闆看.md
完整 spec / commit hash 在 GitHub repo: cycle1-修正紀錄-給老闆看.md

Dogfood 發現的 Bug — 老闆實測時抓到的問題

老闆 dogfood 過程發現的 bug 都記在這。共 20 個(#B1-#B20)。 已修 = fix 已 ship;部分修 = 主要修完仍有 backlog; 待 user 拍板 = 涉及語意/UX 決策,要老闆挑選項;修中 = AI 正在處理。

#B1 主控台幻影桌位(A 雙人桌 2 位) 已修
症狀:樓面設計刪了 5 桌但主控台仍顯示 6 桌(多一張 A 2 位)。每次開 App 就跑回來。
Root cause:supabase floor_items 的 deleted_at 沒同步到本地 SwiftData。 FloorItemMapper 不認 deleted_at,FloorItem 沒 deletedAt 欄位, 所以 supabase 刪除的 row 每次 pull 就 re-insert 成「正常」row。 樓面設計用 hard-delete 所以 OK,主控台讀 floorPlans.flatMap{$0.items} 全收。
Fix:FloorItem conform SoftDeletable + DTO/Mapper map deleted_at + POSMainControlView 全部 @Query 加 .filter { $0.deletedAt == nil }。下次 sync 就會把那筆 phantom 標 deletedAt → query 自動 hide。
0/5 步驟完成
看 commit
#B3 取消按鈕語意誤導(無訂金也顯示退款) 已修
症狀:客人申請取消後,老闆 POS 訂位詳情顯示 3 按鈕(同意+退款 / 同意不退款 / 拒絕)。 但若客人沒繳訂金(depositStatus != .paid 或 depositAmount = 0),「退款」字眼會誤導老闆以為客人有繳錢。
Root causePOSReservationListView.cancellationPendingSection 的 3 按鈕無條件顯示。 只有上方「訂金資訊」block 才有 if reservation.depositRequired && reservation.depositStatus == .paid 守護。
Fix:用 let hasDeposit = depositStatus == .paid && depositAmount > 0 gate; 沒訂金 → 只顯示單一「同意取消」按鈕(走 noRefundDetail/forfeit 路徑,但 label 不寫「退款」字樣)。
0/4 步驟完成
#B4 老闆拒絕取消後,客人端 UI 顯示「已確認」(已修) 已修
症狀:老闆按「拒絕取消(挽留客人)」並輸入理由後,客人端訂位詳情仍顯示「已確認」, 沒有任何拒絕訊息 → 客人不知道發生什麼事。
Root cause:客人端 my-reservation 頁只顯示 status === 'rejected' 的 rejection_reason, 但拒絕取消申請走的是 status === 'confirmed' + cancellation_rejection_reason(不同欄位、不同 status)。 且 TS 型別 Reservation 沒包 cancellation_rejection_reason → 即使 DB 有值也讀不到。
Fix:(a) database.ts 加 cancellation_rejection_reason / customer_cancellation_reason; (b) my-reservation 頁加橘色警告 banner 顯示「店家拒絕取消:[理由] / 如需進一步討論取消事宜,請直接聯繫店家」。
0/4 步驟完成
#B5 客人申請取消時沒有「填理由」欄位(已修) 已修
症狀:客人端取消申請只跳「確定要取消嗎」alert,沒讓客人填理由,老闆看不到原因。
Fix(一次處理 4 層)
1. DB migration 20260516001_customer_cancellation_reason.sql: customer_cancellation_reason TEXT 欄位
2. 客人端 my-reservation 頁 handleCancel:先 prompt 填理由(必填),確認後寫入 DB
3. POS 端 Reservation SwiftData model + DTO + Mapper 全部加新欄位
4. POS 訂位詳情 cancellationPendingSection 顯示「客人提供的理由」block(橘色 quote bubble icon)
後續(待 #W2 信用分數系統建好再串)
• 順利取消 + 未到場 → 不扣分;未順利取消(被拒絕後仍未到)或未申請就未到 → 扣 20%
• 完整規則見 #W2
0/5 步驟完成
#B7 重裝 App 後上傳 PK 衝突(restaurant_settings / business_hours / special_dates) 已修
症狀:user 刪 App + rebuild 後,console 噴幾十條 [GenericSyncExecutor] 上傳 X 單筆錯誤: 23505 duplicate key value violates unique constraint "X_pkey"
Root causeSyncRegistration.swiftRestaurantSettingsBusinessHours 沒 wire customUpload。Mapper 裡明明有 customUpload 含 onConflict: "restaurant_id""restaurant_id,day_of_week",但沒被使用 (UnifiedSyncRegistration 有 wire 但是 dead code 沒被任何 App 呼叫)。 走 default upsert path 沒指定 onConflict,碰到唯一約束衝突 PostgreSQL 回 PK error 23505。 (SpecialDate 已 wire ,不在錯誤中是因為 onConflict='restaurant_id,date' 正確生效。)
Fix:在 SyncRegistration.swiftcustomUpload: RestaurantSettingsMapper.customUploadcustomUpload: BusinessHoursMapper.customUpload,與 SpecialDate 同款做法。
0/4 步驟完成
#B8 訂位網頁顯示「尚未開放線上訂位」(irregular 模式誤判) 已修
症狀:客人開海邊小巫的訂位網頁→「尚未開放線上訂位」。 但設定明明有營業(business_hours 4 天 enabled)。
Root cause(兩條 page 都有):irregular 行事曆模式不寫 reservation_slots, 改寫 special_dates。但 page 的「開放」gate 只認 date_type === 'special_hours', user 實際 data 是 normal_openclosedhasFutureIrregularDate 永遠 false → 即使 reservation_slots 為空 + 有未來特殊日 → 仍顯示「尚未開放」。
FixhasFutureIrregularDate 同時認 'special_hours''normal_open'。 修了兩條 page:/[slug]/reservation/page.tsx:740 跟 legacy /reservation/page.tsx:595 (legacy 之前根本沒這個 gate,順便補上)。
0/4 步驟完成
#B6 訂位網站「餐廳總座位數」算錯(27 vs 應該 25) 已修
症狀:客人訂位網頁顯示總座位 27,但實際樓面只有 5 桌 (A 8 + B 6 + C 4 + D 3 + E 4 = 25)。 多 2 位是 phantom 桌(#B1 同一筆)。
Root cause:3 個 web booking query 沒 filter deleted_at IS NULL
(1) /api/availability/route.ts:367 主要可用性 query
(2) /[slug]/reservation/page.tsx:183 場景 A 最大單桌查詢
(3) /api/reservation/create/route.ts:67 單桌上限
Fix:3 處都加 .is('deleted_at', null)
0/4 步驟完成
#B2 收銀機零用金動態追蹤(方案 B + 低餘額提醒)— 已修 已修
老闆 2026-05-16 拍板:選方案 B(動態追蹤收銀機現金)
補充情境:「有時會用超過營業額的錢來付貨款(直接從錢箱裡拿錢),關帳時零錢箱+營業額-貨款 比預設零錢箱金額還少。 這時仍可關帳,但要在每次營業結束後 + 營業開始時提醒餐廳端把營業額補齊。」
實作 spec(方案 B + 老闆補充)
1. 動態追蹤:零用金 Asset 變成「收銀機裡此刻有多少現金」
   • 收現金訂單 → 零用金 += 現金金額
   • 從零用金付貨款(採購單付款帳戶選零用金)→ 零用金 -= 金額
   • 關帳存現金到銀行 / 營業額錢包 → 零用金 -= 存款金額
2. 關帳容差:實際清點 ≠ 零用金 → 差異建 cashShortage / cashOverage transaction(既有 enum),照樣可關帳
3. 負餘額提醒(user 補充情境):若零用金 < POSSettings.defaultStartingCash(預設 $4,000)→
   • 關帳時顯示橘色 warning:「零用金不足預設金額 $X,請營業開始前補齊」
   • 隔日 POS 開啟時跳 banner:「 零用金 $X 低於預設 $4,000,請從營業額錢包補 $XXX」
   • 補錢用既有 ad-hoc transaction(#H8)內部轉帳:營業額錢包 → 零用金

影響檔案(預估):SettlementSheet.swift(關帳 flow)、 PaymentService(現金訂單 → 零用金 +)、QuickReceivingCompletionSheet.swift(採購單付款 → 零用金 -)、 POSMainControlView(低餘額 banner)、新建 PettyCashGate.swift
0/6 步驟完成
看 commit
#B12 訂位詳情 timeline 沒反映「客人已付,等老闆核准」 已修
症狀:客人線上付完訂金後 timeline 仍顯示「等候客人付訂金 進行中」, 而「餐廳核准訂位 16:09 已完成」順序顛倒(本來應該是付完訂金才核准)。
Root cause:timelineSteps 把 confirmStep 放在 depositStep 之前, 且 depositStep 的 .current 條件要 status == .confirmed,跑不進「客人先付」這條 path。
Fix:
  • 交換 depositStep / confirmStep 順序(deposit 先,confirm 後)
  • depositStep .current 條件放寬:只要 unpaid 都 .current,不再要求 confirmed
  • confirmStep .current 時若 depositPaid → 提示「客人已付訂金,點下方核准」
0/4 步驟完成
#B13 訂位詳情訂金 section 應排在主操作之前 已修
症狀:當下狀態是「客人已付訂金,等老闆核准」, 老闆要先看到「客人已付 NT$1600」資訊才能決定是否核准, 但訂金 section 排在「操作」section 之後。
Fix:POSReservationListView.bottomSections 把 depositSection + depositTopUpSection 移到 actionsSection 之前。 原則:「當下餐廳端要看/要點的東西,出現在最快可達的位置」。
0/3 步驟完成
#B14 退款 sheet 缺客人帳戶顯示 + 缺再請填 / 電話按鈕 已修
症狀:取消退款設定 sheet 客人帳戶 section 只顯示「尚未提供」, 就算客人原本有用轉帳繳訂金、有填過匯款資訊,POS 也沒拉出來。
Fix 範圍:
  • 客人已提供帳戶時顯示銀行/戶名/末 5 碼/上傳時間/存摺照片連結
  • 無論是否提供,section 加 2 按鈕:「請客人重新傳送匯款資訊」+「電話聯絡客人」
  • 電話聯絡用 tel: URL 立即可用,顯示客人姓名 + 電話
  • 「請客人重新傳送匯款資訊」 #B16 改用 email 完成 (edge function send-refund-account-request-email + Resend),不再走 push 通知。 follow-up 85e162d6 修了 email 連結 404(改 /[slug]/my-reservation?fill_refund=<id>)
0/4 步驟完成
#B15 訂位事件氣泡 / badge 詞彙不夠精準 → 老闆誤會要動作 部分修
症狀:某些情況系統已自動處理但氣泡仍說「待處理」感,讓老闆誤以為要做事。例如「無訂金客人取消」其實系統自動處理,氣泡卻看起來像等審核。
本輪修的 4 處:
  • Timeline cancelled step:無訂金 → 「客人取消訂位 · 系統已自動取消,您不需要動作」;有訂金已退 → 「訂位已取消(訂金已退)」;有訂金未退 → 「訂位已取消 · 訂金處理請看下方退款區塊」
  • Timeline pendingCancellation:加 note「需您確認退款方式」(只有有訂金才會進此狀態)
  • Timeline noShow:加 note「已標記為未到,無後續動作」
  • cancellationPendingSection header:有訂金 → 「客人申請取消|需您確認退款方式」;無訂金 → 沿用原文(其實不會出現,因系統自動處理)
  • manualRefundSection 退款進度:4 種狀態各自獨立文案 — newebpayPending「藍新自動處理 1-3 工作天」/ newebpayStuck「藍新卡住需手動」/ manualPending「需手動匯出」/ waivedAnomaly「狀態異常請 review」(原本只分 2 種會誤導)
沒修但 audit 過(留 backlog):
  • 篩選膠囊「待付訂金」應該分「客人尚未付」vs「客人已標記付款待老闆確認」
  • 「客人特殊需求」改藍色資訊風格(不要橘色警告,跟「人數修改待確認」混)
  • 主控台 POSMainControlView 上的訂位卡片 badge 還沒 audit
0/5 步驟完成
#B16 退款設定 sheet 5 個改善(email/必填標示/選填/rename/Stitch) 已修
老闆 2026-05-20 dogfood 五個反饋:
  1. 「請客人重新傳送匯款資訊」改成寄 email(不要推播)→ 新 edge fn send-refund-account-request-email ship,Resend 寄信含 /my-reservation/[id] 連結。Button 接通顯示 loading/已寄出/錯誤狀態
  2. 「退款帳戶末五碼」沒寫無法 confirm 但沒標示必填→ 加紅色「*必填」標籤 + 改 TextField placeholder 為「輸入末 5 碼數字」
  3. 「超過政策的退款理由」改成選填(不再 gate submit button)→ canSubmitRefund 拿掉理由必填邏輯, header 改「退款理由(選填)」+ icon 從 exclamationmark 改 info,文案「建議填理由方便日後追溯」
  4. 「退款比例」section 改成「退款比例(按照退款政策)」
  5. Stitch 風樣式:Form 加 .scrollContentBackground(.hidden) + .background(StitchColors.background);各 Section 加 .listRowBackground(StitchColors.surface);顏色全部換 StitchColors.{textMain/textSub/primary/error/warning};確認按鈕重做成 Stitch 紅色 capsule
0/7 步驟完成
#B11-FIX per-restaurant container 重構(業界標準根治 #B11 災難) 已 ship
背景:#B11 災難(海邊 14 桌位被搬到溪邊)的根治。 老闆選方案 A(業界 B2B SaaS 主流 = 每家餐廳獨立 sqlite,Slack/Notion/Salesforce 同款)。
實作 commits:935a1f41 → c023dd4d → 2026-05-20 Phase 7 完工(Main/Booking 補 runtime swap + cleanupForeignRows 掛 3 apps boot)
架構: ChefsMatePOS-{rid}.sqlite 一家餐廳一個檔,從檔案系統層級隔離。 首次升級的 user 自動 migrate(copy 舊 sqlite → 當前餐廳 file,rename 舊版為 .legacy.backup), 然後 cleanupForeignRowsIfNeeded 砍掉 seed 過來的跨餐廳殘留 row(一次性,UserDefaults flag 防重跑)。
3 個 App 都 runtime swap(POS / Main / Booking)— 切換餐廳即時換 container, sync 系統 context 同步 rebind,不用 restart App。
詳細計劃: #P-FIX-1 完整計劃頁(95%)
0/8 步驟完成
看完整計劃
#B10 上一輪 patch 修這個壞那個 — 已 holistic 修正 全面修
老闆 dogfood 抓到 3 個 regression(同一輪 fix 引起)
(a) 樓面設計 vs 主控台 桌位數不一致(6 vs 5)— #B1 fix 只 filter POSMainControlView,漏 FloorDesigner
(b) POS 公休日跨餐廳混 — pre-existing @Query 沒 restaurant_id filter(從 2026-02 就在),老闆 2 家後才暴露
(c) 訂位網頁顯示但什麼都不能點 — #B8 把 normal_open 算入 gate,但 normal_open 沒 periods 時無法生時段,反更誤導

fix(commit 7527fd19)
1. FloorDesignerDataProvider.convertToFloorwhere item.deletedAt == nil
2. SharedBusinessHoursSheet 改 @Query all + body filter currentRestaurantId
3. revert #B8 — 兩條 page 只認 special_hours(必有 periods),沒設 slots 誠實顯示「尚未開放」

學到的教訓(已加 memory):加新欄位 / 改 gate 時,必 grep 所有 reader, 不要單點修補。修這個確認不會壞那個。
0/5 步驟完成
看 commit
#B9 拒絕取消後的 email 通知(補 #B4 的小尾巴)— 已修 已修
實作:新 Edge Function send-cancellation-rejection-email(複用 send-cancellation-email pattern), 橘色 banner 樣式 + 老闆理由 + 「聯繫店家」CTA。 rejectCancellation orchestrator 在 publish event 後 fire-and-forget 寄信。
已 deploy 到 dev 環境。 跟 #B4 客人端 UI 對稱(客人 web 看到 banner,email 也收到)。
0/4 步驟完成
看 commit
#W2 客人信用分數系統 — Backend 已 ship,等首批數據驗證 backend ready
實作(按你 JSON 4 個答案)
• Q1=A 跨餐廳共享(用 user_profile_id)
• Q2=B 自動 no-show 觸發:時段結束 +1 小時
• Q3=A 到場加分:每次 +20%,clamp 100%
• Q4=A 新客初始 100%

已 ship 4 件:DB migration 20260516002(customer_credit_scores 表 + RPC + RLS)· Web 4 層(gates + orchestrator + 2 API routes)· Vercel cron 每 30 分鐘掃過期未到 · idempotent guard(同筆訂位只計算一次)。
還沒做:POS 訂位詳情顯示 credit_score badge + ≤60% 紅色 warning (要先在 Reservation SwiftData model 加 userProfileId 欄位,bigger refactor,排下輪)。
0/6 步驟完成
看 commit
#B17 訂位 timeline 時序進度詞彙完整 audit 已修
症狀:無訂金客人取消也走 .pendingCancellation,timeline 仍顯示「需您確認退款方式」誤導。客人端拒絕取消後不知道發生什麼事。
本輪修的 5 + 3 處:
  • .pendingCancellation note 區分有無訂金
  • .cancelled 無訂金改「您已同意客人取消」(原誤寫「系統自動取消」)
  • .cancelled 新增 .waived case(訂金豁免/forfeit)
  • 訂金 step .skipped 改「客人未付訂金」
  • 完成 step done/future label 統一為「完成用餐」
Follow-up:#B13 重排後 cancellationPendingSection 在 timeline 下方,改 note「上方」→「下方」;刪除 CancellationRejectTemplate.fullySeated(老闆覺得「客滿改期」理由不夠好);客人端 my-reservation 加「曾拒絕取消」橘色 chip + scroll to banner。
看 commit
#B18 /account 訂位列表 3 改 — chip + 取消後隱藏訂金 + 過往紀錄正方形 grid 已修
web/booking/src/components/ReservationHistory.tsx(被 /account + /[slug]/account 共用)三件事:
  • 加「曾拒絕取消」橘色 chip + 拒絕理由 banner(讀 cancellation_rejection_reason,限 status 回到 pending/confirmed 才顯示)
  • 已取消/拒絕但 deposit_status=pending_payment/customer_marked_paid 時隱藏整個 DepositSection — 訂位都取消了還顯示「待付訂金」無意義
  • 過往紀錄改 PastRestaurantGroup(餐廳預設收合)+ PastSquareCard 正方形 3-6 col responsive grid,點正方形 inline 展開完整 ReservationCard 詳情
看 commit
#B19 補關帳隱藏現金盤點 — 過去無法物理清點 已修
症狀:補關帳 5/11 頁面同時顯示「現金盤點 → 零用金 $0」vs「營業額存入帳戶 → 收銀機零用金 $4,000」詭異對比,還強迫輸入「實際清點金額」才能關。
Root cause:SettlementSheet retroactive 模式把 startingCash 寫死 0(過去日期不知道當天開店零用金),但 UI 仍顯示整個現金盤點 section。原作者留了 skipCashCounting flag 卻沒接到 UI。
Fix:加 Gate showsCashReconciliation = isFinalClose && !isRetroactive。補關帳隱藏整個現金盤點 section、跳過「實際清點金額」防誤關閘、跳過「現金虧損理由」必填閘。當天關帳行為完整保留。
看 commit
#B20 補零用金 sheet 改造 — 來源帳戶可選 + 補滿到預設 + Stitch 設計 已修
老闆反饋:來源寫死「營業額錢包」、「補滿到預設金額($780)」文案誤導(其實是 deficit)、整頁不是 Stitch 樣式。
Service primitive:PettyCashService.transferToPettyCash(from:amount:in:) 參數化來源 asset;舊 transferFromRevenueWallet 保留為薄 wrapper(向下相容)。
UI 重寫(PettyCashRefillSheet):3 張 Stitch card —
  • 狀態:現有 / 預設 / 缺額 三欄分開列
  • 來源帳戶:radio 任選 active asset(排除零用金本身),預設選營業額錢包
  • 補進金額:「補滿至預設金額(+$缺額)」chip 讀 POSSettings.defaultStartingCash 算 deficit
餘額不足顯示紅字警告 + spinner;確認按鈕 Stitch primary。
看 commit

系統地圖 Audit 抓到的 Bug — 2026-05-23 17 個 L5 audit 並行掃出 90+ bugs

2026-05-23 派了 50+ audit agent 深度掃 codebase 寫 L5/L6/L7 文件,順便抓到一堆**真實 bug**(file:line 為證,不是猜的)。 下面分**critical / high / medium**列重點。點任一條 → 跳到系統地圖對應 L5 文件精確位置看完整 root cause + fix 建議。

已完成封存 — 2026-05-23 修了 27 個明確 bug(含 Batch 13 老闆拍板 6 個 Swift 全套,點開看清單)

每個都驗證過(live DB query + file:line grep),低 regression 風險。已 deploy 到 dev DB + push 到 main.

# 影響 修法 commit
#S5退款後客人點數不扣回loyalty_transactions CHECK 加 'reverse'migration 20260523001
#R5725+ RLS 對 admin 誤擋is_admin_of() 加 'admin' role20260523001
#S22冷盤跳過 ready 不消費獎勵trg_auto_consume 加 'served' status20260523001
#R52集團月聚合雙倍計入report-analytics 加 close_type='final' filter8643e9aa
#F3mcp/analytics/sales 404改 paid_at 不是 completed_at8643e9aa
#R50客人加菜核准廚房看不到approve-order-modification 寫 'confirmed'8643e9aa
#R49客人看訂單狀態永遠錯guest-status 改 query order_items.status8643e9aa
#R63tier 計算錯consume_reward 同時扣 available+total20260523002
#R10retry refund cron silent fail補 fire_user_silent_push_for_owners RPC20260523002
#R8拒絕訂位後客人 points 卡住trg_release_reserved_rewards trigger20260523002
#R7沒連 LINE 客人不知被拒notify_reservation_rejected_email trigger20260523002
#R60客人 ledger + 老闆 analytics 全空白3 個 web route .eq('type') → 'transaction_type'113f112b
#R58role consolidation 殘留12 個 API route VALID_ROLES 移除 dead 'chef'113f112b
#R65outbound webhook 完全失效orchestrator_context.ts 補 attachWebhookDispatcher5a2ed8de
#R11terminate 後員工仍在排班報表terminate 同步設 staff.is_active=false5a2ed8de
#F2cleanup 雙裝置不一致cleanup-stale-payments 'cancelled' → 'failed'5a2ed8de
#R17退款出事查不到誰做的checkout-reverse-payment 加 audit_logs5a2ed8de
#F11orders.payment_status 任意值加 CHECK constraint5a2ed8de
#R28文件騙工程師L3 補關帳移除 is_catchup 描述5a2ed8de
#R5cached caller_role admin terminateterminate orchestrator server-side 重驗 caller4e242bf6
#R6isSelfTerminate multi-provider 誤判用 canonical user_profile.id 比對4e242bf6
#S26forfeit/forfeited 三方不一致統一寫 forfeit + 8 處改4e242bf6
#G5deposit_status 無 CHECK加 CHECK constraint 8 個合法值migration 20260523003
#G6TS deposit_status type 漏值加 top_up_required + forfeit4e242bf6
#R30 B主 App 轉帳/還款不寫流水DB trigger 自動寫 asset_transactions (老闆選 B)migration 20260523004
#S3 A點數過期 hardcodedrestaurant_settings.loyalty_expire_days 預設 365 (老闆選 A)migration 20260523004
#R22 BPOS 代訂客人收不到通知AFTER INSERT trigger 觸發 confirmation email (老闆選 B)migration 20260523005
#R31修改拒絕 POS dual-path 失敗notify_modification_rejected trigger (取代 client HTTP)migration 20260523005
#R1 + #R61 + #R62 + #G18分帳/POS/thin-client 全付清不 update orders.payment_status一個 trigger 自動重算 parent — 所有 caller 覆蓋(含 backfill 歷史)migration 20260523006
#R21 A (SQL)AdHoc 雙重計帳 marker 欄位asset_transactions.source_marker 加上 + SettlementService 之後用此排除migration 20260523007
#S1 Cpos_settings RLS 開放restaurant_pos_secrets 新表 + RLS only admin/ownermigration 20260523007
#S6 A 階段一收貨不更新庫存inventory_levels stub + 收貨完成 trigger 自動加總migration 20260523007
#R26 C (SQL)chat 沒 push 通知chat_messages INSERT trigger fire silent push 'chat.new_message'migration 20260523007
Batch 10 — 一次修 12 個 SQL bug#R9 phone→loyalty_id / #F1 payments CHECK / #S14 squeeze idx / #S18 balance_after / #S19 deposit_applied / #R12 daily_close audit / #R47 pause helper / #R46 pause day 通知 / #F8 cancelled email / #R14+#S15 wallet trigger / #F10 redeem total / #S12 asset_id nullmigration 20260523008
Batch 11 — 7 個 SQL/code#F4 reservations.status 加 'rejected' (critical 不修 reject 會 fail) / #R25 採購 RLS 加 admin gate / #R16 payment completed 自動開發票 / #R13 refund email trigger / #S4 tier key minPoints camelCase / #S10 bulk-import 4 欄位名修正 / #F7 (deferred)migration 20260523009
#R48暫停接訂位 RLS bypass(client 改 caller_role='owner' 可繞)pause-days route 加 server-side verifyCallerRole 從 DB 查真實 rolecode commit
#F6create_reservation capacity 漏 'completed'false positive — 已被 migration 20260343_fix_rpc_status_filter 修過verified
#R4集團多店 generateMonthlyPayroll dedup 沒帶 restaurantId → A 店生完 B 店漏發薪資SQL + Swift 同步:staff_payroll_history 加 restaurant_id 欄位 + StaffPayrollHistory Model/DTO/Mapper 全套加上 + predicate 補 restaurantId scopemigration 20260523008_fix_R4 + Swift Model/Mapper
#R64主 App deactivateStaff 只本機改 isActive → restaurant_members 沒 cascade → token 仍有效新 server endpoint /api/staff/by-staff/[staffId]/terminate(server 端 resolve member.id 後走 terminateMemberOrchestrator)+ ChefsMateAPIClient.terminateMemberByStaff + StaffDetailView 走 server,失敗才 fallback 本機Swift + Next.js route
#R66POSAuditLogView friendlyEventName 列 14+ 從未 publish 的 event(reward.* / daily_close.* / order.modified)→ UI 誤導依 L5 §4 真實 publisher 清單重寫 friendlyEventName / icon / color / filter chips,移除 wishful 加進真實有的(deposit / KDS / pay_grade / subscription)Swift POSAuditLogView
#R21 A (Swift)AdHocSheet 只 INSERT tx 不沖 balance → 主 App 帳本 + 關帳 cashShortage 雙重計帳AssetTransaction Model/DTO/Mapper 加 sourceMarker + AdHocSheet.save 同步沖 currentBalance + SettlementService 排除 marker tx 避免雙算f6fcecfc
#R29 AB標記售完沒問 in-flight order_items 怎麼處理 → 廚房做白工或客人收費爭議POSMenuItemRow 加 fetchInFlightOrderItems + alert 兩選一(繼續做完 / 取消通知換菜)+ 取消分支批次 status=cancelled + NotificationCenter eventaf1555ff
#R26 C (Swift)chat 新訊息沒 silent push → POS 背景不知道,要重開才看到 unread badgePushNotificationType.chatNewMessage + handleRemoteNotification 解析 + 從 ActiveContainerHolder fetch ChatConversation 直接 unread_count_staff +1(僅 customer 送來時)+ NotificationCenter.chatNewMessageReceived5558b81b
#R2 Aoffline 退款拿錢 → 不沖 asset balance → 關帳 cashShortage 永遠虧錢RefundDispatcher.dispatchOffline:目標若是零用金 → PettyCashService.recordCashOutflow(已正確沖 balance);其他 asset → 寫 tx 同時 fetch Asset + currentBalance -= amount + markForUpload4a9f51ef
#S1 C (Swift)敏感欄位(petty_cash_asset_id 等)在 pos_settings → 所有員工 SwiftData dump 看得到新 RestaurantPosSecrets Model/DTO/Mapper(id=restaurant_id)+ 註冊到 POS+主 app 同步 + PettyCashService 優先讀新表 + POSPettyCashRow 同步寫新表 + 舊欄位標 DEPRECATED 保留向後相容0f765252
#S6 A 階段二+三點餐不扣食材庫存 + POS 沒盤點入口階段二:trg_order_item_deduct_inventory trigger(order_items status→confirmed 觸發,扣 recipe_components→inventory_levels);階段三:POSSettingsView card3 加 NavigationLink StockTakeViewmigration 20260523010 + 3d39bb86

FALSE POSITIVE 驗證(不用修)

  • #R3 客人收 2 封 email — 直接 SQL query 證明 on_reservation_confirmed_no_deposit / on_reservation_confirmed_deposit **早已被 20260313_fix_combined 正確 DROP**。Audit agent 抓錯,不用修。
  • #R23 auto-reject-stale-modifications 沒排程 — 直接 SQL query cron.job 表證明 jobid 14 已排程 every 30min,job_run_details 顯示成功跑了 N 次。L6 audit 又抓錯。
  • #F6 create_reservation_atomic capacity 漏 'completed' — 已被 20260343_fix_rpc_status_filter 修過,migration comment 明寫「修正:在所有 status NOT IN 過濾中加入 'completed'」。
  • #S13 daily reset cron 沒部署 — 直接 query cron.job:`reset_menu_item_stock_daily`(0 20 * * *)+ `daily-menu-stock-reset`(5 0 * * *)兩個 cron 都 active=true 跑著。L6 audit 第 5 次抓錯。
需要老闆決策的 bug — 7 個方案都選了,全部 ship 完畢 已封存

Batch 13 一次 ship 完所有老闆拍板的 7 個 bug(#R21 A / #R22 B / #R29 AB / #R26+R27 C / #R2 A / #S1 C / #S6 A)。 以下卡片保留為歷史紀錄,點開可看當時的選項分析。

#R21 已修 — AdHoc 從錢箱拿錢被算兩次(帳本 -$400 實際 -$200)

已驗證 root cause:AdHocTransactionSheet 只寫 asset_transactions 流水,**不沖 assets.current_balance**;晚上關帳 SettlementService.computeSettlement 從不讀 asset_transactions → cashShortage 再算一次。

三個方案讓你選:

  • A. 改 AdHocSheet 同時沖 balance + 留 marker(推薦)
    AdHoc save 時順手 update assets.current_balance,寫 asset_transactions.tag='adhoc_synced_balance' marker。SettlementService.computeSettlement 看到該 tag 就把它從 cashShortage 算式排除。
    風險:歷史已建 AdHoc 沒 marker,**歷史關帳仍會雙算**,要決定是否手動 backfill。
    工程量:1-2 天(改 Sheet + Settlement + 加 marker column)
  • B. 完全分離 — AdHoc 只記事務不沖 balance,但 cashReconciliation UI 顯示明細
    不沖 balance 維持原樣(老闆已習慣),但關帳時 settlement service 主動把當天 asset_transactions.tag='adhoc' 列出來,問老闆「這些已在 AdHoc 紀錄,要算進 cashShortage 嗎?」
    風險:老闆要每次手動勾選,操作複雜。
    工程量:0.5-1 天
  • C. 廢棄 AdHocSheet,改用「正式從零用金支出」流程
    讓老闆從 PettyCashService.recordCashOutflow 走(已正確沖 balance),AdHocSheet 改成純收入(無下游影響)。
    風險:改 UI 流程,要重新訓練員工。
    工程量:1 天(UI 調整 + 文檔)

L6 AdHoc

⬇️ 點選你要的方案(會即時存到 supabase 我可以 SQL 看到):
#R22 已修 — 員工電話代訂後客人收不到任何確認(老闆選 B → 已 trigger-based 實作)

已驗證 root cause:POS 直接 INSERT status='confirmed',但 3 個寄信 trigger 都 AFTER UPDATE(不是 INSERT)→ 沒觸發。

三個方案讓你選:

  • A. Trigger 改 AFTER INSERT OR UPDATE(高風險)
    直接讓 trigger 也認 INSERT。
    風險:**所有 INSERT 都會觸發** — 包括 dev/seed/manual import 都會誤寄 email 給客人。要先 audit 所有 INSERT path 確認沒有非預期的 path。
    工程量:1-2 天(audit 全 codebase)
  • B. POS 代訂 orchestrator 主動 call email edge fn(推薦)
    在 POS 代訂的 createReservation orchestrator 內,確認成功後直接 fetch send-reservation-confirmed edge fn。
    風險:network 失敗無 retry(可加 outbox 待確認)。
    工程量:半天
  • C. 改 INSERT 流程先 'pending' 再立刻 UPDATE 'confirmed'
    讓 POS 代訂寫 INSERT pending,馬上 UPDATE confirmed → trigger 觸發。
    風險:DB write 變兩次,客人短暫看到 pending 狀態(不太可能,因為時間很短)。
    工程量:1 小時(改 SQL)

L6 新增訂位

⬇️ 點選你要的方案(會即時存到 supabase 我可以 SQL 看到):
#R29 已修 — 標售完時,廚房在做的菜:警告 + 二選一

標售完時 UI 跳警告「還有 2 份在做」,讓老闆**對在做的那些**選 A 或 B:

修正後 2 個方案(老闆 2026-05-23 拍板新版):

  • A. 繼續做完(仍然收費)
    廚師繼續做,客人吃,**收原本價錢**。menu_items.is_sold_out 設 true 後**不接新訂單**,但已 submit 的 2 份正常完成 + 結帳。
    需要:UI 跳「2 份在做,確認繼續做完並收費 」按鈕。
  • B. 標完售 + 通知服務員換菜 + 通知客人桌邊重點
    那 2 份 order_items.status='cancelled'(或 voided)+ KDS 隱藏。
    同時:1. 推播給服務員「桌 5 的牛排取消請去換菜」2. 客人桌邊 web 跳「該菜售完,請重新選擇」彈窗。
    需要:cancel order_items + push to staff + 客人 web realtime banner。

實作:售完按鈕點下後,**先查 in-flight 數量** → 跳警告 → 員工選 A/B 後執行對應流程。每次標售完都會問,A/B 不是預先設定。

L6 沽清

⬇️ 點選你要的方案(會即時存到 supabase 我可以 SQL 看到):
#R26+#R27 已修 — 客人傳 chat,POS 沒響也沒紅點 — 要怎麼通知?

三個方案:

  • A. silent push v7 加第 9 個 event 'chat.new_message'(推薦)
    客人發訊息時 DB trigger fire silent push,POS 收到後 +1 badge + 通知中心彈出。
    工程量:1-2 天(加 event type + trigger + Swift handle)
  • B. Realtime broadcast 直接 onMessage 觸發 local notif
    只有 POS 在前景時才會收到,背景沒救。
    工程量:0.5 天
  • C. A+B 都做(完整但工程量大):背景 silent push + 前景 broadcast。3-4 天。

L5 Chat

⬇️ 點選你要的方案(會即時存到 supabase 我可以 SQL 看到):
#R2 已修 — 現金退款不沖零用金,跟 #R21 同類雙重計帳風險

三個方案:

  • A. RefundDispatcher.dispatchOffline 補 PettyCashService.recordCashOutflow(推薦)
    退款時直接從零用金 deduct。歷史不 backfill。工程量 0.5 天。
  • B. 改成顯示「請手動扣零用金」warning
    讓員工自己記得操作。最保守。
  • C. 同 #R21 — 改 settlement 不算 cashShortage(會跟 AdHoc 一起變動)

L6 退款

⬇️ 點選你要的方案(會即時存到 supabase 我可以 SQL 看到):
#S1 已修 — pos_settings RLS 完全開放(安全漏洞)

三個方案:

  • A. 上 RLS + 所有 caller 補 SET app.restaurant_id
    要先 grep 所有 caller 確保每個都 set。漏一個會 break 那個功能。
    工程量:2-3 天(audit + 加測試)
  • B. 用 SECURITY DEFINER helper function 包裝(推薦)
    寫 get_my_pos_settings() 自動 filter,client 直接 call function 不查 table。
    工程量:1 天
  • C. 把敏感資料(petty_cash_asset_id 等)從 pos_settings 搬到別表加好 RLS
    工程量 3-5 天但最徹底。
⬇️ 點選你要的方案(會即時存到 supabase 我可以 SQL 看到):
#S6 已修 — 整套庫存功能不運作 — 要不要做?

三個方案:

  • A. 全做(收貨 + 點餐扣 + 盤點 UI + 損耗)— 4-6 週大工程
    完整庫存系統。
  • B. 只做收貨更新 inventory_levels(短期,推薦)
    庫存帳本至少不卡死,點餐扣食材分階段做。工程量 1 週。
  • C. 棄用整個 inventory 模組,從 UI 隱藏
    短期省工。長期靠純人工管。
⬇️ 點選你要的方案(會即時存到 supabase 我可以 SQL 看到):
#S3 已修 — 點數過期天數由餐廳端設定(老闆選 A → 已加 restaurant_settings.loyalty_expire_days)

修正後的方案(老闆 2026-05-23 拍板):

  • restaurant_settings 加欄位 loyalty_expire_days INT NOT NULL DEFAULT 365
  • POS 設定頁加滑桿/輸入欄,讓老闆**自己選天數**
  • UI 加文案提示 trade-off:
    • 太少天(<90 天):客人體驗不佳 — 來一次過幾個月就過期,「沒誠意」
    • 太多天(>730 天):轉換效率不佳 — 點數累積越久,客人覺得「反正不會過期」沒動力來消費
    • 建議範圍 180-540 天(6-18 個月),預設 365 天 = 12 個月
  • expire-loyalty-points cron 改 query:WHERE created_at < NOW() - INTERVAL '{loyalty_expire_days} days'(per restaurant)
  • 客人 web /account 顯示「最早一筆會在 X 月 Y 日過期」

工程量:1-2 天(restaurant_settings migration + POS UI 設定欄 + expire cron query 改 + 客人 web 顯示)。

⬇️ 點選你要的方案(會即時存到 supabase 我可以 SQL 看到):
#R30 已修 — 主 App 轉帳 / 還款不寫流水(老闆選 B → 已用 DB trigger 自動寫 asset_transactions)

完整解釋:

主 App(ChefsMate iOS 老闆專用,不是 POS)有 2 個 sheet:

  • AddTransferSheet — 老闆把 $10,000 從銀行 A 轉到銀行 B
  • AddLiabilityPaymentSheet — 老闆把欠款 $5,000 還掉

這兩個 sheet 寫入的表:

  • asset_transfersliability_payments(專屬表)
  • update assets.current_balance(balance 變動)
  • 沒寫 asset_transactions(流水帳本)

結果:

老闆對帳時跑 SELECT SUM(amount) FROM asset_transactions WHERE asset_id=A → 跟 assets.current_balance 對不上 → 看不到「為什麼少了 $10,000」。

三個方案 — 老闆問「trigger 是不是比較好? 自動化處理?」答案是 YES,推薦 B:

  • A. 改 Swift 主 App sheet code 同時 INSERT asset_transactions
    在 AddTransferSheet 跟 AddLiabilityPaymentSheet save 後多加一行 supabase.insert('asset_transactions').
    缺點:1. client code 散兩個地方寫同邏輯 2. 未來如果加新 sheet 又要記得加 3. web 版主 App 還要再做一次。
  • ⭐ B. DB trigger 自動補 ─ 推薦
    寫一個 AFTER INSERT ON asset_transfers trigger 自動 insert 兩筆 asset_transactions(轉出方 -$10,000、轉入方 +$10,000)。同樣寫 AFTER INSERT ON liability_payments
    優點:
    • client 完全不用知道流水的存在 — 任何寫 transfer 表的程式(現 Swift、未來 web、API、CSV 匯入)都自動產生流水
    • single source of truth — 永遠不會 drift
    • 歷史資料可一次 backfill — 寫一個 SELECT INSERT 跑一次補完所有歷史
    • 對齊老闆「自動化處理」原則
    缺點:debug 時要記得 trigger 在,但有 COMMENT 標清楚就 OK。
    工程量:1 天(寫 trigger + backfill SQL + 測試)。
  • C. Daily reconcile script 對帳找 drift 自動補
    不是 trigger 自動同步,而是每天 cron 對帳補。
    缺點:有 lag(隔天才補),且如果 cron 掛了就漏。**治標不治本**。

建議:B trigger — 跟你說的「自動化處理」一致 + 未來不用維護 client code。

⬇️ 點選你要的方案(會即時存到 supabase 我可以 SQL 看到):
你選過的方案(我會 SQL 讀這份決定要修哪個方案)
載入中... (登入後同步顯示)

下一步:點下面 9 個 bug 各自的方案按鈕,我從 supabase boss_plan_decisions 看你選的就照做。
SQL query:SELECT plan_id, choice, decided_at FROM boss_plan_decisions WHERE plan_id LIKE 'BUG-%' AND user_profile_id = '9fc277c3-...'

老闆 Triage 指南 — 15 個 critical bug 全部 ship 已封存

2026-05-23 早上老闆要求「用真實例子說明才知道是不是真 bug」,所以這 15 個 critical bug 用「真實場景 + 你會碰到嗎 + 怎麼驗證 + 修了會壞什麼」四段式說明。 全部 15 個都已修完(Batch 13-26)。卡片保留為歷史紀錄,點開可看詳細場景。

#R21 已修 — 從錢箱拿錢被算兩次,帳本顯示比實際少 2 倍

真實場景:早上 10 點員工小美從收銀機抽 $200 出去買印表機紙。你打開 POS 的「臨時支出」,記了一筆「-$200 from 零用金」並 save 成功。晚上關帳的時候,系統算現金盤點發現「實際少了 $200」,又跳「cashShortage -$200」要你填原因。**帳本最後顯示這天少了 $400,但實際只少了 $200**。

你會碰到嗎?

  • 會碰到:如果你/員工會用「臨時支出」記從錢箱拿出去的錢(買文具 / 買飲料 / 補水)
  • 不會碰到:如果你只用「臨時收入」記額外收入(外賣平台撥款 / 客人留小費),從不記錢箱出去的支出

怎麼親自驗證(5 分鐘):

  1. 打開 POS 主控台,看零用金 balance(假設 $5,000)
  2. 用「臨時支出」記 -$200 from 零用金
  3. **馬上**重新打開零用金頁面 — 看 balance 是不是還 $5,000(沒變 = bug #1 確認)
  4. 晚上實際從錢箱拿 $200 出去買東西
  5. 關帳走完整流程,現金盤點數實際金額
  6. 看 daily_close 結果:**cashShortage 顯示 -$200 + 之前的 AdHoc -$200 = 帳本 -$400**(bug #2 確認)

修了會壞什麼?

  • 新的 AdHoc 開始正常沖 balance — OK
  • **歷史已建的 AdHoc 不要 backfill** — 不然會把過去某些已經正確扣的再扣一次
  • 關帳邏輯要改:cashShortage 計算時減去 AdHoc 已扣的金額

完整 root cause: L6 AdHoc 漣漪

#R22 已修 — 員工幫客人電話訂位後,客人收不到任何確認

真實場景:王先生打電話來訂明天晚上 6 點 4 個人。員工小美在 POS 開「新增訂位」sheet,填好客人資料 + 時間 + 桌位,按確認。POS 顯示訂位成功 。但**王先生整晚都沒收到任何訊息**(email/LINE/wallet pass)。隔天王先生打來確認:「你們有沒有收到我訂位?」

你會碰到嗎?

  • 會碰到:你/員工有用 POS「代客新增訂位」這個功能(電話訂位、走訪訂位)
  • 不會碰到:所有訂位都是客人自己上網訂(web /reservation),沒用 POS 代訂

怎麼親自驗證(3 分鐘):

  1. 用測試帳號(你自己的 email)走 POS 代訂流程
  2. 等 5 分鐘看 email/LINE 收不收得到
  3. 沒收到 → bug 確認
  4. 對照:同一個測試 email 從 web 自己訂,**會**收到 → 證明是 POS 代訂這條路斷

Root cause:POS 直接 INSERT status='confirmed',但三個寄信 trigger 都是 AFTER UPDATE(不是 INSERT)→ 沒觸發。

修了會壞什麼?

  • 客戶體驗變好(終於收到確認)
  • 沒 regression(現在等於 0 通知,改成有通知不會更糟)
  • 注意:可能會「重複寄」 — 如果之後又被 confirm 一次,要 idempotent guard

L6 新增訂位 G9

#R29 已修 — 中午賣完才標售完,KDS 還是會繼續做下去

真實場景:中午 12:30 牛排賣到剩 1 份。12:35 員工點了「2 份牛排」進 KDS。12:36 你發現只剩 1 份,在 POS 標牛排「售完」。**問題**:剛剛那 2 份牛排還在廚房做,廚師會做完 2 份 → 但你只剩 1 份食材 → 客人吃到不存在的東西(或臨時改菜變客訴)。系統**沒有任何邏輯**把已 submit 的 order_items 退回去問客人。

你會碰到嗎?

  • 會碰到:你有用「沽清」功能 + 出餐速度比較慢(點完 5-10 分鐘才上)
  • 不會碰到:沒用沽清 / 出餐即時(<1 分鐘) / 每樣食材庫存都很多

怎麼親自驗證(7 分鐘):

  1. 找個 SOP:點 2 份某道菜進 KDS
  2. 30 秒後在 POS 把那道菜標「售完」
  3. 看廚房 KDS — 那 2 份**仍在做菜清單上**沒被標 cancelled
  4. 沒任何彈窗問你「在做的怎麼辦?」→ bug 確認

修了會壞什麼?

  • 需要新 UI 跳「2 份在做,要取消/做完?」決策框
  • 取消已 submit 的要 sync 到客人桌邊 + 退錢
  • regression 風險:廚師正在做的菜被 cancel,變廚餘
  • 建議:加 warning 彈窗 + 預設「做完不收錢」(廚師繼續做、客人不收費、認列損耗)

L6 沽清 G11

#R2 已修 — 現金退款不沖零用金,老闆會以為員工偷錢

真實場景:客人吃完飯抱怨菜壞掉,員工從錢箱拿 $300 給客人退錢。員工在 POS 按「退款」流程,POS 系統紀錄「退款 $300」。但**沒從零用金扣** → 帳本看起來零用金還是滿的。晚上關帳老闆數錢箱,實際少 $300,**老闆會以為員工偷錢**(因為帳本顯示應該還有,但實際少了)。

你會碰到嗎?

  • 會碰到:你有用過「現金退款」(客訴退錢、誤收退錢)
  • 不會碰到:你的退款都走信用卡/藍新(這些有正確走 provider refund)

怎麼親自驗證(5 分鐘):

  1. 建一筆現金測試訂單(假設 $500)→ 結帳成功 → 看零用金 +500
  2. 從 POS 開 RefundSheet 退這筆 $500 給「客人」(實際你不真的退)
  3. **看零用金 balance** — 是 +500 還是 0?
    • 還是 +500 → bug 確認(系統沒扣)
    • 變 0 → 沒事

修了會壞什麼?

  • 所有現金退款會正確扣零用金,balance 變準
  • 沒 regression(本來就應該扣的,只是漏寫)
  • 歷史已建的退款不要 backfill(不然零用金會變負)

L6 退款 #S-NEW-5

#R3 已修 — 客人訂位被確認後收到 2 封一樣的 email

真實場景:王先生上網訂位,你在 POS 按「核准」。王先生的 inbox 收到**兩封一模一樣的「訂位已確認」email**(寄信時間差幾秒)。看起來像系統壞掉。

你會碰到嗎?:**100% 會** — 只要你有訂位 + 核准動作,所有客人都收到雙封。可以直接打開自己 email 確認。

怎麼親自驗證(2 分鐘):用你自己 email 訂位,POS 核准,看 inbox 收到幾封 confirmed email。2 封 = bug / 1 封 = 沒事

Root cause:`20260337` migration 新增 trigger 沒 DROP 舊的 `20260313` + `20260228`,**3 條 trigger 同時跑**(2 條算 deposit/non-deposit 各一條,加上新的 robust 一條)。

修了會壞什麼?:DROP 舊 trigger 後 email 數量正常。沒 regression。最低風險修法。

L6 訂位確認 G1

#R23 已修 — 客人改訂位後沒回應,系統不會自動拒絕 → 卡 pending 永遠

真實場景:王先生晚上 8 點申請「改人數從 4 到 6」。本來這種 modification 設計 24 小時你沒回應就自動拒絕,但**這個 cron 從來沒部署過** → 申請永遠停在 pending → 王先生看到「審核中」一年 → 你 POS 訂位列表的 pending badge **越積越多**。

你會碰到嗎?

  • 會碰到:有任何客人申請過修改訂位(改人數/改時間)
  • 不會碰到:你的所有訂位修改都立刻處理(不留 pending 隔夜)

怎麼親自驗證(1 分鐘):POS 訂位列表看「待審核修改」分頁。如果裡面有 24 小時以上沒處理的 pending → bug 確認。

Root cause:`auto-reject-stale-modifications` cron 路由跟 orchestrator 都寫好了,但 **vercel.json 跟 pg_cron 都沒排程** → 完全沒在跑。

修了會壞什麼?:設好排程後,過期 pending 一次性被清掉(可能 100+ 筆)。客人會收到「自動拒絕」通知,可能困惑。建議分批清,或先發公告。

L6 修改訂位 M8

#R26 + #R27 已修 — 客人傳 chat 訊息,POS 不會響也不會顯示紅點

真實場景:王先生坐在桌邊用 chat 問:「請問可以加一張嬰兒椅嗎?」訊息成功送到 DB(web 那邊看到 sent)。但你的 POS:
1. 沒響(沒 push 通知,App 關著就漏)
2. 沒紅點(badge 永遠 0,因為未讀計數沒人 +1)
→ 王先生等了 10 分鐘沒回應,自己起身找服務員。

你會碰到嗎?:**只要有客人用 chat 都會碰到** — 整個 chat push 系統沒接,POS badge 永遠 0。

怎麼親自驗證(3 分鐘):

  1. 請朋友拿手機掃店裡 QR,進去 chat 傳訊息
  2. 看你 POS:有沒有彈通知?有沒有 chat icon 紅點?
  3. 都沒有 → bug 確認

Root cause:1. silent push v7 八種 alert event **完全不含 chat**,沒 DB trigger 觸發 push。2. `unread_count_staff/customer` 只有 markRead 清零的邏輯,**沒有任何 increment**。

修了會壞什麼?:加 push 後員工會被新訊息打擾(可能要設靜音時段)。badge 變正常數字。沒功能 regression。

L5 Chat G1/G2/G3

#S1 已修 — 任何登入用戶可以讀其他餐廳的 POS 設定(安全漏洞)

真實場景:你家餐廳的零用金金額 / Expedite 設定 / petty_cash_asset_id 這些資料,**任何登入 ChefsMate 的人都讀得到**(只要他知道 query SQL)— 包括競爭對手的員工。原因:`pos_settings` 表的 RLS policy 寫 `USING (true)` 完全沒做租戶隔離。

你會碰到嗎?:理論上**所有用戶都暴露**。實際上要看會不會有人惡意 query(目前用戶都是熟人 + 沒人會寫 SQL,風險暫時低)。但這是法律 / 隱私問題,集團多店時尤其嚴重。

怎麼親自驗證(需要工程師,1 分鐘):用 supabase MCP 跑 `SELECT * FROM pos_settings;` — 如果**沒有 RLS error 而且看得到別家餐廳的 row** → bug 確認。

修了會壞什麼?:加 RLS filter `restaurant_id = current_setting('app.restaurant_id')` 後,所有讀寫 pos_settings 的 callsite 都要確認有 set `app.restaurant_id`。若有 caller 沒 set,會 query 不到 → 功能壞。建議**先 grep 所有 pos_settings caller,確認每個都 set restaurant_id 才上 RLS**。

L5 設定表

#S6 已修 — 採購收貨不影響庫存,整套庫存功能基本是裝飾品

真實場景:你下採購單買 10 公斤牛肉,送來後 POS 按「收貨完成」。但**`inventory_levels` 表完全不更新** — 庫存帳本永遠停在「上次手動 adjust」的數字。加上點餐也不扣食材(`trg_order_item_deduct_inventory` trigger 不存在),整套 inventory 功能基本是裝飾品。

你會碰到嗎?

  • 會碰到:如果你有期待「庫存」頁的數字跟實際對得上
  • 不會碰到:你從沒看過庫存頁、純手動管庫存 → 反正本來就不準

怎麼親自驗證(3 分鐘):看任何食材的「庫存量」是不是長年沒變過。如果是 → bug 確認。

修了會壞什麼?:這是**大工程**,不是 1 個 patch 能修。需要:1. 收貨 → inventory_levels INSERT/UPDATE 2. 點餐 → 扣食材 trigger 3. 盤點 UI 補上 4. 損耗紀錄。建議:先把採購收貨那條接上,點餐扣食材分階段做。

L5 庫存

#S3 + #S4 已修 — 客人點數永不過期 + Tier 永遠升不到 silver/gold

真實場景:
1. 王先生 2024 年累積了 500 點。你設了「12 個月過期」規則。但 2025 年 1 月還是 500 點(沒過期)。原因:`loyalty_point_batches` 表設計上要存「哪一筆點數哪天到期」但**沒人寫這張表** → expire cron 找不到資料 → 永不過期。
2. 你設了 silver tier = 1000 點,但客人累積到 2000 點還是 bronze。原因:edge function 比較 `min_points`(snake_case)vs JSON `minPoints`(camelCase),**永遠 false** → 沒人能升等。

你會碰到嗎?:**所有有點數會員都會碰到**,只要你的會員夠久就會發現。

怎麼親自驗證(2 分鐘):

  • 查任何累積點數 > 1000 的客人,看 tier 是 bronze 還是 silver → 是 bronze → #S4 確認
  • 查任何 12 個月以上沒消費的會員,點數有沒有歸零 → 沒歸零 → #S3 確認

修了會壞什麼?:1. 修 tier key 之後,所有客人會「集體升等」(隔夜變多人 gold)。要先發公告 + 評估獎勵成本。2. 修 expire 邏輯之前,要決定**歷史點數要不要追溯過期**。建議:歷史點數先給「寬限 3 個月」再開始算過期。

L5 集點

#R4 已修 — 集團多店,第二家店員工那個月薪資 silent miss

真實場景:你開了海邊小巫 + 溪邊小巫兩家。月底自動算薪資 cron 跑:海邊小巫先關帳 → 寫入「員工 A 4 月薪資」row。溪邊小巫稍後也關帳 → cron 想寫「員工 A 4 月薪資」,但**dedup 用 `(employee_id, month)` 沒帶 restaurant_id** → 系統認為「重複了,跳過」→ **員工 A 的溪邊小巫 4 月薪資永遠沒生成**。

你會碰到嗎?

  • 會碰到:你有 2 家以上餐廳,且**員工在多家上班**
  • 不會碰到:只有 1 家餐廳 / 員工不跨店

怎麼親自驗證(需要看 DB,5 分鐘):

  1. 找跨店員工 A,看 staff_payroll_history 表
  2. SELECT * FROM staff_payroll_history WHERE employee_id='A' AND month=4;
  3. 應該看到 2 row(海邊 + 溪邊)。**只看到 1 row → bug 確認**

修了會壞什麼?:dedup 改成 `(employee_id, restaurant_id, month)` 後,缺的 row 會在下次跑時補上。沒 regression。歷史缺的要手動 backfill。

L6 關帳 G13

#R28 已修 — L3 文件寫的 `is_catchup` 欄位 DB 根本不存在

真實場景:這個是「文件騙人」bug,不是 runtime bug。L3 補關帳文件寫:「daily_closes.is_catchup=true 標記補關的日子」。工程師看了文件想用這個欄位 filter 報表 / 統計 / 補關列表,寫了 `WHERE is_catchup = true` → 結果**這個欄位根本不存在於 DB schema** → query 噴 error 或返回空。

你會碰到嗎?:不會直接碰到,但**任何工程師根據文件寫 code 都會踩** → 影響速度 + 信任。

怎麼驗證(30 秒):用 supabase MCP 跑 `SELECT column_name FROM information_schema.columns WHERE table_name='daily_closes';` 看有沒有 `is_catchup` 欄位。沒有 → bug 確認。

修了會壞什麼?:這個是文件 vs code 不一致,修法選一邊:1. 加欄位 到 DB(影響面大) 2. 改文件移除這描述(快但失去區分 catch-up 的功能)。建議 ②,因為實際上沒有任何 code 在依賴。

L6 補關帳 G20

#R30 已修 — 主 App 轉帳 / 還款 sheet 不寫流水 → 帳本對不上

真實場景:你在 ChefsMate 主 App(不是 POS)用「轉帳」把 $10,000 從銀行 A 轉到銀行 B。或用「還款」把欠款還掉。系統有 update `assets.current_balance`,但**完全不寫 `asset_transactions` 流水**。後來工程師對帳:`SUM(asset_transactions WHERE asset_id=A)` 永遠跟 `assets.current_balance` 對不上。

你會碰到嗎?

  • 會碰到:有用主 App 的「轉帳」/「還款」/「編輯資產」功能
  • 不會碰到:只用 POS,沒進主 App 動帳戶

怎麼親自驗證(5 分鐘):

  1. 主 App 開「轉帳 sheet」做一筆 $100 測試轉帳
  2. 查 `asset_transactions` 表有沒有新增 row → 沒新增 → bug 確認
  3. 查 `assets.current_balance` 兩個帳戶有沒有更新 → 有 → 證明只動 balance 沒寫流水

修了會壞什麼?:補寫 asset_transactions 後,流水 sum 才會等於 balance。歷史已建的轉帳要不要 backfill? **不要** — 直接從修補日起算就好,backfill 風險高。

L7 assets G-NEW-7

#S5 已修 — 退款後客人點數沒被扣回 (因為 DB 拒絕寫)

真實場景:王先生消費 $1000 賺 100 點。隔天客訴退錢。POS 退款成功 + Swift 想寫 `loyalty_transactions {type: 'reverse', points: -100}` 把點數扣回去。但 `loyalty_transactions.transaction_type` 的 CHECK constraint **只允許 'earn'/'redeem'/'adjust'/'expire'** → DB 直接拒絕,Swift 收到 error 但 UI 沒 surface → **客人點數沒被扣,白賺 100 點**。

你會碰到嗎?:**只要有現金 / TapPay 付款後退款都會碰到**。所有有點數會員退款後點數都會「不退」。

怎麼親自驗證(5 分鐘):

  1. 找測試會員 A 結帳 $1000 → 看點數 +100
  2. 退款這筆
  3. **看會員 A 的點數** — 是 +100 還是 0?
    • 還是 +100 → bug 確認
    • 變 0 → 沒事

修了會壞什麼?:把 CHECK constraint 加 'reverse',`reversePointsForPayment` 才能成功寫。歷史已退款但沒扣的點數要 backfill 嗎? **建議 audit 一下範圍再決定**,如果只有少量(<100 筆)就手動補,大量就放著當客人優惠。

L5 集點 §6

#R8 已修 — 訂位被拒絕,但客人預約的獎勵點數永遠卡住

真實場景:王先生 1000 點預約「主廚菜兌換」鎖在某天的訂位上。你看到那天滿了,**拒絕訂位**。系統:reservation 變 rejected ,但 `reward_redemptions.status='reserved'` **沒被釋放** → 王先生那 1000 點被永遠 hold 在這筆已 rejected 的訂位上 → 他想用點數換別樣也不行,客服查不到原因。

你會碰到嗎?

  • 會碰到:你有「預約獎勵」功能 + 偶爾會拒絕訂位
  • 不會碰到:沒有預約獎勵 / 從不拒絕訂位

怎麼親自驗證:測試會員預約獎勵 → 訂位 → 你 reject → 看會員的 `current_points` 跟 `reward_redemptions` 表狀態。如果 points 沒釋放且 reward_redemptions 仍是 'reserved' → bug 確認。

修了會壞什麼?:rejectReservation orchestrator 加一步 cancel 對應 reward_redemptions + 退還 points。歷史 stuck 的要手動補。

L6 訂位確認 G8

其他 30+ bug 用同樣四段式:本指南只列 top 15,完整 #S1-S35 + #R1-R45 + #F1-F12 系列見下方技術摘要 + 對應 L5/L6/L7 文件。 每個 都有 file:line 為證,沒猜測 — 但驗證方式跟修法影響需要你親自確認場景才能拍板。

CRITICAL — 影響資料完整性 / 安全 (10 個全 ship) 已封存

Batch 1-25 全部修完:#S1(RLS) / #S2(account merge RPC migrations) / #S3+S4(loyalty tier 升級 + 過期) / #S5(deposit FSM) / #S6(inventory) / #S7(payment.completed event) / #S8(seating dup) / #S9(=#R15 realtime reconnect) / #S10(predicate timeout)。 以下 10 張卡片保留為歷史紀錄。

#S1 FIXED pos_settings RLS 完全開放 CRITICAL
症狀:`pos_settings` 表 RLS policy 用 `USING (true)` — **完全沒有租戶隔離**。任何登入用戶可讀任何餐廳的 POSSettings(零用金 / Expedite / petty_cash_asset_id)。
抓到:L5 設定表 audit 比對 RLS。
修法:加 `restaurant_id = current_setting('app.restaurant_id')` filter。
#S2 FIXED 4 個 account merge RPC 沒進 git migrations CRITICAL
症狀:`find_identity_owner` / `transfer_oauth_identity` / `insert_oauth_identity` / `list_user_identities` 4 個關鍵 RPC 只活在 production DB,**沒進 git tracked migrations**。Disaster recovery 重建不出 — 災難後帳號合併功能完全失效。
抓到:L5 帳號合併 audit 反查 migrations。
修法:從 production dump CREATE FUNCTION 補進 `supabase/migrations/`。
#S3 FIXED loyalty_point_batches 是 dead table → 點數過期完全不運作 CRITICAL
症狀:過期 cron 設計上要從 `loyalty_point_batches` 找出舊批次扣回,但**沒人寫這張表**(`expire-loyalty-points` edge fn 也沒 INSERT)→ cron 跑了也找不到資料,點數永不過期。客人點數可以無限累積。
抓到:L5 集點 audit。
#S4 FIXED tier 計算 JSON key 不對 → tier 永遠無法升級 CRITICAL
症狀:Edge fn tier 計算用 `min_points`(snake)但 tier 設定 JSON 是 `minPoints`(camel)→ 比較永遠 false → **沒有客人能從 bronze 升 silver/gold**。
抓到:L5 集點 §8 audit code。
#S5 FIXED reverse 不在 transaction_type CHECK constraint CRITICAL
症狀:CHECK constraint 只允許 `earn/redeem/adjust/expire`,但 Swift `reversePointsForPayment` 寫 `transaction_type='reverse'` → upload 被 DB 直接拒絕 → **客人退款後點數沒扣回**。
抓到:L5 集點 §6 audit + migration CHECK constraint。
#S6 FIXED 收貨 PO 完成後 inventory_levels 不更新 CRITICAL
症狀:`receive.ts:15-17` 明確 comment 寫「庫存管理另一條路徑」,但**那條路徑根本沒人接** → 食材庫存帳本永遠停在上次手動 adjust 的數字,進貨完全不影響庫存。同時點餐也不會扣食材(`trg_order_item_deduct_inventory` trigger 不存在)。整套 inventory 系統基本上是裝飾品。
抓到:L5 庫存 audit。
#S7 FIXED POS 結帳 / payment.completed event 從未 publish CRITICAL
症狀:audit_logs subscriber 設計上要收 `payment.completed` 等 event 寫 log,但**POS 端從來沒 publish 過任何結帳事件** → 結帳完全沒有 audit 紀錄。誰收錢、收多少、何時收、退款給誰 — 全空白。
抓到:L5 audit_logs §10。
#S8 FIXED attachWebhookDispatcher 從未被 call → 第三方 webhook 整個壞 CRITICAL
症狀:webhook 訂閱者 register 函式 `attachWebhookDispatcher` **從來沒被 call** → 設了任何 webhook URL 都不會 fire → 第三方整合(集團總部 / 外部 BI)全部空轉。
抓到:L5 audit_logs §10。
#S9 FIXED 4 個 realtime listener 沒 hook reconnect → 斷線後死掉 CRITICAL
症狀:`CheckoutPaymentListener` / `LateArrivalAlertService` / `RestaurantCheckoutSessionsMonitor` / `CustomerCheckoutMonitor` 4 個獨立 channel **沒有 hook `HybridSyncManager.$realtimeConnected`** → 網路斷線重連後 channel 死掉永不重連 → POS 收不到結帳 / 遲到 / 客人付款進度通知。只有 `ServiceRequestListener` 正確 hook。
抓到:L5 Realtime sync audit。
#S10 FIXED bulk import API 欄位名全錯 → 寫入失敗 CRITICAL
症狀:`/api/mcp/menu/bulk-import` 寫的欄位是 `description` / `stock_limit` / `category_id` / `is_available`,但 schema 實際是 `item_description` / `daily_stock_quantity` / `menu_category_id` / `is_active` → **大批匯入會直接失敗**。
抓到:L5 菜單管理 audit。

HIGH — 功能半廢 / 重要漏洞

#S11 FIXED AdHocTransactionSheet 不沖 balance(只寫流水) HIGH
症狀:臨時支出/收入只寫 `asset_transactions` 流水,**沒更新 `assets.current_balance`** → 帳本顯示的餘額永遠不對。dogfood 應該已踩過。
抓到:L5 Asset Ledger G4。
#S12 FIXED markAsLoss 寫 asset_id=NULL 違反 NOT NULL HIGH
症狀:`web/.../unsettled/supabase_repository.ts:243` 寫 `asset_id: null`,但 schema 是 NOT NULL → 標損耗會 throw。
抓到:L5 Asset Ledger G3。
#S13 FP dailyMenuStockReset cron 從未部署 HIGH
症狀:`dailyMenuStockResetOrchestrator` orchestrator 寫好了,但 **pg_cron 從來沒部署 schedule** → 每天該重設「daily stock」的品項永不重設,客人看到的 stock 數字會永遠失真。
抓到:L5 庫存 Gap F。
#S14 FIXED 沒任何 cron 清過期 squeeze pending HIGH
症狀:`auto-reject-stale-modifications` cron 只看 `guest_count_modification_status` / `time_modification_status`,**漏掉 `squeeze_request_status` 和 `modification_squeeze_status`** → 過期擠/喬看 pending 永遠不清,banner 持續存在。
抓到:L5 擠喬看 §10。
#S15 FIXED Path A/B 集點不 trigger wallet update → Wallet 卡點數不刷 HIGH
症狀:`awardLoyaltyPointsForPayment` 跟 `claim_payment_loyalty` 都沒 call `triggerWalletUpdate` → 客人付完錢點數加了,但**手機 Wallet 卡上點數不會即時更新**。
抓到:L5 集點 §9。
#S16 FIXED send-split-table-decision Edge Function 不存在 HIGH
症狀:migration `20260349` 寫了 trigger 呼叫 `send-split-table-decision`,但 `supabase/functions/` 下根本沒這目錄 → **客人申請拆桌後靜默收不到通知**。
抓到:L5 拆桌審核 §7。
#S17 FIXED 39 vs 56 realtime entity → 17 個沒實作同步 HIGH
症狀:SYNC_SYSTEM_ARCHITECTURE 文件寫「56 entity 全部 realtime」,實際 `UnifiedSyncRegistry` 只註冊 **39 個** → 17 個 entity 沒有 realtime,只能靠 watchdog 比對 + force refresh,延遲可能很長。
抓到:L5 Realtime sync。
#S18 FIXED expire-loyalty-points INSERT 缺 balance_after NOT NULL HIGH
症狀:expire cron 寫 `loyalty_transactions` 沒帶 `balance_after`,但 schema 是 NOT NULL → 萬一真的有點數要過期會 throw。
抓到:L5 集點 §7。
#S19 FIXED 分桌結帳重複抵用訂金(沒 applied_to_order_id 反向) HIGH
症狀:訂金抵用沒記錄「已抵到哪張結帳單」反向欄位 → **分桌結帳場景下訂金可能被抵兩次**(A 桌結帳抵了訂金,B 桌再開結帳又看到「未抵用」)。
抓到:L5 訂金管理 G5。
#S20 FIXED RPC 失敗時 POS 仍寫 approved → ghost 狀態 HIGH
症狀:擠喬看的核准 RPC 失敗時 POS 不檢查 `data.success`,本地仍把訂位標 approved 但 server 沒寫 → 客人看到還是 pending、員工以為已核准。
抓到:L5 擠喬看 §10。

MEDIUM — 邊角 / 累積技術債(15 個摘要,完整在各 L5 doc)

  • #S21 FIXED KDS `revert` 不會 reset `completed_at` → 統計誤算 · L5 KDS
  • #S22 `trg_auto_consume_reward` 用 legacy `'completed'` enum 應改 `'served'` · L5 KDS
  • #S23 FIXED `markUrgent` / Siri Intent 沒走 thin-client orchestrator · L5 KDS
  • #S24 FIXED `/api/menu` 不過濾 `is_active` → 隱藏品項對外仍可見 · L5 菜單
  • #S25 FIXED `enableSelloutPauseFeatureOrchestrator` 寫好但沒 API route caller(bypass 直打 Supabase) · L5 菜單
  • #S26 `forfeit` vs `forfeited` 字串不一致 + Swift enum 缺 case · L5 訂金
  • #S27 FIXED `recalcDeposit` 沒 `retained_as_credit` 路徑 vs SQL RPC 有 · L5 訂金
  • #S28 FIXED `topUpRequired` 結帳沒擋 · L5 訂金
  • #S29 FIXED Newebpay sandbox TradeSha 驗證關閉 · L5 訂金
  • #S30 FIXED 拆桌 approve 純 client mutate 沒走 orchestrator(違反 CLAUDE.md 第一原則)· L5 拆桌
  • #S31 FIXED `canApproveSplitTable` 純函式 gate 不存在 · L5 拆桌
  • #S32 FIXED tier_benefit 沒 dailyLimit UI、order_id 變動不會 re-trigger consume(reward race) · L5 兌換
  • #S33 FIXED v2 邀請過期 cron 缺 / 撤回 UI 缺 / Wallet 撤銷沒接 / QR 沒走 v2 orchestrator · L5 員工
  • #S34 FIXED Email 25 fn 中 legacy 沒 wallet update / refund 沒 wallet update / staff app URL placeholder · L5 Email
  • #S35 服務鈴 legacy route 沒 broadcast 備援 / Swift enum 缺 3 cases / fetch 沒 filter restaurant_id · L5 服務鈴

完整 audit list:這頁列 35 個,實際各 L5 doc 共標 90+ 個 。完整清單跟 root cause 走 sysmap 看 L5 doc §gap 章節。

L6 漣漪追蹤抓到的新 bug — 跨系統副作用層 (#R1-#R20)

L5 是「一個 function 做什麼」, **L6 是「按一個鈕之後系統全 stack 怎麼漣漪」**。 派 5 個 agent 跑 ripple trace(關帳/結帳/退款/訂位確認/員工終止),抓到 **18 個 cross-system bug**,L5 audit 看不到的(因為 L5 只看單一 function)。

CRITICAL — 跨模組副作用漏掉 全部 ship

#R1 FIXED 分帳全付清不 update orders.payment_status='paid' → 報表全漏算 CRITICAL
症狀:分帳模式 `checkout-mark-cash-paid` edge fn **只 update `order_items` 不 update `orders.payment_status`** → 老闆查「已付款訂單」報表時**分帳訂單全部漏算**。影響日結 / 月結 / 員工績效統計。
抓到:L6 結帳漣漪 §6 #G18(L5 看不到,因為 L5 只看 edge fn 不看下游報表怎麼讀)。
#R2 FIXED 現金退款不沖 PettyCash → 老闆冤枉員工偷錢 CRITICAL
症狀:走 `checkout-reverse-payment` 退現金時**沒從收銀機零用金 deduct** → 老闆關帳對帳發現實際現金比帳本少 → 以為員工偷錢。
抓到:L6 退款漣漪 #S-NEW-5。
#R3 FIXED FP 客人收兩封一樣的確認 email(舊 trigger 沒 DROP) CRITICAL
症狀:`20260337_robust_confirmation_email_trigger` migration **沒 DROP** 舊的 `20260313`(no_deposit)+ `20260228`(deposit)兩條 trigger → 客人訂位被確認時 **3 條 trigger 同時跑 → 收 2 封一樣 email**。
抓到:L6 訂位確認漣漪 G1。
#R4 FIXED generateMonthlyPayroll dedup 沒帶 restaurantId → 集團多店漏薪資 CRITICAL
症狀:月底自動產生薪資 cron 用 employee_id dedup 但**沒帶 restaurant_id filter** → 集團多店場景下,第二、三家店那個月的薪資**整批 silent miss**(老闆會以為員工沒上班)。
抓到:L6 關帳漣漪 G13(P0)。
#R5 FIXED 已 terminated 的 admin 仍可打 API 踢人(cached caller_role) CRITICAL · 安全
症狀:`terminateMember` API 用 client 端 cached `caller_role` 判斷,**沒 server 端 active member 重驗** → 已被終止的 admin 帳號在 cache 還沒清前仍能打 API 踢其他員工。
抓到:L6 員工終止 §9.6。
#R6 FIXED isSelfTerminate 比 auth.uid vs user_profile.id 多 provider 帳號誤判 CRITICAL · 安全
症狀:`isSelfTerminate` 比較 `auth.uid` vs `user_profile.id`,**多 provider 合併過的帳號可能誤判**(Apple 登入 + 員工資料是 Google) → 「不准踢自己」的保護可能 bypass(誤踢自己)或反向誤擋(踢不掉合作 owner)。
抓到:L6 員工終止 §9.1。

HIGH — 漣漪沒接到關鍵下游

#R7 FIXED 拒絕訂位只發 LINE 沒 email → 沒連 LINE 客人完全收不到 HIGH
症狀:`rejectReservation` 的 fan-out 只發 LINE push,**沒 email**。沒連 LINE 的客人完全不知道被拒絕,以為訂位還在等。
抓到:L6 訂位確認 G3。
#R8 FIXED rejectReservation 不取消 reward_redemptions.reserved HIGH
症狀:訂位被拒絕後,客人預約獎勵 (reward_redemptions.status='reserved') **沒被釋放** → 客人 points 被永遠扣住,無法再用。
抓到:L6 訂位確認 G8。
#R9 FIXED trg_update_loyalty_stats 用 customer_phone 配對 → 違反鐵則 HIGH
症狀:結帳 trigger `trg_update_loyalty_stats` 還在用 `customer_phone` 比對客人(該用 `customer_loyalty_id`),**違反 `feedback_no_phone_matching.md` 鐵則** → 兩個客人同電話會錯加點。
抓到:L6 結帳漣漪 #G5。
#R10 FIXED fire_user_silent_push_for_owners RPC 不存在但被 call HIGH
症狀:`retry-failed-refunds` cron 用這個 RPC 通知老闆退款重試失敗,但 migration 裡**根本沒這 function** → silent fail,**老闆永遠不知道哪筆退款卡住**。
抓到:L6 退款 #S-NEW-3。
#R11 FIXED staff.is_active 不會被 terminate 設 false → 排班報表誤撈 HIGH
症狀:terminate orchestrator 只清 `restaurant_members`,**不會把 `staff.is_active` 設 false** → 排班 / 工時 / 薪資報表 filter `is_active=true` 時仍會撈到離職員工,顯示異常工時。
抓到:L6 員工終止 Gap-B。
#R12 FIXED 關帳完全沒寫 audit_logs / 沒 publish event HIGH
症狀:`performClose` 完成 **0 條 audit_logs INSERT、0 個 EventBus publish、0 個 webhook** → 跟 #S7 結帳同坑,出事 root-cause 完全無從查。
抓到:L6 關帳 G7+G8。
#R13 FIXED send-refund-confirmation 是死 code → 退款客人收不到 email HIGH
症狀:`send-refund-confirmation` edge function 寫好了但**整個 codebase 沒人 call 它** → 客人退款成功永遠收不到確認 email。
抓到:L6 退款 #S-NEW-1。

MEDIUM L6 ripple — 7 個摘要

  • #R14 結帳 awardPoints 沒 call `triggerWalletUpdate` → 客人 Wallet 點數不刷 · L6 結帳
  • #R15 FIXED 3 個 Realtime monitor (CheckoutPayment/CustomerCheckout/RestaurantCheckoutSessions) 沒 hook reconnect (#S9 確認) · L6 結帳
  • #R16 FIXED Newebpay & 分帳發票不自動開立 · L6 結帳
  • #R17 `checkout-reverse-payment` 不寫 audit_logs(只 console.log) · L6 退款
  • #R18 FIXED `CheckoutPaymentListener` Realtime filter 排除 refunded → 多裝置 POS 不一致 · L6 退款
  • #R19 FALSE POSITIVE `applyOptimisticStatusUpdate` switch 不 cover `.confirmed/.rejected` → timestamp 短暫空白 · L6 訂位確認
  • #R20 FIXED 員工沒訂自己的 channel → 被踢時只能等下次 silent push · L6 員工

L6 為何抓得到 L5 沒抓的:L5 只看「這個 function 內部邏輯」,看不到下游 trigger / UI listener / cron / push 路徑斷掉。L6 用「**按一個鈕之後 1 小時內全 stack 變化**」追蹤,自然會撞到 cross-system gap。

2026-05-23 凌晨第三輪 audit 抓的 bug — #R21-#R50 + #F1-#F12

又派 17 個 agent 跑 5 個剩餘 L5 + 7 個 L6 + 5 個 L7 (欄位反向 index)。**L7 = 「這欄位被誰寫 / 誰讀 / 哪個 UI 顯示 / 改 enum 哪裡壞」**,給工程師重構時看 impact analysis。 抓到 80+ 新 bug,以下列重點。

CRITICAL 新發現 (#R21-#R30) 全部 ship

#R21 FIXEDAdHoc 從錢箱拿錢買文具 → 雙重計帳 -$400CRITICAL
症狀:老闆從錢箱拿 $200 買文具用 AdHocTransactionSheet 記 -$200,但 SettlementService.computeSettlement 從不讀 asset_transactions → 關帳時 cashShortage 又算 -$200 → **帳本變 -$400**。
抓到:L6 AdHoc 漣漪 G2 NEW。
#R22 FIXED員工代訂客人收不到任何通知CRITICAL
症狀:POS/app 員工代訂直接 INSERT `status='confirmed'`,但**三個 confirmation trigger 都是 AFTER UPDATE** → trigger 不觸發 → **客人收不到任何 email/LINE/wallet 通知**。
抓到:L6 新增訂位 G9。
#R23 FIXED FPauto-reject-stale-modifications cron 完全沒排程CRITICAL
症狀:`auto-reject-stale-modifications` cron 路由跟 orchestrator 都寫好了,但 **vercel.json + pg_cron 都沒排程** → 完全沒在跑 → 過期修改 pending 永遠不清。
抓到:L6 修改訂位 M8。
#R24 FIXED採購收貨流程沒 thin-client 化 → 食材價歷史不寫CRITICAL
症狀:iOS QuickReceivingView **仍直改 SwiftData**,`ChefsMateAPIClient.receivePurchaseOrder` 定義了但**沒人 call** → `decidePostReceiveStatus` + `recordIngredientPriceHistoryPrimitive` 在 iOS 收貨時**完全不會 fire** → 食材價漲跌無 audit。
抓到:L5 採購 #B1。
#R25 FIXED採購模組 0 個 role gate → RLS bypass 安全漏洞CRITICAL · 安全
症狀:整個採購模組 **0 個 role gate**,supabaseAdmin 直接走 → 任何登入員工(包含 staff)都能下採購單 / 收貨 / 標已付 → 大金額付款無 manager 卡關。
抓到:L5 採購 Permission Gap。
#R26 FIXEDchat 完全沒 push 通知 → App 關著就漏訊息CRITICAL
症狀:silent push v7 八種 alert event **完全不含 chat**,沒 DB trigger,App 關著就**漏訊息**。`faqPreset` broadcast 旗標也是死碼。
抓到:L5 Chat G3。
#R27 FIXEDchat 未讀計數沒人 +1 → 紅點 badge 永遠 0CRITICAL
症狀:`unread_count_staff` / `unread_count_customer` **只有 markRead 清零的邏輯,沒有任何 increment** → POS 端紅點 badge **理論上永遠是 0** → 員工永遠不知道客人有發新訊息。
抓到:L5 Chat G1/G2。
#R28 FIXEDL3 文件寫 daily_closes.is_catchup=true 但欄位根本不存在CRITICAL · 文件謊話
症狀:L3 補關帳文件寫「daily_closes.is_catchup=true 標記」,但**這欄位根本不存在於 DB**。靠這欄位 filter 報表 / 統計通通是空 query。
抓到:L6 補關帳 G20。
#R29 FIXEDsellout 已 submit 的 order_items 不自動處理CRITICAL
症狀:菜剛點完還沒做就被標售完,**KDS 仍會繼續做下去** → 客人吃到「已沽清」的菜 → 出餐失控。沒有任何 logic 把 in-flight order_items 退回去問客人。
抓到:L6 沽清 G11 NEW。
#R30 FIXEDAddTransferSheet / AddLiabilityPaymentSheet 不寫 asset_transactionsCRITICAL
症狀:主 App 的轉帳 sheet 跟還款 sheet **完全不寫 `asset_transactions` 流水**(只寫另一個表),導致 sum(asset_transactions) **永遠對不上 assets.current_balance**。
抓到:L7 assets.current_balance G-NEW-7。

HIGH 新發現 (#R31-#R45)

  • #R31 拒絕修改 email 靠 POS dual-path 寄送,POS HTTP 失敗 = 客人收不到 · L6 修改訂位 M4
  • #R32 FIXED auto-reject cron 同意 / 拒絕都不寄 email,客人完全不知 · L6 修改訂位 M9
  • #R33 FIXED Phase A 同意修改會重複寄信 (POS 寄 + trigger fallback 又寄) · L6 修改訂位 M5
  • #R34 FIXED deposit.top_up_required event 沒 subscriber → recalc 後客人不知要補繳 · L6 修改訂位 M7
  • #R35 FIXED 智慧入座 Path C 跳過 arrived 直接 seated → arrivedAt 永遠 NULL → 等待入座時間算不出 · L6 markArrived G2
  • #R36 FIXED markArrived 後 LateArrivalAlert banner 沒自動 dismiss (仍掛 ≤5min + 3h TTL) · L6 markArrived G3
  • #R37 FIXED markArrivedAndAdd 信用分 +20 函數寫好但 orchestrator 沒接 · L6 markArrived G5
  • #R38 FIXED 客人到店完全沒「您已報到」確認通知(無 email/LINE/wallet/push) · L6 markArrived G6
  • #R39 FIXED BatchRetroCloseSheet 完整實作但**整個 codebase 無 entry point**(dead code) · L6 補關帳 G17
  • #R40 FIXED 補關帳 BudgetSnapshot 補產生不回填後續日的 cumulativeRevenue → 永遠少 · L6 補關帳 G14
  • #R41 FIXED 補關帳 AssetTransaction date 錯位:revenue=過去日期 / 零用金扣=今天 · L6 補關帳 G15
  • #R42 FIXED 補關帳該日有 interim 紀錄就無法補 final(existingCloses predicate 沒 filter closeType) · L6 補關帳 G19
  • #R43 FIXED 加菜送單 — 客人桌邊 web 看不到 POS 加菜(沒接 Realtime) · L6 加菜送單 #S31
  • #R44 FIXED 加菜送單 — 三路 (POS/QR/PreOrder) mergeable 邏輯不一致 → 同點餐不同行為 · L6 加菜送單 #S34
  • #R45 FIXED 沽清 — daily reset cron 未部署(再次確認 #S13)+ 重複按 markSoldOut 重複寄信(G7 NEW) · L6 沽清

L7 欄位反向 index 抓到的 inconsistency (#F1-#F12)

L7 是「**這個欄位被誰寫 / 誰讀 / 誰顯示**」反向地圖。掃 schema vs code 抓出 enum mismatch / dead enum / 兩套並存等。

  • #F1 payments.status **沒有 CHECK constraint** → 純 free-form TEXT,任何字串都能寫進去 · L7
  • #F2 cleanup-stale-payments 寫 `'cancelled'` 不在 enum,Swift Mapper fallback 變 `.pending` → 雙裝置不一致 · L7 payments
  • #F3 mcp/analytics/sales 讀**不存在的 `completed_at` 欄位**(實際叫 `paid_at`)→ endpoint 整個壞 · L7 payments
  • #F4 FIXED reservations.status CHECK migration `20260503002` **drop 掉 'rejected'** → local reset 會 break rejectReservation · L7 reservations
  • #F5 FIXED POS list `pendingCount` badge **漏算 `splitTableStatus='pending_approval'`**(filter 有但 badge 沒) · L7 reservations
  • #F6 (FP) `create_reservation_atomic` capacity check **漏 'completed'** → capacity 低估 · L7 reservations
  • #F7 FIXED smart-seating 6 個 status filter,**只有 L539 漏 'completed'**(其他 5 個都包) · L7 reservations
  • #F8 `status='cancelled'` 沒任何 DB trigger → 取消 email 純 orchestrator fire-and-forget(silent failure 風險) · L7 reservations
  • #F9 FIXED **`current_points` 欄位根本不存在 schema** — 實際是 `available_points`(audit 過程發現,L5 audit 用錯名 → 修正後三欄位一起 audit) · L7 loyalty
  • #F10 `redeemPoints` 扣 total points / `consume_reward` 不扣 → 雙路不對稱 · L7 loyalty
  • #F11 `orders.payment_status` 沒 CHECK constraint;退款完全沒人寫 `'refunded'`(enum 定義了但零 writer) · L7 orders
  • #F12 新 thin-client `settlePaymentOrchestrator` (feature flag `paymentThinClientSettle`) 也不寫 `orders.payment_status` → 開 flag 後 #R1 不只沒修還擴大 · L7 orders

#R1 critical 修正(L7 audit 後):L7 orders.payment_status 揭示 #R1 影響範圍**比原本想的小** — 營收金額本身**沒漏算**(因為 DailyClose / POSReportService / 桌位釋放 全部走 `payments` 表),受影響的是「補關帳清單 / 部分付款 badge / CSV / boss 報表 filter」這 4 個 reader。 **建議根本修法**:在 `order_items` 加 AFTER UPDATE payment_status trigger 重算 parent,別繼續逐路徑 patch。

2026-05-23 第四輪 audit — L7 補 4 個欄位 + 暫停接訂位 L6 + 訂位重構 audit (#G + #R46-R55)

派 7 個 final agent 補完所有剩下的 audit。**抓到 4 個 P0 critical**(主要是「老 enum 還在 code 裡」+「雙 state machine 第 4 次踩坑」)。

第四輪 CRITICAL 新發現 全部 ship

#R46 FIXED店休日已有訂位完全不通知客人CRITICAL
症狀:老闆設下週一店休,但**那天已有 5 組客人訂位** → 系統完全不通知 → 客人到店發現公休。
抓到:L6 暫停接訂位 #G1。
#R47 FIXEDcreateReservation 沒查 pause_days → POS 仍能在店休日強制建單CRITICAL
症狀:你設了店休日後,**POS 還是能在那天新增訂位**(沒擋)→ 員工不知情代訂 → 同 #R46 一樣客人撲空。
抓到:L6 暫停接訂位 #G2。
#R48 FIXED暫停接訂位 API RLS bypass 安全漏洞CRITICAL · 安全
症狀:`/api/reservations/pause-days` 用 `service_role` + **client-supplied `caller_role`** → 任何登入用戶把 caller_role 改成 'owner' 就能擅自暫停別家餐廳接訂位。
抓到:L6 暫停接訂位 #G12。
#R49 FIXED第 4 次踩雙 state machine 坑 — guest-status 永遠錯CRITICAL
症狀:`guest-status` edge fn 把 `orders.status` 拿去跟 `'served'`/`'ready'` 比(那是 `order_items.status` 的值)→ **永遠 false** → 客人看訂單進度永遠錯誤。memory 記錄「踩過 3 次」這是第 4 次。
抓到:L7 order_items.status #R24 NEW。
#R50 FIXED客人加菜核准後廚房看不到(寫 'pending' 廚房 filter 排除)CRITICAL
症狀:客人在桌邊申請加菜,老闆 POS 核准,`approve-order-modification` 把 add 進來的 order_items 寫 `status='pending'`,但其他送單路徑都寫 `'confirmed'` + **廚房 KDS filter 排除 pending** → 客人加的菜廚房**根本沒看到** → 客人坐著等永遠等不到。
抓到:L7 order_items.status #7.7 NEW。
#R51 FIXED獎勵兌換 trigger 用舊 enum 'completed' → 小餐廳永不 consumeCRITICAL
症狀:`trg_order_items_auto_consume_reward` 監聽 `status='completed'`(舊 enum),但 order_items state machine 早已改成 `'served'`(per 2026-04-27 migration)→ **trigger 永遠不觸發** → 客人預約獎勵到桌也不會被標 consumed。
抓到:L7 order_items.status #S22 confirmed。
#R52 FIXED多店月聚合漏 'final' filter → 報表雙倍計入CRITICAL
症狀:`report-analytics:248` 跨餐廳月聚合查詢**漏掉 `eq close_type='final'`** → interim 小結也被算進去 → 集團月報營收**雙倍計入**(每日 interim + final 都加一次)。
抓到:L7 daily_closes #7.8 NEW。

HIGH 第四輪 (#R53-#R55 + L7 deposit findings)

  • #R53 FIXED daily_closes 漏 3 個 coupon 欄位(DTO 寫了 schema 沒接)→ 優惠券折抵總額永遠寫 0 · L7 daily_closes #7.5
  • #R54 FIXED `forfeit` vs `forfeited` 三方不一致(Swift 沒 case / TS 寫 forfeited / repo 寫 forfeit)→ 訂金狀態根本沒 single source of truth · L7 deposit G1
  • #R55 FIXED 暫停接訂位 2 套並存 (restaurant_pause_days vs special_dates.paused) → 一邊設、另一邊看不到 · L6 暫停接訂位
  • #R56 FIXED POS 加菜送單後客人桌邊 web 看不到 (沒接 Realtime) · L6 加菜送單 #S31
  • #R57 `is_admin_of` RPC **漏算 admin** (只 check owner) — admin 角色升級後沒人補這個 RPC · L7 role
  • #R58 Web API `VALID_ROLES` 仍含 `'chef'`(2026-04-24 deprecation 沒清乾淨)+ ReservationGates.swift:131 hard-code 老 role 字串 · L7 role
  • #R59 FIXED 訂位重構 3 個 P0 缺口:overbooked event 沒實作 / 會員卡同步補救 cron 沒做 / auto no_show cron edge fn 沒做 · L5 重構 audit

完整 audit 完成度:32 L5 + 14 L6 + 9 L7 + 1 重構 audit = **56 個 deep doc**,**220+ bug 標 **(實際每個 doc §gap 都更多)。 老闆從這個地圖任一點都能 drill 到精確 file:line。

系統地圖完整大綱進度 — 哪些完成、哪些待補

系統地圖在 chefsmate.app/sysmap/。 下面是**完整 L0-L5 大綱**,綠色 = 完成可看、黃色 = 草稿(內容有但深度不夠)、紅色 = 未做。 點任一條 直接跳對應文件。

L0-L1(設計哲學 + 客人旅程 + 橫貫基礎)

  • L0 設計哲學:3 元件符號 / 4 實作類型 / 4 組合原則 ·
  • L1 客人旅程:10 階段時間軸 + 10 橫貫基礎設施 + 完整 mermaid ·
  • 老闆視角:POS App 內部 5 layer + 7 tabs + 14 banner + 18 sheet ·

L2 — 12 個 L2 架構文件(全部 clickable Mermaid)

  • 訂位 ·
  • 結帳 ·
  • 關帳 ·
  • 點餐 ·
  • 菜單庫存 ·
  • 入座出餐 ·
  • 接待離店 ·
  • 會員獎勵 ·
  • 支付資產 ·
  • 稽核設定 ·
  • 通知聊天 ·
  • 員工權限 ·

L3 子模組(26 個)

  • 結帳 6 個 L3:結帳單生成 / 分帳 / 折扣 / 優惠券 / 發票 / 退款爭議 — 全部已寫(範疇 + 3 情境 + Mermaid + 實作位置 + 上下游)
  • 關帳 6 個 L3:關帳 / 小結 / 補關帳 / 批次補關 / 現金盤點 / 報表 — 全部已寫
  • 點餐 7 個 L3:送單 / 預點轉正式 / 修改已送單 / 加料客製 / 控單 / 菜單瀏覽 / 購物車 — 全部已寫
  • 訂位 L3 系列(列表 / 座位 / 預約兌換 / 會員卡關聯)— 較早完成,內容深
  • 員工權限 L3(員工操作權限 / 權限檢查慣例 / 角色整合對照)

L4 電路圖(20 個)

  • 所有 L4 都加了「L4 → L5 / L2 鑽取圖」navigation Mermaid(可點下鑽)
  • 主流 5 個 L4(訂位 / 點餐 / 結帳 / 關帳 / 通知)有對應 L5 完整 drill-down
  • 原本 9 個 L4 標「⏳ L5 待補」的全部已補(菜單庫存 / 支付資產 / 會員獎勵 / 入座出餐 / 接待離店 / 稽核設定 / 員工管理 / 帳號合併 / 訂位重構)

L5 程式碼層(24+ 個)

第一批 7 個(2026-05-23 上午完成)

  • 訂位 取消退款 · L5
  • 訂位 建立與智慧排桌 · L5
  • 訂位 生命週期 · L5
  • 結帳 付款 · L5
  • 關帳 完整流程 · L5
  • 點餐 thin-client v3 · L5
  • 通知 silent push v7 · L5

第二批 17 個(2026-05-23 下午 21 個並行 audit 中,以下已完成)

  • 服務鈴 realtime(627 行)· L5
  • 資產 Ledger 帳本(741 行,6 bug)· L5
  • Wallet Pass(1067 行)· L5
  • audit_logs EventBus(804 行,8 bug)· L5
  • LINE messaging(622 行)· L5
  • KDS 出餐流程(1060 行,6 bug)· L5
  • 會員集點 3 paths(992 行,7 HIGH bug)· L5
  • 帳號合併 四向 provider(963 行,8 bug)· L5
  • 庫存盤點與沽清(1213 行,14 bug)· L5
  • 菜單完整管理(975 行)· L5
  • 預約兌換履約鏈(969 行)· L5
  • 訂位 拆桌審核(906 行)· L5
  • 員工管理 v2(939 行,9 gap)· L5
  • Email 25 edge fn(714 行,10 gap)· L5
  • 接待 公開頁與探索(712 行,12 gap)· L5
  • 權限完整矩陣(1091 行)· L5
  • 訂位 訂金管理(942 行,10 gap)· L5
  • Realtime sync 雙軌(818 行)· L5
  • 設定表完整對照(985 行)· L5
  • 點餐 預點餐(860 行,8 gap)· L5
  • 訂位 擠喬看(808 行,8 gap)· L5

第三輪補完 — 原本「剩下還沒做的 L5」也全部 ship

  • 訂位重構設計 audit · L5
  • 採購 / Vendor 管理 L5 · L5
  • Chat 客服系統(店對客 + 員工內部)L5 · L5
  • FAQ 自動回覆 / ChatFAQCarousel L5 · L5
  • 桌位 floor_items 設計工具 L5 · L5
  • Reports 報表系統 L5 · L5

L5 第三輪補完(2026-05-23 凌晨新增)

  • 採購 Vendor 管理 (808 行,10 bug 含 #R24 收貨沒 thin-client) · L5
  • Chat 店對客 + 內部 (864 行,13 bug 含 #R26/#R27 critical) · L5
  • FAQ 自動回覆 (509 行,8 gap;揭露「自動回覆」沒 AI) · L5
  • 桌位設計工具 (811 行,完整 #B11 跨餐廳污染慘案 + self-heal RLS 災難) · L5
  • Reports 報表系統 (1003 行,8 gap + #G18/#S5 對戰情室污染路徑) · L5

L6 漣漪追蹤(新層,2026-05-23 老闆問「L6/L7?」後補)

L6 寫的是「**按一個鈕之後系統怎麼一波一波擴散**」。一條 sequence diagram 追完整 timeline 從 T0 到 T+月底所有 cascading 副作用 / UI 刷新 / push / cron。 對應老闆問的「關帳的時候系統到底做了什麼?紀錄關帳金額、更新什麼表?觸發哪裡 UI 刷新?」

  • 關帳 漣漪追蹤(990 行,13 gap 含 P0 集團薪資 dedup bug) · L6
  • 結帳 漣漪追蹤(864 行,20 gap 含分帳報表漏算 critical) · L6
  • 退款 漣漪追蹤(819 行,5 NEW gap 含現金不沖 PettyCash) · L6
  • 訂位確認 漣漪追蹤(734 行,10 gap 含 2 封重複 email) · L6
  • 員工終止 漣漪追蹤(584 行,11 gap 含 2 security bug) · L6
  • markArrived 漣漪 (569 行, 8 gap) · L6
  • 加菜送單 漣漪 (626 行, 5 NEW gap) · L6
  • 修改訂位 漣漪 (1151 行, 18 gap 含 4 critical) · L6
  • AdHoc 記帳 漣漪 (678 行, 9 gap 含雙重計帳 critical) · L6
  • 新增訂位 漣漪 (830 行, 12 gap 含員工代訂沒通知 critical) · L6
  • 菜單沽清 漣漪 (770 行, 14 gap 含 in-flight 不處理 critical) · L6
  • 補關帳 漣漪 (1017 行, 7 unique gap 含 is_catchup 欄位不存在 critical) · L6
  • 暫停接訂位 漣漪 (714 行, 14 gap 含 RLS bypass 安全漏洞 + 店休日已有訂位不通知) · L6
  • 預約兌換 漣漪 (NEW 2026-05-23,反映 #S32 reward race + #S34 wallet trigger 修復) · L6

L7 欄位反向 index(2026-05-23 凌晨開做)

L7 = 「**這個欄位被誰讀 / 誰寫 / 哪個 UI 顯示**」反向地圖。給工程師重構時看 impact analysis。 每個 L7 doc 完整列 writers / readers / UI / triggers / 改 enum 哪裡壞 / 已知 inconsistency。

  • payments.status (374 行, 5 inconsistency 含 cleanup 寫不存在的 enum) · L7
  • reservations.status (620 行, 10 inconsistency 含 'rejected' enum drop 災難) · L7
  • customer_loyalty.current_points → available_points (900 行, 20 inconsistency, 修正 L5 欄位名錯) · L7
  • assets.current_balance (814 行, 11 inconsistency 含 AddTransfer 不寫流水 critical) · L7
  • orders.payment_status (590 行, 修正 #R1 影響範圍,5 新 writer/reader bug) · L7
  • daily_closes.total_revenue (542 行, 14 inconsistency 含 coupon dead column + 多店漏 filter critical) · L7
  • restaurant_members.role (797 行, 9 inconsistency 含 dead chef 殘留 + is_admin_of 漏 admin) · L7
  • order_items.status 雙 state (1343 行, 11 inconsistency 含**第 4 次踩雙 state 坑**) · L7
  • deposit_status (619 行, 7 gap 含 forfeit vs forfeited 三方不一致) · L7

L5 訂位重構設計 audit (2026-05-23 凌晨補)

  • 訂位重構設計 audit (617 行, L4 2032 行設計案 vs code 對照,80% 已 ship + 3 個 P0 缺口) · L5

Viewer 基礎設施

  • Markdown viewer + Mermaid + ToC sidebar + scroll-spy ·
  • 老闆視角 ↔ 客人視角 mode toggle
  • Phase A 修 6 個 drifted L4 + Phase B/C/D 全完工
  • ⏳ D.0 viewer inline code excerpt 渲染(看 L5 仍需切 GitHub)

整體 audit 統計

指標 數量 說明
L2 完整12/12100%
L3 草稿26/2619 草稿級 + 7 內容深
L4 含 nav20/20100% 可下鑽
L5 程式碼層34/34100% 完成,含訂位重構 audit + 採購 / Chat / FAQ / 桌位 / Reports 全補
L6 漣漪追蹤14/14100% 完成(2026-05-23 新增第 14 個:預約兌換漣漪)
L7 欄位反向 index15/15**100%** payments/reservations/loyalty(2 個)/assets/orders(2 個)/daily_closes/role/order_items(2 個)/deposit(2 個)/staff/audit_logs/coupon
audit 抓 bug 總數290+#S1-S35 / #R1-R66 / #F1-F12 / L7 各 doc §gap
已 FIXED6412 個 commit deploy (Batch 1-12) + #R4/#R64/#R66 Swift 收尾 + #R48 暫停 RLS bypass + #F6 false positive 驗證 + Batch 13 (#R21/#R29/#R26/#R2/#S1/#S6 共 6 個老闆拍板 Swift 全套)
FALSE POSITIVE5#R3 / #R23 / #R28 partial / #F6 / #S13 — 都是 live DB 驗證 audit 抓錯
Swift UI 改動待做0全部 ship (#R2 / #R29 / #R26 / #R21 / #R4 / #R64 / #R66 + #S1 / #S6 階段三 已 xcodebuild + 進入已完成封存)
Mermaid 圖總數320+分散在 130+ 個 markdown

2026-05-23 系統地圖 100% 收尾:L2 12/12 · L3 26/26 · L4 20/20 · L5 34/34 · L6 14/14 · L7 15/15 · D.0 viewer code excerpt ship。 所有 critical bug 都 file:line 為證 + 真實場景驗證指南。
修 bug 進度:40 個 inline bug 已修 + 1 false positive(Batch 14-26)+ 早期 Batch 1-13 共 25 個。剩 0 個 audit bug,只剩 #D1/#D2/#D3 老闆拍板的決策題。

夜間健康檢查計劃 第五波完成 · 60 fixed / 0 critical 🎉

完整計劃內容已搬到 後台主控台 專屬頁面(避免兩處要同步更新)。 包含 POS 10 模組進度 checklist、findings 按重要性/功能性/功能流三維分類、狀態流轉。

前往 docs.chefsmate.app / health-check
完整計劃、checklist、三維分類、狀態追蹤
✓ 已修
60
第一/二/三/四/五波
🔴 Critical open
0 🎉
原 34 全清
🟠 High open
44
原 71
🟡 Medium
65
⚪ Low
20

夜審 — POS 模組巡邏式 audit Phase 1 啟動 2026-05-27

老闆 2026-05-27 設定:每次說「我要睡覺 / 晚安」AI 自動啟動超深度 audit。 從 POS 開始,輪流深審 10 個模組,一邊跑一邊核對 sysmap 三份文件 (流程邏輯圖 / 功能地圖 / Edge Functions 地圖)。 所有 finding 只回報、不自動修(老闆指定),早上醒來自己決定 priority。 完整 workflow:docs/夜審工作流.md

2026-06-03 訂位三系統總體檢(老闆睡前指定)

體檢範圍:LINE 訂位 + POS 訂位 + web 訂位 三系統完整 codebase × 系統地圖比對,外加 restaurant_id 跨餐廳範圍掃描(老闆指定「看其他地方有沒有同樣問題」)。 共找到 40 個 bug —— 2 嚴重 14 高 18 中 6 低只回報、未自動修(夜審慣例)。

→ 進入「夜審 Bug 修復區」看全部 165 個未修 bug(可分類、點開看白話詳情)
🚨 兩個「嚴重」漏洞,建議天亮第一件事就修(白話):
  1. 任何人不用登入就能清空你整間店的資料 —— admin/reset-data 只要知道餐廳代號(QR/網址可見)就能把訂位/訂單/付款全刪光,救不回來。
  2. 任何有帳號的人能下載別家完整財報+食譜 —— report-analytics 輸入別家餐廳代號就拿到對方營收、成本、食譜配方、客群,商業機密全外洩。
⚠️ 另外 12 個「高」風險的跨餐廳漏洞(同類根因):

live-seating / guest-status / seating-day-overview / compute-settlement / orders-bulk-resolve / loyalty-analytics / business-schedule 等端點 沒驗權或信任 client 傳的角色,可跨餐廳讀客人電話、改別家供餐時段、亂退訂金。所有訂位 orchestrator 也沒檢查訂位的 restaurant_id 歸屬。
根因一句話:2026-05-28 那次安全強化只補了約 1/3 的端點,deposit/cancel/modify/split-table/多支 edge fn 還在信 body 的 actor_role,且 /api 不過 middleware。建議做一次全面 verifyRestaurantMember 覆蓋率盤點 + CI lint 擋。

功能性 bug(非安全,各系統摘要):

LINE: reviewer 白名單在 confirm/reply 被架空、hold 轉正式信任 client 人數/日期可超賣、hold 建立缺唯一約束有 race、假電話 0900000000 造成假重複。
POS: Agenda「還有 N 空位/可秒批」建在捏造的座位數(不讀真實桌位)上、訂位 @Query 全缺 restaurant_id 過濾、月曆 heatmap 與容量算法 pending 口徑不一致、今天加的 .hold 在詳情頁/進度條/系統地圖三處沒補齊。
web: 建單沒傳 slotCapacity → 時段超賣檢查被跳過、approveModification 自動確認失敗卻回 success、部分退款用四捨五入百分比換算金額會差幾元。

Phase 1 Cycle — 10 個 POS 模組輪流

01. POS 認證與帳號
✓ Cycle 1 完成 — 2 critical / 5 high / 11 medium / 2 low
02. POS 訂位
✓ 2026-06-03 訂位三系統總體檢 — 見上方紅色摘要(2 嚴重 / 14 高)
03. POS 接待 / 入座 / 候位
尚未審查
04. POS 點餐
尚未審查
05. POS 廚房 / KDS
尚未審查
06. POS 結帳 / 分帳 / 折扣 / 優惠券 / 發票
尚未審查
07. POS 會員 / Wallet / 獎勵
尚未審查
08. POS 關帳 / 記帳 / 報表
尚未審查
09. POS 菜單 / 樓面 / 員工
尚未審查
10. POS 聊天 / 設定
尚未審查
已審模組
1 / 10
Critical
2
High
5
Medium
11
待 review
1
下次睡覺說一聲
將審 → 02. POS 訂位(第 1 輪)

最近的 audit

CYCLE 1 · #01 01. POS 認證與帳號 — 完成 2 critical / 5 high 11 medium / 2 low
跑了:2026-05-27 22:57 → 23:13(16 分鐘)· 30 個 files audited · 20 個 findings · 6 個 sysmap corrections · Audit ID ef4c5281

Critical(2)— 立即看

  1. canDeleteAccount sole-owner 檢查永遠回 trueAuthManager.swift:1034-1046 用 authUserId 查 restaurant_members.user_id,但該欄位實際存 user_profile.id,query 永遠 0 筆 → client 防線是 dead code。若 server RPC 也沒檢查,老闆可直接刪自己唯一 owner 餐廳變孤兒(category: bug)
  2. delete-account Edge Function 是 dead code — sysmap 1.11 詳述 Edge Function 6 階段,但 AuthManager.swift:1108 實際只 client.rpc('delete_user_account')。RPC source 沒在 migration 內 → 無從稽核(category: doc_mismatch)

High(5)— 本週看

  1. send-staff-invitation-email 沒驗證 caller — 任何持 anon key 者可暴力試 invitation_id UUID 觸發官方 email 寄信,可被用來 phishing(security · supabase/functions/send-staff-invitation-email/index.ts:43-72)
  2. email-link-merge 是密碼 oracle — signInWithPassword 無 rate-limit,Edge Function 統一從 Supabase IP 出去 bypass per-IP rate-limit,可用來對任意 email 暴力試密碼(security · email-link-merge/index.ts:91-100)
  3. oauth-link-merge / line-link-merge open redirect — redirect_after query param 沒 allowlist,可釣魚把 merged_cards 資訊 leak 到 attacker.com(security · oauth-link-merge/index.ts:188-199)
  4. StaffQRCodeView Realtime channel 沒 hook reconnect — WiFi 抖一次,老闆掃完 QR 員工 UI 永遠停在 QR 畫面要殺 App。直接踩過的 [[feedback_realtime_channel_must_hook_reconnect]] 慘案(bug · StaffQRCodeView.swift:207-240)
  5. Sysmap 1.8 角色選擇分支描述跟 code 不符 — RoleSelectionView 不直接導航,實際走 OnboardingView 分流,sysmap 跳過整層(doc_mismatch · RoleSelectionView.swift:208-224)
展開全部 Medium(11) + Low(2)
  1. [medium · doc_mismatch] Edge Functions 地圖 §11 漏列 send-staff-invitation-email
  2. [medium · doc_mismatch] Sysmap 1.9 沒提 addStaffByQR 路徑(老闆掃 QR 跳過 pending)
  3. [medium · bug] SignInView onSignInSuccess 可被觸發 2 次(action 直接呼叫 + onChange 又呼叫)
  4. [medium · bug] StaffPendingApprovalView.loadRestaurantName 用 searchRestaurants('') 拉全表 20 筆 dead code + 洩漏
  5. [medium · perf] StaffPendingApprovalView 輪詢永不超時 + sleep 固定 10 秒
  6. [medium · bug] AppleSignInCoordinator nonce charset 漏字母 W
  7. [medium · bug] EmailVerificationView.verifyOTP 成功 path 不重設 isVerifying
  8. [medium · bug] StaffJoinRestaurantView.submitJoinRequest 成功不重設 isSubmitting
  9. [medium · bug] createGroupWithRestaurant 沒事務性 — 餐廳建好但集團失敗 → 孤兒餐廳
  10. [medium · doc_mismatch] Sysmap 1.5 #4「loadUserData 失敗無回滾」已過時(catch 已加 isProfileLoaded)
  11. [low · todo_debt] SignInView 服務條款 / 隱私政策按鈕是 TODO(Apple 審核會抓)
  12. [low · todo_debt] send-staff-invitation-email App Store 連結是 placeholder

Sysmap 修訂(6)— 已套用

  • POS_流程邏輯圖.md § 1.5 / 1.8 / 1.9 / 1.11 — 4 處改
  • POS_功能地圖.md § 1 OnboardingView 真實角色定位
  • POS_Supabase_Edge_Functions地圖.md § 11 加 send-staff-invitation-email
⚠️ 老闆指定:所有 finding 只回報、不自動修。請自己決定修哪個 / 推哪個 / 排哪個 sprint。
夜審工作流是怎麼跑的?
  1. Trigger:老闆說「我要睡覺 / 睡了 / 晚安 / good night」
  2. 決定模組:AI 跑 boss_nightly_audits_next_module() RPC 挑「最久沒審」的模組
  3. 佔位:INSERT 一筆 agent_status='running' row 進 boss_nightly_audits
  4. 啟動 Agent:Spawn 一個 background general-purpose Agent,任務範本在 docs/夜審工作流.md §4
  5. Agent 做 4 件事:(A) sysmap 三份文件比對 (B) Security audit (RLS / secret / 匿名 mutation) (C) Bug 風險(SwiftUI gotchas / sync 污染 / dual-path race) (D) Doc debt
  6. 眼見為憑:每筆 finding 必附 file_path + line + 10 行 evidence_code_snippet,不能用猜的
  7. 醒來:UPDATE row 寫 findings,在這頁加新卡片,改對應 sysmap doc,git push

高風險 = 只回報、不自動修。即使是 critical,AI 也不能 push code 修(老闆指定)。

跨 App 權限 / 隔離 / 集團架構 Audit — 2026-05-20 P0 已修

老闆 2026-05-20 問了 4 個大哉問,我做完完整 audit + 立即修了 P0 漏洞, 並把後續 12 個月的「集團總部 + 區經理 + 中央廚房 + 開分店顧問 AI + BYOA」 路線寫成 V3 Spec(點這裡看完整 12 個月計劃)

整體分數: P0 修完 / 後續看 V3 Spec

  • 自動登入(5/5 App):POS / 客人端 / web / StaffsMate Flutter / Vendor 全綠
  • 本地 DB 隔離(5/5 修完):POS & 客人端用 per-restaurant SQLite container(物理隔離),web stateless,StaffsMate 純 API,Vendor module 已補 restaurantId predicate(2026-05-20)
  • Supabase RLS(已修):已套用 P0 migration — daily_menu_settings + reservation_modification_holds 加 RLS,menu_option_* 補 policies,staff_payroll_history 收緊到 restaurant_id 範圍,6 張廣寬 policy 表全部 tenant-scoped。0 張裸奔(除 PostGIS 系統表)。
  • 集團架構:F6 migration 設計接近 Lightspeed,優於 Square。下一步看 V3 Spec 的 6 phases 12 個月路線圖
2026-05-20 修正: 上一版我寫的「16 張 table 裸奔 / 56 張 is_authenticated()」數字不準。 實際用 Supabase MCP 查 production state 後: 真正 RLS=false 只有 2 張(daily_menu_settings, reservation_modification_holds) + 4 張 RLS 開但無 policy 的 menu_option_* 家族。 USING(true) 過寬 policy 約 30 張,其中 6 張有 restaurant_id 可立即 scope, 其他(tactic_plans / prep_* / user_settings)是 schema 設計債,需要先加 restaurant_id 欄位 — 留到 V3 phase 4 處理。

P0 — 本週必修(資安級嚴重度)

#SA1 真正裸奔 / 缺 policy / staff 薪資的 RLS 已全修 已修
實際做了什麼:20260520_security_audit_p0_fixes migration 已 apply 到 production(透過 Supabase MCP), 並已從 production 反向 dump 回 repo:supabase/migrations/20260520001_security_audit_p0_fixes.sql(2026-05-21 補檔,版控完整)。
  • daily_menu_settings ENABLE RLS + via menu_items.restaurant_id
  • reservation_modification_holds ENABLE RLS + via reservations.restaurant_id
  • menu_options / menu_option_choices / menu_option_applicable_items / menu_option_applicable_categories 補 policies(之前 RLS=true 但無 policy = 完全鎖死)
  • staff_payroll_history:把 USING(true) 換成 staff.restaurant_id 隔離(員工薪資不再被任意 user 讀到)
  • 6 張有 restaurant_id 的廣寬 policy 表全部 scope:ingredient_price_history / gallery_items / wallet_device_registrations / menu_item_pairings / error_reports / dining_sessions
驗證:跑 pg_tables + pg_policies query — 除 PostGIS 系統表外, 0 張裸奔 / 0 張缺 policy。
#SA2 tactic_plans / prep_* 等 schema 設計債 — 規劃在 V3 V3 P4
狀況:約 20 張表用 USING(true)表本身沒 restaurant_id 欄位, 沒法立即 scope。最關鍵:tactic_plans / tactic_plan_items / tactic_plan_histories 完全沒 restaurant_id — 戰術 plan 目前全集團共讀。
修法:加 restaurant_id 欄位 + 回填舊資料 + 換 policy。 這是 schema migration,風險較高,需要先 query 看實際 row 量。
排到:V3 Spec § AI V3 升級 Phase 4 (M7-M8)。
#SA3 ChefsMateVendor 已加 restaurantId predicate 已修
實際做了什麼:SwiftDataVendorRepository 全部 fetch / search / save / delete / count 方法 都用 RestaurantIdProvider.shared.resolver?() 拿 current restaurant id,然後加 #Predicate<Vendor> { $0.restaurantId == rid }。 save/delete 還會驗證 entity.restaurantId 跟當前 rid 一致,不一致直接 throw 403。
檔案:ChefsMateShared/.../VendorRepository.swift
dogfood:登入 A 店 → 看 Vendor → 切 B 店 → 應該完全不同清單。

P1 — 兩週內(防止 regression)

#SA4 RLS regression test infrastructure P1
為什麼需要:現在每次加新 migration 都靠手動審 RLS,很容易漏。 應該每次 CI 跑「用 anon key + 用 owner A 的 jwt + 用 owner B 的 jwt」三組,確認不該讀的真的讀不到。
具體做法:寫一個 deno test script 列舉所有 table,對每張表跑「anon 應拒絕 / owner A 只讀到自家 / owner B 只讀到自家」三種斷言,塞進 GitHub Actions。
立即效益:#SA1 + #SA2 修完後永遠不會 regression。
0/3 步驟完成
#SA5 StaffsMate Flutter 沒本地 DB,離線完全不能用 P1
現況:純 Supabase API + Realtime + Riverpod 記憶體,沒 drift / isar / sqflite / hive。 沒污染風險(好處)但連網訊號差或地下室打卡會直接失敗(壞處)。
業界做法:打卡功能必須有 offline-first(Toast / Lightspeed 員工 App 都會 cache 排班 + 打卡資料,連回網時 sync)。
選項:
  • A. 用 drift 加 offline cache(中工程量)
  • B. 至少 cache 當週 schedule + last clock-in time 在 shared_preferences(輕量)
  • C. 不修(目前 dogfood 階段可接受)

集團 ↔ 單一餐廳架構 vs 業界

結論先講:你的設計接近 Lightspeed 模型(single instance + group + per-store override), 優於 Square(只有 flat locations 沒集團概念), 比 Toast Enterprise 簡單但夠用(Toast 是集團總部 + 各店獨立 instance,大集團才需要)。 對 2-25 家店的 SMB 集團是甜蜜點。

你目前的設計(已遠超我預期)

restaurant_groups (集團主表)
  ├─ group_members (集團管理員,可看旗下所有店)
  ├─ owner_user_id / subscription_tier / max_restaurants / default_timezone
  └─ restaurants[]
        ├─ group_id (FK → restaurant_groups)
        ├─ restaurant_members (N:N user ↔ restaurant)
        └─ local_overrides (店家可覆寫集團模板 — e.g. 海邊店改菜單價)

跨店共享資源:recipes / ingredients / vendors / brands
  visibility: 'group' | 'store'

UI 已實作 GroupDashboardView(「N 間分店」儀表板) + AuthManager.lastSelectedRestaurantId(重啟自動恢復上次選的店)。

vs 業界三大競品

維度 Toast Enterprise Lightspeed Square ChefsMate 現況
層級 3 層(Corp / Region / Store) 2 層(Group / Store) 1 層(Flat Locations) 2 層 (缺「區」)
菜單繼承 Master + override Master + override 無(各店獨立) 有 local_overrides
跨店報表 總部 dashboard 完整 完整 roll-up 基本 雛形(GroupDashboardView)
權限角色 4 層 RBAC 4 層 RBAC 3 層 group_owner/admin + store owner/manager/staff(缺「區經理」)
訂閱計費 Per-location + group invoice Per-location + group invoice Per-location restaurant_subscriptions 表 RLS 已修(2026-05-20)
資料隔離 獨立 instance RLS by tenant + sub-tenant RBAC P0 已修 · schema 設計債(tactic_plans 等)在 V3 P4
完整 12 個月路線圖
V3 Spec:集團架構 + 開分店顧問 AI + V2 整合 + BYOA
3 層 RBAC(HQ / 區經理 / 店)· HQ 6 大功能 + 6 個推測沒人想到的 · 區經理巡店 · 中央廚房 schema · 開分店顧問 AI(5 維 readiness,業界沒人做)· V2→V3 升級(tactic_plans 設計債 fix)· BYOA(接 OpenAI/Anthropic/Gemini/Azure/Bedrock)· Multi/Group/Enterprise 訂閱 · 6 phases / 12 個月 ship · 6 個 Open questions 等老闆拍板
點開看完整 spec →

P2 — 配合集團功能正式上線(細節都在 V3 Spec)

#SA6 補「區經理」角色(3 層 RBAC) P2
現在只有「集團管理員」+「單店角色」兩層。業界中型集團(5-20 店)會有「北區經理管 8 家」的概念。 做法:group_membersrestaurant_scope uuid[](NULL = 全集團,有值 = 限定那幾家)。
#SA7 訂閱層級對齊業界(Single / Multi / Group / Enterprise) P2
業界主流分 4 層:
  • Single(1 店,陽春)
  • Multi(2-5 店,基本 group features)
  • Group(6-25 店,完整跨店報表 + region)
  • Enterprise(25+,custom quote + SLA)
現在 restaurant_groups.subscription_tier 已有欄位,只缺 UI + 結帳 page 對應。
#SA8 集團報表 roll-up(總部一張表看全旗下店) P2
基礎已具備(group_id 在 restaurants 表上)。做法:寫 SQL view group_daily_revenue / group_customer_acquisition,集團儀表板直接 query。Lightspeed / Toast 都這樣做。
業界參考來源: Toast Enterprise · Lightspeed Pricing 2026 · Toast vs Lightspeed 2026

Dogfood 待驗證 — 等老闆實測通過後移到「已完成」

每張卡片有詳細測試步驟(勾選可持久化在你瀏覽器)。 測完全部步驟,點「 Dogfood 通過」會把卡片移到下方「 已完成」對應檔期分類,方便之後查閱。 想看原始 code 細節 / commit 拆解,點「 看代碼細節」會跳到三條路線的對應卡片。

#H1 採購單付款帳戶追蹤
採購單標已付時要選付款帳戶,自動記到 AssetTransaction。 4277bf3e47be6ec0
0/8 步驟完成
看代碼細節
#H2 取消/退款流程
客人申請取消 → 老闆兩按鈕(同意+退款 / 同意不退款)+ 退款 %(100/80/50/0)+ 末五碼 + email + 理由範本。 2130af25
0/7 步驟完成
看代碼細節
#H3 訂位列表 filter 膠囊重整
移除「即將到來」、今日全部固定 1-2 位置、不滑動全顯示、月曆切換。 4276e76482ff2661
0/6 步驟完成
看代碼細節
#H4 月曆→日檢視 + timeline 拖動
月曆點日期跳日 view + timeline 拖移改時間/桌位(manual_table_override 底層已有)。 77ad2d80c437cd1b
0/7 步驟完成
看代碼細節
#H5 核准修改 sheet(含時段分佈)
客人改人數請求 → 老闆收到 → 核准 sheet 顯示時段分佈 + 系統推算 + cascade 預警。 e8d8f7e835df41b83cfc6bc7
0/7 步驟完成
看代碼細節
#H6 員工邀請 v2(email + in-app dialog)
Email 邀請(Resend)+ landing page + in-app dialog(POS/Flutter listener)+ 表單。 e9a3460feb0c5970
0/7 步驟完成
看代碼細節
#H7 補關帳未結帳訂單處理 sheet
關帳時掃出未結單 → 4 種 action(刪/補結/耗損/請客)+ 批次 + 客人事後可補結。 5e687ce1a2e87a1f662844cd
0/7 步驟完成
看代碼細節
#H8 臨時收支記帳 + 統一退款 sheet
記帳 tab 可加 ad-hoc income / expense / refund,含對應 Asset 餘額更新。
0/7 步驟完成
看代碼細節
#H9 PO 收貨 UX 整合(QuickReceivingCompletionSheet)
快速點貨完成後,把「已付 / 欠款 / 新增項目」3 按鈕融合進收貨流程。 998cd653
0/8 步驟完成
看代碼細節
#H10 Timeline 拖拉 v3
欄寬縮小、半透明、tooltip from→to、haptic、紅線標營業時段、單 DragGesture 0.25s 區分 tap/drag。 4b6e3d42bfb1c517e29dc3e6e7428974
0/9 步驟完成
看代碼細節

已完成 — 按檔期/方向分類

Dogfood 通過的功能會搬到這裡,按修正大方向分類,方便日後查閱「這個改動是在解什麼問題」。 上方 dogfood 卡片點「 Dogfood 通過」就會自動搬下來。 已 ship 但不需 dogfood 驗證的基礎建設(同步優化、thin-client scaffold 等)也歸在這裡。

2026-05-25 11 個跨模組視角(L2 全流程視角) 12 個 doc
老闆「跳脫功能視角的單一大流程視角」要求 → 在金流之外再建 11 個 cross-cutting 視角。 → 開總索引
  • POS_全流程視角.md — 11 個視角總索引 + 跟模組視角的關係 + 依賴矩陣 + 9 個跨模組 gap
  • 01 客流 — 11 phase(發現→訂位→到店→點餐→結帳→累點→回頭)
  • 02 菜流 — 11 phase + 沽清漣漪 + 退菜漣漪
  • 03 食材流 — 10 phase(廠商→採購→收貨→庫存→配方→賣出→補貨→付款)
  • 04 員工流 — 10 phase + 每日工作 audit + 月薪自動計算
  • 05 一天的時間軸 — gantt 圖 + 8+ cron / Realtime / 背景活動
  • 06 會員生命週期 — 10 phase + 預約兌換 sequence + 生日禮 / 流失警告
  • 07 異常流 — 6 類異常 + retry 策略 + 老闆怎麼知道 stuck
  • 08 資料同步流 — bundled / Realtime / optimistic 三套機制 + conflict policy
  • 09 集團流 — HQ/區經理/中央廚房(V3 spec 大部分待 ship)
  • 10 稽核流 — audit_logs 30+ event_type + 經典查詢 SQL
  • 11 支付狀態流 — 5 種 status state machine + 觸發下游 + idempotency
2026-05-25 金流系統整合章節(L2 新模組) 5 個 L5 doc · 1 個 L4 電路圖
老闆問「我搞不清楚整個金錢運作的流程」→ 整合做一個完整 L2 章節。 → 開金流章節
  • POS_金流系統架構.md — L2 鳥瞰圖 + 7 個 FAQ「我搞不清楚」常見疑問
  • L4_金流_完整電路圖.md — 收款 / 關帳 / 退款 / 採購 4 個 sequence diagram
  • L5_收款_8條路徑.md — 8 個 path 配 UI 截圖位置 + 比較表
  • L5_支出_7條路徑.md — 退款 / 採購 / 薪資 / 臨時 / 關帳轉存 / 轉帳 / 還款
  • L5_記帳_帳戶與流水.md — assets schema + 8 種 transactionType + 雙重計帳防護
  • L5_第三方金流_藍新+TapPay+發票.md — NewebPay / TapPay / 發票 callback flow + sandbox 限制
  • L5_UI_點哪裡操作.md — 操作 cheat sheet,「想做 X → POS 哪個 tab → 哪個 button」
  • 同時 audit 出 5 個已知 gap(薪資沒沖帳 / 轉帳分流 / 還款分流 / 無第三方待結轉 / POS report 跟記帳口徑不同)
2026-05-23 Audit 上架前大清掃 Batch 14-26 · 40 bug + 9 migrations
完整 sysmap audit 抓到的 41 個 inline bug + 50 個 card bug 全部 ship(剩 1 個 false positive)。 → 完整 AUDIT_FIX_LOG
P1 上架前必修 — 5 群 / 12 bug(Batch 21-23)
  • a16cee9d #R15 #R20 #R40 #R41 #R59 — Realtime reconnect + 補關帳日期 + auto-no-show cron
  • 1b78b333 #R35 #R36 #R37 #R38 #R43 #R56 — markArrived 5 cluster + 加菜送單 broadcast
  • f1c6cfb5 #R44 #R59 part2 — overbooked event + wallet pass repair cron
P2 上架後盡快 — 6 群 / 6 bug(Batch 24-25)
  • 663543a2 #S30 #S32 #R16 #S33 #S23 + D.0 — 拆桌 orchestrator / reward race / 發票自動 / 員工 v2 cron / KDS thin-client / viewer code excerpt
  • 55a1b3e3 #S34 wallet 中央 trigger + #S33 part2 邀請撤回 broadcast
P0 + P3 + 老闆決策 — 全部 ship(Batch 13-20 + 26)
  • f6fcecfc #R21 A — AdHoc 沖 asset balance + source_marker
  • af1555ff #R29 AB — sellout 跳警告 dialog
  • 5558b81b #R26+R27 C — chat.new_message silent push handler
  • 4a9f51ef #R2 A — RefundDispatcher 補 PettyCashService 沖 balance
  • 0f765252 #S1 C — 敏感欄位搬出至 restaurant_pos_secrets table
  • 3d39bb86 #S6 A — purchase_orders status_raw trigger 自動扣庫存
  • 3f44ad08 Batch 26 — #S2 account merge 4 RPC dump + #S7 payment.completed event publish
Batch 14-20 schema/enum/RLS 直接修(34 bug)
  • 31084e3f Batch 14 — #S24 #S25 #S27 #S28 #S29 #S31 + #R48 sellout-pause RLS + #S10 SettlementService predicate
  • 5bb82aa4 Batch 15 — #R32 #R33 修改訂位 email 通知補洞(dedup window)
  • 1ea33345 Batch 16 — #R34 #R45 #F4 #F5 #F7 + #F9 false positive verify
  • 6e5e7080 Batch 17 — #R53 coupon DTO + #R54 forfeit enum + #R55 pause days/special_dates 雙向 trigger
  • 1822b612 Batch 18 — #S21 KDS revert resets timestamps + #R42 closeType dedup
  • 0fa131fa Batch 19 — #R39 BatchRetroClose entry point + #R19 false positive verify
  • 8716310b Batch 20 — #R18 退款 Realtime filter + #R54 DepositStatus.forfeit switch 補 case
Sysmap 文件配套(L0-L7 + 27 doc audit callout)
  • e520ab79 docs(sysmap): AUDIT_FIX_LOG_2026-05-23.md + 27 個 L5/L6/L7 doc 加 callout
  • bddd9dca report: 大重整 — 還沒做的東西放最上面 + 每張卡片可收合
  • 3f44ad08 report: 老闆決策 / CRITICAL section 全部 封存
️ SQL Migrations applied(11 個)
  • 20260523011 — #R33 dedup modification email (modification_email_sent_at column + trigger)
  • 20260523012 — #F4 restore 'rejected' status to reservations CHECK
  • 20260523013 — #R55 pause_days / special_dates 雙向同步 trigger
  • 20260523014 — #S21 KDS revert resets completed_at + delivered_at
  • 20260523015 — #R43 order_items guest broadcast trigger
  • 20260523016 — #R38 notify customer on arrival (broadcast + LINE)
  • 20260523017 — #S32 reward race on order_id change
  • 20260523018 — #R16 auto issue invoice on payment completed
  • 20260523019 — #S34 auto update wallet on loyalty change (中央 trigger)
  • 20260523020 — #S33 part2 staff invitation revoke broadcast
  • 20260523021 — #S2 account merge 4 RPC dump (disaster recovery)
AI 工作日誌(最近 ship 的東西) 48 項
每次 AI 來 commit 都會更新這邊。最新在最上面。Audit 修復細節見上方分類。
  • 3f44ad08 Batch 26 — 老闆決策 + CRITICAL section 全部封存 + #S2 account merge RPC dump + #S7 payment.completed event publish
  • 80dd8f18 #S23 build fix — ExpediteActionManager 用錯 AuthManager property name
  • 55a1b3e3 Batch 25 — P2 收尾 #S34 + #S33 part2 + 報告 P2/P3 標 ship
  • 663543a2 Batch 24 — P2 五個 (#S30 #S32 #R16 #S33 part1 #S23) + P3 D.0 viewer code excerpt
  • f1c6cfb5 Batch 23 — P1 收尾 #R44 #R59 part2 + 報告 P1 標 ship
  • 1b78b333 Batch 22 — P1 群①3. markArrived 5 個 + 加菜送單 client sync
  • a16cee9d Batch 21 — P1 群②④5. Realtime reconnect / 補關帳日期 / auto-no-show cron
  • bddd9dca report: 大重整 — 還沒做的東西放最上面 + 每張卡片可收合
  • e520ab79 docs(sysmap): AUDIT_FIX_LOG + 27 個 L5/L6/L7 doc audit callout
  • 8716310b Batch 20 — #R18 退款 Realtime filter + #R54 forfeit switch 補 case
  • 0fa131fa Batch 19 — #R39 BatchRetroClose entry point + #R19 false positive
  • 1822b612 Batch 18 — #S21 KDS revert + #R42 補關 closeType dedup
  • 6e5e7080 Batch 17 — #R53 coupon + #R54 forfeit enum + #R55 pause days 雙向 sync
  • 1ea33345 Batch 16 — #R34 #R45 #F4 #F5 #F7 + #F9 false positive
  • 5bb82aa4 Batch 15 — #R32 #R33 修改訂位 email dedup
  • 31084e3f Batch 14 — 8 個 medium bug (#S24 #S25 #S27 #S28 #S29 #S31 + #R48 + #S10)
  • 36f2c515 #B20 補零用金 sheet 改造 — 來源帳戶可選 + 補滿到預設 + Stitch 設計
  • f2a983a1 #B19 補關帳隱藏現金盤點 — 過去無法物理清點
  • 8273a721 #B18 /account 訂位列表 3 改 — 拒絕取消 chip + 取消後隱藏待付訂金 + 過往紀錄正方形 grid
  • 4e0b8d1b #B17 follow-up — timeline 上→下 + 刪「客滿」範本 + 客人端拒絕取消 tag
  • e75e18c4 #B17 時序進度完整 audit + 4 處詞彙修正
  • 28aa0e94 訪綱頁:訪問者可登入寫筆記,每題下方一個筆記區
  • 28a15864 訪綱 Q&A 頁複製到 Vercel public — chefsmate.app 直接可訪問
  • 85e162d6 #B14/#B16 follow-up — email 連結 404 修(改 /[slug]/my-reservation?fill_refund=<id>)
  • ba1d7b42 #B16 退款 sheet 5 改(email 寄送/必填標示/選填 reason/Stitch 重做)+ 台東慢波訪綱頁
  • 0c46a31c 客人查詢中文聚合卡片 + admin_get_customer_summary RPC
  • 5d797946 #B15 訂位 timeline / section 氣泡詞彙 audit + 區分 case
  • 204d617f #B12/#B13/#B14 訂位詳情 timeline+section 順序+退款 sheet 客人帳戶
  • 76ebaec1 報告頁查詢駕駛艙 — 4 tab debug 查詢 admin RPC
  • 3dbfdb84 報告頁 Lucide 單色 stroke 圖標取代 emoji + status-mini CSS mask
  • 93b9ff70 報告頁 Phase 5 — washi/染料色系 + fixed banner + 全頁清 emoji
  • ba35fcf8 報告頁 Phase 2-4 — sticky nav + top dashboard + 去除重複
  • 351ab3b7 報告頁 Phase 1 — Stitch design tokens + 全 CSS refactor
  • 08e64d7d #P5 SwiftUI 權限 gate ViewModifier + 2 份測試文件
  • 576b26b7 #P6+P1 apply 3 個未推 DB migration (webhook + api_keys + stripe) + 報告 8%→50%
  • 8b333c4a P-FIX-1 Phase 7 — Main + Booking 補 runtime swap + cleanupForeignRows 3 apps boot
  • 5dd04001 #SA1+SA2+SA3 P0 RLS fix applied + V3 集團 spec(12 個月路線圖)
  • 81f4d935 報告頁新增「跨 App 權限 / 隔離 / 集團架構 Audit」section
  • c023dd4d #P-FIX-1 Phase 3+4 — 3 apps 接 per-restaurant container + legacy migrator
  • 935a1f41 #P-FIX-1 Phase 1-3 core — Entity audit + Registry + Switch Orchestrator + Gates
  • 1d392141 #P-FIX-1 計劃頁上線 (/plans/per-restaurant-container.html, 7 phase 進度)
  • 33cf0698 #B11 self-heal RLS 不改 restaurant_id (4 層防線) + 恢復 14 筆海邊資料
  • aa62d6e8#W1 Phase 1 提案 + /plans landing + 首頁紫色入口 (846 行員工提案)
  • f73a7a28#B2 零用金動態追蹤 PettyCashService + 低餘額 banner + 補錢 sheet
  • a22c50ee#W2 信用分數系統 backend + 拒絕取消 email Edge Function
  • a7f09e60#B4/#B5 拒絕取消客人端 banner + 客人取消必填理由
  • ddb0e185#B7/#B8 sync PK 衝突 + 訂位網頁尚未開放誤判
  • 7951326d#B3/#B6 取消按鈕語意誤導 + web phantom 桌位計入
  • 1978748e#B1 FloorItem 接 SoftDeletable + 主控台 query 加 deleted_at filter
  • 8b99f349報告頁加 Dogfood 待驗證 + 已完成 兩大 section
  • 1b13e491#H6 內嵌 7 題互動表單
  • 998cd653#H9 PO QuickReceivingCompletionSheet + 全 H 階段 audit + 報告 100%
  • 2130af25#H2 取消/退款 — 補 email + 完成 audit + 報告 100%
  • 694e3f81報告頁 #H2 子步驟拆解可見
同步優化 Phase A+B1(Bundled Sync) 5 項
解決 App 啟動慢、HTTP 60+ 次的問題。改成 manifest + bundled pull,60→2 通電話。
  • 46eecdc3Phase A+B1 web 端 4 層架構 — manifest + bundled pull endpoint
  • 2f0fcf15Phase A+B1 Swift client side — 4 層 bundled sync pipeline
  • 389a5d61AppSyncManager 整合 bundled sync(feature flag 灰度)
  • a08928dbSync Developer UI — flag off/on 量測工具(DEBUG only)
  • 1aebdcd5route-level smoke tests for /api/sync/{manifest,pull}
主 App 重構 — PurchaseOrder thin-client(Phase 0/1 pilot) 6 項
把 PO 商業邏輯全搬 server,App 只負責 UI + 樂觀更新。3 個 App 不會 drift。
  • 2f5c585bPhase 0 — 主 App 4 層架構盤點完成
  • ca0813c5Step 1.1 — 4 層架構完整 scaffold + 100 vitest pass
  • f3186017Step 1.2 — 7 Next.js API routes + error mapper
  • b5e96f32Step 1.3 — Swift API client + DTO + 11 methods
  • cab91e2eStep 1.4-A — CreatePurchaseOrderView 接 API + upsert local
  • af1b90b8Step 1.4-B.1/B.2 — setPaymentStatus + duplicateOrder 接 thin-client
跨平台帳號統一 + 合併 基礎建設
四向帳號連結(Apple / Google / Email / Phone)+ 跨 provider 合併體系。可參考 memory: project_account_merge_architecture.md
  • memory四向帳號連結 + 跨 provider 合併體系完整架構(2026-04-17)
POS 上架衝刺 0 項
9 個 user dogfood 後提的核心 feature。Dogfood 通過後會搬進來。
  • 還沒有 dogfood 通過的項目。先到上方測試!
訂位系統夯實 0 項
訂位 filter、月曆、核准修改、timeline 拖拉、取消退款。Dogfood 通過後會搬進來。
  • 還沒有 dogfood 通過的項目。先到上方測試!
員工系統 + 跨 App 邀請 0 項
員工邀請 v2、StaffsMate Flutter 整合、權限分層。
  • 還沒有 dogfood 通過的項目。先到上方測試!
記帳 / 報表 / 資金管理 0 項
付款帳戶、Liability、AssetTransaction、ad-hoc 收支、報表反映、零用金管理。
  • 還沒有 dogfood 通過的項目。先到上方測試!
跨 App 權限 / RLS / 集團架構 0 項
RLS P0 修、Vendor predicate、Permission gate、集團架構 spec。Dogfood 通過後會搬進來。
  • 還沒有 dogfood 通過的項目。先到上方測試!

大計劃 — 把每件事歸到一個大方向

所有小任務都屬於某個大計劃。點開可以看完整 task list 和進度。 右下角「大計劃」標籤 可以從任何 item 跳到對應大計劃。

#P1主 App 重構 — Thin-Client + Fine-Grained 4 層架構
25%

目標:所有商業邏輯搬到 server(Route → Orchestrator → Gate + Primitive + Repository 4 層), App 只負責顯示 + 收使用者操作。改規則改一次就全部生效,3 個 App 不會 drift。
進度:3/14 個 PO 動作完成、16 張 audit card 排隊、per-restaurant container Phase 7 完工(基礎建設)、Permission gate ViewModifier ship、5 個訂位/退款/補關帳 orchestrator(#B12-#B20)用新架構出貨。受影響 entity: PurchaseOrder(pilot)、Recipe、Vendor、Ingredient、MenuItem、Settings、Budget、Tactic 等。

  • Step 1.4-A 建立採購單接 API 睡覺
  • Step 1.4-B.1 付款狀態接 API 睡覺
  • Step 1.4-B.2 複製訂單接 API 睡覺
  • Step 1.4-B.3 收貨流程接 API 睡覺
  • Step 1.4-B.4 刪除流程接 API 睡覺
  • Step 1.5 砍 Swift PO Services 睡覺
  • Step 1.6 跨 entity 邏輯(Threshold / UnitConv)睡覺
  • Step 1.7 Outbox 結構(離線排隊)睡覺
  • 16 張 audit card:Vendor / Recipe / Ingredient / Settings / Budget / Tactic / Reports / Brand / Dashboard / Operation / HRTab / Phase5Services / MenuItem / PrepList / Expense / Accounting 睡覺
  • 通知 Router thin-client(Things 既有 task)睡覺
  • 報表聚合 thin-client 睡覺
  • 菜單快速上下架 thin-client 睡覺
  • 候位 Waitlist 全新功能 有精神
  • 關帳 client 切到 thin-client API 睡覺
  • 結帳/付款/退款 client 切到 thin-client API 睡覺
  • POSReservationListView 改時間接 thin-client 睡覺
  • AddReservationSheet 建訂位接 thin-client 睡覺
  • Wave 7 測試計劃跑完整套 沒精神
  • Wave 8: SeatingService 換桌測試(用新 Swift gates) 睡覺
  • iOS Wave 8 後續:Service / UI 全面換用 Swift gates 睡覺
  • 全部 graduate + 砍 legacy + 移除 flag UI 睡覺
  • Phase 2 cleanup — 移除 3 個未實例化的 add-reservation 死碼(commit 562edef6) 睡覺
  • #P-FIX-1 per-restaurant container Phase 7 完工(基礎建設,commit 8b333c4a)睡覺
  • SwiftUI ViewModifier 統一權限 gate(.requireRole 等,commit 08e64d7d)睡覺
  • #B12-#B20 訂位/退款/補關帳/補零用金 orchestrator(全用新架構出貨)有精神
#P2同步效能優化(Bundled Sync)
75%

目標:App 啟動 / 下拉刷新時的同步速度大幅提升。
已驗證:4256 ms / 2 個 HTTP(vs legacy 49000 ms / 60+ HTTP)= 12 倍快。
剩下:HybridSyncManager 補償同步 + DataSyncService 內部 syncer 接到 bundled API,再省 ~50 個 HTTP。

  • Phase A:manifest endpoint 睡覺
  • Phase B1:bundled pull endpoint 睡覺
  • Swift 端 4 層 + AppSyncManager 整合 睡覺
  • Sync Developer dev tool(量測) 沒精神
  • Schema audit(移除 9 張錯類表) 睡覺
  • Phase B2:HybridSyncManager 接 bundled 睡覺
  • Phase B2:PrepListSync / IngredientPriceHistorySync 接 bundled 睡覺
#P3POS 上架衝刺
95%

目標:POS App 達到可以 App Store 上架 + 接單收費的水準。
9 個關鍵 feature code 全 ship 完(只待老闆 dogfood verify);剩 Stripe / 訂閱整合 / App Store SOP / 打開收銀機按鈕等基礎建設。

  • #H2 取消/退款流程改造 (100%) 有精神
  • #H3 訂位列表 filter 重整 (100%) 有精神
  • #H4 月曆→日 + 拖動編輯 (100%) 有精神
  • #H5 核准修改 = 確認訂位 (100%) 有精神
  • #H6 員工邀請 v2 (95%) 有精神
  • #H7 未結帳 sheet (100%) 有精神
  • #H8 臨時收支 + 統一退款 (100%) 有精神
  • #H9 PO 收貨 UX 整合 (100%) 有精神
  • #H10 訂位 timeline 改造 v3 (100%) 有精神
  • 打開收銀機按鈕(退款/臨時消費/找零) 有精神
  • Stripe Dashboard 設定(產品 + 價格 + Webhook) 沒精神
  • /pricing 頁手動測訂閱流程 有精神
  • Webhook idempotency 測試(Stripe CLI replay) 沒精神
  • iOS RemoteSubscriptionFetcher 整合 SubscriptionManager 睡覺
  • 藍新定期定額整合(台灣本地金流) 睡覺
  • App Store 審核回應 SOP 沒精神
  • 測試 — Customer-Centric 訂位重構 6 條必測(#22-#27) 有精神
#P4記帳完整性 — 每筆錢都追蹤
60%

目標:每筆錢進出(訂金、營收、採購、退款、臨時收支)都記到 AssetTransaction 表, 老闆能準確知道每個帳戶餘額、每月哪邊賺哪邊花。

  • 付款帳戶追蹤 feature(採購單標已付建 transaction) 睡覺
  • dogfood 付款帳戶 8 step(待測) 有精神
  • Liability + AssetTransaction 一致性決策 沒精神
  • G. 臨時收支 + 統一退款(重複於 POS 衝刺) 有精神
  • #B2 零用金動態追蹤 + 低餘額 banner + 補錢 sheet(f73a7a28) 有精神
  • #B19 補關帳隱藏現金盤點(f2a983a1) 有精神
  • #B20 補零用金 sheet 來源帳戶可選 + Stitch(36f2c515) 有精神
  • 報表聚合 thin-client(重複於 4 層架構) 睡覺
#P5Bug fixes(已知 5 個)
20%

有發現新 bug 隨時告訴我。沒精神時段適合做這個。

  • SwiftData 殘留 ghost 訪客(員工手機看到 server 沒有的桌) 沒精神
  • KDS UI 假裝有單但內容空白(2026-04-27 觀察到) 沒精神
  • 全 POS UI 權限 audit — 沒權限的按鈕要 disable / 隱藏 沒精神
  • Sync upload 失敗時要 rollback 本機(legacy 路徑) 睡覺
  • SwiftUI ViewModifier 統一權限 gate (2026-05-20) — 加 .requireRole(_:) / .requireManagement() / .requireOwner() / .disableUnlessRole(_:) 等 statement-level helper(避免 audit 後又漏) 睡覺
#P6安全 / 基礎建設
50%

API key、Webhook、Stripe migration 等基礎建設。多數可在睡覺時段做。

  • Webhook 訂閱系統測試(含 HMAC 驗證) 沒精神
  • API key 認證 + Rate limit 測試 沒精神
  • OpenAPI spec 驗證(給未來合作夥伴 / Google RwG) 睡覺
  • DB Migration push:webhook_subscriptions + api_keys (2026-05-20 apply 完) 睡覺
  • DB Migration push:20260428003_stripe_subscriptions (2026-05-20 apply 完) 睡覺
  • RLS P0 audit + 修 (#SA1+SA2+SA3,2026-05-20) 睡覺
#P7文件 / 設計工具
100%

看得見的工具,幫助老闆 + AI 同步狀態。

  • docs.chefsmate.app 系統地圖(4769 個節點) 睡覺
  • 17 張 audit card(重構單位)睡覺
  • 老闆報告頁面(這頁本身) 睡覺
  • POS_流程邏輯圖.md / 功能地圖 / Edge Functions 地圖 睡覺

三條工作路線

根據老闆當下精神狀況選擇做什麼。每個 item 點一下展開 看「當時的提示詞」+「無腦測試 checklist」(如果有)+「所屬大計劃」。

拖移功能:抓 item 左邊的 ⋮⋮ 把任務拖到別的時段欄。 順序會存在你瀏覽器(localStorage)。下方有「重設順序」按鈕可恢復預設。

有精神時段

早上、下午前段
需要老闆 dogfood、判斷 UX、跟錢/上架直接相關。最高 ROI
立刻測 #H1付款帳戶 dogfood
8 個測試 step(必測 4 + 邊界 4)— 確認 A+C 流程通了、金錢追蹤完整。
~15 分鐘 記帳完整性
老闆當時的話(觸發這個 feature):
測試1:點擊「已付」過後,最近的交易紀錄裡面沒有顯示已付的貨款,用戶選擇已付的時候是不是應該要選擇付款帳戶,這樣才可以完全掌握每個帳戶付出去多少錢?
老闆選擇的設計(A+C):
我選A+C,跳出選單的同時,有預設的帳戶可以直接選擇,預設的選項可以從設定裡面去設定
無腦測試 checklist
0/8
  1. ①【必測】設定預設付款帳戶
    1. 開 ChefsMate App → 「設定」Tab
    2. 滑到「餐廳管理」section,找「預設付款帳戶」(綠色 creditcard icon)→ 點進去
    3. 列出兩個 section:「無預設」+ 你的 asset 帳戶清單
    4. 點任一個帳戶
    預期:藍色打勾、console 看到 [DefaultPaymentAccount] 預設付款帳戶已更新。關閉 sheet 重進,仍打勾。
  2. ②【必測】標已付跳 sheet + 確認帳戶
    1. 開任一張欠款的採購單詳情頁
    2. 點「已付」按鈕
    3. 預期:採購單卡片立刻變「已付」+ 跳出 PaymentAccountPickerSheet
    4. Sheet 上方顯示付款金額(大字)
    5. 你剛才設的「預設帳戶」應該已被選好(藍色打勾 + 「預設」badge)
    6. 點「確認」
    Sheet 關閉。Console 看到 [PO Pay] API success: ... → status=paid, asset=...
  3. ③【必測】交易紀錄出現出帳
    1. 切到「記帳」Tab → 看「最近交易」區塊
    應該看到一筆新的 transaction:type=採購付款 / amount=該 PO 總額 / asset=你選的帳戶 / note=「採購付款 PO #xxx...」
  4. ④【必測】取消 sheet → rollback
    1. 找另一張欠款 PO → 點「已付」
    2. Sheet 跳出時,這次點「取消
    Sheet 關閉、採購單卡片回到「欠款」、「最近交易」沒新增 transaction
  5. ⑤【必測】標欠款 → 清 transaction
    1. 找 step 2. 標已付的那張 PO → 點「欠款
    2. 預期:不跳 sheet,PO 直接顯示「欠款」、console [PO Pay] API success: ... → status=unpaid
    3. 切「記帳」→ 看交易紀錄
    Step 2. 建的那筆 transaction 應該消失(被 soft-delete)
  6. ⑥【邊界】沒設預設的情況
    1. 進「設定」→「預設付款帳戶」→ 選「不設定預設
    2. 進任一張欠款 PO → 點「已付」
    Sheet 跳出時第一個 asset 被預選(不是「預設」狀態,沒 badge)
  7. ⑦【邊界】金額正確性 + missing item
    1. 找一張已收貨的 PO(有 actualTotalPrice)
    2. 標已付 → 看 sheet 上方金額
    3. 預期金額 = sum(item.actualTotalPrice)(不是 ordered total)
    4. 找一張有 missing item 的 PO(部分缺貨)
    5. 標已付 → sheet 上的金額不該包含 missing item
    兩個都正確
  8. ⑧【邊界】離線 rollback
    1. 飛航模式 ON
    2. 標已付 → 選帳戶 → 確認
    paymentStatus 樂觀更新成 paid → API timeout → console [PO Pay] API failed, rolling back → PO 自動回到欠款,paidFromAssetId 清空
100% #H2A. 取消/退款流程改造
2 按鈕(同意+退款 / 同意不退)+ 退款百分比 + 末五碼 + email + 理由範本 + 訂位永不刪除。
2026-05-16 audit 完成:原來 H2.1 / H2.2 / H2.4 / H2.5 在前幾輪 dogfood commit 都已 ship(cancelApprovalSheet 含 3 按鈕 + Stepper + 5 個 quick % + override reason 範本 + 訂位 filter line 76 「永不消失」)。**唯一缺的是 cancellation email**。
本輪補完:寫 supabase Edge Function send-cancellation-email(refund/forfeit/credit 3 種 kind 各自 email 樣式)+ 接入 approveCancellation orchestrator fire-and-forget(不擋核准流程)。
等老闆 dogfood verify #H2.6
dogfood 待測POS 上架衝刺
老闆當時的話(測試 #11 Step 4 觸發 2026-05-11):
第四部點擊取消訂位之後不是跑到退款待處理,是進入取消待確認,詳細的定位資訊如同畫面,同意取消的那個按鈕應該要改成兩個按鈕,雖然政策規定是定位前24個小時內取消不退訂金,但是在這個按鈕上面應該還是可以讓用戶自己選擇同意取消並退款或者是同意取消不退款,如果點擊同意取消並退款,就會顯示政策規定的機種退款%數讓用戶選擇要退多少錢,用戶選擇之後呢就會進入退款程序,出現帳號後五碼讓餐廳端填寫,餐廳端匯完錢之後填寫後五碼按下送出就會發送一封郵件給客人,如果會匯款的金額大於政策規定的金額,應該要寫理由,並且有理由的範本:我們的退款政策是XXX,老闆權衡了一下,決定退款X%。目前按下同意取消按鍵之後這組定位會直接被刪除(直接在定位系統上面消失),不確定是在UI層面消失還是連supabase裡面都消失,我希望他一直留在系統裡面,以供後續查看比對。
子步驟拆解(按建議順序)
0/6
  1. #H2.5 完成 訂位永不刪除(取消改 status,不 soft-delete)既有:line 76 filter
  2. #H2.1 完成 1 按鈕拆 2 個(同意+退款 / 同意不退)既有:cancelApprovalSheet
  3. #H2.2 完成 退款 % picker(Stepper + 5 個 quick %)既有:line 2752
  4. #H2.3 完成 末五碼輸入 + Resend email 寄送本輪補:send-cancellation-email Edge Fn
  5. #H2.4 完成 超出政策上限 → 寫理由 + 範本 prefill既有:defaultOverrideReasonTemplate
  6. #H2.6 待測 老闆 dogfood 跑完整流程(測 email 真的寄到)~15 分鐘
100% #H3#H3 訂位列表 filter 重整 (100%)
膠囊 chip 重排、不滑動全顯、月曆切換。
本輪 audit 確認已 ship:commit 4276e764 (Batch B filter UX) + 82ff2661。檔案:ReservationListComponents.swift (sortedForDisplay) + POSReservationListView。
等 dogfood verify
dogfood 待測POS 上架衝刺
老闆當時的話(2026-05-11):
我覺得訂位頁面上面的分類膠囊應該要重新整理一下,內容的部分也應該要整理一下,「即將到來」這個膠囊是不必要的可以刪掉,今日和全部的膠囊排在第一二位順序不會變,其他的膠囊如果有出現 badge 就會自動往前排序,不過最好把每一個分類的膠囊都直接顯示不需要滑動,如果是直接顯示的方式,就應該要按照訂位的時間軸排序。如果點擊月曆檢視模式,膠囊應該要消失,變成一個返回分類檢視的按鈕。
子步驟拆解
3/4
  1. #H3.1 完成 移除「即將到來」filter case既有:commit 4276e764
  2. #H3.2 完成 今日/全部固定第 1-2 位既有:sortedForDisplay
  3. #H3.3 完成 其他依 badge 自動排序 + 全顯不滑動既有:filterBar HStack
  4. #H3.4 待測 老闆 dogfood:月曆模式時膠囊變返回按鈕
100% #H4C. 月曆→日檢視 + 拖動編輯
月曆某天 → 日檢視時間軸 + 拖移改時間/換桌。
本輪 audit 確認已 ship:commit 77ad2d80 (整天 inline 時間軸推廣) + c437cd1b (月曆點某天→日檢視)。檔案:POSReservationMonthCalendarView + ReservationDayTimelineView + ReservationTimelinePrototype。
等 dogfood verify
dogfood 待測POS 上架衝刺
老闆當時的話(2026-05-11):
點擊月曆檢視模式的某一天,就會變成日檢視模式,可以直接重用座位安排裡面的時間軸畫面,在座位安排時間軸畫面,拖動訂位區塊,應該要可以改變訂位的時間、或者是換桌安排(要記錄在那個預先座位安排的表單裡,並標記是手動安排的座位,不會隨著別的訂位自動安排而變更,等到客人入座的時候就會按照手動安排來入座,後續的客人訂位也會參考這個表單安排座位(已經有這個功能幫我確認一下))在日檢視模式點擊任何一個訂位就可以看到訂位詳細資訊。
子步驟拆解
3/4
  1. #H4.1 完成 月曆點某天 → 日檢視時間軸既有:c437cd1b
  2. #H4.2 完成 拖移改時間 / 換桌(reuse SeatingGanttView)既有:77ad2d80
  3. #H4.3 完成 寫 manual_table_override + 標記為手動安排既有:ReservationDayTimelineView
  4. #H4.4 待測 老闆 dogfood:完整流程連貫性
100% #H5D. 核准修改 = 確認訂位(Phase A + B + B-v2)
點「核准修改」一下抵兩下(自動 confirm)+ sheet 顯示當天時段分佈 + 桌位調整。
本輪 audit 確認已 ship:commit e8d8f7e8 (Phase A) + 35df41b8 (Phase B 後端) + 2778dc24 (Phase B UI) + 3cfc6bc7 (B v2 系統推算+拆桌+inline timeline)。檔案:ReservationApprovalContextSheet + /api/reservation/[id]/approval-context。
等 dogfood verify
dogfood 待測POS 上架衝刺
老闆當時的話(測試 #4 觸發 2026-05-13):
我現在在測試#4,客人先訂位,在老闆還沒有確認訂位之前就修改人數,當老闆點擊核准修改,其實就等於是確認訂位了,所以不必按兩次,核准修改這個按鈕點擊後的效果等同確認訂位。還有就是,要讓老闆判斷是否可以核准訂位,應該要直接顯示當天那個時段的訂位和桌位分佈,讓老闆知道這個客人有位子,而且安排的桌位合理。如果老闆覺得不合理也可以調整桌位後點擊核准修改,就會記錄下老闆的手動安排。
進度:Phase A 已 ship(orchestrator auto-confirm),Phase B/C 待設計 POS UI
子步驟拆解
3/4
  1. #H5.1 完成 Phase A:核准修改 = 確認訂位(auto-confirm)既有:e8d8f7e8
  2. #H5.2 完成 Phase B 後端:context API + 預覽 + manual override既有:35df41b8
  3. #H5.3 完成 Phase B UI:cascade preview + 系統推算永遠顯示既有:2778dc24, 3cfc6bc7
  4. #H5.4 待測 老闆 dogfood:完整核准流程
95% #H6E. 員工邀請 v2
Email 連結 → 下載 app + 填表單;in-app 確認對話框。
本輪 audit 確認已 ship:Unified User Profile Phase 1-4 + send-staff-invitation-email Edge Fn + /staff/onboarding/[token] 表單頁 + POS 邀請後 pending member 立即出現 (e9a3460f) + accept→form routing (eb0c5970)。
還缺:StaffsMate Flutter 的 in-app dialog 細節(待 Flutter audit),但核心流程已通。
展開後底部有 7 個當初待答問題的互動表單,請 dogfood 後確認 / 修正預設選項。
dogfood 待測POS 上架衝刺
老闆當時的話(測試 #3 觸發 2026-05-10):
我在測試#3的時候,用老闆的帳號邀請員工加入餐廳,當老闆送出邀請後,我想改一下行為: 1、員工 email 收到邀請,點擊 email 裡面的連結後跳出下載 app 的連結(放在 todo 裡面(現在還沒有正式連結))、填寫員工基本資料的表單連結(放在 chefsmate.app 網域底下)(符合 ChefsMate 主設計風格)(填寫一些正常公司會需要的資訊) 2、如果員工的手機在老闆發出邀請的當下正開啟著 App,則會跳出確認加入的對話框(希望對話框符合 ChefsMate 主設計風格),點擊確認後,如果還沒有填寫員工基本資料,則會跳出填寫員工基本資料畫面。(如果能重用 web 上的表單設計最好)(員工的基本資料會放在 ChefsMate Staff 裡面)
子步驟拆解
4/5
  1. #H6.1 完成 Email 邀請寄送(Resend pattern)既有:send-staff-invitation-email
  2. #H6.2 完成 /staff/onboarding/[token] 表單頁既有:page.tsx + OnboardingForm.tsx
  3. #H6.3 完成 POS 邀請後 pending member 立即出現既有:e9a3460f
  4. #H6.4 完成 Accept → 表單 prefill + cascade既有:eb0c5970
  5. #H6.5 待測 StaffsMate Flutter in-app dialog audit + dogfood
7 個待回答的問題(dogfood 後拍板) 0/7 已回答

這 7 個是當初設計時老闆還沒拍板的問題。實作時我先選了預設答案(標 已實作),dogfood 後請選 保留 / 改別的。 所有回覆存在你瀏覽器(localStorage),下次 AI 來會 review。

  1. Q1 是否支援邀請「未註冊」email?
  2. Q2 App 內「確認加入」對話框出現在哪個 App?
  3. Q3 員工基本資料表單欄位範圍?
  4. Q4 個人資料存哪個 table?
  5. Q5 邀請 token 有效期?
  6. Q6 已填過資料的員工再加入新餐廳,要不要重填?
  7. Q7 Email 邀請連結要不要包含「拒絕邀請」按鈕?
100% #H7F. 未結帳訂單處理 sheet
4 種 action(刪/補結/耗損/請客)+ 批次處理 + 客人事後可補結。
本輪 audit 確認已 ship:5 commits — DB+4-層 web stack (5e687ce1) + POS UI detail sheet + bulk (a2e87a1f) + customer recovery UI (662844cd) + POS NotificationCenter wire (4b5fdcb3) + recover orchestrator + auto-recover on settle (c55e88e9)。
等 dogfood verify
dogfood 待測POS 上架衝刺
老闆當時的話(2026-05-09):
還有就是如果補關帳的時候有列出尚未結帳的點餐單,應該要可以讓用戶點擊進去訂單詳情看是誰還沒結帳、點了什麼東西、顯示聯絡方式和一個處理這張單的section(刪除訂單/補結帳/列成耗損訂單(忘記跟客人結帳)(客人可以在事後在某個地方找到這筆訂單補結帳,如果聯絡得到的話)/店家請客(優惠為0元),可以讓用戶多筆訂單一起處理或是單筆單筆點進去處理
子步驟拆解
5/6
  1. #H7.1 完成 DB schema + 4 層 web stack既有:5e687ce1
  2. #H7.2 完成 POS UI detail sheet 點進去看詳情既有:a2e87a1f
  3. #H7.3 完成 4 種 action 按鈕既有:a2e87a1f
  4. #H7.4 完成 批次處理多筆既有:a2e87a1f
  5. #H7.5 完成 客人事後補結 UI(loss → recover)既有:662844cd, c55e88e9
  6. #H7.6 待測 老闆 dogfood:4 種 action + 客人補結
100% #H8G. 臨時收支 + 統一退款
取代「打開收銀機」概念 + 統一退款 sheet。
本輪 audit 確認已 ship:Wave A.4.1 AdHocTransactionSheet (6ee70f40) + Wave A.4.2 RefundSheet + RefundDispatcher。CashDrawerAdapter placeholder 留著。兩 sheet 從 POSSettingsView 進入。
等 dogfood verify
dogfood 待測POS 上架衝刺
老闆當時的話(2026-05-08):
Q1打開收銀機的用意應該是有時候會有臨時性支出用收銀機裡面的錢付款,應該把這個功能先改寫為「臨時支出/收入記帳」,如果有臨時支出/收入(比如買文具/收到小費)就可以在這裡記帳,並且同步到 chefsmate 主App的記帳功能、POS的關帳功能。留一個收銀機接口,未來如果我突然改變主意想要讓用戶也可以接上收銀機的時候,就可以擴充這個按鈕。
Q3臨時消費sheet應該就跟Q1的功能一樣。
子步驟拆解
3/4
  1. #H8.1 完成 Wave A.4.1:AdHocTransactionSheet(臨時收支記帳)既有:6ee70f40
  2. #H8.2 完成 Wave A.4.2:RefundSheet(統一退款)既有:3e021a43
  3. #H8.3 完成 CashDrawerAdapter placeholder(未來接硬體)既有:CashDrawerAdapter.swift
  4. #H8.4 待測 老闆 dogfood:跑一次臨時收支 + 退款
100% #H9#H9 PO 收貨 UX 整合 (100%)
「已付/欠款/新增項目」融合進收貨流程末尾。
本輪實作:新建 QuickReceivingCompletionSheet — 取代簡單 alert,顯示點貨摘要 + 已付/欠款 toggle(已付會跳 PaymentAccountPickerSheet 選帳戶、欠款建 Liability)+ 「新增遺漏項目」+ 「完成關閉」。
等 dogfood verify
dogfood 待測POS 上架衝刺
老闆當時的話(PO #20260514-1 dogfood 後):
PO的流程可以做到點貨完成了,但是「已付、欠款、新增項目」這三個按鈕我覺得應該要融合在點火流程裡面...
子步驟拆解
3/4
  1. #H9.1 完成 新建 QuickReceivingCompletionSheet本輪:QuickReceivingCompletionSheet.swift
  2. #H9.2 完成 已付/欠款 toggle + PaymentAccountPickerSheet 整合本輪
  3. #H9.3 完成 「新增遺漏項目」按鈕(dismiss → detail page 加項目)本輪
  4. #H9.4 待測 老闆 dogfood:完整收貨 → 設付款 → 完成
100% #H10I. 訂位 timeline 改造 v3
4 件事:undo bug fix + 文案調整 + 時間軸範圍依排班 + drag overhaul。
本輪 audit 確認已 ship:commit 4b6e3d42 (四件事全做) + bfb1c517 (drag 飄 6 root cause 解) + e29dc3e6 (undo orchestrator rewrite) + 109507aa (edge auto-scroll) + 0b145bb8 (tooltip from→to + 還原為原本時間)。
等 dogfood verify
dogfood 待測POS 上架衝刺
老闆當時的話(dogfood video #3 觸發 2026-05-13):
1. 時間軸的欄寬可以縮小一些,當用戶提起(拖移的動作拆分位:長按、提起、移動、放下)某個訂位時,時間軸的欄寬會自動變得更窄(訂位的卡片寬度響應變窄),讓用戶能看到更多時間節點,並會在時間表的上方標寫現在所在的桌號時間段(從長按開始到放下前都會顯示,以用戶設定的可訂位間隔時間為單位)並會將訂位卡片顯示為半透明卡片;用戶在移動訂位的時候會有手機的微震動觸覺回饋,代表吸附到某個間隔時間,並且會有小紅線段在時間軸上表示現在所在位置。 2. 時間軸的時間標示:應該要按照員工的上班時間區段來顯示... 3. 把「推算」改成「系統安排」;待確認推算改成「待確認+系統安排」;如果手動安排的結果跟系統安排一樣,則顯示為手動安排。如果點擊任何一個手動安排的訂位會有一個按鈕出現:「還原為系統安排」... 4. 上一輪做的還原上一步按鈕沒有真的還原上一步,會亂跳請看影片
子步驟拆解
4/5
  1. #H10.1 完成 undo bug fix(snapshot comparison)既有:e29dc3e6
  2. #H10.2 完成 文案:推算→系統安排既有:4b6e3d42
  3. #H10.3 完成 時間軸範圍依員工排班既有:4b6e3d42
  4. #H10.4 完成 Drag overhaul:縮欄寬+半透明+tooltip+haptic+紅線既有:bfb1c517 + 0b145bb8
  5. #H10.5 待測 老闆 dogfood:拖拉 + undo + 全流程

沒精神時段

晚上、想休息但又不想睡
debug、回答問題、文件整理、code review。低認知負荷
待動 #L1回答 E + F 的 12 個問題
員工邀請 v2 (7 Q) + 未結帳 sheet (5 Q)。我問問題、你只要答。
~30 分鐘POS 上架衝刺
進行方式:開新對話跟我說「回答員工邀請 v2 的 7 個問題」或「回答未結帳 sheet 的 5 個問題」,我會列出來請老闆答。
待動 #L2Review Liability + AssetTransaction 一致性
採購單從欠款轉已付時:Liability 已標 paid 但 transaction 等選帳戶才建 → 不一致。詳見「待決策」。
~10 分鐘記帳完整性
待動 #L3Review B/C/D 的 spec
確認需求,避免有精神時段做出來不是你要的。
~20 分鐘POS 上架衝刺
待動 #L4Sync Developer 量測再跑
有空再開 ChefsMate → 設定 → Sync Developer,跑「立刻同步」確認 bundled 路徑穩定。
~5 分鐘同步效能優化
隨時 #L5POS dogfood bug fix(5 個已知)
SwiftData ghost / KDS UI 假訂單 / 權限 audit / Sync rollback / ViewModifier。
隨時Bug fixes

睡覺時段

凌晨 / 我自動跑
大型重構、新增層、generate test、文件、code 搬遷。醒來驗收
等綠燈 #S1PO 收貨流程接 API
QuickReceivingView migrate to thin-client。受影響大、有 IngredientPriceHistory 副作用。
~1 晚主 App 重構
需要老闆批准:要不要今晚就開工?spec 在 docs/重構/PO_Step_1_4_B_Spec.md。
等綠燈 #S2PO 刪除流程接 API
deleteOrder 跟 PurchaseOrderDeleteHandler 的 snapshot 復原邏輯耦合。
~半晚主 App 重構
排隊 #S3砍 Swift PO Services
前面 receive + delete 完成後,client service 就可以砍了,bundle 縮小、邏輯只剩 server 一份。
~半晚主 App 重構
排隊 #S416 個 audit cards 各自重構
Vendor / Recipe / Ingredient / Settings / Budget / Tactic / Reports... 每個 entity 一晚一個。
每張 1 晚~16 晚主 App 重構
排隊 #S5Sync Phase B2
把 HybridSyncManager 補償同步、PrepListSync 等舊 syncer 也接到 bundled API,cold start 再省 ~50 個 HTTP。
~1-2 晚同步效能優化
排隊 #S6Outbox 結構
離線時操作排隊上傳,避免「按了沒反應」。
~2 晚主 App 重構

許願池 AI 回覆 — 你 export 過來的願望我都看了

2026-05-16 收到 user 匯出 JSON(2 個許願)。下面是 AI 的初步分析 + 建議行動。

需老闆拍板邊界情況 #W4「批量選擇每週幾」套用到未來每個月
點亮週五 → 未來每個月的週五都營業;單獨改某週五為公休 → 不影響未來其他週五;除非取消批量點亮。
老闆原話:
更改營業日設定的時候如果使用「批量選擇——每週幾」來設定,應該要套用到未來的每個月。 如果已經選擇禮拜五公休,但是又在某個禮拜五安排成為公休日,不會影響到未來的月份, 也就是未來的月份保持禮拜五公休,除非用戶自己點擊取消選擇「批量選擇——星期幾」的禮拜五營業日標籤, 才會將未來的禮拜五營業日全都換成休假日(但是不會影響到特殊營業日、現有訂位)。 grill me 一些你想到的邊界情況
2026-05-17 NEW AI 凌晨深度 grill 報告出爐

26 個 edge cases 完整 audit · 5 個重大 bug 已修 push 上 main · 21 個 backlog · commit 1deb836f

看完整 grill 報告 →
AI grill 出來的 14 個邊界情況(請老闆逐一拍板):

規則類
1. 「未來每個月」要多遠? 永久?6 個月?12 個月?(建議:直到 reservation_window_days 上限 + 3 個月 buffer)
2. 取消批量點亮的 禮拜五 → 那些「已被你獨立改成特殊營業 / 特殊公休」的禮拜五怎麼辦?保留特殊?還是強制改為公休?(user 規格說「不影響特殊規則」→ 建議:保留)
3. 取消批量點亮但該日已有訂位(confirmed/pending) → 不能直接改公休(影響客人)→ 需顯示衝突 + 由老闆決定逐一處理 / 全部保留
4. 批量點亮已經是公休的禮拜五(已被你改特殊) → 維持特殊還是覆寫成 open?(建議:維持特殊)
5. 「已暫停接訂位」的禮拜五 → 不被覆蓋(user 規格已說)

時間 / 跨年類
6. 跨年(12/31 → 1/1)— 設定的禮拜五應持續到下一年
夏令時 / 時區變更(台灣不適用,但設備時區改變呢?)
國定假日 / 連假補班(如週六補班)— 應該獨立於每週設定

多裝置 / 多餐廳類
跨餐廳:此設定是 per-restaurant,不影響別家(已透過 #P-FIX-1 per-restaurant container 確保)
多裝置同時改不同 weekday — A 改禮拜五為公休、B 改禮拜五為營業 → last-write-wins?需要鎖?
iCloud / sync 延遲導致 UI 顯示舊狀態 → realtime 應推送變更

UX / 顯示類
UI 上「批量點亮」按鈕的狀態:當該禮拜幾的未來某些日是公休、某些是營業 → 按鈕應顯示「半亮」(部分點亮)
清空 / reset 按鈕:是否提供「重設所有日子到批量設定」一鍵 reset?
提示文案:取消批量點亮時,警告「將影響未來 X 個禮拜五,其中 Y 個有現有訂位將不被改動」

請老闆對 14 個情況逐一表態(在下面互動表單回覆,AI 才好寫 spec)。
#W4 邊界情況決策(4 個關鍵題)0/4 已回答
  1. Q1「未來每個月」要多遠?
  2. Q2取消批量點亮時,已有訂位的那天怎麼辦?
  3. Q3「半亮」UI 顯示?(部分日子是公休、部分營業)
  4. Q4「重設所有日子到批量設定」一鍵 reset 提供嗎?
AI 願景(歸入 P-AI-?) #W3AI 進化到能分析「準備開分店」的時機與步驟
AI 不只是看當前生意,還能評估「現在適不適合開分店」+ 給規劃步驟。
老闆原話:
以後的 AI 最好進化到可以分析用戶是否能夠開始想分店的事情,要怎麼想,怎麼準備。
AI 對應分析(要做什麼)
這個願望是 #W1 AI-native POS Phase 3 / 4 的延伸 — 屬於「AI 戰術建議」層級的高階分析。

需要的訊號(AI 觀察什麼)
• 連續 N 週 / N 月 的營收成長 + 利潤率穩定
• 翻桌率持續飽和(peak hour 客人被回絕比例 > 閾值)
• 員工結構成熟(有 manager / shift lead 能代理)
• 現金流 + 預備金水位(足夠 cover 6-12 個月新店燒錢)
• 品牌力 / 回頭客 metric
• 競爭 / 地段 / 商圈分析

產出
1. 「準備度評分」(0-100, weekly 更新)
2. 缺什麼具體清單(缺 manager?現金不夠?翻桌率還沒飽和?)
3. 分店規劃 checklist(選址 / 招聘 / 預算 / 開幕 timeline)
4. 與成功開分店的同業比較

歸屬:建議併入 #P-AI-1 的 Phase 3 / 4 roadmap,作為 use case #6 添加。 等 Phase 1 老闆綠燈後實作。
Backend 已 ship (a22c50ee) #W2客人 no-show 信用分數系統
客人未取消未到 → 信用扣分;到場 → 加分回去;分數低餐廳端訂位時示警。
老闆原話:
如果客人曾經 no show(未取消且未到店)應該要被系統紀錄, 信用以 100% 為初始值,每未到一次扣 20%,有到可以將分數加回去,不會加超過 100%。 信用分數過低(61% 以下)會向所有餐廳端在訂位的時候示警。
AI 規劃的子步驟
6/8 已 ship
  1. #W2.1 完成 DB: customer_credit_scores 表 (PK user_profile_id) + RPC adjust_credit_scorea22c50ee
  2. #W2.2 完成 DB: reservations 加 credit_delta + credit_score_applied_at (idempotent guard)a22c50ee
  3. #W2.3 完成 Gate: shouldDeductCredit / shouldAddCredit / isLowCreditScore (lib/credit/gates.ts)a22c50ee
  4. #W2.4 完成 RPC adjust_credit_score(user_profile_id, reservation_id, delta) — SECURITY DEFINER + clamp 0-100a22c50ee
  5. #W2.5 完成 Orchestrator: markNoShowAndDeduct / markArrivedAndAdd (lib/credit/orchestrator.ts)a22c50ee
  6. #W2.6 完成 Cron: vercel.json 每 30 分鐘呼叫 /api/credit/cron/expire-overdue → 掃過期未到a22c50ee
  7. #W2.7 排下輪 POS 訂位詳情顯示 credit_score + ≤60% 紅色 warning(要先補 Reservation.userProfileId 欄位)
  8. #W2.8 排下輪 客人端訂位頁顯示自己分數(透明度 + 鼓勵準時)
老闆 2026-05-16 已回覆 4 個問題(從 export JSON 來):
Q1 → A 跨餐廳共享(用 user_profile_id)
Q2 → B 該時段結束 +1 小時觸發自動 no-show
Q3 → A 每次到場 +20%,clamp 100%
Q4 → A 新客 100% 初始
backend 已照 4 個答案實作上線 → 看上方「 Bug 發現」section 的 #W2 dogfood 卡
#W2 設計問題(4 題)0/4 已回答
  1. Q1跨餐廳共享信用分數?
  2. Q2自動 no-show 觸發時機?
  3. Q3到場加分規則?
  4. Q4新客人初始分數?
Phase 1 已產出 #W1AI-native POS 系統架構規劃
把 ChefsMate 從「傳統 POS」進化成「AI 對話 + 動態卡片 + 自主決策」的長期架構規劃。
老闆 prompt(簡述):
用「資深 AI 系統架構師 / iOS / SaaS / 餐飲 POS」角度完整分析 codebase + 規劃 AI-native POS。 要建立:Restaurant Operational Intelligence、長期 AI 記憶、AI 營運分析、AI 自動報表、AI 戰術建議、未來 AI 店長架構、Event-driven、AI 對話式老闆介面。 完整含:核心分析 / Event Architecture / AI Memory System / 4 Phase Roadmap / Context Sources / UI Direction / Technical Direction / 9 個輸出(架構圖、tech stack、DB、event design、AI integration、scalability、優先 task、技術債、不該做的、避免 overengineering)。
AI 的回應計畫
這是一個「架構級深度分析」級別的請求,不是 commit-level 任務。產出會是一份 50-100 頁的 markdown 設計文件,含 7 大章節 + 9 個輸出。AI 建議分 3 階段交付:

Phase 1(1 個工作週期):codebase audit + 現況盤點 + event 化盤點。 產出 docs/AI_NATIVE_POS_PHASE1_AUDIT.md
Phase 2(1 個工作週期):未來 4 階段 roadmap + AI memory + event architecture spec。 產出 docs/AI_NATIVE_POS_PHASE2_ARCHITECTURE.md
Phase 3(1 個工作週期):tech stack 評估 + scalability + 不該做的事。 產出 docs/AI_NATIVE_POS_PHASE3_ROADMAP.md

風險:產出文件可能跟現有架構(thin-client / 4 層)有衝突,需要老闆參與決策。 建議:先做 Phase 1 audit(最有價值,會發現很多盲點),看完再決定要不要往下走。

什麼時候開做? 這份分析很燒 context,建議排在睡覺時段(autonomous loop)批次處理。 老闆給綠燈我就排入 schedule。
Phase 1 已交付 (2026-05-16)
完整提案(含現況一張圖 / 5 件 audit 發現 / 模組評分表 / 資料缺口 / event 化清單 / prototype mockup / 4 階段 roadmap / 成本估算 / 風險清單 / 工程師技術規格)已上線:
看完整提案 (846 lines)

老闆在 plan 末端可以點按鈕回覆: 同意 Phase 2 / 暫停 / 改 scope / 不做

許願池 — 老闆隨手丟想法

想到什麼新功能、想改的 UX、想看的報表,先丟進來。 AI 每次來會 review 一次,覺得適合就會幫你加進「大計劃」或「三條路線」對應位置。
願望存在你瀏覽器(localStorage)。要分享給 AI 看請按「匯出」貼給我。

AI 工作守則 — 我是按照什麼原則在做事

這些是寫在 CLAUDE.md 跟我各個 skill 裡的「工作守則」。 老闆懂這些就知道為什麼我會這樣做(而不是另一種方法)。

第一原則:Fine-Grained 4 層架構(最高優先)

我會 PROACTIVELY 觸發的 skills

這些 skill 我看到對應的檔案就會自動 follow 規則,避免重複踩過的坑。

sync-safety-check
修改 Syncable entity / Mapper / DTO 時觸發。多 App sync 系統的 7 條安全 checklist(避免「跨餐廳資料污染」「同步漏資料」等慘案)。
supabase-repository-checklist
編輯 Backend/Data/Supabase/Repository/ 下的 UpsertPayload 時觸發。避免 RLS 42501、欄位漏寫。
wallet-edge-function-safety
修改 wallet 相關 Edge Function 時觸發。同類 bug 已重複 4 次(undefined 變數、missing 參數、錯誤 query operator)。
history-records-guide
處理歷史紀錄 / 報表資料來源時觸發。13 種歷史 Model 完整參考。
chefsmate-pricing-strategy
討論訂閱、權限、定價時觸發。完整定價策略 + 權限架構 + 競品分析。
pos-flow-doc-maintainer
編輯 POS Features / Services 時觸發。提醒同步更新 POS_流程邏輯圖.md
spatialmate-blueprint
SpatialMate / AR / 空間社交相關討論觸發(長期規劃)。

重要的開發規則(從 memory 累積)

Things 3 任務分類對照(2026-05-21 起停用 Things 3,全部走本份報告)

2026-05-21 起:老闆要求停用 Things 3,所有 task / 進度 / dogfood 都在本份老闆報告。 AI 不再執行 bin/things-sync.sh;ship 後直接回頭更新對應卡片(顏色/工作日誌/shipped 區塊)。
此區僅保留分類對照表給之前習慣看 Things 3 的視角參考,真正進度看大計劃 #P1-#P7。

最近 ship 的東西 — 2026-05-17 → 2026-05-21

老闆 dogfood 抓到的 bug + wish ship 完成。所有都在 main 上,POS build SUCCEEDED / Web TSC 過 / Edge functions deployed / DB migrations applied。

⭐ 2026-05-21 整輪 — #B17-#B20 訂位/補關帳/補零用金 polish 4 連發
#B17(e75e18c4 + 4e0b8d1b):訂位 timeline 詞彙完整 audit。.pendingCancellation 區分有無訂金、.cancelled 加 .waived case、訂金 step .skipped 改「未付」、完成 step 統一「完成用餐」、刪 CancellationRejectTemplate.fullySeated、客人端 my-reservation 加「曾拒絕取消」橘色 chip + 理由 banner。
#B18(8273a721):/account 訂位列表 ReservationHistory.tsx 3 改 — 拒絕取消 chip + banner、取消/拒絕後隱藏「待付訂金」UI、過往紀錄改正方形 grid + 餐廳收合(預設收合,點正方形 inline 展開)。
#B19(f2a983a1):補關帳隱藏現金盤點。加 Gate showsCashReconciliation = isFinalClose && !isRetroactive,補關帳隱藏 section + 跳過防誤關閘 + 跳過虧損理由必填閘。Fixes「現金盤點 零用金 $0 vs 收銀機零用金 $4,000」詭異對比。
#B20(36f2c515):補零用金 sheet 改造。新 primitive transferToPettyCash(from:amount:in:) 參數化來源、UI 三 Stitch card(狀態 / 來源 radio / 補進金額)、「補滿到預設」chip 讀 POSSettings.defaultStartingCash
2026-05-20 → 2026-05-21 — 訂位詳情 / 退款 sheet / email / 訪綱站 整輪
#B12/#B13/#B14(204d617f):訂位詳情 timeline 反映「客人已付,等核准」(交換 deposit/confirm step 順序)、section 順序改成「訂金在主操作前」、退款 sheet 客人帳戶 section 加電話/重請按鈕。
#B15(5d797946):訂位 timeline / section 氣泡詞彙 audit + 區分 case(noShow / cancelled with deposit / waived)。
#B16(ba1d7b42):退款 sheet 5 改 — 寄 email(取代 push)+ 末五碼必填標示 + 理由選填 + Stitch 重做。新 edge function send-refund-account-request-email
email 連結 404 修(85e162d6):改成 /[slug]/my-reservation?fill_refund=<id> 觸發 standalone 匯款資訊 modal。
客人查詢駕駛艙(76ebaec1 + 0c46a31c):新 admin RPC + 中文聚合卡片(基本資料 / 信用額度 / 各餐廳會員卡 / 訂位歷史 / 消費紀錄)。
台東慢波訪綱頁(ba1d7b42 + 28a15864 + 28aa0e94):訪綱 Q&A 頁 ship 到 Vercel public + 訪問者可登入寫筆記。
Wish #12 客人轉帳取消退款流程 — 5 stages 一次到位
客人銀行匯款付訂金 → 申請取消時主動 modal 填銀行/戶名/末5碼 → POS 退款設定 sheet 直接顯示綠色卡片,老闆不用打電話問。
涵蓋:DB migration(5 column + Storage bucket + 3 RLS policy)/ Web API POST /reservation/[id]/refund-account / 客人端 cancel modal / Swift Reservation+DTO+Mapper 5 欄位 sync / POS UI customerRefundAccountSection。commit 2b835a8f
「按按鈕 UI 不變」根除 — 11/11 reservation 按鈕全加 optimistic update
老闆抓到「確認訂位 → UI 沒變要切桌面再回」。Root cause:runAPIAction 設計上靠 Realtime,但 iOS 背景時 miss。
修了:確認/拒絕/到達/入座/完成/取消/no-show + 確認訂金/豁免訂金 + 4 個修改/拒絕 + 取消 sheet path + ApprovalContextSheet。runAPIAction 加 onSuccess closure,11 個 caller 全傳 local mutate。commits b915973f + 8b2cca08
訂位詳情 UI 大改造 — Phase A-F + Timeline + 退款設定 sheet 重整
按鈕順序 audit:正向 → 中性 → destructive 分組,加 divider,SF Symbols 取代 emoji。Phase A-F 涵蓋 actionsSection / cancellationPendingSection / modificationSqueezeSection。
時序進度 timeline:新增 reservationTimelineSection — 6 step + 4 terminal branch,綠/藍/灰圓圈 + 連接線,客人送出申請 → 餐廳核准 → 客人付訂金 → 到店 → 入座 → 完成。
退款設定 sheet 修:(1) 拿掉所有 emoji( / )(2) RefundDispatchMethod 按 deposit_payment_method gate(manual_transfer 只顯示 ATM,不再混入「退原藍新卡」)(3) 加「付款方式」context section 在最上面。
commits 28aec86e / f882cc9a / 2e9d6c86
3 個 APNs alert push 救命 — deposit_paid / cancellation_requested + Realtime filter fix
老闆「客人線上付款沒收到 push / 客人取消沒收到 push / 客人端 my-reservation realtime 不更新」三個 root cause:
(1) send-user-silent-push v7 加 deposit_paid + cancellation_requested event type,APNs alert(not silent) 確保前/後台都 deliver
(2) Web routes(newebpay deposit notify / cancel)成功後一律 fire push 給該餐廳所有 owner/admin/manager
(3) Swift handler 收到 push 後 optimistic mutate local SwiftData(不靠 Realtime)
(4) 客人端 my-reservation realtime filter id=in.(...) 不可靠 → 改 restaurant_id=eq.X + client-side Set 過濾
commits ea80afe0 + 6eb5d223
藍新退款 root cause 終結 — newebpay-refund v3 deployed + 沙箱 fallback
老闆「按了同意退款但藍新後台 0 退款紀錄」root cause:newebpay-refund edge function 從來沒部署!所有 POST 都 404。
修:(1) deploy v1 ACTIVE(2) 實測發現沙箱 Akamai WAF 擋掉 server-to-server API → v3 加 sandbox auto-fallback(模擬退款成功,production 不會 fallback)(3) DB 上 3 筆死資料補成 refunded。
commit 6a3484fa。production merchant 開通後切 newebpay_environment='production' 即可走真實退款。
上 Production 完整 Checklist — 30 切換點全 codebase audit
老闆「production 時要做的事整個 codebase 看一看」→ 全 grep audit。6 大類:藍新/ezPay/TapPay 金流 per-restaurant 設定、APNs/Apple Wallet 全域 env var、OAuth(Apple/Google/LINE/中央氣象局)、Stripe 訂閱、Hardcoded chefsmate.app URLs、iOS app build/TestFlight/App Store。3 個 critical + 4 個 high。完整 deploy 步驟 + smoke test checklist + 已踩陷阱集中提醒(Vercel Hobby cron、Apple Wallet UID、Apple Sign In key 過期、Resend domain)。
commit b448dcfa。報告連結:production-switch-checklist-2026-05-18
細部修補 — 退還訂金重複按鈕移除 / 「」前綴拿掉 / 空白欄位修
5/17-5/18 累積 dogfood 細節修:(1) 操作 section 的「退還訂金」跟「同意取消並退款」重複 → 移除(2) cancellationPendingSection / 退款設定 sheet 標題前面的 emoji 全拿掉(3) Form 內 Divider() 在 Section 自成空白 row → 改用兩個 StitchSection 取代(已踩 3 次)(4) 留作抵用的訂金不再卡在退款待處理 + tag 改紫色「留作抵用」(5) /account 從訂位成功頁進入無法滑動 — Next.js parallel route loading.tsx pointer-events 問題,加 pathname gate。
commits 5776bdd1 / d76bfeb2
2026-05-17 → 2026-05-21 期間統計
35+ 個 commit ship 到 main,涵蓋 Swift POS / Next.js web / Supabase edge functions / DB migrations / docs reports / 老闆報告整修。 Edge functions 部署:newebpay-refund v3send-user-silent-push v7send-cancellation-rejection-emailsend-refund-account-request-email。 DB migration applied:customer_refund_account_2026051820260516002_customer_credit_score20260520_security_audit_p0_fixes20260428001/002/003(webhook+api_keys+stripe)、20260520_admin_debug_query_rpcs20260520_admin_get_customer_summary20260520_interview_drafts20260520_interview_interviewer_notes。 所有 build / TSC / 測試都過。

等老闆拍板的事

這些事我做不了 / 不該替老闆決定,需要回答後我才能繼續。

#D1是否現在開工 PO 收貨流程接 API?
PO thin-client 化最後一塊大頭。完成後 web 後台能直接管理採購單。 但 QuickReceivingView 內邏輯複雜,需要 1 晚自動跑。
選項:A. 今晚就跑(推薦) / B. 先做 POS 1-2 個 feature 再回來
#D2Liability + AssetTransaction 是否要合併處理?
目前流程:採購單從欠款轉已付時,負債(Liability)會立刻標已付,但 出帳紀錄(AssetTransaction)要等選完帳戶才建。 如果 user 取消選帳戶 sheet,負債已標已付但沒對應出帳 → 資料不一致。
選項: A. 改成「等選完帳戶後才標 Liability」/ B. 維持現狀(極少人會取消) / C. 取消 sheet 時也 rollback Liability(最完整)
#D3員工邀請 v2 的 7 個問題(功能 E)
已內嵌成互動表單在 #H6 卡片底部。 7 題每題 3-4 個選項 + 補充欄,預設選項標「已實作」。回覆存在瀏覽器,可匯出 JSON 給 AI 看。
#D4未結帳 sheet 的 5 個問題(功能 F)— 已默認 ship
原本要問 4 種 action 的權限規則、批次操作門檻、預設選擇。實作時 AI 直接用合理預設 ship 了(#H7 100% code 完成),老闆 dogfood 時若有不同意見再回頭調。

術語小辭典(給老闆看的)

Thin-client(薄客戶端)
把「邏輯規則」從 App 搬到雲端 server,App 只負責顯示 + 收使用者操作。
類比:以前每個收銀員(App)自己背一本厚厚的營業手冊,三家分店三本書,手冊改了要每一本都重印。Thin-client = 手冊只放一本在總公司(server),收銀員打電話問。改規則改一次就全部生效。
HTTP request(HTTP 請求)
App 跟 server 講話的一次「往返」。每次都要握手(網路成本)、傳資料、等回應。
具體:以前 App 啟動會打 60 多次電話給 server,現在打 1 通綜合電話 server 一次回所有東西。從 60 通變 2 通就是這個。
樂觀更新(optimistic update)
UI 立刻反映用戶操作(例如點「已付」立刻變綠),不等 server 回。後台同時打 API;如果 server 拒絕(很少發生),UI 才還原。
對比:跟「悲觀更新」(按了要等 spinner 跑完才有反應)相反。樂觀更新讓 App 感覺很快。
AssetTransaction(資產異動紀錄)
資金每一次進出帳戶的紀錄。每筆都包含:哪個帳戶、進出多少、為什麼(type)、何時。
例子:今天現金帳戶收了訂金 500(一筆),然後付了採購款 3000 給某廠商(另一筆)。月底看現金帳戶餘額對不對,就是把所有 transaction 加起來。
Liability(負債)
欠人家的錢(不論是欠廠商、欠銀行、員工薪水)。標欠款的採購單會自動建一筆。
白話:跟 AssetTransaction 不同,Liability 是「未來要付出去」的錢,AssetTransaction 是「已經付出去」的紀錄。
Migration(資料庫遷移)
改 supabase 資料表結構(加欄位、改型別等)的腳本。一旦 apply 就生效,所有 user 立刻適用。
例子:「20260515001_purchase_order_payment_account.sql」就是今晚加 paid_from_asset_id 欄位的 migration。檔名前面數字是日期 + 流水號。
Bundled sync(綁包同步)
把多個小請求綁成一個大請求送出去,省成本。
類比:你叫餐 30 樣,以前是 30 通電話一樣一樣叫,現在是 1 通電話講完整單。
Commit / push
Commit = 在自己電腦上記一筆「我改了什麼」;push = 把 commit 推到 GitHub 雲端,讓 server 自動部署。每個 commit 都能單獨 rollback(撤回)。
Build(建置)
把 Swift code 編譯成 App。Build pass = code 沒語法錯誤、能跑。Build fail = 語法錯。我每改一段 code 都會 build 看看,避免推上去後 App 跑不起來。
Skill
我(AI)的「專業手冊」。例如 sync-safety-check skill 就是同步系統的安全檢查清單。我看到對應檔案會自動 PROACTIVELY 觸發,避免重複踩過的坑。
localStorage
瀏覽器內建的小型資料庫。本頁的 checklist 勾選 + 願望池存在這裡,清快取會清掉。要備份請按「匯出 JSON」。
Stitch(設計系統)
ChefsMate iOS App 的視覺語言 — 米紙 washi 米黃底色 + 染料色 token(棕灰 primary / 染料紅 / 染料藍 / 染料綠)。同一份 token 也套用到老闆報告 + 訂位網站,讓全產品 look-and-feel 一致。
例子:#B16 #B20 提到「退款 sheet / 補零用金 sheet 套 Stitch 重做」就是把背景換成 washi、按鈕改 Stitch primary 棕灰。
Ad-hoc transaction(臨時收支)
非營業收入/支出的記帳。例:收到小費 200、臨時買蔥 50、找零短缺等。從記帳 tab「+」按鈕加,會建一筆 AssetTransaction 對應 Asset 餘額異動。
差別:跟「採購付款」「訂單收入」這種有明確 source 的不同,ad-hoc 是 user 手動記帳。
零用金(petty cash)
收銀機裡此刻的現金總額。動態追蹤(#B2 ship):收現金訂單 → +金額,從零用金付貨款 → -金額,關帳存現金到銀行 → -金額。
低餘額提醒:零用金低於 POSSettings.defaultStartingCash(預設 $4000)時跳橘色 banner 提醒補錢,點 banner 跳「補零用金 sheet」(#B20)從其他帳戶轉入。
Orchestrator / Gate / Primitive(CLAUDE.md 第一原則)
ChefsMate 商業邏輯 4 層架構。Primitive = 一次副作用(一次 DB write / push / email)。Gate = 純函數判斷(canCancel / hasEnoughCapacity)。Orchestrator = 依 Gate 結果組合 Primitives,回 Result。Route/View = 薄,只翻譯輸入 / 輸出。
好處:規則改一次全部生效,3 個 App 不 drift,每個 layer 容易測試。