📊完成度

10 / 10
Phase 1 Cycle 1 完成
100% ✅
✅ 已完成:10 模組(全部) 📅 用時:2026-05-27 22:57 → 2026-05-28 凌晨(~3h wall time, 9 平行) 累積 findings:190 個 累積 sysmap 修訂:46 條

🛡️最新一輪夜審 — Cycle 3 · 01. POS 認證與帳號 (2026-05-31)

重審帳號/身分相關函數與權限,抓到 2 個 Critical(帳號接管) + 3 個 High。 其中 4 項今晚已修並驗證,1 項(合併會員卡深層授權)已先擋匿名、深層待老闆 dogfood。

📋整體計劃 — POS 10 個模組(Phase 1)

🛤️Phase 演進路線

未來模組擴充:Phase 1 跑完後可加入 ChefsMateShared / Edge Functions / Web Booking / Customer App / StaffsMate Flutter 等模組。

🔬累積 Findings — 按嚴重度 / 功能性 / 功能流分類

總 findings
190
🆕 待處理 open
129
🛠 修中
0
✓ 已修
60
⏸ 延後
0
🚫 false positive
1
📖 前往 老闆白話修正紀錄(真實餐廳情境舉例)
每個 fix 都用海邊小巫/張三/客人小明的場景描述「以前會怎樣 → 怎麼修 → 修好後」,不講工程術語
✅ 2026-05-28 第一波 + 第二波 — 37 個 critical/high 已修
Critical 從 34 → 8 open(26 fixed + 1 false positive)。High 從 71 → 59 open(12 fixed)。

第一波(commit 301df6a9):
• SQL migration 20260528002:DROP dining_sessions_all / tsc_select|insert|update / checkout_sessions/payments_read|write_auth / menu_items|menu_categories|floor_items|floor_plans authenticated_read_active_*(全平台可讀風險);重建 inventory deduct trigger 用 NEW.status(原本拼錯 status_raw)。
send-wallet-link/index.ts 改成從 restaurants 表查 slug(原本查 restaurant_settings.slug 不存在 → email 兩個 wallet 按鈕從第一天就沒出現)。
POS_流程邏輯圖.md + POS_功能地圖.md 頂部加 cycle 1 doc_mismatch warning block。

