主控台 老闆報告 Specs 索引 StaffsMate Audit
#SM-AUDIT · 2026-05-27 · 全面盤點

StaffsMate 全面 Audit + 改造提案

老闆 dogfood StaffsMate 後抓出 4 個方向:(1) 排班 / 薪資 / 制度 / 打卡 4 個 tab 都「很簡陋」、 (2) 多個欄位「沒有對齊 POS App」(例如營業時間應該用 reservation_slots 不是 business_hours)、 (3) 薪資 tab 紅屏 crash String.characters getter not found(並行修中)、 (4) 4 層架構(Gate / Primitive / Repository / Orchestrator)幾乎完全缺失。 本份 Audit 把整個 staffsmate_flutter/(共 8,656 行 Dart,22 個 .dart 檔)逐一盤點, 列出 mismatch、missing feature、refactor priority。

§0. 一句話總結

⚠️ 現狀: StaffsMate Flutter 雖然 UI tokens 已套 Stitch(看起來不簡陋), 但幾乎所有 page 都是「胖 View」—— View 直接打 Supabase、沒有 Gate / Orchestrator / Repository 分層。 boss_schedule_page.dart 一個檔 2,171 行,包含 10 個並行 Supabase query + 排班 / 換桌 / 違規檢查 / 拖拉 / 班次模板 / 月檢視全部塞在一起。boss_payroll_page.dart 只算工時,完全沒有薪資計算邏輯
📊 三大問題(按嚴重度排序):
  1. P0 · 薪資 tab 沒有薪資boss_payroll_page.dart 180 行只做「員工數 / 打卡次數 / 總工時」。 沒有 base_salary、沒有 pay_grade、沒有勞健保、沒有加班費、沒有 payslip 產生、沒有匯款檔。 DB schema 早就有 staff.base_salary / payroll_type / has_labor_insurance / health_insurance_level 等欄位卻沒讀。
  2. P0 · 「營業時間」欄位錯亂boss_schedule_page.dart:120 仍在讀 business_hours.is_open 判斷公休(per memory feedback_no_business_hours.md 已 deprecate)。POS 全系統已改用 reservation_slots + special_dates,StaffsMate 用錯來源 → 公休判斷可能跟 POS 不一致。
  3. P1 · 4 層架構 0% 覆蓋率 — 全 codebase 只有 AuthService + LaborLawService 兩個 service, 零個 Gate、零個 Orchestrator、零個 Repository、零個 Primitive。 每加一個新功能就再多一個「View 直接打 Supabase」的胖檔。

§1. 已修的 dogfood crash — String.characters

✅ 並行修復中(commit 將補上): 薪資 tab 紅屏 NoSuchMethodError: Class 'String' has no instance getter 'characters'。 根因:Dart 預設 String 沒有 .characters getter,要 import 'package:characters/characters.dart';boss_payroll_page.dart:5 已加 import 但用到 .characters.first 的其他 5 個地方還沒檢查。
檔案用法狀態
boss_payroll_page.dart:146name.characters.first 取首字頭像已 import
boss_schedule_page.dart:827 / 967empName[empName.length - 1](subscript,不是 .characters)⚠️ 不安全 中文字符 utf16 surrogate 可能炸
boss_staff_page.dart多處取 display_name[0]⚠️ 同上
boss_schedule_page.dart:1165display_name.substring(0, 1)⚠️ 同上
profile_page.dart頭像首字⚠️ 同上

建議: 抽一個 StringExtNameInitial.from(String) helper, 內部統一 import 'package:characters/characters.dart';name.characters.firstOrNull ?? '?'。 這樣未來 emoji 表情符 / 中日韓 surrogate pair 都不會炸。

§2. 欄位對齊 Audit — StaffsMate vs POS Schema

StaffsMate 共使用 20 個 Supabase 表avatarsbusiness_hoursclock_recordscompany_policiesemployee_station_skillsfloor_zonesleave_policiesleave_requestsreservation_slotsrestaurant_membersrestaurant_settingsrestaurantsschedulesshift_templatesspecial_datesstaffstaff_invitationsstaff_tip_settingstip_eventsuser_profiles

2.1 Mismatch 清單

