HomeMate 專案開發狀況 Dashboard

開發團隊與業務/產品團隊的溝通橋樑・每次 production 部署時重新產生
主線進行中數
12 / 23
current/partial/next 狀態
ADR 總數
23
Proposed 3 · Accepted 4 · Implemented 16 · 未分類 0
Known Bugs 未修數
29 / 60
未修/總計
Backlog 項目數
59
功能/強化待辦池
最近 commit 日期
2026年7月25日
台北時間

Roadmap 主線狀態

ID名稱狀態
HM-DOC-01 Documentation Governance文件集中、路徑治理、狀態來源統一 current
HM-ADM-01 Admin Foundation後台骨架、履歷、仲介、收單基礎 shipped
HM-ADM-02 Admin Lifecycle目錄、面試、訂單、onboarding、在職與期滿管理 shipped
HM-CMP-01 Compliance Hardening合規補洞、migration audit、政策治理 current
HM-WEB-01 Employer Portal雇主前台 chrome、公開頁、dashboard、互動流程 shipped
HM-CNV-01 Candidate Communication and Match履歷導向聯繫、訊息、面試時段、matching requests shipped
HM-TWF-01 Taiwan Agency Form Alignment官方類別、政府表單、看護/幫傭、worker legal profile shipped
HM-OPS-01 Release and EnvironmentVercel、Supabase、migration state、deploy runbook、email invite/recovery 連結導向(ADR 0016)、忘記密碼自助流程與平台 SMTP(ADR 0017)、專案狀況 dashboard(T02) current
HM-FTR-01 Deferred Media and AICloudflare RealtimeKit 視訊面試、錄影、AI 字幕/翻譯 未分類
HM-AGC-01 Agency Portal UI Consistency仲介中台 Mezzanine 元件與 design token 一致性 未分類
HM-RBAC-01 Agency Resource RBAC and Console Merge仲介資源指派 RBAC、精準工作集、中台併入後台、直聘轉型 partial
HM-MOB-01 Mobile App單一 mobile app(雇主/幫傭/顧問):i18n、資料串接、合約簽核、視訊 partial
HM-MOB-02 Mobile Dual-Track MVP雇主+移工雙端 MVP 三波(ADR 0004/0005/0006) partial
HM-CASE-01 Case Journey Task Layer案件 journey/task 層、當事人流程引導、work item(ADR 0001–0003) partial
HM-TEAM-01 Org Team Operations組織 team 協作:capability、歸屬分派、值班、升級、稽核 partial
HM-MOB-03 Mobile UX Consolidationmobile UX 收斂:任務深連結、結果閉環、可互動性契約、推播事件目錄 partial
HM-FORM-01 Resume/Intake Form Realignment表單重整:工人履歷上傳表單與雇主 intake 超集合表單重構 partial
HM-MOB-04 Mobile Employer Experience Upliftmobile 雇主旅程優化:詢問、CTA、預覽、追蹤、術語(ADR 0013) shipped
HM-MOB-05 Mobile Security, Role, and Caption Resiliencemobile session 安全儲存、多角色工作台切換、伺服器講者字幕整合(ADR 0020;BL-07/BL-08/BL-34) partial
HM-FORM-02 Candidate Resume Shared Wizard候選人履歷管理兩端共用化:共用 3 步 wizard、平台端新增履歷、完整履歷檢視兩層並存、雇主端相容性修繕(KB-45/KB-46) partial
HM-ADM-03 Candidate Review Workflow候選人履歷送審→平台審核完整流程(規劃中):`draft → pending` 送審由台灣仲介 owner 觸發、平台待審佇列與核准/退回完整迴圈、可撤回、退回原因迴圈;BL-28 啟動 shipped
HM-FORM-03 Candidate Resume Editor Consolidation候選人履歷單一編輯器整合:demo seed 精簡結構化重寫、wizard 開放全候選人(含硬護欄防舊格式覆蓋)、skills/languages 併入 wizard(受控 multi-select/獨立手動欄,含 canonical 格式定案)、移除抽屜快速編輯入口(ADR-0022;仲介中台共用套用)(收斂 BL-43) shipped
HM-FORM-04 Employer Resume Display and Public API Hardening雇主端登入解鎖完整履歷展示(apps/web 詳情頁 step1 全 7 section+媒體)、影片上傳解禁(client 端 mp4box.js remux 剝除 GPS metadata,收斂 BL-22)、公開候選人 API 面收斂(`resume_json` 對匿名與任意登入角色之整欄曝露洞封閉,含 mobile 資料通道改道;ADR-0023 Accepted)——~~Phase 0 治理前置完成(T0.1/T0.2),Phase 1–4 待 [HsuTse] 核准開工~~ → ~~Phase 0–3 全數交付(2026-07-24),Phase 4(全 workspace gate/`/opus-review final`/PR)收尾中~~ → **Phase 0–3 交付+Phase 4 完成**(`/opus-review final` `PASS_WITH_MINOR`、PR #35 已開待 merge,2026-07-25;**Phase 3 追加 T3.4–T3.6**:[HsuTse] 改判 GPS 須確實剝除,收斂 BL-55/KB-57/KB-59,併入 PR #35) shipped

ADR 清單

編號標題Status日期
ADR 0001 案件 journey task 層疊加於 21 碼 milestone 之上案件 journey task 層疊加於 21 碼 milestone 之上 Implemented 2026-07-06
ADR 0002 task owner=實際行動者,與 milestone 作業經手方分離task owner=實際行動者,與 milestone 作業經手方分離 Implemented 2026-07-06
ADR 0003 聘僱案件八階段模型與 journey 模板骨架聘僱案件八階段模型與 journey 模板骨架 Implemented 2026-07-06
ADR 0004 雇主 mobile app 全流程自足雇主 mobile app 全流程自足 Implemented 2026-07-06
ADR 0005 移工 mobile 範疇三定調(期滿意思表示、candidate 緊急求助、知情…移工 mobile 範疇三定調(期滿意思表示、candidate 緊急求助、知情確認) Implemented 2026-07-06
ADR 0006 mobile MVP 判準(雙端齊備)與三波切分mobile MVP 判準(雙端齊備)與三波切分 Implemented 2026-07-06
ADR 0007 team capability 目錄 v1 與初期兩角色 bundle、值班表粒…team capability 目錄 v1 與初期兩角色 bundle、值班表粒度 Implemented 2026-07-06
ADR 0008 platform_admin 進 mobile 的範圍——例外收件匣單一 sur…platform_admin 進 mobile 的範圍——例外收件匣單一 surface Implemented 2026-07-06
ADR 0009 UI 用語「聘僱邀請」與法律留痕「聘僱意思表示」分離UI 用語「聘僱邀請」與法律留痕「聘僱意思表示」分離 Implemented 2026-07-10
ADR 0010 推播通知事件目錄與命名規約推播通知事件目錄與命名規約 Proposed 2026-07-10
ADR 0011 journey 任務卡深連結映射由前端配置表承載journey 任務卡深連結映射由前端配置表承載 Implemented 2026-07-10
ADR 0012 仲介中台 console 實體併入 admin(Stage B 延後半段)與軟隔…仲介中台 console 實體併入 admin(Stage B 延後半段)與軟隔離 enforcement Implemented 2026-07-09
ADR 0013 雇主可對候選人直接發起文字對話(含仲介來源候選人,pre-order ident…雇主可對候選人直接發起文字對話(含仲介來源候選人,pre-order identity) Implemented 2026-07-13
ADR 0014 家庭幫傭 4 點制資格權威改為 `family_members` + `comp…家庭幫傭 4 點制資格權威改為 `family_members` + `compute_domestic_helper_points_v2`(撤回 `family_composition` jsonb 擴充計畫) Implemented 2026-07-13
ADR 0015 候選人媒體(candidate-media)私有桶 + Keyless Stor…候選人媒體(candidate-media)私有桶 + Keyless Storage RLS 架構 Implemented 2026-07-12
ADR 0016 Admin/Employer 邀請與密碼重設信連結導向修復+Set-Passwo…Admin/Employer 邀請與密碼重設信連結導向修復+Set-Password Landing Page 架構 Proposed 2026-07-15
ADR 0017 三 portal 忘記密碼自助流程+平台自有 SMTP(Cloudflare E…三 portal 忘記密碼自助流程+平台自有 SMTP(Cloudflare Email Service) Proposed 2026-07-16
ADR 0018 Auth 信件連結改走自有網域 token_hash(Gmail 靜默丟棄 su…Auth 信件連結改走自有網域 token_hash(Gmail 靜默丟棄 supabase.co 連結對策) Accepted 2026-07-16
ADR 0019 多語系 auth 信件自建寄送 pipeline(第一波:密碼重設信)多語系 auth 信件自建寄送 pipeline(第一波:密碼重設信) Implemented 2026-07-16
ADR 0020 Mobile secure session storage and explic…Mobile secure session storage and explicit role selection Accepted 2026-07-17
ADR 0021 候選人送審與稽核狀態機(Candidate Submission and Aud…候選人送審與稽核狀態機(Candidate Submission and Audit State Machine) Accepted 2026-07-19
ADR 0022 候選人履歷單一編輯器整合(移除入口 B、平台端 wizard 開放全候選人)候選人履歷單一編輯器整合(移除入口 B、平台端 wizard 開放全候選人) Accepted 2026-07-22
ADR 0023 雇主端履歷完整展示(登入解鎖)與公開候選人 API 面收斂雇主端履歷完整展示(登入解鎖)與公開候選人 API 面收斂 Implemented 2026-07-23

Known Bugs

狀態
嚴重度
ID問題嚴重度狀態
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)**路徑補註(2026-07-19,BL-45 抽共用):常數檔已搬至 `apps/admin/src/components/candidate-resume/media-upload-constants.ts`,本項描述之路徑漂移問題本身未變,僅路徑更新。** 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 新結構化欄位寫入的履歷簡介/經歷敘述不會被雇主端讀出。**→ 排入 HM-FORM-02 PR-B B6 處理(2026-07-19)**。→ **已修**(2026-07-19,branch `feature/candidate-full-resume-view`):`profileSummaryFromResume`/`experienceStatementFromResume` 改為先判格式——`Array.isArray` 走原 Quadrats 路徑(不回歸),`isRecord` 走新結構化路徑(讀 `experienceNarrative` 當簡介、把首筆 `employmentHistory` 條目格式化為與舊格式相容的「年份 · 地點 · 描述」一行字串),其餘輸入(null/malformed)安全回傳 `null` 不 crash;`scripts/test-public-candidate-resume-format.ts` 三種 fixture(Quadrats 陣列/wizard 結構化物件/null/malformed)共 25 個斷言全過來源證據:`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`),雇主瀏覽/詳情頁完全看不到此欄位。疑似落差非刻意排除。**→ 排入 HM-FORM-02 PR-B B6 處理(2026-07-19)**。→ **已修**(2026-07-19,branch `feature/candidate-full-resume-view`):`service_categories` 補進 `PUBLIC_FIELDS`(`DETAIL_FIELDS` 沿用同一常數,一併補上),`PublicCandidate` 新增 `serviceCategories` 欄位並在 `normalize()` 填入;詳情頁 `bioMetaGrid` 新增「服務類別」消費點(`detail-client.tsx`),標籤沿用本檔既有慣例(`CONTACT_MODE_LABELS` 同款 hardcoded 中文 map,不新增 `libs/i18n` key)。列表頁(browse-client 卡片)尚未加對應徽章,留作後續小工來源證據:`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 已修
KB-49 `candidates_agency_admin_write` RLS policy(台灣仲介 owner)為無欄位限制的 `for all`(`using`/`with chec…`candidates_agency_admin_write` RLS policy(台灣仲介 owner)為無欄位限制的 `for all`(`using`/`with check` 僅檢查 `agency_id` 歸屬),與 app 層精心設計的狀態機(`(dashboard)/candidates/actions.ts` 的 `CANDIDATE_ALLOWED_TRANSITIONS`)及欄位 allow-list RPC(`manage_update_candidate` 明確 deny `status`)形成不對稱信任邊界——台灣仲介 owner 理論上可繞過 app 層任何驗證,直接以自己的 authenticated client 呼叫 Supabase REST API 任意寫入 `status` 或其他欄位(例如直接 `UPDATE candidates SET status='published' ...`),不受狀態機合法轉移限制。目前僅靠「信任台灣仲介 owner」的產品假設支撐,無 DB 層 CHECK constraint 或 trigger 兜底。[HsuTse] 2026-07-19 裁決:登記待辦,建議收斂為 allow-list RPC(比照 `manage_update_candidate` 模式)。**→ 收斂於 HM-ADM-03 / ADR-0021(2026-07-19)**:agency-only BEFORE-UPDATE guard(platform_admin/service_role 豁免)+ `agency_transition_candidate_status` DEFINER RPC + `candidates_agency_admin_write` policy 收斂,Step 2 migration 落地後關閉。**已收斂關閉(2026-07-19,HM-ADM-03 Step 2 migration `20260719123907`+`20260719125005` 已套用生產庫)**:BEFORE 守衛+敏感欄釘死(Option B,ADR-0021)已生效,仲介繞道直寫 `status` 已被 DB 層擋(42501 實測,四象限 e2e 5/5 PASS)。來源證據:`supabase/migrations/20260421000000_fix_agency_members_recursion.sql:100-102`(`candidates_agency_admin_write` policy,`for all` 無欄位限制)vs `apps/admin/src/app/[locale]/(dashboard)/candidates/actions.ts`(`CANDIDATE_ALLOWED_TRANSITIONS` 狀態機)與 `supabase/migrations/20260630181133_manage_update_candidate_rpc.sql`(`manage_update_candidate` 明確 deny-list 排除 `status`);HM-FORM-02 審核流程盤點(2026-07-19,[HsuTse] 裁決登記待辦) MEDIUM 未修
KB-50 `parse-jobs/actions.ts` 的 `resume_parse_jobs` 稽核寫入靜默失敗:approve/reject 流程透過 `createAdminSer…`parse-jobs/actions.ts` 的 `resume_parse_jobs` 稽核寫入靜默失敗:approve/reject 流程透過 `createAdminServerClient()`(RLS-enforced client,非 service-role)直接對 `audit_log` 表執行 INSERT,但 `audit_log` 啟用 `force row level security` 且僅有 `audit_log_platform_admin_select` 一條 SELECT policy、**無 INSERT policy**(註解「INSERT 走 service-role bypass」,實際呼叫端並非 service-role)——INSERT 被 RLS 靜默拒絕,錯誤未浮現、稽核紀錄未寫入,且無人察覺。[HsuTse] 2026-07-19 裁決:併入 HM-ADM-03 Step 2 修復,改用固定 `action` 的窄 DEFINER RPC(`record_parse_resume_audit`)取代直接 INSERT,避免開放通用 audit RPC 造成偽造風險。**→ 收斂於 HM-ADM-03 / ADR-0021(2026-07-19)**。來源證據:`apps/admin/src/app/[locale]/(dashboard)/candidates/parse-jobs/actions.ts:522-529`(`audit_log` 直接 INSERT)vs `supabase/migrations/20260426200000_p0_parse_resume_authz_depth.sql:108-121`(`audit_log` 僅 SELECT policy、無 INSERT policy);HM-ADM-03 Step 1 治理登記(2026-07-19,前置事實驗證 status 寫入路徑列舉時發現) MEDIUM 未修
KB-51 agency-console 候選人列表「刪除草稿」列 action 的 UI gate(`canDeleteDraft`,委派 `canEdit`)僅檢查 `source_age…agency-console 候選人列表「刪除草稿」列 action 的 UI gate(`canDeleteDraft`,委派 `canEdit`)僅檢查 `source_agency_id` 歸屬,未檢查使用者是否具備 admin 身分;但實際刪除的 server action `softDeleteCandidateDraft` 內部呼叫 `requireSourceAgencyAdminScope()`,僅限 admin 執行。一般 `agency_staff` 成員只要滿足來源歸屬條件即會看到刪除按鈕,點擊後觸發 `requireSourceAgencyAdminScope()` 拋出的未處理錯誤(無使用者可見的友善訊息)。HM-ADM-03 Step 5 新增的送審/撤回按鈕(`canSubmitForReview`/`canRevertToDraft`)已改用三參數 gate(含 `canManageAccounts`),比照 `candidate-contact-drawer.tsx` 的 `canOperate` 模式防禦性鏡射 `requireAgencyAdminScope()`,防止同型缺口;本項屬既有(`canDeleteDraft`,HM-FORM-01 T1.11 引入)未修,非本次新增功能造成。**→ 已修(2026-07-20,commit `2494e5ad`,`feature/hm-adm-03-followups`)**:`canDeleteDraft` 加入 `canManageAccounts` 第三參數,比照 `canSubmitForReview`/`canRevertToDraft` 三參數 gate,非 admin 的 `agency_staff` 不再看到刪除草稿按鈕。來源證據:`apps/admin/src/app/[locale]/agency-console/candidates/agency-candidates-client.tsx:214-216`(`canDeleteDraft` 委派 `canEdit`,無 `canManageAccounts` 檢查)vs `actions.ts:447-458`(`softDeleteCandidateDraft` 呼叫 `requireSourceAgencyAdminScope()`);對照同檔 `canSubmitForReview`/`canRevertToDraft` 三參數 gate(`:228-260`);HM-ADM-03 Step 5 review 發現(2026-07-19) MEDIUM 已修
KB-52 平台端候選人審核抽屜(`(dashboard)/candidates/candidate-detail-drawer.tsx`)「核准履歷」確認 Modal 彈出時,Modal 標…平台端候選人審核抽屜(`(dashboard)/candidates/candidate-detail-drawer.tsx`)「核准履歷」確認 Modal 彈出時,Modal 標題與說明文字未實際渲染出來(DOM 存在對應 heading/文字節點,但畫面完全空白,只看到取消/核准按鈕);功能本身仍正常運作(點擊「核准」後狀態正確變為 approved),純視覺缺陷。範圍判斷:`candidate-detail-drawer.tsx` 不在 HM-ADM-03 本輪變更檔案清單內,判定為既有缺陷,非本次新增功能引入。**定性更正(2026-07-20)**:上述「既有缺陷」判定有誤——實際根因為 PR #30 履歷第二層面板(`resume-view-panel.module.scss`,`--mzn-z-index-popover` 1005)蓋過 Mezzanine 共用 Modal portal 容器(固定單例、z-index 1004),是 **PR #30 引入的互動回歸,非 pre-existing**。→ **已修(2026-07-20,commit `57528b72`,`feature/hm-adm-03-followups`)**:`ConfirmHost`(`libs/ui/src/lib/admin/confirm-host.tsx`)改為 portal 進專屬容器並顯式設 z-index 1010(高於既有全部 Mezzanine 層級),已於核准 repro 與另 3 個消費點驗證。來源證據:`apps/admin/src/app/[locale]/(dashboard)/candidates/candidate-detail-drawer.tsx:387-389`(`openConfirm({ title: labels.review.confirm.approveTitle, description: labels.review.confirm.approveDescription })`);HM-ADM-03 QA F2(2026-07-19,截圖 act5-02/act5-03-approve-confirm,等待 600ms 後仍空白) LOW 已修
KB-53 agency-console 頁尾(`AgencyShell`/`Layout` footer)使用者選單 `Dropdown` 於頁面載入時間歇出現 React hydratio…agency-console 頁尾(`AgencyShell`/`Layout` footer)使用者選單 `Dropdown` 於頁面載入時間歇出現 React hydration mismatch(server/client `aria-controls`/`useId()` 屬性不一致,console 一次錯誤/頁載),與候選人送審功能無關,疑似整個 admin app 共用 shell 既有問題。與 KB-47(2026-07-16 wizard QA 首次觀察,同一元件、同型症狀)疑似同源,本輪於 `/en/agency-console/candidates` 頁面重新觀察到,另登記獨立編號存查;production build 下是否重現仍未驗。**→ agency-console 側已修(2026-07-20,commit `57528b72`,`feature/hm-adm-03-followups`)**:`AgencyShell` 的 `NavigationUserMenu` 補顯式 `listboxId="agency-shell-user-menu-listbox"`,移除對 Mezzanine `Dropdown` 內部 `useId()` hook 呼叫順序的依賴。**同型風險未修留觀察**:主 admin dashboard shell(`apps/admin/src/components/admin-shell/admin-shell.tsx`/`admin-user-menu.tsx`)同樣使用 `NavigationUserMenu` 但未設顯式 `listboxId`,可能有同款潛在 hydration mismatch,待重驗。來源證據:`apps/admin/src/app/[locale]/agency-console/_components/agency-shell.tsx:95`(`NavigationFooter`);HM-ADM-03 QA F3(2026-07-19,`/en/agency-console/candidates` console log 完整 hydration mismatch stack trace) LOW 已修
KB-54 `candidate_conversation_notifications`(migration `20260502110000_candidate_conversations.s…`candidate_conversation_notifications`(migration `20260502110000_candidate_conversations.sql`)為 write-only 死 outbox:唯一寫入路徑是 `agency_send_candidate_message` DEFINER RPC(`20260701184951_agency_definer_rpcs_t21.sql:649`),寫入 `status='queued'` 列後,全站無任何消費端——無 cron job(該 migration 未排 `pg_cron`)、無 edge function 讀取此表(`supabase/functions/` 全站 grep 零命中)、無 UI 顯示通知。自建表以來(2026-05-02)`queued` 列從未被實際處理過。影響:仲介透過候選人訊息功能觸發的通知從未真正寄出或顯示,功能對使用者而言形同不存在。與剛落地的 BL-48 `candidate_review_notifications` outbox(同源設計、但已接 `cron_invoke_send_...`+edge function 消費端)形成對比,凸顯本表缺口。建議:(a)比照 BL-48 pattern 補消費端(cron+edge function),或(b)確認此表已無實際用途後廢除,兩者擇一。來源證據:`supabase/migrations/20260502110000_candidate_conversations.sql:92-107`(建表+RLS,僅 `platform_admin_all` policy,無 cron schedule);`supabase/migrations/20260701184951_agency_definer_rpcs_t21.sql:649`(唯一 INSERT 來源);`grep -rl candidate_conversation_notifications supabase/functions/` 零命中(2026-07-20 盤點,HM-ADM-03 後續批次 BL-48 施工時附帶發現) MEDIUM 未修
KB-55 **[生產回歸,熱修待批准]** anon-definer 收斂 sweep(`20260720012221`+`20260720050006`,2026-07-20 套用)誤收 …**[生產回歸,熱修待批准]** anon-definer 收斂 sweep(`20260720012221`+`20260720050006`,2026-07-20 套用)誤收 7 個 **RLS 基礎設施函式**的 anon EXECUTE,導致共用 develop 遠端 DB 的 anon 公開瀏覽全面 401。根因:`candidates` 等 anon 可讀表的 permissive policy(無 `to` 子句、對 anon 生效)在 USING/WITH CHECK 引用 `has_role`/`auth_user_agency_ids`/`auth_user_is_agency_admin_of`/`auth_user_is_agency_member_of`/`auth_user_invited_hold_ids`/`candidate_slot_within_availability`/`worker_owns_active_ledger`;anon 查詢時 Postgres 求值 policy 需 execute 這些函式。前置分類只 grep 前端 `.rpc()`、漏了 **policy 內部引用**路徑。這 7 個是 advisor `anon_security_definer_function_executable` WARN 的 **false positive**(RLS 必需)。熱修已備妥(`20260720054230_regrant_anon_rls_infra_functions.sql`,未套用未 commit,待 [HsuTse] 裁決路 A re-grant/路 B policy 改造,詳見 `candidate-review-workflow.md` §6.1)。**教訓通則**:宣稱「某 definer 函式無合法呼叫者可收 anon」前,除 grep 前端 `.rpc()`,必須另 grep 全 migration 的 `create policy` USING/WITH CHECK 引用。來源證據:fable 最終總審實測(2026-07-20,production REST anon key):`GET /candidates?status=eq.published` → 401 `42501 permission denied for function auth_user_agency_ids`;熱修盤點見 `20260720054230_...sql` 檔頭 表↔policy↔函式 全對照 HIGH 未修
KB-56 HM-FORM-04 雇主端完整履歷展示(`employer-resume-view.tsx` `renderScalar`)的數字欄位(`expectedSalaryMin`/`…HM-FORM-04 雇主端完整履歷展示(`employer-resume-view.tsx` `renderScalar`)的數字欄位(`expectedSalaryMin`/`expectedSalaryMax`/`heightCm`/`weightKg`/`yearsOfExperience`/`childrenCount`/`birthOrder`/`siblingsCount`)一律以 `String(raw)` 原樣輸出,無千分位分隔或單位。同一詳情頁的 hero 區塊顯示期望待遇為 `NT$ 24,000`(`toLocaleString()`),完整履歷區塊卻顯示裸數字 `24000`,同頁兩種格式並存不一致,薪資/身高/體重欄尤其明顯。純顯示層一致性問題,不影響資料正確性。來源證據:`apps/web/src/components/employer-resume/employer-resume-view.tsx:232-233`(`case 'number': return isFiniteNumber(raw) ? String(raw) : empty;`)vs `apps/web/src/app/[locale]/(public)/browse/[candidateId]/detail-client.tsx:211`(`` `NT$ ${salary.toLocaleString()}` ``);web-qa F2、HM-FORM-04 T4.1 doc-sync(2026-07-24 盤點) LOW 未修
KB-57 ~~HM-FORM-04 T3.2 GPS 位置 metadata 掃描器(`scanForLocationMetadata`)對「結構異常/被截斷的 box」有已知 fail-o…~~HM-FORM-04 T3.2 GPS 位置 metadata 掃描器(`scanForLocationMetadata`)對「結構異常/被截斷的 box」有已知 fail-open 缺口:box 走訪遇到 `boxLen < headerLen || off + boxLen > length`(malformed/truncated)時僅對殘餘位元組做窄範圍的 Apple reverse-DNS key(`com.apple.quicktime.location`)掃描後即中止走訪,**不**對 4-byte 的 `©xyz`/`loci` 型別簽章掃描殘餘區段——若位置 box 恰好落在此類 malformed/truncated 殘餘內,可規避偵測而未被 `finalize` 拒收。程式碼註解自承「KNOWN FAIL-OPEN (Finding 2 — documented, not fixed here)」,正解需 container-sniff(先辨識合法 webm/EBML 以保住 passthrough,再對疑似 ISO-BMFF 但畸形者 fail-closed 拒收),且需先備妥 malformed-container fixture 才可落地,T3.2 未一併修復。**補充(2026-07-24,final review R2)**:另有第二種、獨立的 fail-open 分支(非上述 malformed/truncated 分支)——當某個 top-level box 的 `size32 === 0`(代表「跑到 EOF」)且其 `type === 'mdat'` 時,`boxLen = length - off` 會把**從該 box 起到檔尾的全部剩餘 bytes**都歸給 mdat,因程式判斷 `type !== 'mdat'` 為 false 而完全跳過 `collectSignals` 掃描;若該檔案是刻意構造的畸形檔(mdat 實際上並非真正最後一個 box,其後仍有 moov/udta/©xyz 等結構化資料,只是宣稱 size=0),這些真實存在的位置 metadata box 會被整段吞掉、從未被掃描到。模組頂部檔頭註解「moov may sit at the END (after mdat)」與「size==0 (to-EOF) are all handled」兩句分別成立,但**兩者同時成立**(size==0 的 mdat 之後其實還有 moov)時彼此矛盾,此組合情境的行為與註解宣稱「已處理」不符,程式碼本身未言明此交集情境,亦未修復。~~ → **已修(2026-07-25,PR #35,`video-metadata-strip.ts`)**。收斂方式不是逐個補洞,而是**把預設從 fail-open 反轉為 fail-closed**:新剝除器要求 top-level walk 必須**完整交代每一個 byte**、且 `moov` 數恰為 1,否則一律拒收——這一個條件同時關掉本條記載的兩個分支(malformed/truncated 殘餘、`size==0` 假 `mdat` 吞尾部 `moov`),`size==0` 更是直接列為拒收原因(實務 muxer 不產生)。原本擋住「無條件拒收 malformed」的理由是「會誤傷合法 webm」,而 T3.5 已把 `video/webm` 移出允許 MIME,該顧慮消失。`scanForLocationMetadata` 本身的寬容行為**維持不變**,但角色已從「合規 gate」降為「剝除後的重驗器」,故其寬容不再構成合規缺口(該檔註解已明載「勿再把它升回 gate,否則須重開 KB-57」)。負向測試:`test-candidate-video-gps-strip.ts` F-STRIP-5(7 案)來源證據:`apps/admin/src/components/candidate-resume/video-metadata-scan.ts:137-160`(`KNOWN FAIL-OPEN (Finding 2...)` 註解+ `if (boxLen < headerLen || off + boxLen > length) { ...; break; }` 分支);`:130-135,165-167`(`size32 === 0` 分支+ `if (type !== 'mdat') { collectSignals(...) }`,本補充所指第二分支);HM-FORM-04 T3.2 review Finding 2、T4.1 doc-sync(2026-07-24 盤點) MEDIUM 已修
KB-59 ~~HM-FORM-04 storage `candidate_media_storage_employer_select` policy(migration `202607231…~~HM-FORM-04 storage `candidate_media_storage_employer_select` policy(migration `20260723164028`)只以 `(storage.foldername(name))[1]`(candidate_id)+ `candidate_is_published(candidate_id)` 收斂,對物件路徑第二段(kind,如 `photo`/`tattoo`/`video`)**無任何限制**——只要候選人狀態為 published,任何 kind 前綴皆可被雇主 list/sign/下載。今日無害:現行三種 kind(photo/tattoo/video)本就是雇主應可見的公開履歷媒體。但 BL-32(mobile 候選人詳情「文件」分頁)若把體檢報告、犯罪紀錄等**聘後或敏感文件**放進同一 bucket 的新 kind 前綴(例如 `{candidateId}/health/`),任何 `has_role('employer')` 的自助註冊帳號即可直接對該候選人(僅限 published 狀態,非任意候選人)的敏感文件 list/sign/下載,不受產品設計意圖限制。**T1.3b 開工前必須先處理**:policy 應加 kind allow-list(例如 `and (storage.foldername(name))[2] = any(array['photo','tattoo','video'])`),斷開「新增 kind=自動對雇主開放」這條隱性耦合。 ~~ → **已修(2026-07-25,PR #35,migration `20260725022522` ②③④)**。4 條 candidate-media storage policy 全部加上 kind allow-list:寫入集=`photo`/`tattoo`/`video-inbox`;成員讀取集=上列+`video`;**雇主讀取集=`photo`/`tattoo`/`video`(不含 `video-inbox`)**。kind 檢查刻意置於 predicate 最外層(與 `bucket_id` 同層、在 `platform_admin` OR 分支之外),故連 platform_admin 也受限——invariant 要對所有 JWT caller 一致成立。BL-32 若新增 `health/` 等敏感 kind,**不會**再自動對雇主開放(需顯式加入 allow-list)。回歸守護:`test-candidate-media-rls.ts` case 19 `unknown-kind-is-rejected`來源證據:`supabase/migrations/20260723164028_employer_resume_public_api_hardening.sql:326-332`(`candidate_media_storage_employer_select`:`using (bucket_id = 'candidate-media' and public.has_role('employer') and public.candidate_is_published((storage.foldername(name))[1]::uuid))`,無 `[2]` kind 檢查;對照同檔 storage insert/update/delete 與既有 `candidate_media_storage_select` 皆同款僅 key `[1]`);`docs/roadmaps/backlog.md` BL-32(mobile 文件分頁 taxonomy 待定,T1.3b 觸發點);HM-FORM-04 final review R2(2026-07-24 盤點) MEDIUM 已修
KB-58 3 筆既有已上架候選人(`resume_json` 為 legacy Quadrats 富文本陣列格式,非 wizard 結構化物件)在雇主端完整履歷 RPC(`get_emplo…3 筆既有已上架候選人(`resume_json` 為 legacy Quadrats 富文本陣列格式,非 wizard 結構化物件)在雇主端完整履歷 RPC(`get_employer_candidate_resume`)與 mobile 詳情皆將自我介紹/經歷欄位降級為空。RPC 內建 `jsonb_typeof(resume_json) = 'object'` 守衛會把非物件形態(含陣列)的 `resume_json` 一律收斂為 `null` 再交給前端(安全預設,避免未知格式打穿投影型別),代價是這 3 筆候選人的 `experienceNarrative`/`duties`/`languageProficiencies`/`employmentHistory` 在雇主視角與 mobile 端全部顯示為空,即使該筆候選人在 admin/agency-console 端仍可見(走舊 Quadrats 相容渲染路徑,未受影響)。純資料層落差非程式邏輯錯誤,需資料遷移(backfill 舊格式→新結構化格式,或雙格式相容處理,比照 KB-45 已修模式)才能還原顯示。來源證據:實測 SQL(project `gjsvnyrkyftaxmfhqwze`,2026-07-24):`select id, display_name, status, jsonb_typeof(resume_json) from candidates where resume_json is not null and jsonb_typeof(resume_json) <> 'object'` → 3 列,皆 `status='published'`:`51ca152c-4618-45d7-9b6a-4dbcc29780ad`(E2E Direct 20260502121751)/`d43763e3-d5d1-4648-860f-016bbe447da9`(E2E Agency 20260502121751)/`dcd06f1c-8249-4e4e-9b90-1651eb77ae04`(E2E Matching 20260502121751);`apps/web/src/components/employer-resume/employer-resume-projection.ts:136-150`(`buildEmployerResumeValues` 文件註解說明 RPC guard 行為) MEDIUM 已修
KB-60 PR CI 檢查 `Supabase Preview`(Supabase branching,project ref `domytgnnctqsvpvkbnkg`)自 2026-0…PR CI 檢查 `Supabase Preview`(Supabase branching,project ref `domytgnnctqsvpvkbnkg`)自 2026-07-24T13:00Z 起全面失敗:`ERROR: relation "public.resume_parse_jobs" does not exist (SQLSTATE 42P01)`,中止於 `20260426200000_p0_parse_resume_authz_depth.sql` 的 `drop policy ... on public.resume_parse_jobs`。根因:該表由 `20260427060000_p2_1_resume_parse_jobs.sql` 的 `create table` 建立,但依**檔名版本號**排序,`20260426200000` 早於 `20260427060000` 執行——「從零重播」(fresh replay,含 CI 的 Supabase Preview branching)必然在建表之前先跑到引用該表的陳述式而崩潰。共用生產庫(project `gjsvnyrkyftaxmfhqwze`)因兩檔**實際套用順序**與檔名排序不同(真實歷史上建表檔先跑),故從未出錯,只有「從零重播」情境會炸。已完整踏查範圍:抽取所有 migration 內 `public.<identifier>` 參照與所有 `create table/type/function/view` 宣告比對,`resume_parse_jobs` 是唯一「被引用但依檔名排序從未被建立」的物件;另比對出的 11 個候選皆為 false positive(10 個是既有 index 名稱經 `drop index`/`comment on index` 反查、1 個是 `tg_set_updated_at` 因 `create` 與 `or replace function` 分兩行寫而規則式掃描漏抓,實際存在且早於各處使用)。`.future-dated-baseline.json` 只記錄「2026-04-26 前已套用但檔名為未來日期」的 18 筆治理債(供 strict audit 分辨舊債與新違規),性質不同,**不**涵蓋這種「檔名排序與實際套用順序不同導致從零重播崩潰」的情境。此缺陷推翻 `docs/operations/deploy.md` Go-Live checklist 所稱「rollback path 已確認,包含 DB forward-fix 策略」的前提——若真需從零建置新環境(DR 情境),現有 migration 集合無法完整重播。修法本身有治理難題:純新增 forward migration(今日日期)必然排在兩個既有檔案之後,從零重播會在跑到它之前就已在 `20260426200000` 崩潰,**無法單靠 forward migration 解決**;唯一能讓重播不崩潰的方式,是替 `20260426200000` 內三段引用 `resume_parse_jobs` 的陳述式加上 `to_regclass` 存在性守衛(對已有該表的環境,含現行生產庫,行為證明零改變),但這牴觸 `docs/engineering/migration-governance.md`「已套用到遠端的 migration 不做 history rewrite,只有註解可改、不得改陳述式」的既有指引。已備妥守衛版 patch 與搭配的 forward repair migration 內容供審閱,**未實際套用**,待團隊裁決是否核准此類「replay-order 缺陷」的一次性例外處理方式。。**→ 已修(2026-07-25,`fix/migration-replay-order`)**:[HsuTse] 核准一次性例外——(a)`20260426200000_p0_parse_resume_authz_depth.sql` 的三段依賴(drop 兩條 source_agency policy/guard trigger/composite index)包進 `to_regclass('public.resume_parse_jobs') is not null` 守衛,原敘述以註解保留在旁,**語意不變、對已套用環境為零影響**;(b)新增 forward migration `20260725195607_kb60_resume_parse_jobs_replay_order_repair.sql`——光有守衛不夠,因為重播時 `20260427060000` 會把兩條 source_agency policy 重新建起來、且 guard trigger 與 composite index 都不存在,**只做到「不崩」會留下靜默的終態偏差,比崩潰更危險**,故必須在表確定存在後重新宣告原意圖;(c)`docs/engineering/migration-governance.md`「修正已套用 migration 的策略」補上 **replay-order retrofit** 類別與四項適用前提,避免下次成為臨時決定。**驗證方式**:本機無法驗(CLAUDE.md 禁 `supabase start`/`db reset`),真實驗證=push 後觀察 `Supabase Preview` 檢查是否由 FAILURE 轉 SUCCESS。**⚠️ 範圍更正(2026-07-25 第二輪)**:初次踏查結論「`resume_parse_jobs` 是唯一缺口、屬單一事件」**是錯的**——該掃描問的是「每個被引用的物件是否都在某處被建立?」,一個**物件存在性**問題,因此結構上看不到第二種機制。首次修復 push 後 `Supabase Preview` 由 9 秒(第一個依賴敘述即中止)推進到 46 秒後仍失敗,新錯誤為 `42P13 cannot change name of input parameter "p_signed_at"`:`public.compute_milestone_due_at (text, timestamptz, date)` 第二參數在檔名順序上來回改名四次(`p_signed_at` → `p_case_started_at` → `p_signed_at` → `p_case_started_at`,後兩者屬 baseline 那批),而 `create or replace function` 不能改參數名。**改用順序感知分析器**(「依檔名順序執行時每一步前置條件是否成立」)後,兩類失敗的完整下限為 C1=0/C2=2,全部落在同一函式——**範圍可控,非開放式循環**,故不需 baseline squash。分析器經雙向驗證(停用 guard 辨識→重報 2 筆;對修復前 commit `00f4a92a` 跑→報 5 筆),排除 vacuous green。第二輪修法:於兩處 `create or replace` 前置 `drop function if exists public.compute_milestone_due_at (text, timestamptz, date)`,**不需**配對 forward migration(終態不變);查證該函式無 GRANT/REVOKE、未被 RLS policy/view/generated column 引用,故無 KB-55 類權限回歸風險來源證據:CI 執行紀錄(`Supabase Preview` check,2026-07-24T13:00Z 起持續失敗):`ERROR: relation "public.resume_parse_jobs" does not exist (SQLSTATE 42P01)`;`supabase/migrations/20260426200000_p0_parse_resume_authz_depth.sql:22-23,65-70,74-76`(引用 `resume_parse_jobs` 的三段陳述式);`supabase/migrations/20260427060000_p2_1_resume_parse_jobs.sql:19`(`create table public.resume_parse_jobs (...)`,唯一建表點,`git log --all -S"create table public.resume_parse_jobs"` 確認);`supabase/migrations/.future-dated-baseline.json`(範圍不含此類缺陷);`docs/engineering/migration-governance.md`「修正已套用 migration 的策略」段;`docs/operations/deploy.md:60`(rollback path 前提);live schema 經 `scripts/audit-migration-state.ts` 沿用的 `audit_introspect_artifacts`/`audit_list_applied_migrations` RPC,與 PostgREST OpenAPI(`GET {SUPABASE_URL}/rest/v1/`,`Accept: application/openapi+json`)比對確認欄位定義一致(2026-07-25 盤點,project `gjsvnyrkyftaxmfhqwze`,`audit_list_applied_migrations` 回傳 207 筆,`resume_parse_jobs`/`tg_assert_resume_parse_job_candidate_published`/`resume_parse_jobs_set_updated_at` 皆 EXISTS) HIGH 已修

Backlog

ID項目狀態
BL-01 `taiwan_agency`/`source_agency` enum 正名為顧問語彙(ADR 0002 附註;含 DB enum 與 i18n)`taiwan_agency`/`source_agency` enum 正名為顧問語彙(ADR 0002 附註;含 DB enum 與 i18n)啟動前置:HM-CASE-01 task 層 schema 定案後一併評估 待排程
BL-02 `interview_slot_proposals` 狀態機補 DB trigger 守護(現僅靠 RPC,mobile 直連會破壞狀態機)`interview_slot_proposals` 狀態機補 DB trigger 守護(現僅靠 RPC,mobile 直連會破壞狀態機)啟動前置:工程評估;來源:2026-07-06 移工行動節點盤點 待排程
BL-19 `loadServerEnv` 拆分(raw key 收窄至 `libs/config/src/server-secret.ts`,保留 `loadPublicEnv`/secur…`loadServerEnv` 拆分(raw key 收窄至 `libs/config/src/server-secret.ts`,保留 `loadPublicEnv`/security-headers 自由 import)啟動前置:`libs/config` production 改動、4-app blast radius,需獨立 review;來源:HM-RBAC-01 console 合併 OQ-5 裁定(`docs/adr/0012-agency-console-physical-merge.md`),非合併所需,deferred 待排程
BL-30 fee-summary union 收窄(HM-CMP-01-T08 衍生):`apps/web` fee-summary 的 `FeeSummaryGroup.id` union…fee-summary union 收窄(HM-CMP-01-T08 衍生):`apps/web` fee-summary 的 `FeeSummaryGroup.id` union 型別(`apps/web/src/components/fee-summary/fee-summary.tsx:39`)仍含永久不再使用的 `'worker'` 字面量(隱藏 worker 群組後刻意保留、無風險),純清理項。啟動前置:無(低優先,純型別清理);來源:HM-CMP-01-T08 移工零付費(2026-07-13 盤點) 待排程
BL-03 mobile 電商 tab(現為 coming-soon 佔位)mobile 電商 tab(現為 coming-soon 佔位)啟動前置:**[產品決策]** 商業範疇未定 待排程
BL-04 mobile 匯款 tab(現為 coming-soon 佔位;平台不涉薪資金流)mobile 匯款 tab(現為 coming-soon 佔位;平台不涉薪資金流)啟動前置:**[產品決策]** 與 ADR 0004 金流邊界一致性確認 待排程
BL-05 HM-MOB-01-T05 殘項:Realtime 訂閱取代輪詢(對話列表 20s/訊息串 6s)HM-MOB-01-T05 殘項:Realtime 訂閱取代輪詢(對話列表 20s/訊息串 6s)啟動前置:無 待排程
BL-07 → HM-FTR-01-T04/HM-MOB-05-T08(2026-07-17;2026-07-18 blocked):mobile 講者字幕的 server STT。Realt…→ HM-FTR-01-T04/HM-MOB-05-T08(2026-07-17;2026-07-18 blocked):mobile 講者字幕的 server STT。RealtimeKit 已有 managed real-time transcription,不需自建 audio subscriber;但其已文件化語言不含 zh-TW、fil-PH、id-ID、th-TH、vi-VN,且需 preset/Workers Paid 成本決策。先解決 HM-FTR-01-D10 才做 provider transcript→caption relay 與 mobile integration。RN 不跑裝置端 STT。啟動前置:`docs/roadmaps/mobile-security-role-caption-phase.md` 已認領/完成
BL-08 → HM-MOB-05-T01~T04(2026-07-17):mobile session token 改為安全儲存。不得直接把完整 session 塞進 SecureStore…→ HM-MOB-05-T01~T04(2026-07-17):mobile session token 改為安全儲存。不得直接把完整 session 塞進 SecureStore;先完成 authenticated-encryption adapter spike,再遷移現有 AsyncStorage plaintext session。啟動前置:ADR 0020;`docs/roadmaps/mobile-security-role-caption-phase.md` 已認領/完成
BL-09 mobile 帳號頁語言切換收進設定子頁,預設使用系統語言;避免在帳號頁第一層直接平鋪語言選項。mobile 帳號頁語言切換收進設定子頁,預設使用系統語言;避免在帳號頁第一層直接平鋪語言選項。啟動前置:UX 定義;來源:HM-MOB-02-Q01 W1 待排程
BL-10 mobile Loading `Shimmer` 提升載入感知;現行 700ms 透明度呼吸太弱,視覺上像空方框,可改為更明顯動效或輔助 icon/文案。→ 已修第一版(2026-…mobile Loading `Shimmer` 提升載入感知;現行 700ms 透明度呼吸太弱,視覺上像空方框,可改為更明顯動效或輔助 icon/文案。→ 已修第一版(2026-07-09):提高 fill 對比並縮短呼吸週期。啟動前置:設計確認;來源:HM-MOB-02-Q01 待排程
BL-11 mobile 啟動時避免不必要改變系統音訊工作階段;目前開 app 時會讓手機背景音樂出現類似「進山洞」的混音效果,疑似 RealtimeKit/react-native-webr…mobile 啟動時避免不必要改變系統音訊工作階段;目前開 app 時會讓手機背景音樂出現類似「進山洞」的混音效果,疑似 RealtimeKit/react-native-webrtc 啟動階段設定 AVAudioSession。啟動前置:工程調查;來源:HM-MOB-02-Q01 待排程
BL-12 mobile 文件上傳成功後顯示已上傳文件/圖片列表,讓 W8/E7 使用者能回頭確認剛上傳的內容;目前只有預覽與一次性 toast。mobile 文件上傳成功後顯示已上傳文件/圖片列表,讓 W8/E7 使用者能回頭確認剛上傳的內容;目前只有預覽與一次性 toast。啟動前置:無;來源:HM-MOB-02-Q01 W8/E7 待排程
BL-13 mobile 日期/時間輸入統一改用系統原生 DatePicker/TimePicker,並修正鍵盤彈出時表單自動上推;W9 請假與 E8 家庭成員出生年都遇到同類問題。mobile 日期/時間輸入統一改用系統原生 DatePicker/TimePicker,並修正鍵盤彈出時表單自動上推;W9 請假與 E8 家庭成員出生年都遇到同類問題。啟動前置:工程評估;來源:HM-MOB-02-Q01 W9/E8 待排程
BL-14 雇主端首頁移除重複的「瀏覽」入口;底部 tabbar 已有瀏覽功能。→ 已修(2026-07-09)。雇主端首頁移除重複的「瀏覽」入口;底部 tabbar 已有瀏覽功能。→ 已修(2026-07-09)。啟動前置:產品確認;來源:HM-MOB-02-Q01 待排程
BL-15 mobile 案件進度八階段支援切換/查看非 current stage 的任務完成數,降低「本階段 X/Y」與整體 journey 進度混淆;也方便 A3 類跨階段同步驗證。mobile 案件進度八階段支援切換/查看非 current stage 的任務完成數,降低「本階段 X/Y」與整體 journey 進度混淆;也方便 A3 類跨階段同步驗證。啟動前置:UX 定義;來源:HM-MOB-02-Q01 A3/黃金路徑 待排程
BL-16 雇主端面試管理「確認此時段」CTA 改用既有 mobile Button 視覺語彙、間距與層級,避免像臨時 web-style button。雇主端面試管理「確認此時段」CTA 改用既有 mobile Button 視覺語彙、間距與層級,避免像臨時 web-style button。啟動前置:設計確認;來源:HM-MOB-02-Q01 E2 待排程
BL-31 mobile 雇主合約上傳加入 PDF 原生選檔:在既有拍照/相簿影像之外接入 `expo-document-picker`,讓中文版與幫傭母語版契約可直接選擇 `applicat…mobile 雇主合約上傳加入 PDF 原生選檔:在既有拍照/相簿影像之外接入 `expo-document-picker`,讓中文版與幫傭母語版契約可直接選擇 `application/pdf`;沿用現有 20 MiB BFF 限制、雙檔整批上傳與失敗回滾,不改合約文件權限。BFF 已接受 PDF,目前缺口只在 native picker 與消費端檔案正規化。啟動前置:工程評估(Expo SDK 相容版本、iOS/Android file provider URI/base64 行為)+重建 dev-client 並以兩平台真實 PDF 選檔驗證;來源:HM-MOB-03-T18、`apps/mobile/src/lib/contract.ts`、`apps/mobile/src/screens/ContractUploadScreen.tsx` 待排程
BL-32 mobile 雇主端候選人詳情「文件」分頁接真實內容;目前 `EmployerDetailScreen` 對 `docs` tab 無條件顯示空狀態,雖 detail query …mobile 雇主端候選人詳情「文件」分頁接真實內容;目前 `EmployerDetailScreen` 對 `docs` tab 無條件顯示空狀態,雖 detail query 已讀 `resume_file_url`,但該歷史欄位用途與公開權限不夠明確。實作只得呈現經確認可供聘前雇主查看的履歷/公開附件,必須明確排除健檢、犯罪紀錄、案件文件等敏感或聘後文件;private storage 一律由 RLS-bound BFF 驗權後產生短效 signed URL,不可直接曝光 storage path。啟動前置:**[產品決策]** 先定義「文件」分頁 taxonomy、公開條件與空狀態;個資/權限 review;協調 HM-FORM-01 candidate-media Phase D,避免另造簽 URL 邏輯;來源:HM-MOB-03-T19、`apps/mobile/src/screens/EmployerDetailScreen.tsx`、`apps/mobile/src/lib/employer-data.ts` 待排程
BL-33 同一受邀仲介允許多位成員同時加入同一面試室。現行 mobile token 流程以每位使用者建立 invite 並記錄個別 entry ack,但 insert 同時帶 `user…同一受邀仲介允許多位成員同時加入同一面試室。現行 mobile token 流程以每位使用者建立 invite 並記錄個別 entry ack,但 insert 同時帶 `user_id` 與 `agency_id`;`interview_room_invites_agency_uidx` 又限制同 room/role/agency/version 只能有一筆,第二位同仲介成員會在 `ensureInterviewVideoInvite` insert 觸發 unique conflict,且無法以自己的 `user_id` refetch。需收斂為可稽核的 per-user participant/entry ack 模型,不得放寬「所屬仲介已有 accepted advisor invitation」的既有授權邊界。啟動前置:工程設計+migration(唯一鍵/invite identity/撤銷語意)與獨立 security review;以同仲介兩個真實成員帳號同時進房驗證;來源:HM-MOB-03-T14 審查追蹤、`libs/mobile-api/src/interview-video.ts`、`libs/video/src/video-room-service.ts`、migration `20260531201516_video_interview_rooms.sql` 待排程
BL-34 → HM-MOB-05-T05~T07(2026-07-17):mobile 多角色帳號切換 UI。登入與 session 還原回傳全部 active mobile roles;本…→ HM-MOB-05-T05~T07(2026-07-17):mobile 多角色帳號切換 UI。登入與 session 還原回傳全部 active mobile roles;本機 active role 僅為偏好,永不構成授權;首次多角色登入選擇、後續可切換,role-mismatch deep link 必須明確要求切換。啟動前置:ADR 0020;`docs/roadmaps/mobile-security-role-caption-phase.md` 已認領/完成
BL-35 對話訊息寫入與通知入列改為可恢復的 transactional outbox。現行 mobile BFF 已用 `client_message_id` 做訊息 idempotenc…對話訊息寫入與通知入列改為可恢復的 transactional outbox。現行 mobile BFF 已用 `client_message_id` 做訊息 idempotency,正常重送與並發重送不會重複寫訊息或通知;但若程序在訊息 insert 成功後、`queueReplyNotification` 前中斷,後續 retry 會命中既有訊息並直接成功,無法安全補送通知。另需定義同一 idempotency key 搭配不同 body 時回 conflict,而非靜默回舊 message id。啟動前置:工程設計+migration(outbox 或 notification 的 message/recipient 唯一鍵)與 worker retry/去重策略;不得以 check-then-insert 造成重複通知;來源:KB-11 2026-07-15 獨立複審、`libs/mobile-api/src/conversations.ts` 待排程
BL-36 agency-console 全域 mobile/窄螢幕 RWD:sidebar(agency-shell)固定不收合,≤768 佔 ~241px 壓縮內容區、375 寬時內容整體…agency-console 全域 mobile/窄螢幕 RWD:sidebar(agency-shell)固定不收合,≤768 佔 ~241px 壓縮內容區、375 寬時內容整體溢出視窗(scrollW 481>375)被裁切,mobile 實質不可用。需 sidebar 收合/抽屜化+全 console 頁面 RWD 收斂;可一併解 KB-41(斷點統一)與 KB-43(wizard 768 殘餘橫捲)。啟動前置:UI/UX 設計+`agency-console/_components/agency-shell.tsx` 改造;來源:2026-07-15 候選人流程視覺評估 P1-1(25 張截圖) 待排程
BL-37 Mezzanine focus ring 顏色與錯誤色系過近:空欄位聚焦時顯示 brand 紅橘色 focus 框,與驗證錯誤紅色視覺相似,易被誤讀為填寫錯誤。屬全域 design…Mezzanine focus ring 顏色與錯誤色系過近:空欄位聚焦時顯示 brand 紅橘色 focus 框,與驗證錯誤紅色視覺相似,易被誤讀為填寫錯誤。屬全域 design token/theme 層,調整影響整站,需設計端定奪後統一處理。啟動前置:design token 調整評估(全站影響面盤點);來源:2026-07-15 候選人流程視覺評估 P3-2 待排程
BL-38 SectionCard 卡片基礎樣式(`agency-console/_components/section-card/section-card.module.scss`)與 ca…SectionCard 卡片基礎樣式(`agency-console/_components/section-card/section-card.module.scss`)與 canonical 來源 `agencies/[id]/agency-detail-client.module.scss` `.section`/`.sectionTitle` 為 verbatim 雙份——token 調整時需雙檔同步,有 drift 風險。建議讓 agency-detail 段落改 consume 共用 SectionCard 元件(注意其 `.section` 另掛 container-query 擴充,非完全可互換),或抽共用 SCSS placeholder。**補充(2026-07-19,HM-FORM-02 A1)**:SectionCard 已 git mv 至 `apps/admin/src/components/section-card/`(原 `agency-console/_components/section-card/` 路徑已淨空),收斂 agency-detail 段落仍待另行處理。啟動前置:收斂重構(agency-detail 遷移至 SectionCard);來源:2026-07-16 wizard 3 步重構 final review Maintainability finding;`feature/agency-wizard-3step` 待排程
BL-17 Admin 工作收件匣結案改為 row-level pending/optimistic remove resolved row,避免整張 table 進入 loading 導致操…Admin 工作收件匣結案改為 row-level pending/optimistic remove resolved row,避免整張 table 進入 loading 導致操作脈絡消失。→ 已修第一版(2026-07-09)。啟動前置:無;來源:HM-MOB-02-Q01 A2 待排程
BL-18 Admin 工作收件匣 table 欄寬與資訊密度重整;多筆同名 task 需要一眼看見候選人、案件階段、時間與行動方,避免內容截斷造成人工辨識困難。→ 已修第一版(2026-07…Admin 工作收件匣 table 欄寬與資訊密度重整;多筆同名 task 需要一眼看見候選人、案件階段、時間與行動方,避免內容截斷造成人工辨識困難。→ 已修第一版(2026-07-09)。啟動前置:UX 定義;來源:HM-MOB-02-Q01 黃金路徑 待排程
BL-48 候選人送審/審核站內通知:台灣仲介送審後通知平台待審佇列、平台退回後通知台灣仲介退件原因,兩者目前皆無站內通知機制,僅靠使用者主動進頁面查看。[HsuTse] 2026-07-19…候選人送審/審核站內通知:台灣仲介送審後通知平台待審佇列、平台退回後通知台灣仲介退件原因,兩者目前皆無站內通知機制,僅靠使用者主動進頁面查看。[HsuTse] 2026-07-19 裁決 HM-ADM-03 本期只做列表篩選+待審標示,站內通知列為 follow-up。可複用既有 queue-table pattern(`interview_schedule_notifications`/`candidate_conversation_notifications`,見 `supabase/functions/send-interview-schedule-notification/index.ts` 與 `supabase/migrations/20260502110000_candidate_conversations.sql`),不另起爐灶。**→ 已啟動(2026-07-20,HM-ADM-03 後續批次):Email 版 MVP([HsuTse] 裁決),範圍三事件(送審→平台、退回/核准→台灣仲介;核准事件為裁決時明列)。**啟動前置:工程評估(是否沿用既有 queue-table pattern 或另立通知渠道);來源:HM-ADM-03 Step 1 治理登記(2026-07-19,ADR-0021 Consequences) 待排程
BL-20 HM-FORM-01 履歷表單機翻的 4 語系(fil-PH/id-ID/th-TH/vi-VN)字串,加上新增的 `admin.candidates.resumeForm.mac…HM-FORM-01 履歷表單機翻的 4 語系(fil-PH/id-ID/th-TH/vi-VN)字串,加上新增的 `admin.candidates.resumeForm.machineTranslatedNotice` key,需要母語者審閱校對(現為機器翻譯,僅標示 AI 翻譯,未經人工校對)。啟動前置:需排定母語審閱資源;來源:HM-FORM-01 Phase 1.5 六語系機翻(commit `f066086`/`4b35859`) 待排程
BL-21 T1.3a candidate-media 上傳:進入媒體上傳精靈步驟(create mode)會先建立一筆 draft candidate row;若使用者中途放棄,會留下空 d…T1.3a candidate-media 上傳:進入媒體上傳精靈步驟(create mode)會先建立一筆 draft candidate row;若使用者中途放棄,會留下空 draft row 與對應的孤兒 storage 物件,需要排程 GC 清理未觸碰的空 draft 與其孤兒 storage 物件。**(2026-07-12 擴充,Phase C review)**:除空 draft 案例外,Phase C 表單接線(`candidate-resume-form.tsx` 的 `makeMediaUploader`,`:649-656`)呼叫 `uploadCandidateMediaAction` 時從未帶入 `replacePath`(只 set `candidateId`/`kind`/`file`);`uploadCandidateMediaAction` 的舊物件清除(`media-upload-actions.ts:184-186`)僅在收到非空 `replacePath` 時才會 best-effort 移除,而 `MzFileUploadField` 的移除/替換路徑(`mz-file-upload-field.tsx:284-322` `handleChangeWithUpload`)本身也不呼叫任何刪除 server action——不論是單純移除一筆媒體(`introVideoUrl` `maxFiles={1}` 的「先刪後加」或 `photoUrls`/`tattooPhotoUrls` 多檔欄位手動移除單一項目),或移除後再上傳新檔取代,舊 Storage 物件都不會被清除,形成孤兒物件。排程 GC 需一併涵蓋此 per-item 案例(非僅空 draft 整列),或改由表單層在移除/替換時明確帶入 `replacePath`。啟動前置:工程評估(排程機制、判定「未觸碰」的門檻;或改表單層接線 `replacePath`);來源:HM-FORM-01 T1.3a candidate-media 上傳(2026-07-12 盤點;per-item 案例為 Phase C sonnet review 發現) 待排程
BL-22 ~~T1.3a candidate-media 影片上傳現為原始檔(≤100 MiB)直存,未做轉碼/正規化;需評估 Edge Function + ffmpeg vs Cloud…~~T1.3a candidate-media 影片上傳現為原始檔(≤100 MiB)直存,未做轉碼/正規化;需評估 Edge Function + ffmpeg vs Cloudflare Stream(專案已用 CF RealtimeKit)方案,統一 codec/解析度/bitrate,並產生封面縮圖(poster thumbnail)。~~ → GPS 合規前提部分收斂(**HM-FORM-04** Phase 3:TUS resumable 直傳+client 端 mp4box.js remux 剝除 GPS metadata(不轉碼)+server pure-JS box 掃描把關;ADR-0023 D3;見 `docs/roadmaps/employer-resume-display.md`);轉碼正規化/封面縮圖未竟部分轉 **BL-58**啟動前置:工程評估(vendor 能力查證,比照 BL-07 vendor 查證模式);來源:HM-FORM-01 T1.3a candidate-media 上傳(2026-07-12 盤點) 待排程
BL-23 履歷「經歷」自由文字欄位(仲介+外傭本人雙寫入):在工人履歷新增一個多行 TextArea「經歷」欄位,捕捉工人工作/生活經歷的敘事性描述(自由文字,非結構化資料)。雙寫入來源:(…履歷「經歷」自由文字欄位(仲介+外傭本人雙寫入):在工人履歷新增一個多行 TextArea「經歷」欄位,捕捉工人工作/生活經歷的敘事性描述(自由文字,非結構化資料)。雙寫入來源:(1) 仲介於 agency-console 履歷表單填寫/編輯;(2) 外傭本人登入 **worker 行動 app**(`apps/mobile`)後自行編輯。觸及面:新增履歷欄位(獨立 `candidates` column 或 `resume_json` key,設計時再定);agency-console 履歷表單接線(新增 TextArea 欄位);worker mobile app 履歷編輯介面;以及 RBAC——工人本人若要自行編輯此欄位,須將其加入 `candidate_update_own_profile` RPC 的 allow-list(現排除多個 PII 欄位),仲介端寫入則走既有 draft/agency RLS 路徑。需與既有結構化經歷欄位(`years_of_experience` typed column、`resume_json.employment_history[]` 結構化就業史陣列)的關係先釐清:本欄位為自由敘事文字,非取代前述結構化欄位。**補充(2026-07-19,[HsuTse] 裁決,HM-FORM-02 A4b/B1 範圍)**:獨立 column vs `resume_json` key 已定案採 `resume_json` key(零 migration);本輪(HM-FORM-02)交付範圍縮為「共用 wizard 表單欄位+完整履歷檢視顯示」(仲介端與平台端 wizard 皆可寫入/檢視);殘餘範圍=worker mobile 本人編輯介面+`candidate_update_own_profile` RPC allow-list 擴充(涉及 PII 政策,留待後續)。啟動前置:工程評估(決定獨立 column vs `resume_json` key;RBAC allow-list 擴充涉及 PII 政策,比照 HM-FORM-01 design.md §4.2 Open Q9 同類決策模式);來源:[HsuTse] 本次 session 要求(2026-07-12),參照 `docs/roadmaps/forms-realignment/design.md` 履歷欄位盤點 待排程
BL-24 HM-FORM-01 Phase 2.1 雇主需工表 `baseEmployerIntakeShape` 的 `WORKER_AGE_MIN=18`/`WORKER_AGE_MAX…HM-FORM-01 Phase 2.1 雇主需工表 `baseEmployerIntakeShape` 的 `WORKER_AGE_MIN=18`/`WORKER_AGE_MAX=65`(`libs/forms-shared/src/employer-intake.ts:124-125`)為明確標註的 placeholder(原始 comment:「design.md does not specify an authoritative legal min/max for a requested worker's age...narrow later if/when an authoritative number is confirmed」),目前刻意取寬鬆值以避免誤擋合法輸入。需與法務/營運確認外籍家庭幫傭聘僱年齡的權威上下限後收斂驗證範圍。啟動前置:待法務/營運確認權威年齡上下限;來源:HM-FORM-01 Phase 2.1(`baseEmployerIntakeShape`,commit `90417e0c`,2026-07-13 盤點) 待排程
BL-25 HM-FORM-01 Phase 2.2/T2b 新增的 `family_member_point_conditions` 特殊需求兒童 condition_code 7 選項(`…HM-FORM-01 Phase 2.2/T2b 新增的 `family_member_point_conditions` 特殊需求兒童 condition_code 7 選項(`SPECIAL_NEEDS_CONDITION_CODES`)標籤僅補上 `libs/i18n/src/locales/zh-TW/common.json`,其餘 5 語系(en/fil-PH/id-ID/th-TH/vi-VN)尚未補譯——既有「家庭成員(4 點制)」區塊本已 6 語系齊備,但本次新增的 7 個 condition code 選項標籤僅落地 zh-TW。啟動前置:需排定翻譯資源(比照 BL-20 母語審閱模式);來源:HM-FORM-01 Phase 2.2/T2b(2026-07-13 盤點;`libs/i18n/src/locales/zh-TW/common.json:4740` 起 vs 其餘 5 語系同路徑缺對應 key) 待排程
BL-26 HM-FORM-01 共用 wizard 骨架 `useWizard().goNext()`(`libs/forms-shared/src/wizard/use-wizard.ts…HM-FORM-01 共用 wizard 骨架 `useWizard().goNext()`(`libs/forms-shared/src/wizard/use-wizard.ts:41-43`)無條件推進 `stepIndex`,不檢查目前步驟欄位是否通過驗證;`WizardShell` 依設計刻意不擁有 `react-hook-form` 實例(design.md §3.6),故 wizard 共用層完全沒有 per-step validation gate 機制,目前完全仰賴各 consumer 元件自行在呼叫 `goNext` 前手動驗證(若有做的話)。需評估是否該在共用層補一個標準化「驗證目前步驟欄位、失敗則不前進」機制,避免各 consumer 各自重新發明或遺漏。啟動前置:工程評估(收斂進 `useWizard`/`WizardShell` 共用層,或維持各 consumer 自行處理);來源:HM-FORM-01 Phase 2.3 demand wizard(commit `3f46760f`)與共用骨架 `libs/forms-shared/src/wizard/use-wizard.ts:41-43`(2026-07-13 盤點) 待排程
BL-27 HM-FORM-01 Phase 2.3 demand wizard 獨立入口(`/matching-requests/new`,非透過 profile 續接的 standalon…HM-FORM-01 Phase 2.3 demand wizard 獨立入口(`/matching-requests/new`,非透過 profile 續接的 standalone entry)首次進入、尚無既有資格/家庭組成資料時的呈現體驗,初步觀察認為值得打磨(例如首屏引導、已知資訊摘要或空狀態呈現),但本項目為本次 session 開發過程中的粗略觀察,尚未深入定位具體檔案或元件範圍,需後續排入前先行盤點現況再定範圍。啟動前置:UX 定義 + 工程盤點(先確認現況缺口範圍,本項證據強度較弱);來源:HM-FORM-01 Phase 2.3 demand wizard 續接(2026-07-13 盤點,`apps/web/src/app/[locale]/(public)/matching-requests/new/`) 待排程
BL-28 admin 審核介面與 rejected 完整政策(HM-FORM-01 KB-32 衍生):KB-32 的 `evidence_status` guard 目前暫定「approv…admin 審核介面與 rejected 完整政策(HM-FORM-01 KB-32 衍生):KB-32 的 `evidence_status` guard 目前暫定「approved 全鎖、rejected 全放行 resubmission」([HsuTse] 2026-07-13 裁定,因平台審核 UI 尚未上線)。admin approval UI 上線時須重新檢視 rejected 完整政策與 `evidence_status` review lifecycle。另注意 approved 列的 `condition_code` 仍可被雇主換值而不觸發 re-review(C-U1 review 的 INFO finding,屬同範疇一併記)。**補充(2026-07-19,HM-FORM-02 審核流程盤點)**:候選人(`candidates` 表)`draft → pending` 送審亦屬同一「審核流程未完整」範疇——DB/RLS/狀態機函式(`CANDIDATE_ALLOWED_TRANSITIONS.draft`)技術上皆已就緒,但全站無任何 UI 觸發點(`agency-console/candidates/scope.ts` 註解自承「finalizing a draft...is a Taiwan-agency action, a separate later task」)、`submitted_at` 欄位全站零寫入點。[HsuTse] 2026-07-19 裁決:送審由**台灣仲介 owner 按送審按鈕**觸發(產品決策,待後續主線實作)。**→ 已啟動轉主線 HM-ADM-03(2026-07-19)**啟動前置:待 admin 審核介面上線後排入;來源:HM-FORM-01 KB-32(`evidence_status` guard 暫定政策,[HsuTse] 2026-07-13 裁定;trigger-guard 實作見 commit `fcb213f4`) 待排程
BL-29 wizard 共用層增強(HM-FORM-01 BUG-1 衍生):(a) `STEP_FIELD_NAMES` 完整性 regression test(目前無自動化鎖,schem…wizard 共用層增強(HM-FORM-01 BUG-1 衍生):(a) `STEP_FIELD_NAMES` 完整性 regression test(目前無自動化鎖,schema 加欄位忘了同步 `STEP_FIELD_NAMES` 會靜默重現 submit silent no-op);(b) 驗證進行中的 UI pending 提示(`gatedGoNext`/`gatedGoBack` 在驗證期間靜默忽略點擊,未曝露 `isValidatingRef` 給 UI 顯示 pending);(c) `onBeforeNext` throw 的 unhandled promise rejection 防禦(目前 consumer 用 `react-hook-form` 的 `trigger` 不 throw,未實際觸發)。啟動前置:工程評估;來源:HM-FORM-01 wizard 共用層 silent no-op 修復(commit `e7fc1ff6`,2026-07-13 盤點) 待排程
BL-39 → HM-OPS-01-T01(2026-07-16,ADR 0019,`feature/auth-mail-pipeline`)**已完成(2026-07-17)**:`libs…→ HM-OPS-01-T01(2026-07-16,ADR 0019,`feature/auth-mail-pipeline`)**已完成(2026-07-17)**:`libs/auth-mail` 六語系密碼重設信自建寄送(generateLink+Cloudflare SMTP+`auth_email_events` rate limit),六語系實測全數送達 Gmail 收件匣、第 4 次請求正確被限流。原項:多語系 auth 信件模板 pipeline(ADR 0017 衍生):Supabase email template 為專案層單一語系,忘記密碼/邀請信目前無法依收件人 locale 出 6 語系內容。若要多語信件,需改走「`generateLink` +自建寄信 pipeline(Cloudflare SMTP)+自有 template」路線,並自建 rate limit 與防枚舉;屆時重新評估 ADR 0017 Decision 1。啟動前置:產品確認多語信件優先級;來源:ADR 0017(2026-07-16) 已認領/完成
BL-40 ~~`apps/web` 與 `apps/worker` 缺 nx `typecheck` target~~ → **已完成(2026-07-16,隨 ADR 0017 branc…~~`apps/web` 與 `apps/worker` 缺 nx `typecheck` target~~ → **已完成(2026-07-16,隨 ADR 0017 branch 一併修復)**:已比照 admin 在兩 app 的 `project.json` 補上 `typecheck` target(`tsc --noEmit -p tsconfig.json` + `dependsOn: ["^typecheck"]`),`pnpm nx run-many -t typecheck -p web worker` 驗證通過,root `pnpm typecheck` 自此涵蓋全部三個 portal app。啟動前置:工程小項;來源:ADR 0017 忘記密碼實作驗證(2026-07-16 盤點) 已認領/完成
BL-41 `libs/auth-mail` 密碼重設信五語系(en/fil-PH/id-ID/th-TH/vi-VN)內文為 AI 初翻(信尾已附 AI 翻譯標示),未經母語審稿;六語系 G…`libs/auth-mail` 密碼重設信五語系(en/fil-PH/id-ID/th-TH/vi-VN)內文為 AI 初翻(信尾已附 AI 翻譯標示),未經母語審稿;六語系 Gmail 送達性已實測通過(2026-07-17),本項僅剩翻譯品質校對。與 BL-20(HM-FORM-01 履歷表單機翻審稿)可合併排程。啟動前置:需排定母語審閱資源;來源:HM-OPS-01-T01(ADR 0019,2026-07-17) 待排程
BL-42 `directory/actions.ts` 的 `publishCandidate`/`unpublishCandidate` 與 `(dashboard)/candidates…`directory/actions.ts` 的 `publishCandidate`/`unpublishCandidate` 與 `(dashboard)/candidates/actions.ts` 的 `updateCandidateStatus` 存在兩套獨立實作的 `approved↔published` 邏輯(各自處理 `published_at`/`spotlighted_at` 副作用),未共用同一套狀態轉移函式。HM-FORM-02 共用 wizard/完整履歷檢視上線後,建議一併評估收斂為單一實作,降低未來邏輯漂移風險。啟動前置:工程評估(收斂為單一 `approved↔published` 實作,兩呼叫點改共用);來源:HM-FORM-02 審核流程盤點(2026-07-19) 待排程
BL-43 平台端既有 `(dashboard)/candidates` drawer 8 欄編輯(Phase 1.4)與 HM-FORM-02 共用 wizard(60+ 欄位)並存,兩套編…平台端既有 `(dashboard)/candidates` drawer 8 欄編輯(Phase 1.4)與 HM-FORM-02 共用 wizard(60+ 欄位)並存,兩套編輯介面/資料路徑重疊,需評估是否收斂為單一入口(例如 drawer 8 欄編輯改導向 wizard 續編,或明確劃分「快速編輯」vs「完整履歷編輯」的使用情境)。→ 已啟動為 **HM-FORM-03**(採「收斂為單一入口/方案 C」:移除 drawer 快速編輯、wizard 開放全候選人;見 `docs/roadmaps/candidate-resume-editor-consolidation.md`、ADR-0022)。啟動前置:UX 定義+工程評估(先確認兩介面實際使用情境是否皆需保留);來源:HM-FORM-02 共用化計劃 v2(2026-07-19) 待排程
BL-44 `resume_parse_jobs` AI 履歷解析(PDF-parse 整合,`approveResumeParseJob` fill-empty-only 規則)目前與 HM…`resume_parse_jobs` AI 履歷解析(PDF-parse 整合,`approveResumeParseJob` fill-empty-only 規則)目前與 HM-FORM-02 新增的平台端「新增履歷」動線各自獨立,未整合。評估是否讓平台端新增履歷動線可選擇「從已上傳履歷 PDF 解析預填」,銜接既有 parse-jobs reviewer 審核流程。啟動前置:工程評估(parse-jobs 現有 reviewer 流程與新增履歷動線的整合方式);來源:HM-FORM-02 共用化計劃 v2(2026-07-19),參照 `docs/roadmaps/forms-realignment/design.md` §291 PDF-parse 整合 待排程
BL-45 平台端與仲介端 candidate 媒體上傳 action 的 auth-agnostic 核心(`validateFile`/zod `metaSchema`/sharp Web…平台端與仲介端 candidate 媒體上傳 action 的 auth-agnostic 核心(`validateFile`/zod `metaSchema`/sharp WebP 正規化管線/storage path 組建/preview+replace-remove)約 100 行逐字鏡像(實質差異僅 ~6 行 auth/ownership),`media-preview.ts` 與 create/update draft actions 亦同款鏡像。評估抽出共用 helper(參數化注入已授權 client 與已驗 ownership 的 candidateId),或明文文件化「保留鏡像以獨立可稽核」的取捨。**裁決補記([HsuTse] 2026-07-19):抽共用 helper,排入後續小任務;本輪兩個 PR 不動。** **已完成(2026-07-19,`feature/candidate-resume-followups`:`media-upload-core.ts`+`media-preview-core.ts` 抽共用)。**啟動前置:工程評估([HsuTse] 定奪抽共用 vs 保留鏡像);來源:HM-FORM-02 PR-A final gate Reviewer B finding(獨立 verifier CONFIRMED 8/10,2026-07-19),`apps/admin/src/app/[locale]/(dashboard)/candidates/media-upload-actions.ts` vs agency-console 同名檔 已認領/完成
BL-46 來源國仲介一般成員(agency_staff)建立履歷權限下放:現行「新增履歷」按鈕與 `/candidates` new/edit server guard 均要求 agency…來源國仲介一般成員(agency_staff)建立履歷權限下放:現行「新增履歷」按鈕與 `/candidates` new/edit server guard 均要求 agency_admin+source_country(HM-FORM-02 PR-A QA 實測確認、屬既有設計)。[HsuTse] 2026-07-19 裁決 staff 也應可建立——需同步調整按鈕閘門與後端 guard 兩處。**已完成(2026-07-19,`feature/candidate-resume-followups`):code 完成+migration `20260719072901`(已套用 2026-07-19,MCP apply,audit 194↔194 綠);「新增履歷」按鈕分流(成員可見)/`requireSourceAgencyMemberScope` guard 換手已落地,CSV 匯入維持 admin-only。**啟動前置:工程實作(按鈕閘+server guard 下放);來源:HM-FORM-02 PR-A web-qa finding F-1(2026-07-19 [HsuTse] 裁決) 已認領/完成
BL-47 RLS 邊界 e2e spec 活化:`tests/e2e/` 四份 RLS spec(agency 軟刪、platform 草稿邊界、兩份讀取案)目前因無 env 載入而全數 s…RLS 邊界 e2e spec 活化:`tests/e2e/` 四份 RLS spec(agency 軟刪、platform 草稿邊界、兩份讀取案)目前因無 env 載入而全數 skip——需接 dotenv playwright config(或 env-injecting test script)+seed 測試 fixtures(demo-superuser、HM-RBAC-01-Q01 帳號),讓四份 spec 在本機/CI 真跑綠燈。**已完成(2026-07-19,`feature/candidate-resume-followups`:`playwright.config.ts` env 載入+`test:e2e:rls` script+fixture 帳號修正,14/14 綠)。**啟動前置:工程實作(env 接線+fixtures seed);來源:HM-FORM-02 PR-A/PR-B final gate(2026-07-19 [HsuTse] 裁決排後續) 已認領/完成
BL-49 新增第 12 個受控技能 `skill_options` key「醫療協助 medical_assist」。HM-FORM-03 Phase 0 暫將 demo 的 medical…新增第 12 個受控技能 `skill_options` key「醫療協助 medical_assist」。HM-FORM-03 Phase 0 暫將 demo 的 medical_assist 映射到 `eldercare`(零成本);若產品確認需獨立『醫療協助』技能標籤,需新增 skill_options row(migration)+ browse alias。啟動前置:產品確認是否需此技能標籤+migration;來源:HM-FORM-03 Phase 0 canonical 定案(2026-07-22) 待排程
BL-50 mobile 雇主端候選人詳情頁履歷 UI 顯示強化:HM-FORM-04(雇主端登入解鎖完整履歷+公開 API 面收斂)計劃 §4 明確排除 mobile 端 UI 顯示強化——…mobile 雇主端候選人詳情頁履歷 UI 顯示強化:HM-FORM-04(雇主端登入解鎖完整履歷+公開 API 面收斂)計劃 §4 明確排除 mobile 端 UI 顯示強化——該線 T1.4 僅改資料通道(列表改讀 `public_candidates` view、詳情改走 `get_employer_candidate_resume` RPC,確保功能不回歸並關閉 `resume_json` 曝露洞),mobile 詳情顯示沿用既有 UI 欄位;step1 全 7 section 完整呈現與媒體 gallery(照片/刺青照/介紹影片)在 mobile 端的對應 UI 強化屬本項後續範圍。啟動前置:UX 定義+工程評估(mobile 版面設計與 `apps/mobile` 元件改動範圍);來源:HM-FORM-04 計劃 §4 NOT in scope 分流(2026-07-23) 待排程
BL-51 GPS 剝除/影片 finalize 動作(`finalizeCandidateVideoUpload`)回傳的 4 個錯誤代碼(`invalid_input`/`invalid_…GPS 剝除/影片 finalize 動作(`finalizeCandidateVideoUpload`)回傳的 4 個錯誤代碼(`invalid_input`/`invalid_video_path`/`video_finalize_download_failed`/`video_contains_location_metadata`)皆無對應中文(或其他語系)在地化訊息,consumer(`candidate-video-upload-client.ts`)原樣把 server action 回傳的英文 snake_case 字串往上拋,落 generic fallback(與既有 KB-29 candidate-media 上傳錯誤代碼未在地化同型態)。需補上 `labels.validation` 或等價 key 對映,`video_contains_location_metadata` 尤其該給使用者可理解的訊息(例如「偵測到影片含定位資訊,請重新上傳」),而非顯示英文代碼原文。啟動前置:需排定翻譯資源(比照 KB-29/BL-20 同型模式);來源:HM-FORM-04 T3.2 review R2(2026-07-24 盤點;`finalize-candidate-video-action.ts:78,86,98,111` 四處 error 定義) 待排程
BL-52 HM-FORM-04 本線新增六語系文案(雇主端履歷展示 `web.employerResume.*`、影片上傳相關字串等;`libs/i18n/src/locales/*/com…HM-FORM-04 本線新增六語系文案(雇主端履歷展示 `web.employerResume.*`、影片上傳相關字串等;`libs/i18n/src/locales/*/common.json` 六語系皆新增同結構 key)之 en/fil-PH/id-ID/th-TH/vi-VN 五語系內容為工程師/AI 初譯,未經母語者審閱校對(與既有 BL-20/BL-41 同型待辦,可合併排程)。啟動前置:需排定母語審閱資源;來源:HM-FORM-04 Phase 1–3 六語系新增(2026-07-24 盤點;`git diff 346943de..HEAD -- 'libs/i18n/src/locales/*/common.json'` 六檔各 +230 行) 待排程
BL-53 `apps/admin-e2e` 目前僅有 Nx 預設 scaffold 產出的 `example.spec.ts`(檢查首頁 `<h1>` 含「Welcome」),無任何 sig…`apps/admin-e2e` 目前僅有 Nx 預設 scaffold 產出的 `example.spec.ts`(檢查首頁 `<h1>` 含「Welcome」),無任何 sign-in flow/測試帳號 fixture 基礎設施;HM-FORM-01~HM-FORM-04 累積至今的候選人履歷/媒體顯示功能(含既有 photo/tattoo 顯示、本線新增影片 player)完全無 e2e 覆蓋,僅靠 web-qa 人工/半自動抽測與 unit script(如 `scripts/test-public-candidate-api-surface.ts`)把關。需先建立 admin 端可重用的 sign-in helper 與測試帳號 fixture(比照既有 `tests/e2e/` RLS spec 的 env 接線模式,BL-47),才能讓 candidate-resume 相關 e2e 真正落地。啟動前置:工程評估(sign-in helper 設計、測試帳號 fixture 來源);來源:HM-FORM-04 T3.3 review flag(2026-07-24 盤點;`apps/admin-e2e/src/example.spec.ts` 為唯一既有檔案) 待排程
BL-54 雇主端履歷完整展示(`employer-resume-view.tsx` `renderDuties`)在候選人「工作能力」duties 全空時,empty fallback 列的…雇主端履歷完整展示(`employer-resume-view.tsx` `renderDuties`)在候選人「工作能力」duties 全空時,empty fallback 列的欄位標籤直接重用該 section 自身標題 `t('sections.workCapability')`(「工作能力」),與 section 本身標題重複顯示於同一畫面。此為既有 pattern(`apps/admin/src/components/candidate-resume/candidate-resume-view.tsx` `renderDuties` 同款寫法,T2.1 刻意鏡射該元件的 PATTERN),非本線新增缺陷、pre-existing。純顯示,不影響功能。啟動前置:UX 定義(empty fallback 該用什麼獨立標籤,或改用不重複的呈現方式);來源:web-qa F3(2026-07-24 盤點;`apps/web/src/components/employer-resume/employer-resume-view.tsx:276-283` vs `apps/admin/src/components/candidate-resume/candidate-resume-view.tsx:301-311` 同型態) 待排程
BL-55 ~~影片 GPS metadata 剝除的 server finalize 掃描(`finalize-candidate-video-action.ts`)僅在使用者透過正常上傳 …~~影片 GPS metadata 剝除的 server finalize 掃描(`finalize-candidate-video-action.ts`)僅在使用者透過正常上傳 UI flow(呼叫 `finalizeCandidateVideoUpload`)時把關;BL-46 既有裁決允許的 agency_staff 直接以 raw REST/PostgREST 寫入 candidate-media Storage 物件並 PATCH 自己草稿的 `intro_video_url`,此路徑完全不經過本次 finalize 掃描,若經此路徑寫入含 GPS metadata 的影片不會被攔截。程式碼註解已明文列為「已知殘留風險(BL-46 raw-REST-own-draft 既有類別的一個實例,非 T3.2 新開的缺口)」,是否需要更強保證(例如對任何 `intro_video_url` 寫入做非同步二次掃描)屬合規裁決,尚未決定。 ~~ → **已修(2026-07-25,PR #35,migration `20260725022522`)**。[HsuTse] **推翻**同日稍早「happy-path 已足夠、本項 accepted」之裁決,改判須確實剝除。**補記:繞過路徑不只原文那條** —— 路徑 A=來源國仲介成員 × 自家 `draft`(BL-46 放寬,仍有送審關卡);**路徑 B=台灣 owner `agency_admin` × 任何狀態含已上架**(`candidates_agency_admin_write` 為 `FOR ALL` 無狀態限制,且 `candidates_guard_status_change` 鎖的 9 欄**不含** `intro_video_url`)——路徑 B **無任何關卡**。實測(套用前真實 JWT 直打 PostgREST)證實兩路徑當時皆可寫入任意值,**含任意外部網址**(該欄原本無格式約束)。收斂=三段相乘 invariant(ADR-0023 §A1):① offset-preserving 剝除+fail-closed 契約(收斂 KB-57)② storage kind allow-list 使 `video/` 對所有 authenticated caller 關閉寫入(收斂 KB-59)③ BEFORE trigger 釘死 `intro_video_url` 必為 `{自己的 id}/video/…`。成員無法覆寫 `video/` 故無 TOCTOU。負向測試:`test-intro-video-path-invariant.ts`(含路徑 B 專項)+`test-candidate-media-rls.ts` F-KIND+`test-candidate-video-gps-strip.ts`啟動前置:**[產品決策]** 依 [HsuTse] 合規裁決決定是否啟動(若啟動需設計 async re-scan 機制,資料層無法純 DB trigger 檢查 Storage bytes);來源:HM-FORM-04 T3.2 review R2、`finalize-candidate-video-action.ts:8-39`("Residual risk" 註解段,2026-07-24 盤點) 待排程
BL-56 `candidate_contact_profiles_public_select` policy(`supabase/migrations/20260502100000_cand…`candidate_contact_profiles_public_select` policy(`supabase/migrations/20260502100000_candidate_contact_profiles.sql:102-114`,無 `to` 子句 = PUBLIC,`using (deleted_at is null and exists (select 1 from candidates c where c.id = candidate_id and c.status = 'published' and c.deleted_at is null))`)目前查無存活的 RLS-subject 消費者:全站直查或經 fkey embed 引用 `candidate_contact_profiles` 的呼叫點逐一核對——apps/web(`interview-actions.ts`/`messages/actions.ts`/`interview-holds/actions.ts`)與 `libs/mobile-api` 皆經 `createWebServiceClient`/`createMobileServiceClient` 等 service-role client 讀取(RLS 全繞過,policy 內容不影響行為);apps/admin 兩處 RLS-bound 讀取(agency-console `candidates/page.tsx` 僅讀自家 owned 候選人、`(dashboard)/candidates/actions.ts` `listCandidates` 以 platform_admin 身分讀取)分別已被 `candidate_contact_profiles_agency_all`/`candidate_contact_profiles_platform_admin_all` 覆蓋,不依賴本 policy。anon 唯一可能摸到本表的路徑——`public_candidates` view 折入 contact_profile 欄——在 `20260723164028` 明確以 `security_invoker = false` 定義(view 以 owner 身分繞過 `candidates`/`candidate_contact_profiles` 兩表 RLS),故 anon 經該 view 讀取也不觸發本 policy。建議另案 DROP 此 policy 或改 `to authenticated`,清理死 policy、避免未來新增 RLS-bound 直查路徑時誤判「anon/authenticated 本就對此表有 published 候選人的公開讀權」。啟動前置:工程評估(DROP vs 改 `to authenticated`;動手前需先 grep 全站確認無新消費點才變更);來源:HM-FORM-04 final review R2(2026-07-24 盤點,`20260724115932` migration 撰寫過程附帶發現) 待排程
BL-57 `apps/mobile/src/lib/__tests__/employer-resume-rpc-projection.test.ts` 的 `RPC_TYPED_COLUMN…`apps/mobile/src/lib/__tests__/employer-resume-rpc-projection.test.ts` 的 `RPC_TYPED_COLUMNS`(`get_employer_candidate_resume` 17 個 typed 欄位)為手抄字面量陣列,未從 codegen 型別(`Database['public']['Functions']['get_employer_candidate_resume']['Returns'][number]`)衍生——sibling script(`scripts/test-public-candidate-api-surface.ts` 等)已證明 `tsx` 執行環境可直接 `import type { Database } from '../libs/db/src/types'` 取用 generated types。若未來 migration 改動 RPC `returns table` 欄位但忘記同步這份手抄清單,測試仍會綠燈、無法偵測欄位漂移,改為型別衍生可取得編譯期保護。(同檔 `RPC_RESUME_JSON_KEYS` 19 個 key 因 RPC 簽章中 `resume_json` 欄本身型別為 `Json`,這些 key 不在 generated types 內、無法比照衍生,維持手抄鏡射即可,非本項範圍。)啟動前置:工程評估(改為從 `Database['public']['Functions']['get_employer_candidate_resume']['Returns'][number]` 衍生 `RPC_TYPED_COLUMNS`,需確認 `tsx` 執行環境下 import path 可行);來源:HM-FORM-04 T1.4 final review R2(2026-07-24 盤點) 待排程
BL-58 T1.3a candidate-media 影片上傳統一轉碼正規化+封面縮圖產出(承接 BL-22 原始範圍未竟部分):需評估 Edge Function + ffmpeg vs …T1.3a candidate-media 影片上傳統一轉碼正規化+封面縮圖產出(承接 BL-22 原始範圍未竟部分):需評估 Edge Function + ffmpeg vs Cloudflare Stream(專案已用 CF RealtimeKit)方案,統一 codec/解析度/bitrate,並產生封面縮圖(poster thumbnail)。HM-FORM-04 Phase 3(T3.1~T3.3)僅收斂 GPS 合規前提(TUS resumable 直傳+client 端 mp4box.js remux 剝除 GPS metadata+server pure-JS box 掃描把關,明確**不轉碼**;ADR-0023 D3),未處理轉碼正規化與封面縮圖產出,此為原 BL-22 範圍 (a)(b) 未竟部分。啟動前置:工程評估(vendor 能力查證,比照 BL-07 vendor 查證模式,沿用 BL-22 原啟動前置);來源:HM-FORM-04 Phase 3 只收斂 GPS 合規前提、轉碼/縮圖未竟部分自 BL-22 分出(PR #35 審查發現) 待排程
BL-59 雇主端其他主動發起流程(面試邀請 `interview_requests` via `create_candidate_interview_request_v2`、聘僱申請 `pl…雇主端其他主動發起流程(面試邀請 `interview_requests` via `create_candidate_interview_request_v2`、聘僱申請 `placement_applications`)的候選人狀態 gate 仍為 `['approved','published']`,未隨 HM-FORM-04「雇主可預約」收窄為 published-only。opus/sonnet review 已獨立驗證此非本次收窄的同 divergence bug(該二流程為 service-role INSERT/RLS 完全 bypass,或 policy 不 reference `candidates`,無 app-DB gate 漂移可能);惟 [HsuTse] 2026-07-25「雇主僅可預約 published 候選人」裁決目前僅 scope 到預約/`candidate_is_bookable` 流程,是否也適用這兩個 sibling employer-initiated 流程屬產品決策,待盤點。啟動前置:產品決策(published-only 是否適用面試邀請/聘僱申請);來源:HM-FORM-04 PR #35 收窄後 opus/sonnet review variant scan 發現 待排程
BL-06 修正 `docs/specs/video-room-ui-design.md` 自創的 `HM-VIDEO-01` 編碼(應歸 HM-FTR-01 下)修正 `docs/specs/video-room-ui-design.md` 自創的 `HM-VIDEO-01` 編碼(應歸 HM-FTR-01 下)啟動前置:無 待排程

最近提交

篩選不影響上方圖表
0 29 57 57
資料表格(每日 commit 數)
日期commit 數
2026-06-260
2026-06-270
2026-06-280
2026-06-297
2026-06-300
2026-07-017
2026-07-0221
2026-07-035
2026-07-0446
2026-07-050
2026-07-0641
2026-07-072
2026-07-080
2026-07-093
2026-07-1057
2026-07-1129
2026-07-1238
2026-07-1340
2026-07-1416
2026-07-1526
2026-07-1619
2026-07-1716
2026-07-182
2026-07-1950
2026-07-2026
2026-07-210
2026-07-223
2026-07-2311
2026-07-2423
2026-07-2521
Hash時間(台北)類型Scope說明
868911e 2026/7/25 晚上11:05 未分類 Merge pull request #37 from fantasywind/fix/employer-booking-preflight-published-only
6287f89 2026/7/25 晚上10:08 docs hm-form-04 register BL-59 sibling-flow narrowing follow-up (review)
34f90ba 2026/7/25 晚上9:10 fix hm-form-04 align web+mobile booking preflight with narrowed DB gate (red-team)
3235305 2026/7/25 晚上9:10 test hm-form-04 assert 42501 in case3b + name narrow migration in red-green hint (opus review)
8527339 2026/7/25 晚上9:07 未分類 Merge pull request #36 from fantasywind/fix/migration-replay-order
7f9573d 2026/7/25 晚上8:59 fix migrations drop compute_milestone_due_at before renaming replaces (KB-60)
9f966f8 2026/7/25 晚上8:43 docs migrations register KB-60 and add replay-order retrofit category
3bed763 2026/7/25 晚上8:42 fix migrations make migration set replayable from zero (KB-60)
00f4a92 2026/7/25 中午12:48 未分類 Merge pull request #35 from fantasywind/feature/employer-resume-display
d207fc1 2026/7/25 中午12:29 docs hm-form-04 record ADR-0023 amendment A1 and sync phase 3 status
ae00b68 2026/7/25 中午12:29 docs hm-form-04 close BL-55 KB-57 KB-59 and record bypass path B
777fbce 2026/7/25 中午12:28 test hm-form-04 assert video prefix RLS and intro_video_url path invariant
1b1292c 2026/7/25 中午12:28 feat hm-form-04 strip GPS server-side via per-console finalize actions
c92368f 2026/7/25 中午12:27 feat hm-form-04 split candidate video storage prefixes and pin intro_video_url path
2fa7b35 2026/7/25 中午12:27 test hm-form-04 add video GPS strip red-green suite
5e10131 2026/7/25 中午12:27 feat hm-form-04 add offset-preserving video location metadata stripper
c7f3829 2026/7/25 清晨6:46 feat hm-form-04 narrow employer booking to published-only per HsuTse ruling
7c6273c 2026/7/25 清晨6:46 docs hm-form-04 sync 4th stale status point in execution-index (PR #35 review)
dac5cc5 2026/7/25 清晨6:16 style hm-form-04 full-width punctuation in browse detail comments (PR #35 review)
c55d52b 2026/7/25 清晨6:16 docs hm-form-04 split BL-22 undelivered transcode/thumbnail into BL-58 (PR #35 review)
408fd5a 2026/7/25 清晨6:16 docs hm-form-04 honest GPS claim in ADR + sync delivery status (PR #35 review)
b204b46 2026/7/24 晚上8:54 docs hm-form-04 triage final-review residuals and record review outcome
9598a13 2026/7/24 晚上8:11 fix hm-form-04 align rls-restore migration filename and wire orphaned test suites
ecac528 2026/7/24 晚上7:48 fix hm-form-04 restore RLS policy deps broken by public policy drop
d32079e 2026/7/24 下午6:09 docs hm-form-04 mark handoff completed
958e664 2026/7/24 下午6:03 docs hm-form-04 sync delivery status and triage residual items
29ed385 2026/7/24 下午5:23 fix hm-form-04 distinguish unlock card copy for authenticated non-employer
25b27f3 2026/7/24 下午4:32 fix hm-form-04 distinguish photo category in lightbox aria-label
ca4c990 2026/7/24 下午4:06 feat hm-form-04 show intro video preview in admin resume view
14822a4 2026/7/24 下午2:53 docs hm-form-04 correct GPS gate overclaim to happy-path enforcement (per opus arch review)