K3-BE: IN-PROGRESS — bước-0 XONG (lead), §1-8 p2 đang chạy # sub-implbe-k3 — K3 BACKEND (S165, wave 3/8: 8 workflow nhóm + finalize + sweep) > 🔴 **KHAI VẾT:** p1 wf_a04124a7-0fe = class *engine-process-exit* (35 tool-use/458s nhưng **0 delta đĩa > + 0 artifact + return rỗng** — lượt chạy coi như chưa từng tồn tại; #53 tally cả wave). Bước-0 dưới đây > = **LEAD tự chạy** (ssh + sqlcmd trực tiếp), p2 seed từ bảng ĐÃ VERIFY này, không cần ssh lại. ## §0 [LEAD] FAIL-CLOSED verify đội-hình QT-DN-V2-001 LIVE — PASS - Instance prod = `localhost\SQLEXPRESS` (named instance — `-S localhost`/`tcp:1433` đều fail; ghi lại cho mọi lane sau đỡ dò). Windows-auth `-E` qua `ssh vietreport-vps` chạy được. - `ApprovalWorkflows WHERE Code='QT-DN-V2-001'` = **3 row: 2 archived (IsActive=0) + 1 LIVE (IsActive=1)**, ApplicableType=**1** (Duyệt NCC/PE — nguồn đội-hình, đúng OG-2 + note owner slot-54 "lấy đúng bộ người duyệt đang cấu hình ở workflow Duyệt NCC prod"). TotalWf active toàn hệ = 7. - **ROSTER bản LIVE (nguyên văn sqlcmd, mojibake console đã chuẩn hoá dấu theo email đã biết):** | Bước | Dept | Cấp | Email | Tên | |---|---|---|---|---| | 1 «Phòng 1» | Phòng Cung Ứng (PRO) | 1 (OR-4) | phuong.nguyen@solutions.com.vn | Nguyễn Thị Bích Phượng | | 1 | Phòng Cung Ứng | 1 | long.chau@solutions.com.vn | Châu Tạ Kim Long | | 1 | Phòng Cung Ứng | 1 | duy.nguyen@solutions.com.vn | Nguyễn Văn Duy | | 1 | Phòng Cung Ứng | 1 | binh.lethanh@solutions.com.vn | Bình Lê Thanh | | 1 | Phòng Cung Ứng | 2 | tra.bui@solutions.com.vn | Bùi Lê Thủy Trà | | 2 «Phòng 2» | P. Kiểm soát Chi phí (CCM) | 1 (OR-4) | luu.tran@solutions.com.vn | Trần Xuân Lưu | | 2 | P. Kiểm soát Chi phí | 1 | truong.letrandang@solutions.com.vn | Lê Trần Đăng Trường | | 2 | P. Kiểm soát Chi phí | 1 | binh.le@solutions.com.vn | Lê Văn Bình | | 2 | P. Kiểm soát Chi phí | 1 | nguyen.ho@solutions.com.vn | Hồ Thị Nữ Nguyên | | 2 | P. Kiểm soát Chi phí | 2 | chuong.phan@solutions.com.vn | **Phan Văn Chương** (TP.CCM — giữ cờ finalize OG-3/OG-9) | | 3 «Phòng 3» | Ban Giám đốc (CEO) | 1 | truong.nguyen@solutions.com.vn | Nguyễn Văn Trường | - **Vá-11 danh-tính (phân giải bằng dept trên bản LIVE):** `truong.letrandang` (CCM C1) ⟂ `truong.nguyen` (BGĐ C1 = CEO) — 2 người khác dept, không nhầm; `binh.lethanh` (PRO C1) ⟂ `binh.le` (CCM C1) — khác dept, không nhầm. Cặp "tring.le"/"thanh.lethanh" trong câu-đố spec KHÔNG xuất hiện trên roster LIVE ⇒ là bẫy chính-tả từ ảnh, roster email là chân lý. - ⇒ **Mô-hình 3 trạm PRO → CCM → CEO** với OR-of-N cấp 1 mỗi trạm + cấp 2 = trưởng phòng. Seed 8 workflow KHKK-N1..N8 mirror ĐÚNG cấu trúc này (3 Steps × Levels như bảng), resolve user theo EMAIL. (§1-8 p2 ghi tiếp bên dưới) --- # §1 [p2] KẾ HOẠCH (ghi TRƯỚC khi code — 3 dòng) 1. **A** — `DbInitializer.cs`: thêm `SeedKhkkGroupWorkflowsAsync(db, userManager, logger)` (UNGATED, đặt sau cụm 4 seeder WorkflowApps V2 ở `InitializeAsync`), mirror khuôn `SeedSampleContractWorkflowV2Async`; resolve 11 email → dict 1 lượt, rồi loop N=1..8 tạo `KHKK-N{n}` (type-10) 3 Steps × Levels theo roster §0. 2. **B** — `MenuKeys.cs`: +8 const `AwV2_KhkkN1..N8` + vào `All` (ràng buộc T6: key ∈ All BẮT BUỘC có menu-row) ⇒ `DbInitializer.SeedMenuTreeAsync`: +8 row con dưới `ApprovalWorkflowsV2` (order 3..10), idempotent per-Key. 3. **C** — `dotnet build SolutionErp.slnx` (0W/0E) + `dotnet test SolutionErp.slnx` full (baseline 609/0) + đếm `MenuKeys.All` bằng lệnh máy → ghi DELTA. **Đo TRƯỚC khi sửa (baseline, lệnh máy chạy ở §4):** `MenuKeys.All` hiện = ? (đo ở §4, không đoán). 🔴 **2 lệch phát hiện lúc khảo sát (khai ngay, KHÔNG tự quyết):** - **L1 — "vùng seed workflow type-10 hiện có (W3 S161)" KHÔNG TỒN TẠI.** `grep ContractSigningPlan DbInitializer.cs` = **0 hit** (chỉ có `SeedKeHoachKyKetAccessAsync` = seed *quyền*, không phải workflow). ⇒ Không có khuôn type-10 để mirror; tôi mirror khuôn gần nhất **cùng lớp** = `SeedSampleContractWorkflowV2Async` (`:226`) / `SeedSampleProposalWorkflowV2Async` (`:276`) — cùng cách dựng `ApprovalWorkflow + Steps + Levels`. - **L2 — `AllowApproverFinalize` bị ÉP `false` server-side cho type-10 ở đường Designer.** `ApprovalWorkflowV2AdminFeatures.cs:380-381`: `AllowApproverFinalize = typeEnum != ...ContractSigningPlan && l.…` (W1 S161 F-8 containment). Seeder ghi entity TRỰC TIẾP nên **không bị chặn**, nhưng nếu admin bấm "tạo version mới" qua Designer thì cờ rơi về false. Tôi vẫn set `true` theo lệnh (OG-3/OG-9) + ghi comment đúng câu lead giao; **nhịp sau cùng wave** port nhánh service + (nếu owner chốt) gỡ ép-false ở `:381`. --- # §2 VIỆC A — `SeedKhkkGroupWorkflowsAsync` — DONE **File:** `src/Backend/SolutionErp.Infrastructure/Persistence/DbInitializer.cs` (2 chỗ) - `:160-171` — gọi trong `InitializeAsync`, **UNGATED** (ngoài `if (!demoSeedDisabled)`), đặt ngay sau cụm 4 seeder WorkflowApps V2 và trước `WarnDefaultAdminPasswordAsync`. Comment nêu gotcha #51. - `:520-…` — thân method, ngay sau `SeedSampleVehicleBookingWorkflowV2Async`. **Đã làm đúng lệnh:** - 8 workflow `KHKK-N1..KHKK-N8`, `ApplicableType = ContractSigningPlan` (=10), `Version=1`, `IsActive=true`, `IsUserSelectable=true`, `Name = $"Duyệt KHKK — Nhóm {n}"` (em-dash + khoảng trắng y như lệnh), `ActivatedAt=UtcNow`. - Idempotent per-Code literal theo lệnh: `if (await db.ApprovalWorkflows.AnyAsync(w => w.Code == code)) continue;` - 3 Steps Order 1/2/3, Name `"Phòng Cung Ứng"` / `"P. Kiểm soát Chi phí"` / `"Ban Giám đốc"`, `DepartmentId` = hint theo mã phòng `PRO` / `CCM` / `BOD` (`SeedDepartmentsAsync:2744`; nullable ⇒ phòng vắng cũng không chặn). - Levels đúng roster §0: Step1 C1 OR-4 + C2 `tra.bui`; Step2 C1 OR-4 + C2 `chuong.phan`; Step3 C1 `truong.nguyen`. - `AllowApproverFinalize = true` **CHỈ** ở Step2/Cấp2 (`chuong.phan`) — ghi comment nguyên câu lead giao (OG-3/OG-9 + "nhánh service port ở nhịp sau CÙNG WAVE trước push nên không phải config-lie #78"). Đặt PER-ROW (khuôn F5/F6) nên chỉ 1 người mang cờ, không phát cho cả Cấp. - Resolve email→user 1 lượt (11 email `Distinct` OrdinalIgnoreCase) qua `userManager.FindByEmailAsync`; thiếu ⇒ log warning gộp + **bỏ slot**, KHÔNG throw. Cấp 0 người ⇒ bỏ Cấp; Bước 0 Cấp ⇒ bỏ Bước + warn; workflow 0 Bước ⇒ VẪN tạo + warn (đúng lệnh). - Log: `logger.LogInformation("Seeded {Count} KHKK group workflows (K3 SP-002)", seeded)` — chỉ khi `seeded > 0`. **2 quyết định nhỏ tôi tự chốt (khai để lead soi):** - ⚠️ **KHÔNG dùng khuôn `AnyAsync(w.ApplicableType == …)`** của 6 seeder mẫu: 8 workflow DÙNG CHUNG type-10 ⇒ check-theo-type sẽ chặn 7 nhóm còn lại ngay sau khi N1 vừa tạo. Đây là chỗ khuôn cũ **không** copy được. - **Order của Cấp đánh LẠI liên tục** (`levelOrder++` chỉ khi cấp có người) thay vì cứng 1/2 — nếu dev-DB thiếu đúng người Cấp 1 thì workflow còn mỗi Cấp Order=2, vi phạm ràng buộc sequential của Designer (`ApprovalWorkflowV2AdminFeatures.cs` `HaveSequentialOrders`). Trên prod (đủ 11 người) kết quả **y hệt** 1/2. **Build chunk A:** `dotnet build src/Backend/SolutionErp.Infrastructure/SolutionErp.Infrastructure.csproj` → **0 Warning / 0 Error**.