第二波 batch A(commit 2f64d53b)— verifyRestaurantMember helper + 20 routes:
新 helper web/booking/src/lib/shared/verify_caller.ts:從 JWT → user_profilesrestaurant_members.role 驗證 caller,不再接 body caller_role
套用到 reservation [id]/* 11 個 route、waitlist、kds/items、order、orders/unsettled、loyalty/[memberId|join|redeem]、daily-close、checkout/session(12 個 critical/high)。

第二波 batch B(commit 57c1e2c8)— 客人端 + 金流 6 個 critical:
• seating/transfer:server-verify caller • qr-order/list:reservation_id 路徑必須帶匹配 sessionToken 或登入身分 • qr-order/submit:menu_item_price + option price_delta 從 server 查,不接 client unitPrice • newebpay/create:totalAmount 從 order_items + options server 端真實計算 • newebpay/deposit/create:驗證 reservation 屬於 body 帶的 restaurant_id • find-recent:不再回 session_token + 窗口縮成 60 秒

第二波 batch C(commit 48373b72)— SQL + 2 個 edge function:
• SQL migration 20260528003:chat_messages silent push trigger NEW.sender_role → NEW.sender_type;merge_customer_loyalty RPC 加 auth.uid() 驗證 manager+ • live-seating:predict-tables 加 restaurant_id filter(原本漏掉,跨餐廳資料外洩) • loyalty-award-points:payment_id 防重複加點

按嚴重度

🔴 Critical34
🟠 High71
🟡 Medium65
⚪ Low20

按功能性(category)

🐛 bug(實際 bug)52
🔒 security(安全)43
📝 doc_mismatch(文件不符)35
💥 data_risk(資料風險)19
🌀 race_condition12
📋 todo_debt10
🔐 rls / ⚡ perf / 🔄 sync7+7+5

按功能流(module)

✅ 01. 認證19
✅ 02. 訂位19
✅ 03. 入座18
✅ 04. 點餐19
✅ 05. KDS14
✅ 06. 結帳 ⚠️26
✅ 07. 會員 Wallet ⚠️24
✅ 08. 關帳22
✅ 09. 菜單 / 員工14
✅ 10. 聊天 / 設定15
ℹ️ 下面「按嚴重度 / 按功能性」兩個 tab 目前只顯示 Cycle 1 pos_auth 的 19 個 sample finding cards。完整 190 個 findings 跨 10 模組 請看「按功能流」tab(每模組 critical/high 摘要),或查 Supabase boss_audit_findings WHERE user_profile_id='9fc277c3-...'。下個 cycle 會 render 完整 cards。
🔴 Critical 34 個跨 10 模組(顯示 pos_auth 2 個 sample)
  • CRITICALbug
    canDeleteAccount sole-owner 檢查用錯欄位 → 永遠回 true
    AuthManager.swift:1034-1046 · 01. POS 認證
    📅 5/27
    open
    👔 給老闆看(展開預設)

    👔 老闆版 — 問題:你「刪自己帳號」按鈕應該要擋你 — 跳出「你是這家店唯一的老闆,刪了餐廳就變孤兒」的警告。但這個防護程式打錯欄位,等於完全沒擋。

    📍 舉例:你週末心情不好按了「刪除帳號」,App 沒任何警告就刪了。下週一發現店在 App 裡消失,員工被踢出,已付訂金的客人變孤兒訂單,POS 完全用不了。

    💡 建議:把客戶端擋人的邏輯接到對的欄位(改一個變數名)。同時要 Supabase 後端那邊也加一道擋人保險,不能只靠客戶端。

    👨‍💻 工程師版(技術細節)
    原因:canDeleteAccount() 用 currentUser.authUserId 去查 restaurant_members.user_id,但該欄位實際存 user_profile.id(整檔其他地方都用對的),query 永遠 0 筆 → soleOwnerRestaurants 永遠空 → throw 不執行 → canDeleteAccount 永遠回 true。Client 端 sole-owner 預檢查實際是 dead code。
    建議:改成 guard let userId = currentUser?.id;驗證 server RPC 是否真有 sole-owner check + 補進 migration 入版控。
  • CRITICALdoc_mismatch
    delete-account Edge Function 是 dead code,client 直接走 RPC
    AuthManager.swift:1108-1127 · 01. POS 認證
    📅 5/27
    open
    👔 給老闆看(展開預設)

    👔 老闆版 — 問題:刪帳號本來設計兩條路:一條 App 直接打資料庫(現在 client 走的),一條走 Edge Function(會做 6 層保護,例如要打「DELETE_MY_ACCOUNT」確認字串才能刪)。實際 App 從來沒走第二條路。

    📍 舉例:就像你家裝兩道門鎖,結果出門只鎖第一道(容易被撬的),第二道防盜鎖完全沒用過。Apple 審核以為我們有兩層,實際只有一層。而且現在用的那條路(資料庫 RPC)source code 沒入版控,連我們都看不到它在做什麼。

    💡 建議:三選一 — (a) App 改走 Edge Function(最安全) (b) Edge Function 標廢棄拿掉 (c) 至少把資料庫那條路的 source 補進版控讓我們能稽核。

    👨‍💻 工程師版(技術細節)
    原因:Sysmap 1.11 詳述 delete-account Edge Function 6 階段(JWT verify / confirmation 碼 / service_role / 等),實際 AuthManager.deleteAccount() 直接 client.rpc('delete_user_account')。Edge Function 所有保護 skip。delete_user_account RPC source 不在任何 migration → 無從稽核。
    建議(3 選 1):(a) client 改打 Edge Function(b) Edge Function 標 deprecated(c) RPC 補進 migration。
🟠 High 71 個跨 10 模組(顯示 pos_auth 5 個 sample)
  • HIGHsecurity
    send-staff-invitation-email 沒驗證 caller,持 anon key 可暴力觸發寄信
    supabase/functions/send-staff-invitation-email/index.ts:43-72
    📅 5/27
    open
    👔 給老闆看(展開預設)

    👔 老闆版 — 問題:「寄員工邀請信」這個介面應該只有「邀請人本人」可以用。現在完全沒檢查身份,任何拿到 App 公開金鑰的人都可以亂試 invitation_id 觸發官方寄信。

    📍 舉例:壞人寫程式暴力試 invitation_id。試中就讓 chefsmate.app 官方信箱寄釣魚信給目標員工。員工看到「ChefsMate 官方信」加上「加入餐廳」連結就會點 — 但連結可能被竄改,變成釣魚陷阱。

    💡 建議:寄信前驗證:看一下打這支 API 的人是不是邀請人本人。再加同 invitation 5 分鐘只能寄一次(防 spam)。

    👨‍💻 工程師版(技術細節)
    攻擊路徑:取得 anon key + 隨機 UUID 暴力試 invitation_id → 命中觸發官方 email 寄到目標。
    建議:加 Auth 驗證 invited_by == user.id;或改 SECURITY DEFINER 內網。加 idempotency。
  • HIGHsecurity
    email-link-merge 是密碼 oracle,可被 brute-force
    supabase/functions/email-link-merge/index.ts:91-100
    📅 5/27
    open
    👔 給老闆看(展開預設)

    👔 老闆版 — 問題:合併帳號功能會用「email + 密碼」跟 Supabase 試登入。Supabase 本來有「同 IP 連續試 N 次密碼就鎖」保護,但我們 Edge Function 統一用 Supabase 自家 IP 出去,Supabase 看到都是「自己人」,保護失效。

    📍 舉例:壞人註冊一個 ChefsMate 帳號(很容易),然後拿合併功能當「免費密碼破解工具」,對全世界任何 email 不停試密碼,試 1000 次也不會被擋。

    💡 建議:加「每個 user 每 5 分鐘最多試 3 次失敗就鎖」+ 不論對錯都回一樣錯誤訊息(現在「email 不存在」跟「密碼錯」會分開講)。

    👨‍💻 工程師版(技術細節)
    原因:signInWithPassword 無 rate-limit;Edge Function 統一從 Supabase IP 出去 bypass per-IP rate-limit。
    建議:加 per-caller rate limit + 統一錯誤訊息 + 記 audit log。
  • HIGHsecurity
    oauth-link-merge / line-link-merge open redirect via redirect_after
    oauth-link-merge/index.ts:188-199 · line-link-merge:86, 269
    📅 5/27
    open
    👔 給老闆看(展開預設)

    👔 老闆版 — 問題:連 Google/LINE/Apple 帳號時,我們收一個「連完跳哪」的參數。現在這個參數沒檢查,可以寫任意網址。

    📍 舉例:壞人寄釣魚連結讓你點 — 你 OAuth 認證完成後,系統會帶著「你連結哪個帳號 + 合併了幾張會員卡」資訊跳到 attacker.com。壞人就知道你的 ChefsMate 帳號狀態 + 餐廳會員量(間接洩漏營業情報)。

    💡 建議:跳轉只允許 ChefsMate 自家網址(com.chefmate.app:// 或 chefsmate.app),其他一律拒絕。

    👨‍💻 工程師版(技術細節)
    攻擊:redirect_after 沒 allowlist,phish 連結讓受害者 OAuth 完跳到 attacker.com 並 leak merged_cards 資訊。
    建議:redirect_after 強制 allowlist。
  • HIGHbug
    StaffQRCodeView Realtime channel 沒 hook reconnect → WiFi 斷一次永遠不重連
    StaffQRCodeView.swift:207-240 · 員工 QR Code 等老闆掃
    📅 5/27
    open
    👔 給老闆看(展開預設)

    👔 老闆版 — 問題:員工加入餐廳要顯示 QR Code 等老闆掃。員工這邊用「即時連線」聽老闆掃完通知。但連線斷一次就死了,要殺 App 重開才會復活。

    📍 舉例:新員工在你店裡 onboarding,WiFi 抖一下(店裡常見) — 老闆掃完員工 App 還停在 QR 畫面,等不到「歡迎加入」。員工會以為 App 壞了,殺 App 重來,變成「老闆掃了 → 員工 App 沒反應 → 殺 App → 重開 → 才看到加入成功」的爛體驗。

    💡 建議:連線斷了要自動重連(其他地方已寫過這邏輯,這裡漏)。再加每 30 秒主動問一次資料庫狀態當保險。

    👨‍💻 工程師版(技術細節)
    對比:AuthManager.startMembershipRealtime line 1330 已正確 hook reconnect,這裡漏寫(同 feedback_realtime_channel_must_hook_reconnect pattern)。
    建議:(a) hook HybridSyncManager.shared.$realtimeConnected (b) channel name 加 userId 後綴 (c) fallback polling 每 30s。
  • HIGHdoc_mismatch
    Sysmap 1.8 角色選擇分支描述跟 code 不符
    RoleSelectionView.swift:208-224 · ✓ sysmap 已修
    📅 5/27
    open
    👔 給老闆看(展開預設)

    👔 老闆版 — 問題:系統文件寫「選了角色直接跳對應畫面」,實際 code 中間還有一頁(OnboardingView)。文件描述跟實際流程不一致。

    📍 舉例:工程師(或 AI 助手)讀文件寫新功能,以為「員工選了角色 → 直接到加入餐廳頁」,實際還有中間頁。後續加「角色選完寄推播給老闆」這種功能會加錯位置,觸發時機不對。

    💡 建議:已經修了 — 把中間那層 OnboardingView 補進系統文件。

🟡 Medium 65 個跨 10 模組(顯示 pos_auth 10 個 sample)
  • MEDIUMdoc_mismatch
    Sysmap 1.5 #4「loadUserData 失敗無回滾」實際 catch 已有保護
    AuthManager.swift:1311-1314 · ✓ sysmap 已修
    📅 5/27
    open
  • MEDIUMbug
    StaffJoinRestaurantView submitJoinRequest 成功時 isSubmitting 不重設
    StaffJoinRestaurantView.swift:279-295
    📅 5/27
    open
  • MEDIUMbug
    createGroupWithRestaurant 沒事務性 — 餐廳建好但集團失敗 → 孤兒餐廳
    AuthManager.swift:1973-1995
    📅 5/27
    open
  • MEDIUMdoc_mismatch
    Edge Functions 地圖 §11 漏列 send-staff-invitation-email
    POS_Supabase_Edge_Functions地圖.md:438-460 · ✓ sysmap 已修
    📅 5/27
    open
  • MEDIUMdoc_mismatch
    Sysmap 1.9 沒提 addStaffByQR(老闆掃 QR 跳過 pending)
    AuthManager.swift:1557-1680 · ✓ sysmap 已加 1.9b
    📅 5/27
    open
  • MEDIUMbug
    SignInView onSignInSuccess 可被觸發 2 次(action 直接呼叫 + onChange)
    SignInView.swift:520-612
    📅 5/27
    open
  • MEDIUMbug
    StaffPendingApprovalView.loadRestaurantName 用 searchRestaurants('') 拉全表 dead code
    StaffPendingApprovalView.swift:217-235
    📅 5/27
    open
  • MEDIUMperf
    StaffPendingApprovalView 輪詢永不超時 + sleep 固定 10 秒
    StaffPendingApprovalView.swift:261-267
    📅 5/27
    open
  • MEDIUMbug
    AppleSignInCoordinator nonce charset 漏字母 W
    AppleSignInCoordinator.swift:65
    📅 5/27
    open
  • MEDIUMbug
    EmailVerificationView.verifyOTP 成功 path 不重設 isVerifying
    EmailVerificationView.swift:249-267
    📅 5/27
    open
⚪ Low 20 個跨 10 模組(顯示 pos_auth 2 個 sample)
  • LOWtodo_debt
    SignInView 服務條款 / 隱私政策按鈕是 TODO(Apple 審核會抓)
    SignInView.swift:256-271
    📅 5/27
    open
  • LOWtodo_debt
    send-staff-invitation-email App Store URL placeholder
    send-staff-invitation-email/index.ts:30-31
    📅 5/27
    open
🐛 Bug — 實際 bug 8 個
  • CRITICAL
    canDeleteAccount sole-owner 檢查用錯欄位 → 永遠回 true
    AuthManager.swift:1034-1046
    📅 5/27
    open
  • HIGH
    StaffQRCodeView Realtime channel 沒 hook reconnect
    StaffQRCodeView.swift:207-240
    📅 5/27
    open
  • MEDIUM
    StaffJoinRestaurantView submitJoinRequest isSubmitting 不重設
    StaffJoinRestaurantView.swift:279-295
    📅 5/27
    open
  • MEDIUM
    createGroupWithRestaurant 沒事務性 → 孤兒餐廳
    AuthManager.swift:1973-1995
    📅 5/27
    open
  • MEDIUM
    SignInView onSignInSuccess 可被觸發 2 次
    SignInView.swift:520-612
    📅 5/27
    open
  • MEDIUM
    StaffPendingApprovalView loadRestaurantName 拉全表 dead code
    StaffPendingApprovalView.swift:217-235
    📅 5/27
    open
  • MEDIUM
    AppleSignInCoordinator nonce charset 漏字母 W
    AppleSignInCoordinator.swift:65
    📅 5/27
    open
  • MEDIUM
    EmailVerificationView verifyOTP isVerifying 不重設
    EmailVerificationView.swift:249-267
    📅 5/27
    open
📝 Doc Mismatch — 文件跟 code 不符 5 個
  • CRITICAL
    delete-account Edge Function 是 dead code(client 走 RPC)
    AuthManager.swift:1108-1127
    📅 5/27
    open
  • HIGH
    Sysmap 1.8 角色選擇分支描述跟 code 不符
    RoleSelectionView.swift:208-224
    📅 5/27
    open
  • MEDIUM
    Sysmap 1.5 #4「loadUserData 失敗無回滾」已過時
    AuthManager.swift:1311-1314
    📅 5/27
    open
  • MEDIUM
    Edge Functions §11 漏列 send-staff-invitation-email
    POS_Supabase_Edge_Functions地圖.md:438-460
    📅 5/27
    open
  • MEDIUM
    Sysmap 1.9 沒提 addStaffByQR(老闆掃 QR 跳過 pending)
    AuthManager.swift:1557-1680
    📅 5/27
    open
🔒 Security — 資安 3 個
  • HIGH
    send-staff-invitation-email 沒驗證 caller
    send-staff-invitation-email/index.ts:43-72
    📅 5/27
    open
  • HIGH
    email-link-merge 是密碼 oracle(可 brute-force)
    email-link-merge/index.ts:91-100
    📅 5/27
    open
  • HIGH
    oauth-link-merge / line-link-merge open redirect
    oauth-link-merge/index.ts:188-199
    📅 5/27
    open
📋 TODO Debt 2 個
  • LOW
    SignInView 服務條款 / 隱私政策按鈕是 TODO
    SignInView.swift:256-271
    📅 5/27
    open
  • LOW
    send-staff-invitation-email App Store URL placeholder
    send-staff-invitation-email/index.ts:30-31
    📅 5/27
    open
⚡ Perf — 效能 1 個
  • MEDIUM
    StaffPendingApprovalView 輪詢永不超時 + sleep 固定 10 秒
    StaffPendingApprovalView.swift:261-267
    📅 5/27
    open
✅ 01. POS 認證與帳號 19 findings · Cycle 1 · 2026-05-27
  • CRITICALbug
    canDeleteAccount sole-owner 檢查永遠回 true
    AuthManager.swift:1034-1046
    📅 5/27
    open
  • CRITICALdoc_mismatch
    delete-account Edge Function dead code
    AuthManager.swift:1108-1127
    📅 5/27
    open
  • HIGHsecurity
    send-staff-invitation-email 沒驗證 caller
    send-staff-invitation-email/index.ts:43-72
    📅 5/27
    open
  • HIGHsecurity
    email-link-merge 是密碼 oracle
    email-link-merge/index.ts:91-100
    📅 5/27
    open
  • HIGHsecurity
    oauth-link-merge / line-link-merge open redirect
    oauth-link-merge/index.ts:188-199
    📅 5/27
    open
  • HIGHbug
    StaffQRCodeView Realtime 沒 hook reconnect
    StaffQRCodeView.swift:207-240
    📅 5/27
    open
  • HIGHdoc_mismatch
    Sysmap 1.8 角色選擇跟 code 不符
    RoleSelectionView.swift:208-224
    📅 5/27
    open
  • MEDIUMdoc_mismatch
    Sysmap 1.5 #4 已過時
    AuthManager.swift:1311-1314
    📅 5/27
    open
  • MEDIUMbug
    StaffJoinRestaurantView isSubmitting 不重設
    StaffJoinRestaurantView.swift:279-295
    📅 5/27
    open
  • MEDIUMbug
    createGroupWithRestaurant 沒事務性
    AuthManager.swift:1973-1995
    📅 5/27
    open
  • MEDIUMdoc_mismatch
    Edge Functions §11 漏列 send-staff-invitation-email
    POS_Supabase_Edge_Functions地圖.md:438-460
    📅 5/27
    open
  • MEDIUMdoc_mismatch
    Sysmap 1.9 沒提 addStaffByQR
    AuthManager.swift:1557-1680
    📅 5/27
    open
  • MEDIUMbug
    SignInView onSignInSuccess 觸發 2 次
    SignInView.swift:520-612
    📅 5/27
    open
  • MEDIUMbug
    StaffPendingApprovalView loadRestaurantName 拉全表
    StaffPendingApprovalView.swift:217-235
    📅 5/27
    open
  • MEDIUMperf
    StaffPendingApprovalView 輪詢永不超時
    StaffPendingApprovalView.swift:261-267
    📅 5/27
    open
  • MEDIUMbug
    AppleSignInCoordinator nonce charset 漏字母 W
    AppleSignInCoordinator.swift:65
    📅 5/27
    open
  • MEDIUMbug
    EmailVerificationView verifyOTP isVerifying 不重設
    EmailVerificationView.swift:249-267
    📅 5/27
    open
  • LOWtodo_debt
    SignInView 服務條款 / 隱私政策 TODO
    SignInView.swift:256-271
    📅 5/27
    open
  • LOWtodo_debt
    send-staff-invitation-email App Store URL placeholder
    send-staff-invitation-email/index.ts:30-31
    📅 5/27
    open
✅ 02. POS 訂位 19 findings · Cycle 1 · 2026-05-28
3 critical / 7 high / 6 medium / 3 low · 最關鍵:所有 reservation API actor_role 從 client body 信(可冒 owner)/ find-recent 用 phone 撈 session_token / newebpay deposit/create 沒驗 reservation 屬於 body 帶的 restaurant。 看 19 筆完整詳情 →
✅ 03. POS 接待 / 入座 / 候位 18 findings · Cycle 1 · 2026-05-28
5 critical(最多 critical 模組之一)/ 7 high / 5 medium / 1 low · 最關鍵:/api/seating/transfer 無 auth 可換任何餐廳的桌 / table_sessions RLS USING(true) / live-seating 漏 restaurant_id filter / smart-seating restaurantId optional。
✅ 04. POS 點餐 19 findings · Cycle 1 · 2026-05-28
3 critical / 7 high / 6 medium / 3 low · 最關鍵:POS 點餐 API caller_role 從 client body 信 / QR 客人 menu_item_price client 可改($0 點任何菜)/ inventory deduct trigger 用錯欄位(從未真正扣庫存)。
✅ 05. POS 廚房 / KDS 14 findings · Cycle 1 · 2026-05-28
2 critical / 6 high / 5 medium / 1 low · 最關鍵:KDS API 無 auth 任何人帶 caller_role:owner 可改任意 order_item / KitchenOrdersView @Query 沒 filter restaurant_id 跨餐廳污染 / Siri ExpediteIntents 跨餐廳指令。
⚠️ 06. POS 結帳 / 分帳 / 折扣 / 優惠券 / 發票 26 findings · 金流模組 critical 最多
5 critical / 11 high(全模組最高 high)/ 8 medium / 2 low · 最關鍵:newebpay/create 信 client totalAmount(可付 $1 結 $1500)/ newebpay-refund 無 auth 知 payment_id 可退別家錢 / payments RLS USING(true) 全平台可讀 / ezpay-invoice 任何人可代開發票 / checkout/session caller_role 可冒 owner 開 100% 折扣。
⚠️ 07. POS 會員 / Wallet / 獎勵 24 findings · critical 最多模組(6 個)
6 critical(全模組最多)/ 7 high / 8 medium / 3 low · 最關鍵:/api/loyalty/redeem 無 auth 可兌任意人任意獎勵 / merge_customer_loyalty RPC 任意 user 可合併同餐廳任兩張會員卡 / /api/loyalty/[memberId] 公開所有會員個資 / 5 支 wallet edge fn 無 auth(可 spam 推播 / 耗 Resend 配額)/ loyalty-award-points 無 dedupe 同筆 payment 重複加點。
✅ 08. POS 關帳 / 記帳 / 報表 22 findings · Cycle 1 · 2026-05-28
3 critical / 9 high / 8 medium / 2 low · 最關鍵:archive-monthly-data 完全沒 auth 可摧毀任何餐廳資料 / /api/daily-close caller_role 可冒 owner / /api/orders/unsettled 無 auth 可列任意餐廳未結帳訂單 / POSReportService 沒 .scoped() 多餐廳 store 殘留會跨餐廳加總報表。
✅ 09. POS 菜單 / 樓面 / 員工 14 findings · Cycle 1 · 2026-05-28
2 critical / 6 high / 5 medium / 1 low · 最關鍵:9 個 staff orchestrator 信 client caller_role 可繞權限(踢人/邀請/改薪) / menu_items / floor_items RLS 任何登入 user 可讀全平台所有餐廳菜單樓面 / MenuItemMapper.customUpload 強制改寫 restaurantId(跟海邊小巫桌位被搬走是同個 pattern)。
✅ 10. POS 聊天 / 設定 15 findings · Cycle 1 · 2026-05-28
3 critical / 6 high / 4 medium / 2 low · 最關鍵:Chat trigger 引用不存在欄位 NEW.sender_role(每次發訊息可能炸 + silent push 從未發)/ NewebPay HashKey/HashIV 所有 staff 都讀得到(離職員工可簽假退款)/ chat_messages RLS 狀態未知可能還是 USING(true)/ POSSettingsView 53 個 modifier 接近 stack overflow / SubscriptionTester 客人可繞 IAP 升 enterprise。

⚙️工作流 — 怎麼跑的

  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
  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 + 攤平:UPDATE boss_nightly_audits row + INSERT findings 到 boss_audit_findings(這頁的資料來源)
  8. 重 render 這頁:在 cycle 進度勾選新模組、把新 findings 加進三維分類、更新統計
  9. 改 sysmap docs + git push
⚠️ 老闆指定:所有 finding「只回報、不自動修」。 即使是 critical,AI 不能 push code 修。老闆自己決定優先級 / 修哪個 / 延後哪個。

🔄Finding 狀態流轉

每筆 finding 有以下 8 種狀態:

  • open — 剛發現,預設
  • triaged — 老闆看過,排程修
  • in_progress — 修中
  • fixed — 已修
  • wont_fix — 老闆決定不修
  • deferred — 延後處理
  • duplicate — 跟之前重複
  • false_positive — Agent 誤報

怎麼改狀態?跟 AI 說「把『XXX 標題』標 fixed / wont_fix / deferred」, AI 會 UPDATE Supabase。下次 trigger 夜審或手動 refresh 這頁就會看到狀態變化。

底層:Supabase table boss_audit_findings + RPC boss_audit_findings_plan(uuid)。 資料 INSERT 一次永不刪除(只改 status),歷史完整保留。