IMPLFE-K4B: IN-PROGRESS # Lane FE K4b — nối `?group=` + vá-3/5/6 (S166, 2026-08-01) Nối finding-A của gate K4a ("`?group=` chết-lâm-sàng" = FLAG-2 lượt trước: leaf trỏ đúng URL nhưng KHÔNG ai đọc). SPEC PIN: spec-cụm2 vá 3 (queryKey 2 khoá) · vá 5 (`phase` derive thay mount-only) · vá 6 (Create preset từ URL) + K4b-7 (URL G1 mang `group=1`). ## §0 Kế hoạch đo trước khi gõ (khuôn S164/S166) - [ ] Đọc `KhkkListPage.tsx` TRỌN vùng state/query ×2 app — có mirror không (SHA) - [ ] Đọc `KhkkCreatePage.tsx` vùng state `approvalGroup` ×2 app - [ ] Grep staticMap 6 leaf G1 ở fe-admin (đề bài dặn: có thì mirror, không thì khai) - [ ] Xác nhận BE nhận `?group=` (K2 wire `[FromQuery(Name="group")]`) — Read-only ## §1 ĐO ĐĨA (ground truth) — TRƯỚC khi gõ ### 1.1 Baseline SHA (cả 2 page ĐANG mirror ×2 app ⇒ được phép `cp`) | file | sha256 trước K4b | |---|---| | `KhkkListPage.tsx` ×2 | `80ebd79dba1356e8f1512f798ab105eca312d84aae2744b7ed852ff667f60f3b` | | `KhkkCreatePage.tsx` ×2 | `677f4ab803b0b7ac73ede9b2d5871a3243f4cbe90153a218b320d642c6431268` | ### 1.2 🔴 TIỀN-ĐỀ ĐỀ-BÀI CẦN BẺ: vá-5 "derive thay useState" nguyên văn sẽ **GIẾT bộ lọc chip** `phase` KHÔNG chỉ đến từ URL — nó còn là state do người dùng bấm: `KpiCard onClick :153-156 setPhase(c.value)` (6 chip Tất cả/Soạn/Chờ/Đã/Trả lại/Từ chối). Comment `:11-12` khai rõ chủ đích: *"Chip lọc chỉ đổi STATE, KHÔNG ghi lại URL — giữ nguyên URL của leaf đang đứng nên menu không sáng nhầm"* (bài S155). ⇒ Nếu làm `const phase = urlPhase` thuần thì `setPhase` mất chỗ đứng, **6 chip thành nút chết** — hỏng CÂM, build vẫn xanh. ⇒ Giải đúng = **state override + reset theo danh tính URL** (khuôn React "adjust state during render", KHÔNG `useEffect`, không nháy 2 pass): `chipPhase: KhkkPhaseValue|null|undefined` — `undefined` = "chưa bấm chip, dùng URL"; `null` = "user chủ động chọn Tất cả" (2 nghĩa khác nhau, không gộp được). URL đổi ⇒ `chipPhase=undefined` + `page=1`. ### 1.3 🔴 BE `/deleted` KHÔNG nhận `group` (rào: không sửa BE) `ContractSigningPlansController.cs:59-66 ListDeleted(page, pageSize, search, sortDesc)` — **0 tham số group**, khác hẳn `List :42 [FromQuery(Name="group")] int? group`. ⇒ `Khkk_G{n}_Deleted → /khkk/list?group=n&view=deleted` sẽ hiện phiếu xóa CỦA MỌI NHÓM. Không client-side lọc được vì `total`/phân trang do server đếm trên tập chưa lọc ⇒ lọc ở FE sẽ ra số trang nói dối. ⇒ Xử: **gửi `group` chỉ ở nhánh không-xóa** + **không để tiêu đề CLAIM nhóm ở màn đã-xóa** (không nói dối) + FLAG lane BE. Xem FLAG-1. ### 1.4 fe-admin CÓ 6 leaf G1 trong staticMap, nhưng `Khkk_WfView` ĐI ĐƯỜNG KHÁC `fe-admin/Layout.tsx:35` `Khkk_WfView → /system/approval-workflows-v2/ContractSigningPlan` (Designer), 5 leaf còn lại `:36-40` trỏ `/khkk/*` như fe-user. ⇒ mirror `?group=1` cho **5 leaf**; `Khkk_WfView` admin **KHÔNG thêm** `group` (Designer không đọc tham số này — chính ghi chú K4a đã khai). Khai lệch, không mirror mù. ### 1.5 Xác nhận đường BE cho nhánh chính `List :42` `[FromQuery(Name="group")] int? group` → `ListContractSigningPlansQuery(..., group)` `:49`. ⇒ FE gửi `params.group` là ăn. ## §2 THỰC THI