| KB-01 |
mobile 面試同意 UI 仍檢查三方全簽,DB 已拍板兩方即完成(HM-CMP-01-D03)——無見證顧問的案件永遠不顯示「全部已簽署」→ HM-MOB-02-T01 已修(…mobile 面試同意 UI 仍檢查三方全簽,DB 已拍板兩方即完成(HM-CMP-01-D03)——無見證顧問的案件永遠不顯示「全部已簽署」→ HM-MOB-02-T01 已修(2026-07-06)來源證據:`apps/mobile/src/screens/WorkerScheduleScreen.tsx:301-305` vs `supabase/migrations/20260704014816_consent_completion_two_party.sql`(2026-07-06 盤點) |
HIGH |
已修 |
| KB-02 |
mobile 視訊字幕 caption relay 只綁 web cookie session,RN bearer token 呼叫不了——雙方任一在手機,字幕開天窗 → HM-M…mobile 視訊字幕 caption relay 只綁 web cookie session,RN bearer token 呼叫不了——雙方任一在手機,字幕開天窗 → HM-MOB-02-T03 已修 auth 缺口(2026-07-06;殘餘 STT 來源缺口 → BL-07)來源證據:`apps/mobile/src/lib/video.ts:349-362` 檔尾已標注(2026-07-06 盤點) |
HIGH |
已修 |
| KB-03 |
`worker_account_binding` milestone 從未被種子 trigger 自動建立,僅一次性 backfill 處理過舊訂單,新訂單有資料落差。→ 已修(2…`worker_account_binding` milestone 從未被種子 trigger 自動建立,僅一次性 backfill 處理過舊訂單,新訂單有資料落差。→ 已修(2026-07-12):重驗確認五版 seed function 皆缺(根因:`20260427080000` 加 CHECK 與一次性 backfill 但未動 seed function,`20260427120000` 重寫時又對齊到更舊版本);新增 `20260712142627_kb03_seed_worker_account_binding_milestone.sql` 重建 seed function 補 key(排序在 `flight` 之後、owner `admin`)+冪等 backfill 全部未刪除訂單,已 push 至遠端(2026-07-12,strict audit file=188 applied=188)來源證據:比對五個版本 seed function 皆無(2026-07-06 盤點;2026-07-12 重驗確認缺口為真) |
MEDIUM |
已修 |
| KB-04 |
mobile `AccountScreen` 整頁寫死 mock 資料(`IDENTITY` 常數),不隨登入者變動 → HM-MOB-02-T01 已修(2026-07-06)mobile `AccountScreen` 整頁寫死 mock 資料(`IDENTITY` 常數),不隨登入者變動 → HM-MOB-02-T01 已修(2026-07-06)來源證據:`apps/mobile/src/screens/AccountScreen.tsx:19-23`(2026-07-06 盤點) |
MEDIUM |
已修 |
| KB-05 |
`docs/roadmaps/mobile-app-shell.md` 的「Current Shell」段落與同檔 Task Breakdown 矛盾(描述停留在早期原型狀態)。→…`docs/roadmaps/mobile-app-shell.md` 的「Current Shell」段落與同檔 Task Breakdown 矛盾(描述停留在早期原型狀態)。→ 已修(2026-07-12):「Current Shell」段落依 Task Breakdown 與程式碼現況(25 個 screen、`libs/mobile-api` 17 模組)以刪除線+箭頭改寫來源證據:2026-07-06 盤點;以 Task Breakdown 與程式碼現況為準 |
LOW |
已修 |
| KB-06 |
admin 面試逐字稿翻譯面板顯示層仍用三方全簽判定與「三方齊全」文案(功能閘門吃 `consent_recorded_at` 已是兩方語意,僅顯示不一致)。→ 已修(2026-0…admin 面試逐字稿翻譯面板顯示層仍用三方全簽判定與「三方齊全」文案(功能閘門吃 `consent_recorded_at` 已是兩方語意,僅顯示不一致)。→ 已修(2026-07-12):`allSigned` 改為 `bothPartiesSigned`(僅檢查雇主+候選人),agency 卡片標示「(見證)」,`consentTranslate.consent.*` 六語系文案同步改為兩方語意;功能閘門未動。同目錄 `actions.ts` 的「三方」字樣屬簽署角色語意(政策用語)非完成判定,保留來源證據:`apps/admin/src/app/[locale]/(dashboard)/interview-requests/consent-translate-panel.tsx:68-71` 與 `admin.interviewRequests.consentTranslate.consent.*` 文案(2026-07-06 修 KB-01 時發現) |
LOW |
已修 |
| KB-07 |
`libs/db/src/dal/milestone-sla.ts` 的 `MILESTONE_KEYS_V2` 只有 15 值,與 DB canonical 21 碼脫節(缺 d…`libs/db/src/dal/milestone-sla.ts` 的 `MILESTONE_KEYS_V2` 只有 15 值,與 DB canonical 21 碼脫節(缺 domestic_recruitment_posting、job_seeking_certificate、worker_account_binding、arrival_health_check_filed、injury_insurance_register、accident_or_liability_insurance);補齊需一併定義各 key 的 SLA meta,不宜盲修來源證據:`libs/db/src/dal/milestone-sla.ts:14-31` vs `supabase/migrations/20260427090000_p3_arrival_health_check_filed_milestone.sql` 21 值 CHECK(2026-07-06 DB 基線盤點) |
MEDIUM |
未修 |
| KB-08 |
`tg_assert_case_documents_source_agency_scope` 殘留 `up.role` 引用(Sprint 5.2 sub-8 drop `user…`tg_assert_case_documents_source_agency_scope` 殘留 `up.role` 引用(Sprint 5.2 sub-8 drop `user_profiles.role` 時漏遷移),導致所有 `milestone_key <> 'source_country_prep'` 的 `case_documents` 寫入(含 service-role 路徑:web 雇主文件上傳)自 2026-04-29 起 plan error → 已修(2026-07-06,`20260706223506_fix_case_documents_scope_trigger_role.sql`)來源證據:HM-MOB-02-T09 E2E 首次上傳即中斷(`column up.role does not exist`);原函式 `20260427000000_p1_4_source_agency_case_documents_rls.sql:78-107` |
HIGH |
已修 |
| KB-09 |
`20260429170142_create_case_studies_bucket.sql` 的 storage policy 仍引用已 drop 的 `up.role`;`20…`20260429170142_create_case_studies_bucket.sql` 的 storage policy 仍引用已 drop 的 `up.role`;`20260429210200` 只重建了 `case_studies_storage_insert`,其餘同檔 policy 是否已全數遷移待重驗——殘留者會使 case-studies bucket 對應操作 plan error來源證據:`supabase/migrations/20260429170142_create_case_studies_bucket.sql:45,56`(2026-07-06 修 KB-08 時發現;待重驗) |
MEDIUM |
未修 |
| KB-10 |
mobile 翻譯聊天只有 DB trigger 建立 `candidate_message_translations.pending` row,沒有任何 worker/consu…mobile 翻譯聊天只有 DB trigger 建立 `candidate_message_translations.pending` row,沒有任何 worker/consumer 將 pending 轉為 completed,真實訊息會長期停在 Translating;demo seed 手動塞 completed 翻譯掩蓋了缺口。→ 已修 mobile BFF 消費端(2026-07-09):送出與 thread 讀取時會用 service-role 消費 pending translations。來源證據:HM-MOB-02-Q01 W3 真機測試;`libs/mobile-api/src/conversations.ts`;`libs/ai/src/tasks/translate-message.ts`;`scripts/seed-demo-candidates.ts` 手動建立 completed 翻譯假資料。 |
HIGH |
已修 |
| KB-11 |
mobile 訊息串送出訊息後 optimistic row 會短暫消失再出現,疑似 6 秒輪詢覆蓋本地 optimistic state,造成 sending 狀態閃爍。→ 已修…mobile 訊息串送出訊息後 optimistic row 會短暫消失再出現,疑似 6 秒輪詢覆蓋本地 optimistic state,造成 sending 狀態閃爍。→ 已修(2026-07-15):確認根因是 POST 成功後先移除 optimistic row、再非同步重載 thread 的空窗;mobile 以 stable `clientMessageId` 送出,thread fetch 以 client/server id 對應 optimistic row,伺服器重試撞既有唯一鍵時回原 `messageId`,直到 fetch 確認同一訊息才移除 pending,並加 conversation switch stale request 防護。來源證據:HM-MOB-02-Q01 W3 真機測試;`apps/mobile/src/screens/ChatScreen.tsx`、`apps/mobile/src/lib/conversation-pending.ts`、`apps/mobile/src/lib/conversations.ts`、`libs/mobile-api/src/conversations.ts`、`scripts/test-mobile-conversation-pending.ts`;純函式回歸測試、mobile/mobile-api typecheck 與 lint 通過。 |
MEDIUM |
已修 |
| KB-12 |
mobile `Button` 沒有預設水平 padding,合約簽署失敗/重試按鈕在未傳入 style 時文字貼邊跑版。→ 已修(2026-07-09):`Button` bas…mobile `Button` 沒有預設水平 padding,合約簽署失敗/重試按鈕在未傳入 style 時文字貼邊跑版。→ 已修(2026-07-09):`Button` base style 補 `paddingHorizontal`。來源證據:HM-MOB-02-Q01 W4;`apps/mobile/src/components/Button.tsx`。 |
LOW |
已修 |
| KB-13 |
合約簽署成功後未同步 resolve journey task:worker 與 employer 都已在 `contract_signatures` 寫入簽署紀錄,但 `case…合約簽署成功後未同步 resolve journey task:worker 與 employer 都已在 `contract_signatures` 寫入簽署紀錄,但 `case_tasks` 的「簽署合約(本人)」與「簽署合約(雇主)」仍是 `open`,案件進度不會因簽署完成而前進。→ 已修(2026-07-09):新增 `contract_signatures` trigger 與 backfill migration。來源證據:HM-MOB-02-Q01 W4/E5;`supabase/migrations/20260709143000_resolve_contract_signature_tasks.sql`。 |
HIGH |
已修 |
| KB-14 |
mobile 雇主端多個 stack screen 會吃掉底部 tabbar:聘僱意思表示表單、面試管理頁局部區域、合約簽署頁皆會失去 tabbar 脈絡,疑似 SafeArea/…mobile 雇主端多個 stack screen 會吃掉底部 tabbar:聘僱意思表示表單、面試管理頁局部區域、合約簽署頁皆會失去 tabbar 脈絡,疑似 SafeArea/Stack layout padding 與 tab navigator 組合問題。→ 已修主要入口(2026-07-09):新增 tab 內 route alias 並改導覽入口;root deep links 保留相容。來源證據:HM-MOB-02-Q01 E4/E5;`apps/mobile/app/(tabs)/**` route aliases;`JourneyScreen`、`EmployerInterviewsScreen`、`ChatScreen`、`EmployerDetailScreen`。 |
MEDIUM |
已修 |
| KB-15 |
雇主端從訊息列表進入對話串看起來像取代目前 view,而非 push 到下一層,返回語意與底部 tab 脈絡不符合 iOS stack navigation 預期。→ 已修(202…雇主端從訊息列表進入對話串看起來像取代目前 view,而非 push 到下一層,返回語意與底部 tab 脈絡不符合 iOS stack navigation 預期。→ 已修(2026-07-09):新增 `/chat/[conversationId]` tab stack route。來源證據:HM-MOB-02-Q01 E4 入口③真機測試;`apps/mobile/app/(tabs)/chat/[conversationId].tsx`、`apps/mobile/src/screens/ChatScreen.tsx`。 |
MEDIUM |
已修 |
| KB-16 |
Admin 工作收件匣 application-level work item 候選人欄空白:`case_tasks` 只透過 `case_journeys.service_ord…Admin 工作收件匣 application-level work item 候選人欄空白:`case_tasks` 只透過 `case_journeys.service_orders.candidates.display_name` 取候選人;尚未轉成 service order 的 `application_id` journey 無候選人顯示,人工無法辨識案件。→ 已修(2026-07-09):補 `placement_applications -> candidates` fallback。來源證據:HM-MOB-02-Q01 黃金路徑;`apps/admin/src/app/[locale]/(dashboard)/work-items/actions.ts`。 |
MEDIUM |
已修 |
| KB-17 |
HM-MOB-02-Q01 測試計畫原預期「移工送期滿意願 → 雇主合意 → admin 收件匣 S8 任務同步 resolve」,但現行 trigger 只自動 resolve …HM-MOB-02-Q01 測試計畫原預期「移工送期滿意願 → 雇主合意 → admin 收件匣 S8 任務同步 resolve」,但現行 trigger 只自動 resolve worker `期滿意思表示` 與 employer `續約意願確認(雇主)`,admin `續約推進確認` 仍需人工結案。→ 已修文件期望(2026-07-09):保留人工平台確認,不自動跳過 admin task。來源證據:HM-MOB-02-Q01 黃金路徑;`docs/specs/mobile-mvp-q01-test-plan.md`;`supabase/migrations/20260706211420_ending_intents.sql` 設計仍正確。 |
MEDIUM |
已修 |
| KB-18 |
`libs/mobile-api` 的 `getContractSignContextForUser`/`signContractForUser`(barrel-exported …`libs/mobile-api` 的 `getContractSignContextForUser`/`signContractForUser`(barrel-exported primitive)信任呼叫端傳入的 `userId`、內部無獨立 identity 驗證;今日呼叫端皆傳入已驗證的 `auth.user.id`(安全),但作為公開 primitive 對未來呼叫端無防禦。→ 已修(2026-07-12):兩個 primitive 移除 `userId` 參數,改由內部 `client.auth.getUser()` 自行求值(mobile bearer client 與 web cookie session client 兩型態皆驗證成立),失敗回 401 `unauthenticated_client`;呼叫端(mobile BFF handler、`apps/web` contract-sign-actions)同步調整。barrel export 保留(`apps/web` 需經 index 進入,屬既有設計)來源證據:`libs/mobile-api/src/contracts.ts:200`(`getContractSignContextForUser`)、`:267`(`signContractForUser`);barrel export `libs/mobile-api/src/index.ts:28,30`(HM-RBAC-01 console 合併對抗式 workflow 附帶發現,OQ-6,2026-07-10 盤點;建議 mobile team 評估是否停止 barrel-export 這兩個 `*ForUser` primitive) |
MEDIUM |
已修 |
| KB-19 |
`advisor-invites/actions.ts` 的 `listAgencyAdvisorInvitations` 對 `candidates` 表按 ID 直讀 `dis…`advisor-invites/actions.ts` 的 `listAgencyAdvisorInvitations` 對 `candidates` 表按 ID 直讀 `display_name`,未經 `agency_visible_candidate_ids()` 目錄函式收斂(與同檔雇主名稱查詢走 DEFINER view 的手法不一致);pre-existing,隨 T50 搬移時原樣帶入、非本次造成來源證據:`apps/admin/src/app/[locale]/agency-console/advisor-invites/actions.ts:129`(HM-RBAC-01 T50 搬移時發現,OQ-8,2026-07-10 盤點;RLS 仍為底線防護,屬手法一致性/defense-in-depth gap) |
LOW |
未修 |
| KB-20 |
~~`pnpm audit:doc-sync` 的 `portal-apps` 檢查恆為 FAIL——`scripts/audit-doc-sync.ts` 的 `EXPECTED…~~`pnpm audit:doc-sync` 的 `portal-apps` 檢查恆為 FAIL——`scripts/audit-doc-sync.ts` 的 `EXPECTED_PORTALS` 陣列仍含 `'agency'`,但 `apps/agency` 已於 HM-RBAC-01 T50(ADR-0012 實體合併)刪除,code 現只剩 `admin`/`web`/`worker` 三個 Next.js portal;依 `docs/engineering/doc-sync-governance.md` Doc-Sync Matrix 此為 T50 應同步但遺漏的一步,修正需改 `scripts/audit-doc-sync.ts`(code,非 `docs/**`)~~ → **已修**(2026-07-10,commit: `fix(rbac): drop retired agency portal from doc-sync check (HM-RBAC-01-T50 followup)`):`EXPECTED_PORTALS` 移除 `'agency'`,改為 `['admin', 'web', 'worker']`來源證據:`scripts/audit-doc-sync.ts:48`;`pnpm audit:doc-sync` 2026-07-10 實跑輸出:`❌ portal-apps: code=[admin, web, worker];expected=[admin, agency, web, worker]`(HM-RBAC-01-T54 doc-sync 收尾時發現);修正後重驗:`pnpm audit:doc-sync` 與 `AUDIT_FAIL_ON_DRIFT=true pnpm audit:doc-sync`(CI 等效)皆 `pass=6 warn=0 fail=0`(2026-07-10 重跑確認) |
LOW |
已修 |
| KB-21 |
sign-in 登入成功後導向落在無 locale 前綴的 `/agency-console`(角色判定預設導向、或 deep-link `next` 回帶皆同),需靠 next-…sign-in 登入成功後導向落在無 locale 前綴的 `/agency-console`(角色判定預設導向、或 deep-link `next` 回帶皆同),需靠 next-intl middleware 在下一輪請求補回 `/zh-TW` 前綴才落地正確路徑;純 cosmetic 雙重導向,不影響最終可達性與權限判定,本次 agency console 實體合併引入,defer來源證據:`apps/admin/src/lib/auth/sign-in.ts:73`(`redirect(roleCheck.ok ? '/' : '/agency-console')` 未帶 locale 前綴,`:66` 的 deep-link `next` 分支同病);`apps/admin/src/proxy.ts:1,6,12`(`next-intl` `createIntlMiddleware` 於下一輪請求補回前綴);HM-RBAC-01 console 實體合併對抗式 workflow 附帶發現(2026-07-10 盤點) |
LOW |
未修 |
| KB-22 |
HM-RBAC-01 軟隔離 enforcement 的 SHAPE 4 檢查(`checkConsoleServiceFn`)只收集頂層函式再檢查函式體內的 service-ro…HM-RBAC-01 軟隔離 enforcement 的 SHAPE 4 檢查(`checkConsoleServiceFn`)只收集頂層函式再檢查函式體內的 service-role 工廠呼叫;若 client 建構被提升到 module scope(`const service = createAdminServiceClient()` 寫在任何函式之外),該 ctor 不屬任何被收集函式,檔內所有函式被判「非 key-holding」而跳過 authz 檢查,且此形態同時逃過其餘三層(L1 只掃 agency-console、L2 對 console-service `doNotFollow`、L3 只找裸 token)——四層全綠的假保證。非現行漏洞(現碼每個 gated fn 各自建 client),屬 enforcement 偵測缺口;「建一次快取在模組頂層」是常見效能重構,發生機率高。建議修法:guard 加「console-service 內 module-scope service-role ctor 一律違規」規則(module scope 於 request 前執行,結構上不可能做 per-request authz)+ red fixture;或至少比照 (i)–(iii) 在掃描器 header 明文揭露來源證據:`scripts/audit-console-guard.ts:470-490` 附近(`collectFns`+`callPositions` 配對邏輯);PR #12 獨立安全審查發現(2026-07-11);對照掃描器 header 已揭露之 (i) dynamic store-then-property、(ii) bracket notation、(iii) same-file 殘留,獨漏此類別 |
MEDIUM |
未修 |
| KB-37 |
HM-FORM-01 CSV 批次匯入的表頭比對區分大小寫:混合大小寫表頭(例如 `Display_Name`/`NATIONALITY`)會使該列**所有欄位靜默被忽略**(查表…HM-FORM-01 CSV 批次匯入的表頭比對區分大小寫:混合大小寫表頭(例如 `Display_Name`/`NATIONALITY`)會使該列**所有欄位靜默被忽略**(查表用小寫 snake_case key,比對前只 `.trim()`,未 case-fold),使用者只會看到令人困惑的逐列 zod 必填錯誤,看不出根因是表頭大小寫不符。使用者選擇列為已知問題暫不修(不阻擋 HM-FORM-01 上線)。來源證據:`apps/admin/src/app/[locale]/agency-console/candidates/csv-parser.ts:201`(`CSV_HEADER_TO_SCHEMA_FIELD[rawHeaderName.trim()]`,僅 `.trim()` 無 case-fold);實測驗證:表頭 `[Display_Name,NATIONALITY,Passport_No]` 經 `csvRowToDraftInput` 產出 `{}`(2026-07-12 驗證);HM-FORM-01 commit `c4bd0e5` 引入 |
MEDIUM |
未修 |
| KB-24 |
HM-FORM-01 CSV 批次匯入手刻 parser(非完整 RFC-4180 實作)對「非欄位起始位置」出現的雙引號處理不符預期:`parseLine` 對任何位置的 `"`…HM-FORM-01 CSV 批次匯入手刻 parser(非完整 RFC-4180 實作)對「非欄位起始位置」出現的雙引號處理不符預期:`parseLine` 對任何位置的 `"` 字元都會切換 `inQuotes`,不限欄位起始。兩種失效模式——(a) 未配對的雜散引號:整列判定 `unterminatedQuotedField` 並整列丟棄(安全失敗,有錯誤提示);(b) 成對的雜散引號:引號被**靜默剝除**、欄位內容被打亂拼接,且**無任何錯誤提示**(靜默資料錯亂,非安全失敗)。此行為未在檔案 docstring 或 mini-spec 中說明。使用者選擇列為已知問題暫不修。來源證據:`apps/admin/src/app/[locale]/agency-console/candidates/csv-parser.ts:49-93`(`parseLine`,`inQuotes` toggle 邏輯見 `:58-79`);實測驗證:`abc"def"ghi,foo` 解析為單一欄位 `abcdefghi`(引號靜默剝除、欄位合併、無錯誤);`abc"def,foo`(未配對)解析為 `null`/`unterminatedQuotedField`;HM-FORM-01 commit `c4bd0e5` 引入 |
HIGH |
未修 |
| KB-25 |
HM-FORM-01 CSV 批次匯入迴圈內每列呼叫 `createCandidateDraft` → `requireSourceAgencyAdminScope()`(3 處 …HM-FORM-01 CSV 批次匯入迴圈內每列呼叫 `createCandidateDraft` → `requireSourceAgencyAdminScope()`(3 處 `throw`),迴圈本身**沒有 per-row try/catch**;任一列觸發此例外會使整個 batch action 拋出未處理例外——先前已成功 INSERT 的列不會遺失(DB 已提交),但累積中的 `rowResults`/`summary` 物件會被整個丟棄,使用者看不到任何逐列結果回報,只會看到未處理的 rejection。使用者選擇列為已知問題暫不修。來源證據:`apps/admin/src/app/[locale]/agency-console/candidates/csv-import-actions.ts:152-184`(迴圈本體,無 try/catch);`apps/admin/src/app/[locale]/agency-console/candidates/actions.ts:160-168`(`requireSourceAgencyAdminScope` 三處 `throw`,由 `:228` `createCandidateDraft` 每列各呼叫一次);HM-FORM-01 commit `c4bd0e5` 引入 |
MEDIUM |
未修 |
| KB-26 |
`docs/roadmaps/forms-realignment/csv-import-mini-spec.md` §2.2 建議新增 `papaparse` 依賴處理 CSV p…`docs/roadmaps/forms-realignment/csv-import-mini-spec.md` §2.2 建議新增 `papaparse` 依賴處理 CSV parsing,但實作(commit `c4bd0e5`)刻意改手刻 parser(`csv-parser.ts`),未依 spec-first 紀律回寫 mini-spec 決策變更;該檔第一行「狀態」欄仍寫「尚未動 code」,與 code 已上線(同一 commit)的事實不符。屬文件債務非程式碼缺陷,待下次動 CSV parser 相關 code 時一併回寫 mini-spec 狀態與 §2.2 決策理由(改採手刻而非 papaparse 的原因)。來源證據:`docs/roadmaps/forms-realignment/csv-import-mini-spec.md:3`(狀態行「尚未動 code」)、`:75`(papaparse 建議段落);`apps/admin/src/app/[locale]/agency-console/candidates/csv-parser.ts:1-19`(docstring 已記錄手刻理由,但 mini-spec 本身未回寫);HM-FORM-01 commit `c4bd0e5`(2026-07-12 盤點) |
LOW |
未修 |
| KB-27 |
`docs/policies/platform-policies.md` P07(Worker 權益資訊)下「翻譯內容必須標示 AI 翻譯」一條,位置僅列在 Worker-faci…`docs/policies/platform-policies.md` P07(Worker 權益資訊)下「翻譯內容必須標示 AI 翻譯」一條,位置僅列在 Worker-facing 標題之下,但機翻標示實務上是跨 portal 的通用要求(例:HM-FORM-01 履歷表單新增的 `admin.candidates.resumeForm.machineTranslatedNotice` 顯示於 admin/agency-console,非 Worker 端);條文位置易誤導為僅適用單一情境,屬文件澄清問題非規則本身有誤。來源證據:`docs/policies/platform-policies.md:46,50`(P07 標題與該條款);HM-FORM-01 機翻標示功能 commit `4b35859`(2026-07-12 盤點) |
LOW |
未修 |
| KB-28 |
`scripts/test-candidate-media-rls.ts` 的 candidate-media 上傳白名單常數(`BUCKET`/`MAX_SIZE_BYTES`/…`scripts/test-candidate-media-rls.ts` 的 candidate-media 上傳白名單常數(`BUCKET`/`MAX_SIZE_BYTES`/`ALLOWED_MIME`)為獨立硬編碼,未 import `media-upload-constants.ts` 的單一來源常數(`CANDIDATE_MEDIA_BUCKET`/`CANDIDATE_MEDIA_MAX_SIZE_BYTES`/`CANDIDATE_MEDIA_MIME_BY_KIND`)——後者 docstring 宣稱「三處同步」(migration/`config.toml`/本檔),但測試 script 實際是第 4 份獨立副本,任一處調整(例如放寬檔案大小上限)可能悄悄失準而測試仍綠、無人察覺。來源證據:`scripts/test-candidate-media-rls.ts:63-65`(獨立宣告 `BUCKET`/`MAX_SIZE_BYTES`/`ALLOWED_MIME`)vs `apps/admin/src/app/[locale]/agency-console/candidates/media-upload-constants.ts:1-16`(docstring 宣稱「三處同步」但未含此檔);HM-FORM-01 T1.3a candidate-media 上傳(2026-07-12 盤點,uncommitted) |
MEDIUM |
未修 |
| KB-29 |
HM-FORM-01 T1.3a candidate-media 上傳失敗時,`uploadCandidateMediaAction` 回傳的錯誤代碼為英文 snake_case(…HM-FORM-01 T1.3a candidate-media 上傳失敗時,`uploadCandidateMediaAction` 回傳的錯誤代碼為英文 snake_case(例如 `file_size_must_be_1B_to_100MiB`、`mime_must_be_one_of:image/jpeg,image/png,image/webp`、`candidate_draft_not_found_or_not_owned`),未在 `labels.validation`(`ResumeValidationMessageKey`)補上對應中文翻譯;表單的 `translateError` 查無對應 key 時 fallback 回傳原始英文代碼,agency-console 管理員會直接看到未翻譯的英文錯誤字串。部分代碼(如 `mime_must_be_one_of:...`)更帶動態組成的 MIME 清單,無法用固定 key 查表在地化,需改設計(例如只在地化 `code`、忽略動態訊息本體)。來源證據:`apps/admin/src/app/[locale]/agency-console/candidates/media-upload-actions.ts:69,73,120,149,169`(錯誤代碼來源);`apps/admin/src/app/[locale]/agency-console/candidates/candidate-resume-form.tsx:654`(`uploaded.error.message` 原樣回傳)、`:668-670`(`translateError` 查無 key 時 fallback 回傳原字串);`libs/ui/src/lib/form/mz-file-upload-field.tsx:215`(`translateError?.(result.error) ?? result.error`);HM-FORM-01 T1.3a candidate-media 上傳(2026-07-12 Phase C sonnet review 發現,uncommitted) |
MEDIUM |
未修 |
| KB-30 |
HM-FORM-01 candidate-media 編輯模式預覽:既有候選人已上傳的照片/影片在編輯精靈重新載入時,經 `signCandidateMediaPaths` 取得的…HM-FORM-01 candidate-media 編輯模式預覽:既有候選人已上傳的照片/影片在編輯精靈重新載入時,經 `signCandidateMediaPaths` 取得的私有桶 signed URL(含 `?token=<JWT>` query string,JWT 本身含多個 `.`)被餵給 `MzFileUploadField` 的 `UploadFile.url`;Mezzanine `resolveFileType`(`@mezzanine-ui/react` Upload 內部工具,以 `url.split('.').pop()` 取副檔名)吃到 query string/JWT 尾段而非真正副檔名,導致 `isImageFile` 判為 false,畫面顯示為檔名+通用檔案圖示而非行內縮圖。僅視覺降級——功能性 URL 仍正確附掛、仍可點擊/下載。與規劃中的 Phase D(apps/web 顯示,見 `forms-realignment/design.md` §12.2 item 2)為同一類 signed-URL 陷阱,該處實作時須避開同一問題。來源證據:`apps/admin/src/app/[locale]/agency-console/candidates/media-preview.ts:37-63`(`signCandidateMediaPaths`,簽出含 query string 的 signed URL);`apps/admin/src/app/[locale]/agency-console/candidates/[id]/edit/page.tsx:72-76`(`mediaPreviewUrls` 建立與傳入);`libs/ui/src/lib/form/mz-file-upload-field.tsx:144`(`url: item.displayUrl ?? item.path`);Mezzanine `@mezzanine-ui/react` `Upload/upload-utils.js:33`(`resolveFileType` 的 `url.split('.').pop()`,node_modules 原始碼確認);HM-FORM-01 T1.3a candidate-media 上傳(2026-07-12 Phase C sonnet review 發現,uncommitted) |
LOW |
未修 |
| KB-31 |
HM-RBAC-01 console 實體合併(Stage B)後,`requireAgencyConsole()` 登入放行順序仍先呼叫 `checkRole(agency_ad…HM-RBAC-01 console 實體合併(Stage B)後,`requireAgencyConsole()` 登入放行順序仍先呼叫 `checkRole(agency_admin)`/`checkRole(agency_staff)`(讀 `user_role_assignments` 表),只有通過才會走到 `fetchAgencyMemberships`(讀 `agency_members`,per-agency 權威來源)。已實際發生:某示範來源仲介帳號在 `agency_members` 有合法列、但 `user_role_assignments` 缺對應列時無法登入,需手動補種 `user_role_assignments` 才放行。待釐清問題:`checkRole`/`user_role_assignments` 這道前置閘門,在 `fetchAgencyMemberships` 已做 per-agency 權威檢查的現在是否仍屬多餘(應改直接以 `agency_members` 為準),或 `user_role_assignments` 仍是刻意保留的粗粒度角色來源、只是缺了種子資料。屬 HM-RBAC-01 範疇,非 HM-FORM-01。來源證據:`apps/admin/src/app/[locale]/agency-console/_lib/auth/agency-console-guard.ts:101-103`(`checkRole(agency_admin)`/`checkRole(agency_staff)` 前置檢查,讀 `user_role_assignments`)與 `:117`(`fetchAgencyMemberships`,讀 `agency_members`);`libs/auth/src/check-role.ts:55`(`checkRole` 呼叫 `has_role()` RPC,包裝 `user_role_assignments` junction);HM-FORM-01 T1.3a web-qa 過程附帶發現(2026-07-12 盤點) |
MEDIUM |
未修 |
| KB-32 |
HM-FORM-01 Phase 2.2(`/profile` 家庭成員 CRUD):`family_members` 表的 `family_members_employer_up…HM-FORM-01 Phase 2.2(`/profile` 家庭成員 CRUD):`family_members` 表的 `family_members_employer_update` RLS policy 為全列 UPDATE(`using`/`with check` 僅檢查 `employer_user_id = auth.uid()`,無欄位層級限制),而 T2.2 server action `upsertMyFamilyMember` 從不將 `evidence_status` 暴露給雇主輸入(僅 INSERT 時硬編 `'draft'`,UPDATE 路徑完全不觸碰此欄)。App 層雖謹慎,但 DB 層 RLS 允許雇主繞過此 server action、直接以自己的 JWT 呼叫 Supabase REST API(PostgREST `PATCH`)把自己名下任一 `family_members` row 的 `evidence_status` 自我核准為 `'approved'`,讓合規敏感的 4 點制資格計算(`compute_domestic_helper_points_v2`)從 `provisional_ok` 誤判為 `ok`,形同未經實際審核即自我核准。→ 已修(2026-07-14,commit `fcb213f4` trigger-guard + `47c6b097` rename):新增 `20260713134639_hm_form_01_family_members_evidence_status_employer_guard.sql`,以 `BEFORE INSERT OR UPDATE` trigger 封死雇主自我核准(`approved` 全鎖:不得設成/改走/刪;`rejected` 放行 resubmission;admin `has_role('platform_admin')`/service_role `auth.uid() is null` pass),涵蓋 `family_members` + `family_member_point_conditions` 兩表 insert/update/delete,已 apply 生產庫並經 22 格 live rollback matrix 驗證來源證據:`supabase/migrations/20260425181000_p0_family_members_table.sql:113-121`(`family_members_employer_update` policy,列層級、無欄位限制)vs `apps/web/src/app/[locale]/(dashboard)/profile/family-members-actions.ts:316-380`(`upsertMyFamilyMember`,`payload` 從不含 `evidence_status`,僅 `:357` INSERT 路徑硬編 `'draft'`);獨立 Opus final review 發現(2026-07-13 盤點) |
MEDIUM |
已修 |
| KB-33 |
HM-FORM-01 Phase 2.2:`upsertMyFamilyMember` 的 UPDATE 路徑(`family-members-actions.ts:323-344…HM-FORM-01 Phase 2.2:`upsertMyFamilyMember` 的 UPDATE 路徑(`family-members-actions.ts:323-344`)建構的 `payload` 不含 `evidence_status`——不論雇主如何變更 `specialNeedsType`/`disabilityLevel`/`conditionCode`,既有的 `family_members.evidence_status` 值一律原封不動保留,不會重置為 `'draft'`/`'missing'` 強制重新審核。目前 codebase 未發現任何 admin 端對 `family_members.evidence_status` 的核准 UI(僅 `apps/admin` 三個檔含 `family_members` 字串,皆非審核流程),故現況為 dormant(尚無途徑把此欄推進到 `'approved'`);一旦未來補上審核流程,須同步處理「條件變更即重置證明狀態」,否則舊審核結果可能被套用到全新、未經審視的宣告內容上。來源證據:`apps/web/src/app/[locale]/(dashboard)/profile/family-members-actions.ts:323-344`(`payload` 建構不含 `evidence_status`);grep `apps/admin/` 未見對應審核 UI;HM-FORM-01 Phase 2.2(2026-07-13 盤點) |
LOW |
未修 |
| KB-34 |
HM-FORM-01 Phase 2.2/T2b:`family-members-section.tsx` 的 condition_code 選單只依單一 `draftAge < …HM-FORM-01 Phase 2.2/T2b:`family-members-section.tsx` 的 condition_code 選單只依單一 `draftAge < 12` 門檻決定是否顯示與可選擇全部 7 個代碼,未依各代碼自身年齡語意個別收斂選項——`developmental_delay_under_6`(i18n 標籤「發展遲緩(未滿 6 歲)」)語意應僅適用未滿 6 歲兒童,但 6–11 歲成員在畫面上仍可選擇此代碼(與其餘 6 個「\_under_12」代碼一視同仁,僅受同一道「< 12」總門檻限制)。不影響點數計算本身(同屬「特殊需求兒童(未滿 12 歲) 10 點」,不論選哪個代碼點數相同),但會讓法定依據(condition_code)的稽核紀錄與成員實際年齡不符。來源證據:`apps/web/src/app/[locale]/(dashboard)/profile/family-members-section.tsx:455`(`draftAge < 12` 統一門檻)、`:471-475`(`SPECIAL_NEEDS_CONDITION_CODES.map` 無個別代碼年齡收斂);`libs/i18n/src/locales/zh-TW/common.json:4740`(標籤「發展遲緩(未滿 6 歲)」);HM-FORM-01 Phase 2.2/T2b(2026-07-13 盤點) |
LOW |
未修 |
| KB-35 |
HM-FORM-01 Phase 2.2:`upsertMyFamilyMember`(`family-members-actions.ts:316-380`)先寫 `family…HM-FORM-01 Phase 2.2:`upsertMyFamilyMember`(`family-members-actions.ts:316-380`)先寫 `family_members`(INSERT 或 UPDATE),再另外 `await syncFamilyMemberCondition(...)` 寫 `family_member_point_conditions`,兩者間無 Postgres transaction 包裹(design.md §3.8 已記載此為全 codebase 既有慣例:「無 Supabase transaction、兩表更新走 sequential guarded writes」,非本次新增的架構偏離)。若 `family_members` 寫入成功後 `syncFamilyMemberCondition` 因網路中斷或 DB 例外失敗,該成員基本資料已落地但特殊需求 condition_code 未同步——呼叫端會收到錯誤,但 `family_members` row 已是部分 committed 狀態,需重新編輯才能補上 condition_code。來源證據:`apps/web/src/app/[locale]/(dashboard)/profile/family-members-actions.ts:316-380`(`upsertMyFamilyMember`,`:345-350`/`:371-376` 兩個獨立 await 無 transaction 包裹);對照 design.md §3.8「無 Supabase transaction(既有慣例)」;HM-FORM-01 Phase 2.2/T2b(2026-07-13 盤點) |
MEDIUM |
未修 |
| KB-36 |
HM-FORM-01 Phase 2.2/T2b:`family_member_point_conditions` 的 `unique (family_member_id, con…HM-FORM-01 Phase 2.2/T2b:`family_member_point_conditions` 的 `unique (family_member_id, condition_code)` 僅防止「同一成員的同一 condition_code 重複」,不保證「同一成員同時只有 1 個 active(`deleted_at is null`)condition row」。`syncFamilyMemberCondition`(`family-members-actions.ts:258-314`)以「先查現有 → 刪除 → 新增」的 delete-then-insert pattern 在應用層維持此不變式,但僅在單一 request 循序執行下成立——若同一成員遭遇兩個並發請求(例如快速連續切換兩次 condition_code、或多分頁同時編輯),皆可能各自查到「無現有 row」而各自插入不同的 condition_code,導致同一成員出現 2 個以上同時 active 的 condition row(理論性 race,DB 層無 partial unique index 如 `unique (family_member_id) where deleted_at is null` 兜底)。來源證據:`supabase/migrations/20260526235958_taiwan_agency_operational_models.sql:67`(`unique (family_member_id, condition_code)`,非「1 active row per member」的 partial unique);`apps/web/src/app/[locale]/(dashboard)/profile/family-members-actions.ts:258-314`(`syncFamilyMemberCondition` delete-then-insert,僅應用層序列化);HM-FORM-01 Phase 2.2/T2b(2026-07-13 盤點) |
LOW |
未修 |
| KB-38 |
worker portal 月結薪資頁(`monthly-payroll`)對測試移工帳號 `demo-worker-1` 顯示「目前沒有資料」空狀態;read-only DB 診…worker portal 月結薪資頁(`monthly-payroll`)對測試移工帳號 `demo-worker-1` 顯示「目前沒有資料」空狀態;read-only DB 診斷確認該 worker 對應的兩張訂單有正常 `monthly_ledgers`/`monthly_ledger_lines` 資料(July 2026,含 `salary`/`nhi_employer`/`withholding_tax` 等 line,且無任何 worker-fee line_key)。RLS policy `monthly_ledger_lines_worker_select`(SECURITY DEFINER helper `worker_owns_active_ledger()` 核對 `service_orders.worker_user_id = auth.uid()`)已核對=demo-worker-1 的 auth uid,on paper 應 match,但 UI 仍空——根因未確認,待重驗,推測為 SSR session/cookie 未正確 propagate 到 PostgREST 導致 RLS 判定拿不到 `auth.uid()`,可能是 dev 環境限定、非必然 production bug。**2026-07-14 補強證據**:以 `execute_sql` 模擬 demo-worker-1 的 authenticated session 直測 `worker_select` RLS,正確放行 30 條 line(僅 `salary`/`nhi_employer`/`withholding_tax`、無任何 worker fee)→ 證明 RLS 邏輯+資料層+T08 收窄全部正確,根因**確定**為 SSR 未把登入 session 傳到 PostgREST(拿不到 `auth.uid()`)而非 RLS/資料/T08。pre-existing,與 HM-CMP-01-T08 無關(非 T08 造成):T08 僅移除 3 個 worker-fee line_key+收窄 RLS 白名單,DB 診斷確認資料層無 worker fee 且其他 line 正常存在,empty render 與 T08「移除移工費」邏輯無關,屬 payroll 頁本身既有的 session/RLS 互動問題。來源證據:web-qa 2026-07-14 發現;DB 診斷(Supabase project `gjsvnyrkyftaxmfhqwze`);RLS policy `supabase/migrations/20260713134236_hm_cmp_01_t08_worker_zero_fee.sql:258-267`(`monthly_ledger_lines_worker_select`/`worker_owns_active_ledger()`);`apps/worker/src/app/[locale]/(dashboard)/monthly-payroll/page.tsx` |
MEDIUM |
未修 |
| KB-23 |
`apps/mobile/e2e/navigation.spec.ts` 的「agency uses five role-specific destinations」在 `main…`apps/mobile/e2e/navigation.spec.ts` 的「agency uses five role-specific destinations」在 `main` 上即失敗:spec 期望 agency 角色底部導覽 5 個 destination,實際 UI 只剩 3 個——先前 agency 相關改版(HM-RBAC-01 console 併入 admin 後 mobile agency 角色缺乏收斂)後 spec 未同步;與程式碼行為無關,屬測試期望過時。→ 已修(2026-07-15):E2E 改以角色期望陣列長度斷言,顧問契約同步為「今日/邀約/我的」三項;route 註解與 Q02 測試計畫一併校正。來源證據:`apps/mobile/e2e/navigation.spec.ts`、`apps/mobile/app/(tabs)/_layout.tsx`、`docs/specs/mobile-navigation-q02-test-plan.md`;專用 E2E bundle 實跑 navigation 4/4 passed。 |
LOW |
已修 |
| KB-39 |
`fix/admin-invite-link`(ADR 0016)已修好 admin/仲介/雇主三端的邀請與密碼重設信連結(補上 `redirectTo` +新建兩個 set-pa…`fix/admin-invite-link`(ADR 0016)已修好 admin/仲介/雇主三端的邀請與密碼重設信連結(補上 `redirectTo` +新建兩個 set-password landing page),但 **worker(幫傭)角色的邀請連結本輪刻意不接**:`resolveInviteLandingPortal()` 對 `'worker'` 角色回傳 `{ portal: 'none' }`,兩個實際呼叫點(`console-service/candidates.ts` 的 `consoleProvisionCandidateAccount`、`accounts/actions.ts` `inviteAccount` 的 worker 分支)皆維持 `redirectTo` 未設,收件人點連結仍會落到 `site_url`(雇主前台)而非任何可用的 landing page。屬刻意延後(`apps/worker` 目前尚無對應 `(auth)` route group),非回歸——worker 邀請連結修復前後行為一致(皆不可用)。**2026-07-16 更新(ADR 0017)**:worker 端 `/{locale}/reset-password` 落地頁已隨忘記密碼流程建成。**→ 已修(2026-07-17,`feature/auth-mail-pipeline`)**:`resolveInviteLandingPortal()` 補 `worker` 分支、兩個邀請呼叫點接上 redirectTo(cross-portal origin 走新環境變數 `NEXT_PUBLIC_WORKER_PORTAL_URL`)、worker landing 文案中性化;Supabase allowlist 已補 `https://worker.homemate.kusabanabiyori.com/**`(Dashboard 完成);worker landing token_hash 設密碼 E2E 通過。來源證據:`apps/admin/src/lib/console-service/candidates.ts:67-72`(`inviteUserByEmail` 呼叫無 `redirectTo`);`apps/admin/src/app/[locale]/(dashboard)/accounts/actions.ts`(`resolveInviteRedirectTo` 對 `portal==='none'` 回傳 `undefined`);`libs/auth/src/invite-redirect-portal.ts`(`resolveInviteLandingPortal` 函式,`worker` case 文件化為刻意延後);`docs/adr/0016-invite-recovery-redirect-and-set-password-landing.md`(2026-07-15) |
MEDIUM |
已修 |
| KB-40 |
admin 全站邀請/新增帳號流程的 `invite_failed` 錯誤處理兩項缺陷:(1)Supabase(GoTrue)原始英文錯誤訊息(例 `Email address "…admin 全站邀請/新增帳號流程的 `invite_failed` 錯誤處理兩項缺陷:(1)Supabase(GoTrue)原始英文錯誤訊息(例 `Email address "…" is invalid`)未在地化直接露給使用者,違反 zh-TW 文案紀律且使用者無從判斷對策;(2)錯誤對映字面 `error: { code: 'invite_failed', message: inviteErr?.message ?? 'no_user' }` 在至少 5 處複製貼上、無共用 helper(`accounts/actions.ts:602`、`agencies/actions.ts:674`、`settings/actions.ts:135`、`console-service/team.ts:146`、`console-service/candidates.ts:86`;另 `accounts/actions.ts:966` 的 resend(`generateLink`)重用同一 code),修一處漏四處。建議收斂為單一 invite 錯誤對映 helper,並依 GoTrue error code(如 `email_address_invalid`)給在地化訊息。來源證據:2026-07-15 invite 失敗診斷(Jam a0f8a69b/da2f7a93 兩支錄影+多 agent 調查:錯誤字串 grep 全 codebase 0 命中,證明為 GoTrue 原樣透傳;root cause 為測試網域 `homemate.tw` 無 MX/A record 遭 Supabase 收件地址驗證拒收,非 app bug) |
LOW |
未修 |
| KB-41 |
agency-console candidates 家族 RWD 斷點不一致:本輪(`fix/agency-candidate-ui-polish`)把 `candidate-re…agency-console candidates 家族 RWD 斷點不一致:本輪(`fix/agency-candidate-ui-polish`)把 `candidate-resume-form.module.scss` 與 `candidates.module.scss` 的收斂斷點由 `max-width: 760px` 調至 `768px`(修 iPad 直向 768 恰好不觸發 query 導致 2-col 被裁),但同目錄樹另外 4 檔仍為 760(`advisor-invites.module.scss:134`、`matching-requests.module.scss:111`、`list-card/list-card.module.scss:75`、`candidate-messages.module.scss:97`)——761〜768 帶寬下跨頁收斂行為不一致。建議抽 agency-console 共用 breakpoint token/mixin 一次統一(styling-discipline 共用樣式收斂)。→ **已修**(2026-07-16,branch `feature/agency-wizard-3step`,PR pending):新增 `_components/_breakpoints.scss` 定義單一來源 `$agency-console-mobile: 768px`,6 個消費檔(`candidate-resume-form.module.scss`/`candidate-contact-drawer.module.scss`/`advisor-invites.module.scss`/`matching-requests.module.scss`/`list-card/list-card.module.scss`/`candidate-messages.module.scss`)改用 `@use "../_components/breakpoints" as bp` 統一引用該 token,斷點不一致已消除來源證據:2026-07-15 Lane 1 Sonnet review finding(grep 確認 5 檔行號);`fix/agency-candidate-ui-polish`;修復驗證:`grep -rln agency-console-mobile` 命中 6 消費檔+1 定義檔(2026-07-16) |
LOW |
已修 |
| KB-42 |
「管理可預約時段」連結的 gate(`agency-candidates-client.tsx` `canManageAvailability`)只看 `availability_…「管理可預約時段」連結的 gate(`agency-candidates-client.tsx` `canManageAvailability`)只看 `availability_managed_by`,未綁 per-row 歸屬(`isOwned`),granted/case(他家授權可見)候選人列亦顯示該連結;本輪清單化改版該函式邏輯未動(僅型別名調整)。`[id]/availability` 子頁的 server 端權限 gate 是否獨立擋非歸屬仲介**未驗**——若子頁有 server gate 則僅為過度顯示(死連結),否則為真權限缺口,需優先查驗。來源證據:2026-07-15 權限稽核存疑項 #4;`apps/admin/src/app/[locale]/agency-console/candidates/agency-candidates-client.tsx` |
MEDIUM |
未修 |
| KB-43 |
wizard 在 768 寬的殘餘橫向捲動:斷點修復已生效(≤768 收單欄、且由「overflow hidden 裁死不可及」改為「容器內 `overflow-x: scroll…wizard 在 768 寬的殘餘橫向捲動:斷點修復已生效(≤768 收單欄、且由「overflow hidden 裁死不可及」改為「容器內 `overflow-x: scroll` 可捲及」),但 agency-shell sidebar 固定 ~241px 使內容區僅 527px、wizard 表單最小寬 ~720px,768 下仍需橫捲才能看到整行。完全 reflow 需 sidebar 收合(BL-36 console mobile RWD 主線範圍)。**補充(2026-07-16,`feature/agency-wizard-3step`)**:wizard 導覽已改為 fixed footer(`.footer { position: fixed; left: 240px; ... }`,見 `candidate-resume-form.module.scss:116-130`;≤768 降級 `left: 0`,`:151-163`),但殘餘橫捲根因(agency-shell sidebar 固定寬使內容區窄於表單最小寬)未變,本項狀態維持開放,仍歸 BL-36。來源證據:2026-07-15 T6 量測(clippedRight 祖先鏈 `overflow-x: scroll, clientW 527, scrollW 720`);`fix/agency-candidate-ui-polish` |
LOW |
未修 |
| KB-44 |
仲介端停用/恢復幫傭帳號的 server 端 RPC(`suspend/resumeCandidateAccountByAgency`)未限縮聘僱前:[HsuTse] 2026-0…仲介端停用/恢復幫傭帳號的 server 端 RPC(`suspend/resumeCandidateAccountByAgency`)未限縮聘僱前:[HsuTse] 2026-07-15 裁決「限縮為聘僱前」已在 UI 落實(曾有 `service_orders` 紀錄即隱藏停用/恢復區塊、顯示「已聘僱由平台管理」),但 RPC 本身仍允許對已聘僱候選人操作——直接呼叫 API 可繞過 UI gate。需 RBAC 主線(HM-RBAC-01 Stage C 或後續)在 RPC 內補同款 server-side 判定。來源證據:2026-07-15 權限稽核 #15+Lane 2 權限收斂實作;migration `20260701184951`(RPC authz 現況);`candidate-contact-drawer.tsx`(UI gate) |
MEDIUM |
未修 |
| KB-45 |
雇主端履歷摘要邏輯(`apps/web/src/lib/public-candidates/helpers.ts:100-119` `resumeParagraphTexts`/`…雇主端履歷摘要邏輯(`apps/web/src/lib/public-candidates/helpers.ts:100-119` `resumeParagraphTexts`/`collectResumeText`)假設 `resume_json` 為 Quadrats 富文本節點陣列(`Array.isArray` + 逐節點 `.text`/`.children`),但 HM-FORM-01 wizard 寫入的 `resume_json` 是結構化純物件(`apps/admin/.../candidates/schemas.ts` `baseWorkerResumeShape`,經 `actions.ts` `toCandidateColumns` 組出後寫入;`actions.ts:232` 註解明載「structurally JSON-safe plain object」,非陣列)——格式不相容:`Array.isArray(resumeJson)` 為 false,`resumeParagraphTexts` 恆回傳空陣列,`profileSummaryFromResume`/`experienceStatementFromResume` 恆回傳 `null`,wizard 新結構化欄位寫入的履歷簡介/經歷敘述不會被雇主端讀出。來源證據:`apps/web/src/lib/public-candidates/helpers.ts:100-119`;`apps/admin/src/app/[locale]/agency-console/candidates/schemas.ts:413`(`baseWorkerResumeShape`);`apps/admin/src/app/[locale]/agency-console/candidates/actions.ts:232`(`resumeJson` 為 plain object 之註解);2026-07-15 仲介候選人 wizard 3 步重構偵察(scout-domains)發現並經 code read-back 驗證 |
MEDIUM |
未修 |
| KB-46 |
`serviceCategories`(幫傭 vs 看護分支關鍵欄位,對映官方 employment category codes;`apps/admin/.../candidat…`serviceCategories`(幫傭 vs 看護分支關鍵欄位,對映官方 employment category codes;`apps/admin/.../candidates/schemas.ts:516` 定義,寫入 `candidates.service_categories` column)未包含在雇主端 `PUBLIC_FIELDS`(`apps/web/src/lib/public-candidates/queries.ts:114-115`),雇主瀏覽/詳情頁完全看不到此欄位。疑似落差非刻意排除。來源證據:`apps/web/src/lib/public-candidates/queries.ts:114-115`(`PUBLIC_FIELDS`/`DETAIL_FIELDS` 皆未含 `service_categories`,grep 確認 0 命中);`apps/admin/src/app/[locale]/agency-console/candidates/schemas.ts:516`;2026-07-15 仲介候選人 wizard 3 步重構偵察(scout-domains)發現 |
MEDIUM |
未修 |
| KB-47 |
agency-console `AgencyShell` 側欄(`mzn-navigation` footer)dev 模式間歇出現 React hydration mismatc…agency-console `AgencyShell` 側欄(`mzn-navigation` footer)dev 模式間歇出現 React hydration mismatch(server/client 屬性不一致,component stack 指向 nav footer style),2026-07-16 wizard QA 期間於瀏覽器 console 觀察到;與本輪候選人頁變更無關(`agency-shell.tsx` 本輪零 diff);production build 下是否重現未驗,待重驗。來源證據:2026-07-16 web-QA console 觀察;`apps/admin/src/app/[locale]/agency-console/_components/agency-shell.tsx` |
LOW |
未修 |
| KB-48 |
→ 已修(2026-07-17,`feature/auth-mail-pipeline`):Confirm sign up 模板改自有網域 token_hash(type=emai…→ 已修(2026-07-17,`feature/auth-mail-pipeline`):Confirm sign up 模板改自有網域 token_hash(type=email)+web 新增 `/{locale}/confirm` landing(verifyOtp → activated → 可正常登入,E2E 通過)+`signUp()` 補 `emailRedirectTo`。注意:~~雲端專案 email confirmations 目前為關閉狀態~~ → 已於 2026-07-17 依使用者指示在 Dashboard 開啟 Confirm email,新註冊自此需完成 Email 驗證方可登入。原問題:註冊確認信(Confirm signup template)連結仍指向 `<project>.supabase.co/auth/v1/verify`,在 ADR 0017 啟用 Cloudflare custom SMTP 後會被 Gmail 靜默丟棄(根因與對照實驗見 ADR 0018)——Gmail 信箱的雇主完成註冊後收不到確認信,無法啟用帳號。Recovery/Invite 已由 ADR 0018 改走自有網域 token_hash 連結修復,confirm signup 需要另行設計 confirm landing(web 目前無對應頁面)+比照修改 template;`apps/web/src/lib/auth/sign-up.ts` 的 `signUp()` 未帶 `emailRedirectTo` 也需一併補上。Magic link/Email change 模板同病,平台目前未使用,暫不處理。來源證據:ADR 0018(2026-07-16 對照實驗:Cloudflare Activity Log 全 Delivered、Gmail 僅收無外部連結信件);`apps/web/src/lib/auth/sign-up.ts:74`(signUp 無 emailRedirectTo) |
HIGH |
已修 |
| 無符合項目 |