# sub-implementer-frontend-2 — [F-11] nối cờ F6 `allowApproverDelete` vào Designer V2 > run `2026-07-27-S155-pe-delete-approver` · ĐỢT 1 · vai `implementer-frontend` > Spec canonical: `spec-pe-delete-approver.md` §F.4 mục **F-11** (dòng 303) + §F.2 bảng 13 thao tác hạng **2a ✅ AN TOÀN**. > Ghi TRONG LÚC LÀM (5/5 sub run này mất return vì #53) — file này luôn hợp lệ giữa chừng. ## 0. Phạm vi tự chốt trước khi viết dòng nào | Làm | Không làm (đợt 2) | |---|---| | 5 dây Designer fe-admin + ô tick F6 | nút Xóa ở màn duyệt (`PeWorkflowPanel.tsx`) | | 1 dây hiển thị chỉ-xem fe-user (`WorkflowMatrixViewPage:282`) | menu restructure (`Layout.tsx` regex, `menuKeys`) | | type/DTO FE tương ứng (2 chỗ) | màn "Đã xóa" | **Ý nghĩa cờ (viết đúng, không suy diễn):** **PER-NGƯỜI**, KHÔNG per-Cấp. 1 `Level` row = 1 người (`ApproverUserId` là field của row); "Cấp" chỉ là tập row cùng `Order`. Owner chốt per-ROW để giữ sát ý *"người đứng đầu phòng"* = **1 người, admin chỉ đích danh** (spec §B2 dòng 60-66). Khối UI tick nằm trong ô `Quyền duyệt {tên NV}` (`:928-930`) ⇒ ngữ cảnh per-người đã hiện sẵn trên màn. ## 1. Đối chứng: F5 `allowApproverFinalize` đi qua ĐÚNG 5 chỗ nào (đọc trước, không tin spec suông) Grep `allowApproverFinalize` trên `fe-admin/` → 5 hit trong `ApprovalWorkflowsV2Page.tsx` ngoài ô tick: | Dây | Line (trước sửa) | Vai trò | Hỏng gì nếu thiếu | |---|---|---|---| | 1 | `:54` | `LevelDto` — mirror BE `AwAdminOverviewDto` (đọc VỀ) | TS2339 khi đọc `l.allowApproverDelete` ở dây 3 | | 2 | `:110` | `EditLevelEntry` — state form đang soạn | TS2339 ở `updateField` + dây 4/5 | | 3 | `:159` | `copyFromDefinition()` — **Nhân bản** version cũ | tick cũ mất trắng khi admin bấm "Nhân bản" | | 4 | `:177` | `makeDefaultLevelEntry()` — "+ Thêm NV" | entry mới thiếu key ⇒ TS2739 (object literal thiếu field) | | 5 | `:605` | **payload POST** `/approval-workflows-v2` | 🔴 **BẪY**: tick xong KHÔNG gửi lên BE | 🔴 **Vì sao dây `:605` là bẫy thật (không phải cảnh báo lễ nghi):** payload POST là object literal **liệt kê từng field bằng tay** (`:594-606`), KHÔNG spread `...e`. TypeScript **không** báo lỗi khi thiếu field (thừa field mới lỗi, thiếu thì chỉ là object hẹp hơn) ⇒ build vẫn PASS, UI tick vẫn hiện dấu tick, `onChange` vẫn chạy, state vẫn đổi — **chỉ có BE không bao giờ nhận**. Không có compiler/test nào bắt; chỉ lộ khi UAT tick → lưu → mở lại thấy trống, hoặc tệ hơn: quyền xóa im lặng không tới người được chỉ định. ## 2. Thay đổi đã áp — 3 file, 10 neo ### 2.1 `fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx` (+28 dòng) — 5 dây + ô tick | # | Line MỚI (cũ) | Nội dung | |---|---|---| | Dây 1 | `:58` (54) | `LevelDto` + `allowApproverDelete: boolean` ngay dưới `allowApproverFinalize` | | Dây 2 | `:116` (110) | `EditLevelEntry` + `allowApproverDelete: boolean` | | Dây 3 | `:168` (159) | `copyFromDefinition()` → `allowApproverDelete: l.allowApproverDelete ?? false` | | Dây 4 | `:188` (177) | `makeDefaultLevelEntry()` → `allowApproverDelete: false` | | **Dây 5** | **`:620`** (605) | **payload POST** `/approval-workflows-v2` → `allowApproverDelete: e.allowApproverDelete` | | Ô tick | `:1025-1034` | `