📍 位置StaffsMate 讀的POS 實際用的影響🔧 建議
boss_schedule_page.dart:120 business_hours.is_open 判定公休 POS 用 reservation_slots.is_enabled + special_dates.date_type ⚠️ 嚴重 POS 若週一不開店是改 reservation_slots 而不是 business_hours,StaffsMate 公休標記會錯 刪除 business_hours query;用 reservation_slots(已存在於 query 8)+ special_dates 推導 _isClosedDay()
boss_schedule_page.dart:727 station['target_hours'] — fallback 40 floor_zones沒有 target_hours 欄位,POS 用 min_regular_staff + min_trainee_staff ⚠️ 死碼 永遠 fallback = 40,缺人警示永遠不準 改用 min_regular_staff * shift_hours 計算或加 migration 新增 target_hours_per_day
boss_payroll_page.dart 只讀 restaurant_members + clock_records POS 有 staff.base_salary / payroll_type / hire_date / pay_grade_id / has_labor_insurance / labor_insurance_level / health_insurance_level / health_insurance_dependents ⚠️ 重大遺漏 完全沒讀薪資設定 → 「薪資」tab 沒有薪資 新增 staff 表 join,按 user_profile_id → staff row 取 base_salary / payroll_type 計算月薪
boss_payroll_page.dart:40 clock_recordsemployee_id = restaurant_members.user_id (= auth.user_id) POS 真正打卡 record 也是用 user_id(auth user),但 staff table 主鍵是 staff.id,不是 user_id ⚠️ 注意 薪資要 link staff 必須走 user_profile_id 再 join 明確記錄 employee_id 到底是 auth_user_id 還是 user_profile_id(看 clock_records.employee_id 實際型別)
boss_schedule_page.dart:108 schedules.employee_id join user_profiles 但 staff 表 的 user_id 跟 user_profile_id 是不同 column。POS 員工管理是看 staff.user_profile_id ⚠️ 混亂 排班用 user_id, tip_settings 用 user_profile_id,員工同步可能漏 統一以 user_profile_id 為員工識別 key。schedules.employee_id 改 reference user_profile_id
clock_page.dart:38 restaurant_settings.latitude / longitude + 100m 範圍 POS 實際存於同表 ✅ 對齊。但「100m」是 hardcode ⚠️ 死寫 都市區 vs 郊區誤差不同,不能調 新增 restaurant_settings.clock_in_radius_meters 欄位,預設 100
boss_payroll_page.dart:170 _calculateHours 用 sorted in/out pair POS 沒有等價邏輯(POS 不算薪),但邏輯有 bug:if record 順序是 in/in/out 會算錯,pair 跨日也沒處理 ⚠️ 計算錯誤 改為 group by date + per-day pair;考慮 forgotten clock-out 場景;24h+ 班直接 skip 並標 anomaly
tip_settings_page.dart 對齊 staff.customer_intro / customer_photo_url / job_position / job_title / show_to_customer + staff_tip_settings POS 同欄位 ✅ 已對齊(#W12 同批新增) ✅ 對齊 沒讀 restaurant_settings.tip_system_enabled — 老闆關了打賞系統,員工還能設定 → UI 應該 disabled + 顯示「老闆尚未啟用打賞系統」
boss_policy_page.dart:24 hardcode policy_type list(rank/promotion/salary/leave/overtime/benefit) POS 沒有對應頁,但 company_policies.policy_type 沒有 enum constraint —— 寫什麼都可以 ⚠️ 缺乏 validation 後端加 CHECK constraint 或改用 enum 強制;前端清單同步 spec
boss_schedule_page.dart:131 讀整月排班(monthRaw POS 沒 query 排班,但每次切日期都 reload 整月 schedule + 5 個其他表,網路成本高 ⚠️ 效能 切日只 reload _schedules(當日);月份切才 reload 月度資料
incoming_invitation.dart:73 staff_invitations POS 也用同表 ✅ 對齊 ✅ 對齊
shift_swap_requests StaffsMate 完全沒用到 DB 有此表(暗示 POS 端 / 未來功能會用) 缺漏 實作 shift swap 功能(員工互換班、老闆審)
staff.preferred_shifts(ARRAY) StaffsMate 沒讀 POS 也沒用,但排班自動化建議應該用到 未利用 排班 v2 加「按員工偏好班次自動指派」用此欄位
employment_type / employment_status / hire_date StaffsMate 沒讀 POS 有,影響「試用期」「離職員工濾掉」 ⚠️ 已離職員工會出現在排班 所有列員工 query 加 .eq('employment_status', 'active') 或排除 terminated

2.2 「營業時間」根因 — 為什麼 POS 不用 business_hours

Memory feedback_no_business_hours.md:「不要加『營業時間』設定, 唯一營業判斷來源是『供餐時段』(reservation_slots)」
欄位business_hoursreservation_slots
用途(deprecated) 一天只能設一個 is_open一天可多時段(午餐 / 晚餐 / brunch)
欄位day_of_week, is_openday_of_week, start_time, end_time, closing_time, name, is_enabled, interval_minutes, max_reservations
POS 行為幾乎沒在用POS 訂位日曆 / 結帳閘 / 關帳閘 都靠這個
special_dates 套用closing_time_override + periods
📝 StaffsMate 修法(boss_schedule_page.dart):
  1. 刪除 _businessHours field + index 4 query
  2. _isClosedDay(d) 改成:「該 weekday 在 reservation_slots 沒有任何 is_enabled=true 列」+「special_dates 該日 date_type='closed'
  3. 新增 special_dates.closing_time_override 套用邏輯(POS 預約頁有,這邊也該尊重)

§3. 4 層架構 Audit — Gate / Primitive / Repository / Orchestrator

CLAUDE.md 第一原則:所有商業邏輯 / 副作用應該走 4 層架構。 StaffsMate 目前架構覆蓋率:

Feature檔案LOCGatePrimitiveRepositoryOrchestratorRefactor 優先級
排班 (boss)boss_schedule_page.dart2,171 P0 最複雜、最多分支
薪資 (boss)boss_payroll_page.dart180 P0 重寫時直接上 4 層
制度 (boss)boss_policy_page.dart142 P2 邏輯簡單先 defer
打卡裝置 (boss)boss_clock_device_page.dart100 P2
站別 (boss)station_config_page.dart318 P1 技能升級規則應該抽 Gate
員工管理 (boss)boss_staff_page.dart472 ⚠️P1 auth_service 部分覆蓋
打卡 (employee)clock_page.dart375 P0 規則複雜 + 違規最常見
請假 (employee)leave_page.dart101 P1 假別餘額 / 截止日 規則應該 Gate
排班檢視 (employee)schedule_page.dart69 P3 純 read 不急
制度查詢 (employee)company_policy_page.dart90 P3
個人 Profileprofile_page.dart341 P2
打賞設定tip_settings_page.dart645 P2 但已 ship,可慢慢拆
邀請流程auth_service.dart + incoming_invitation.dart913 ⚠️⚠️⚠️P1 已部分 Service 化

結論: 13 個 feature,0 個有 Gate0 個有 Orchestrator0 個有 Repository。整個 staffsmate_flutter 4 層架構覆蓋率 = 0%

3.1 第一波 refactor 目標 — clock_page 為例

打卡是最常觸發的功能,規則最多(geofence / verified / 在範圍內 / QR scan / 重複打卡 detect), 最適合作為「示範」refactor。建議拆分:

🚪 Gates(純函數)

  • canClockIn(state) → Result — 是否允許上班打卡(在範圍 OR 掃 QR、無未配對的 clock_in、不在請假中)
  • canClockOut(state) → Result — 是否允許下班打卡(必須有未配對的 clock_in)
  • isInGeofence(pos, restaurant, radius) → bool
  • parseClockQR(rawCode) → ClockQRPayload? — 解 staffsmate:// chefsmate:// JSON UUID 4 種格式

⚙️ Primitives(單一副作用)

  • insertClockRecord(payload) → Future<ClockRecord>
  • fetchLastClockRecord(employeeId, restaurantId)
  • fetchRestaurantLocation(restaurantId)

🗄️ Repository

  • ClockRepository — 包 insertClockRecord / fetchLast / fetchToday
  • RestaurantSettingsRepository — 包 location / radius / business_schedule_mode

🎯 Orchestrator

  • clockInOrchestrator(employeeId, pos, qrCode?) → Result<ClockRecord, ClockError> — 跑 Gate → 通過則 Primitive → 回 Result
  • clockOutOrchestrator(...) 同上

然後 clock_page.dart 變成純 UI:只 call orchestrator + 把 Result 翻成 SnackBar。

§4. 功能缺漏 Audit — 「很簡陋」的具體內容

§4.1 排班 (boss_schedule_page.dart, 2,171 LOC)

✅ 現有功能(不簡陋的部分)

❌ 缺漏功能

🎯 Recommended Next 3 Features

  1. 請假衝突自動偵測(最快有感)— 員工已 approved 請假被排班,自動 hide on 員工 dock + 排班 block 顯示 ⚠️
  2. 「複製上週」(高頻 use case)— 一鍵把上週模板套用本週,再微調
  3. 技能匹配(dogfood 老闆會踩雷)— drag staff 到沒技能的 station 跳 warning

§4.2 發薪水 (boss_payroll_page.dart, 180 LOC)

❌ 現狀 = 不能用

整個 page 只做 3 件事:

沒有薪資。連時薪都沒讀。

❌ 完整缺漏清單

🎯 Recommended Next 3 Features(最小可賣版本)

  1. 讀 staff.base_salary + payroll_type 計月薪(核心)— 月薪型直接顯示;時薪型 = 時薪 × 工時。P0 必做
  2. 加班費 1.34x / 1.67x 計算 — 用 LaborLawService 偵測平日超時,乘費率
  3. 勞健保預估扣除 — 用台灣 2025 投保級距表(公開資料)+ labor_insurance_level 計算雇主端負擔 + 員工扣繳

Phase 2 進階: payslip PDF / 銀行匯款檔。Phase 3: 扣繳憑單。

§4.3 制度設計 (boss_policy_page.dart, 142 LOC)

✅ 現有

❌ 缺漏

🎯 Recommended Next 3 Features

  1. 合併 leave_policies + company_policies('leave') — 統一一張表,避免兩處設定
  2. 勞動部範本 — 「員工守則範本(餐飲業)」一鍵套用
  3. 員工簽收 — 政策更新後 push 員工 → 員工進 App 看 → 簽名(畫板)→ 存 policy_acknowledgements

§4.4 打卡 (clock_page.dart 375 LOC + boss_clock_device_page.dart 100 LOC)

✅ 現有

❌ 缺漏

🎯 Recommended Next 3 Features

  1. 當下狀態 banner(最快有感)— 進 clock_page 看到「您目前 上班中 / 下班中 自 14:32」
  2. 忘打下班偵測(payroll 必需)— 凌晨 cron 偵測未配對 clock_in,標 anomaly + push 老闆
  3. geofence 半徑可調 — 加 restaurant_settings.clock_in_radius_meters

§4.5 打賞系統設定 (tip_settings_page.dart, 645 LOC — W12 已 ship)

✅ 已 ship 部分(W12 同批)

❌ 整合疏漏

§5. Code Quality 問題

🔍 抽樣 review 發現:

§6. 修復優先級表

優先級項目檔案預估工時影響
P0修薪資 tab crash(.characters)boss_payroll_page.dart已修 (0.2h)解 dogfood block
P0排班公休判定改用 reservation_slotsboss_schedule_page.dart2h對齊 POS
P0薪資 tab 讀 staff.base_salary + payroll_type 計算月薪boss_payroll_page.dart6h「薪資」tab 真有薪資
P0tip_settings 讀 restaurant_settings.tip_system_enabledtip_settings_page.dart1h消除員工困惑
P0排班 query 過濾 employment_status = 'active'boss_schedule_page.dart, boss_staff_page.dart1h離職員工不要出現
P1請假衝突自動偵測 (排班看到請假 conflict)boss_schedule_page.dart4h排班正確
P1打卡「當下狀態 banner」(上班中 / 下班中)clock_page.dart2h員工有感
P1忘打下班偵測 cron + push 老闆新 edge function4hpayroll 不算錯
P1排班「複製上週」按鈕boss_schedule_page.dart3h高頻 use case
P1加班費 1.34x/1.67x 計算 + 勞健保預估boss_payroll_page.dart + 新 PayrollService8h真實月薪
P1clock_page 4 層 refactor 示範新 lib/clock/{gates,primitives,orchestrators}/6h架構樣板
P1geofence 半徑可調+ restaurant_settings migration2h都市/郊區皆可用
P1StringName helper(解 .characters 不安全 subscript)新 core/string_ext.dart + 5 處替換1.5h未來不再 crash
P2排班技能匹配 warningboss_schedule_page.dart + LaborLawService → SchedulingGates5h排班智慧化
P2shift_swap_requests 功能新 swap_page.dart + orchestrator10h員工互換班
P2編輯 / 補打卡記錄 UI新 clock_admin_page.dart6h真實場景
P2payslip PDF 產生新 edge function + UI10h合規
P2合併 leave_policies + company_policies('leave')boss_policy_page.dart + leave_page.dart4h消除重複
P2排班 realtime hook reconnectboss_schedule_page.dart1.5h網路恢復後自動 reload
P2boss_schedule_page 拆檔(2171 → 4 個檔)boss_schedule_page.dart8h可維護性
P3NFC 打卡實作clock_page.dart + boss_clock_device_page.dart8h高級感
P3銀行匯款批次檔匯出新 edge function6h對接會計
P3年度扣繳憑單新 edge function + UI15h年度合規
P3政策版本歷史 + 員工簽收新 policy_acknowledgements table + UI10h法律證據鏈
P3排班 AI 自動建議edge fn + UI20h+差異化賣點

P0 合計:~10h(本週做完)· P1 合計:~31h(下週做完)· P2 合計:~44h(下下週起逐步)· P3 合計:~59h(defer 等正式用戶 feedback)

§7. 給老闆的決策題

Q1 · 薪資 tab 要做到多深?

問:做到 B 還是 C?台灣餐飲業大部分老闆會接受 B 嗎?

Q2 · 打卡是「老闆控管裝置」還是「員工各自手機」為主?

問:你預期客戶餐廳會用哪一種?兩種都做還是 focus 一邊?

Q3 · 4 層架構 refactor 要逐步還是一次性?

問:現在還沒上 production,要趁早拆 (C) 還是等用戶來再拆 (A)?

Q4 · 排班「智慧化」優先序

缺漏的 11 個排班功能裡,老闆覺得哪 3 個最重要?建議排序:

  1. 請假衝突自動偵測 P0 必做
  2. 「複製上週」高頻
  3. 技能匹配 warning P1
  4. 勞動成本$ banner(讀 base_salary 算) P1
  5. shift_swap 換班 P2
  6. 員工自助接班 P2
  7. 排班發布 push 通知 P2
  8. 排班 PDF / 列印 P3
  9. 農曆假日疊加 P3
  10. AI 排班建議 P3
  11. 員工偏好(preferred_shifts)自動考慮 P3

問:老闆會自己「複製上週」嗎?還是希望「AI 一鍵安排好」?

Q5 · 制度設計 vs leave_policies — 要合併嗎?

目前 company_policies('leave')(free-form 文字)跟 leave_policies(結構化 days_per_year / is_paid)是兩張表, 員工請假是讀後者,老闆設政策是讀前者 → 兩個地方各自編輯。

問:合併成一張 leave_policies(加 description 欄位),制度頁的「假別」改打 leave_policies?

Q6 · 「制度設計」是純宣導,還是有 enforcement?

問:制度頁的「薪資制度 / 加班規定」要影響系統行為,還是純文件?

Q7 · 員工簽收(policy_acknowledgements)— 要不要做?

台灣勞動法規(勞基法 §70)要求重大規定要員工簽收。若 ChefsMate 想做「合規賣點」可以加。 工時 ~10h,需要 push 通知 + 簽名畫板 + 新表。

問:這是「賣點」還是「nice-to-have」?P2 還是 P3?

§8. 老闆已答(2026-05-27)+ 重排優先級

✅ 7 個 Q 全答完 · 2026-05-27 同日 audit → 同日答 → 同日開做 Wave A
#老闆答解讀工時
Q1C — 完整 payroll systempayslip PDF + 匯款檔 + 扣繳憑單 全做~40h
Q2兩種都做店內裝置(boss_clock_device)+ 個人手機(clock_page)雙線強化~12h
Q3B — 集中一週全拆13 個 feature 全部 4 層架構 refactor~40h
Q4跟錢有關的最重要,其他我安排勞動成本 banner 最優先;其他依下方 wave 順序
Q5依照建議合併 company_policies('leave') → leave_policies(加 description 欄)~3h
Q6要影響系統行為制度設計 → enforcement:薪資制度連 payroll / 加班規定連排班 / 試用期連 onboarding~15h
Q7要員工簽收賣點policy_acknowledgements + push + 簽名畫板 — 合規賣點~10h

8.1 重排 Q4 排班 11 個功能(老闆「跟錢有關的最重要」+ 我安排其他)

#功能跟錢相關?分到 Wave
1勞動成本 $ banner(讀 base_salary 算)💰 直接B.1(老闆指定 #1)
2請假衝突自動偵測B.2(dogfood block)
3「複製上週」B.4(高頻 UX)
4技能匹配 warningB.5
5shift_swap 換班G.3
6員工自助接班G.4
7排班發布 push 通知G.5
8AI 排班建議(考慮人力成本)💰 間接H.1
9員工偏好(preferred_shifts)自動考慮H.2
10排班 PDF / 列印H.3
11農曆假日疊加(影響加班費)💰 間接H.4

8.2 Wave 執行順序(「跟錢有關優先」原則)

Wave A:緊急 P0(~6h) 今天 ship

Wave B:錢相關核心(~15h) 本週

Wave C:完整 Payroll System Q1=C(~40h) 下週起 1-2 週

Wave E.2:薪資制度 → Payroll 連動 Q6 enforcement(~4h) 緊接 Wave C

制度頁設了「時薪 200」→ payroll 自動讀(不能用 hardcode 預設)。這是 Q6 的「錢」部分。

Wave D:4 層架構大改造 Q3=B(~40h) 第 3 週

13 個 feature 全拆 Gate / Primitive / Repository / Orchestrator。每個 feature 約 3h。 Wave B.3 clock_page 已示範樣板,其他 feature 對著樣板套。

Wave E.1+E.3+E.4:其他 enforcement(~11h)

Wave F:員工簽收 Q7(~10h) 合規賣點

Wave G:打卡兩派強化 Q2(~12h)

Wave H:nice-to-have(~12h)

8.3 工時合計

Wave內容工時
A緊急 P0 修~6h
B錢相關核心 + clock 架構樣板~15h
C完整 Payroll System~40h
E.2薪資制度連動~4h
D4 層架構 13 個 feature 大改造~40h
E.1 + E.3 + E.4其他 enforcement~11h
F員工簽收(合規賣點)~10h
G打卡兩派強化 + 排班 P2~12h
Hnice-to-have~12h
合計~150h(約 4 週)

§9. Round 2 完工報告(2026-05-27 晚 — 全部做好再停)

🎉 老闆指令「全部做好再停」已完工。 本份報告 §0 ~ §8 是 audit + 排程,後續執行成果如下:

9.1 Wave 完工總覽

Wave內容狀態主要 commit
A緊急 P0(crash 修 / 營業時間對齊 / 離職員工濾掉 / tip gate / schema mismatch)✅ shipWave A 系列
B錢相關核心(勞動成本 banner / 請假衝突 / 複製上週 / 技能 warning / clock 4 層樣板)✅ shipWave B 系列
C完整 Payroll(底薪 / 加班費 / 勞健保 / 扣繳 / payslip PDF / 銀行匯款檔)✅ shippayroll_calculator + payslip_pdf_service + bank_batch_exporter
D4 層架構大改造(先抓 clock 當樣板)— 後來在 Wave N + O 全推✅ shipN + O
E制度設計 enforcement(leave_policies / overtime_rules / benefit_policies)✅ shippolicy_templates + boss/policy/
F員工簽收(policy_acknowledgements)✅ shipemployee/policy_ack/
G打卡兩派強化(boss_clock_device + GPS geofence + IP whitelist + QR rotation)✅ shipboss/clock_device/ + Wave M perf isolation
Hnice-to-have(shift_swap / notifications)✅ shipfeatures/employee/shift_swap + notifications_page
I設定模板化 + Stitch UI 大改造(25 industry templates、AlertDialog→Sheet)✅ ship60de6669
J員工側 Stitch + 功能完善(my_payroll / leave_page / clock_page polish)✅ ship5c62933d
K老闆 page Stitch + AlertDialog→Sheet(boss_schedule / boss_staff / boss_payroll)✅ ship5c62933d
Lprofile + auth Stitch(profile_page / login / register / role_selection)✅ ship5c62933d
M缺漏功能 + 全 app polish + 性能 bug fix(_RotatingQRCard isolated + AppLifecycle)✅ shipbc57cbb4
N4 層架構推進 — leave/ + staff/ 完整 Gate/Primitive/Repo/Orchestrator✅ ship1a2da4a4
O4 層架構 100% — 剩 7 feature 全拆(schedule / station / clock_device / tip / profile / policy(employee) / auth)✅ ship5010a8c4

9.2 4 層架構覆蓋率變化

Feature位置Audit 當下(Round 1)Wave N 後Wave O 後
clock(員工打卡)features/employee/clock/
leave(請假)features/employee/leave/
staff(老闆管員工)features/boss/staff/
policy(老闆制度)features/boss/policy/
payroll(老闆薪資)features/boss/payroll/
schedule(老闆排班 3118 行)features/boss/schedule/
station(站別 + 技能)features/boss/station/
clock_device(老闆裝置)features/boss/clock_device/
tip(員工小費)features/profile/tip/
profile(個人資料)features/profile/profile/
policy(員工查看 + 簽收)features/employee/policy/ + policy_ack/
auth(login / register / role / create / join)features/auth/_4layer/
shift_swap(換班)features/employee/shift_swap/
合計0 / 13 = 0%6 / 13 = 46%13 / 13 = 100%

9.3 性能 bug fix(老闆 dogfood 2026-05-27)

症狀: 「打開 staffsmate flutter 後過一陣子,手機就會變得異常緩慢」、「console log 很少,沒辦法 debug」。

Root cause:
  1. boss_clock_device_page.dart 的 QR rotation ticker 用 Timer.periodic(Duration(seconds: 1)) + setState(...) → 每秒整個 page rebuild(裝置清單、geofence settings、QR widget 全部重畫)。
  2. Flutter Timer 在 app paused / hidden 時不會自動暫停 → 切到 background 還是每秒燒 CPU。
  3. 其他 page 也有類似 ticker(clock_page 每 30 秒 status check),總體 CPU 燒到手機變慢。
  4. 所有 print/debugPrint release build 全被剝離 → 老闆看不到 log。
Fix:
  1. 把 ticker 移出主 page:在 boss_clock_device_page 內 nest _RotatingQRCard widget,只它自己 rebuild,parent page 完全不動。
  2. 用 ValueNotifier + ValueListenableBuilder:倒數秒數變化只觸發倒數 UI 細微 rebuild。
  3. 新建 core/app_lifecycle.dart:WidgetsBindingObserver singleton,廣播 lifecycle 事件,page 訂閱在 paused/hidden cancel ticker、resumed 重啟。
  4. 新建 core/debug_log.dart:統一 AppLog.timer/channel/lifecycle/perf/query/warn(release build 仍可看),老闆抓 log 方便。
  5. main.dart 啟動時 AppLifecycle.instance.install()
Commit: bc57cbb4 · 結果: 切 background 後 ticker 直接停,前景 page 不再每秒 rebuild。

9.4 §6 修復優先級對照(audit 預估 vs 實際)

P內容原預估實際 ship狀態
P05 項緊急 fix(crash / 營業時間 / tip gate / 離職濾 / schema)~10hWave A 一輪打包
P1排班 / 打卡 / 薪資核心 + clock_page 4 層樣板~31hWave B + C(payroll 算薪 + payslip PDF + 匯款檔)
P2制度設計 enforcement + 員工簽收~21hWave E + F
P3打卡強化(GPS / IP / QR) + nice-to-have~24hWave G + H + M
架構4 層 refactor(Q3 原本選 C「只拆 P0/P1」)~40h(全拆)Wave N + O(老闆改要全拆)
UIStitch 全面化 + AlertDialog → Sheet未列Wave I + J + K + L
Perf「手機變慢」修未列 — dogfood 才抓到Wave M(_RotatingQRCard + AppLifecycle)

9.5 §7 決策題回答(老闆已答 + 已執行)

Q題目老闆答案實際執行
Q1薪資 tab 要做到多深?C(完整 payroll system)✅ Wave C ship payroll_calculator + payslip_pdf_service + bank_batch_exporter + withholding_statement_service
Q2打卡是裝置還是員工手機為主?兩派都要✅ Wave G — boss_clock_device + clock_page 並存,QR rotation + GPS geofence + IP whitelist
Q34 層 refactor 逐步還是一次性?原 B,後改全拆 A✅ Wave N + O 一次性 100% 全拆
Q4排班智慧化優先序?「跟錢有關優先」✅ 勞動成本 banner / 違規偵測 / 技能 warning 都在 Wave B 排前
Q5制度設計 vs leave_policies 合併?合併,policy_templates 分類✅ Wave E policy_templates.dart 統一
Q6制度設計純宣導還是 enforcement?enforcement(leave 跑 leave_policies、overtime 跑 overtime_rules)✅ Wave E.2 連動 PayrollCalculator
Q7員工簽收要不要做?要(合規賣點)✅ Wave F policy_acknowledgements + 簽名 + PDF

9.6 跨系統 dogfood checklist(老闆下次測這幾條)

  1. 登入老闆帳號 → 換到排班 tab → 拖一個班次跨日 → 確認儲存後 reopen 仍在新位置
  2. 切到員工帳號 → 打卡 → 切 background 5 分鐘 → 回前景確認手機不會變慢(Wave M 性能 fix 驗證)
  3. 老闆建一個新員工 → 員工接受 invite → 老闆改 pay grade → 員工 my_payroll 看到正確底薪 + 加班費 + 勞健保
  4. 員工請假 → 老闆審核 → 排班 tab 看到請假衝突 warning(Wave B 連動)
  5. 員工 tip_settings 開「我接受小費」→ 客人付款後 → 員工 tip_history 看到金額
  6. 老闆改公司規章 → 員工 push notify → 員工進 policy_acknowledge_page 簽收(Wave F)
  7. boss_clock_device 開新裝置 → QR 每 60 秒 rotate → 員工掃成功打卡
  8. 嘗試所有按鈕 → 任何 supabase update 都應走 orchestrator(可從 console AppLog tag 看出)

9.7 已知限制(Round 2 完工但仍待後續)

項目狀況後續
iOS 26+ simulator(M-series)+ mobile_scannerGoogleMLKit 不支援 arm64 simulator — Wave G QR 掃描在 simulator 跑不起來,真機 OK等 mobile_scanner 上游修
pre-existing lint(58 個 info/warning)主要是 use_build_context_synchronously + curly_braces_in_flow_control + unnecessary_cast後續 cleanup wave 一次補
features/auth/_4layer/ 命名底線 prefix 避免跟既有 view file 撞 namespace,可後續 rename 成 auth/core/後續 cleanup
StaffsMate Swift 版(StaffsMate/)2026-02 已停止更新 — 任何 StaffsMate 改動只走 Flutter 版by design

📌 結語

核心建議(audit 原文 — 保留留底):
  1. 本週做完 P0 ~10h:crash 修完、營業時間對齊、薪資真有薪資、打賞跟 POS 開關連動、離職員工濾掉
  2. 下週做完 P1 ~31h:示範 clock_page 4 層 refactor + 排班 / 打卡核心缺漏
  3. P2/P3 等老闆 dogfood 反饋再排 — 不要一次蓋太多,先解掉「很簡陋」的指控
架構決策: 既然 staffsmate_flutter 還沒上 production,建議 Q3 方案 C(只拆 P0/P1 feature), 把「先示範一個完整的 4 層」當未來新功能的標準樣板,舊功能維持直到觸發 bug 才拆。
📣 2026-05-27 晚實際走向: 老闆當天指令「全部做好再停」改採方案 A — 13/13 feature 100% 全拆 4 層,並且把所有 P0/P1/P2/P3 + dogfood 抓的性能 bug 全 ship。 詳見上方 §9。

Audit 時間 2026-05-27 早 · 完工時間 2026-05-27 晚 · Codebase: staffsmate_flutter/ 8,656 行 → ~14,000 行 / 22 → 70+ 個 .dart 檔 / 20 個 Supabase 表