updated: 2026-08-08T00:52+07:00 | session: S182/L13 | branch: main
updated: 2026-08-08T01:08+07:00 | session: S182/L13 | branch: main
goal: YC-013 — 8 workflow "Duyệt KHKK — Nhóm 1..8" mirror ĐỦ chức năng trang Duyệt NCC (thêm/sửa/xóa/edit/ghim, UI không lệch); pipeline anh chỉ định 3-invest-Fable → wave-plan → 2-review-Fable → hmw fan-out Opus 5 MAX
goal: YC-013 — 8 workflow "Duyệt KHKK — Nhóm 1..8" mirror ĐỦ chức năng trang Duyệt NCC (UI không lệch); pipeline anh chỉ định 3-invest-Fable → wave-plan → 2-review-Fable → hmw fan-out Opus 5 MAX
## D3 — 9 checkbox quyền duyệt trên panel KHKK (YC-014, AskUser ~01:20)
**Anh chọn: "C — Mờ ô chưa nghe (Recommended)"**
- Giữ layout y khuôn ảnh; ô nào máy KHKK chưa nghe ⇒ **disabled + tooltip "chưa áp dụng cho KHKK"** — tiền lệ chính trang này (ô Duyệt-thẳng-Cấp-cuối đã mờ cho type-10 từ K3, `ApprovalWorkflowsV2Page.tsx:1292-1302`).
- Hệ quả scope: **W3 (port semantics) HỦY đợt này**. W2d thi hành theo C.
- Danh sách ô mờ CHÍNH XÁC = chờ 2 reviewer chấm (đặc biệt ô #4 Trả-về-Drafter: hành-vi thật = luôn-cho dù cờ tắt — mờ-tick-sẵn hay mờ-thường, reviewer khuyến nghị).
- Ô "Ngưỡng giá trị gói CEO" (`:944-961`): cùng cách — KHKK cố ý không port (OG-3 NĐUQ human-gate).
## D4 — nhãn panel (lead quyết theo đề xuất FE-lens, reviewer chấm)
Title = menu-label "Duyệt KHKK — Nhóm {g}" + phụ đề nghiệp vụ `khkkGroupMenuLabel(g)`.
**Tiền đề 3 lens hội tụ (mỗi cái có file:line trong artifact):**
- **0 MIGRATION** — 9/9 checkbox = 9 cột bit sẵn trên `ApprovalWorkflowLevels` dùng chung; versioning UNIQUE `(Code,Version)` + `IsActive`; Archived = `IsActive=false`.
- **BE generic ~85%** — 5 action controller + PUT diff-by-Id + guard chữ-ký 3-site ĐÃ KHKK-aware + `SetUserSelectable`/`Delete` by-Id.
- **Danh tính nhóm = `Code` (`KHKK-N{n}`), KHÔNG phải ApplicableType** — 8 workflow cùng type=10. Đây là gốc của MỌI việc phải sửa.
- **Hiện trạng "lệch":** 8 route `/system/approval-workflows-v2/KhkkN{n}` (Layout `:188`) đổ về **landing grid** vì `TYPE_CODE_TO_INT` không có key `KhkkN*` (`ApprovalWorkflowsV2Page.tsx:164-172`).
- **Authz:** giữ `Workflows.Create` y trang DuyetNcc (32 policy `AwV2_KhkkN*` 0-consumer BE — đo + control-dương; per-group-authz = đổi hình controller 9-type, KHÔNG làm trừ khi anh lệnh).
- Runtime 9-flag: KHKK hiện chỉ nghe **#8 Finalize**; 4 Trả-về + Sửa-S2 + Sửa-NS + Duyệt-thẳng + XÓA = **BỎ QUA/CHƯA WIRE** ⇒ điểm quyết D3 (dưới).
## MỤC 2 — WAVE-PLAN chi tiết
### W0 — prep local (bắt buộc trước mọi test)
1.`dotnet ef database update`×2 DB (Dev + Design **đang kẹt Mig 71**, đĩa = Mig 72 — committed-but-unapplied class S53).
2. Boot API 1 lần → `SeedKhkkGroupWorkflowsAsync` đẻ 8 row local. ⚠️ Local 8 workflow **RỖNG NGƯỜI là ĐÚNG** (seeder resolve email prod) — acceptance cấu trúc chạy local, acceptance đội-hình chạy prod.
| a | 🔴 **Deactivate-per-Code cho type-10** (mìn M1, 3 lens hội tụ) | `:339-343` | `typeEnum == ContractSigningPlan` ⇒ scope `w.Code == request.Code`; type khác giữ per-type (P1 — KHÔNG làm P2 per-Code toàn cục: đổi hành vi PE/Contract chưa lường) |
| b | **Group-match guard 2-site** (bypass rào-v) | `:603-607` + `SubmitAsync` | extract rào (v) `:479-486` → `EnsureWorkflowGroupMatchAsync(db, awId, group)`; gọi ở Create + UpdateDraft + Submit (chốt-cuối, khuôn 2-tầng `:179-187`). Message lỗi chỉ việc cần làm cho phiếu lỡ pin lệch trước vá |
| c | **Changelog type-10 khi PUT sửa-tại-chỗ** | `:863-893` | thêm nhánh mirror block PE → `ContractSigningPlanChangelogs` (bảng sẵn Mig 69; khuôn ghi `ContractSigningPlanWorkflowService.cs:546-557`), query phiếu pin `def.Id` Phase ∉ {DaDuyet, TuChoi} |
| d | **DELETE usage-check → 409 đích danh** (lợi MỌI type) | `:1193-1205` | pre-count pin 8 module có cột `ApprovalWorkflowId` + LevelOpinions (khuôn `CountLiveOpinionsAsync` theo workflow-id) → 409 "N phiếu đang pin"; hết cảnh `SqlException 547 → 500 thô` (`GlobalExceptionMiddleware.cs:32-39` không map DbUpdateException) |
**Test W1 (test-before cho a/b, test-after c/d):** tạo v2 `KHKK-N1` ⇒ N2..N8 `IsActive` bất biến + regression DuyetNcc tạo-Code-mới-cùng-type vẫn tắt Code cũ · UpdateDraft re-pin lệch nhóm ⇒ 409 · PUT workflow nhóm có phiếu treo ⇒ 1 row `ContractSigningPlanChangelogs` · DELETE version có pin ⇒ 409 (không 500).
| b | Synthetic slice per-Code | `:299-301` | từ type-10: `versions = history.filter(d => d.code === khkkGroupWorkflowCode(g))` · `active = versions.find(v => v.isActive) ?? null` (🔴 KHÔNG tin ô `Active` per-type của BE — nó số-ít, 8 nhóm trộn) · title = "Duyệt KHKK — Nhóm {g}" + phụ đề nghiệp vụ `khkkGroupMenuLabel(g)` (D4 — lead chọn theo đề xuất FE, reviewer chấm) |
| c | `lockedCode` xuyên suốt | `TypePanel:357` → `Designer:620/:650/:798/:927` | prop `lockedCode?: string`; ô Mã `disabled={isEdit || !!lockedCode}`; POST gửi `lockedCode ?? code`. 🔴 Thiếu = "Tạo quy trình mới" từ panel nhóm với mã tự gõ đẻ version **rơi khỏi slice** + không được rào (v) nhận |
| d | **D3 — 7 ô chưa-wire** (chờ anh chốt, xem MỤC 3) | `:1275/:1284/:944-961/…` | thi hành theo phương án anh chọn {A giữ / B port / C mờ-ô} |
| e | (optional) mirror menuKeys | `fe-{admin,user}/src/lib/menuKeys.ts:31-32` | +8 const `AwV2_KhkkN*` — 0 hệ quả runtime, mirror-completeness |
**SHA-mirror 2 app: KHÔNG áp dụng** — Designer là fe-admin-only (đã CHỨNG: fe-user 0 route/0 page/0 nhánh `AwV2_*`); `types/khkk.ts` 2 app identical sẵn, không chạm.
**Regression:** 4 route cũ (`DuyetNcc`/`PhuongAn`/`Contract`/`ContractSigningPlan`) render như cũ · fe-user tạo phiếu nhóm auto-pin `KHKK-N{g}` không đổi API · **hệ quả nghiệp vụ THẬT của nút Ghim:**`IsUserSelectable=false` 1 nhóm ⇒ CHẶN TẠO PHIẾU nhóm đó cả 2 app (`KhkkCreatePage.tsx:104/:113-116`) — acceptance phải nêu để anh biết nút này có răng.
### W3 — CHỈ KHI anh chọn D3=B: port semantics vào `ContractSigningPlanWorkflowService`
F6 XÓA-đúng-lượt (mirror PE 3-rào `PeSoftDeleteFeatures.cs:110-114`) · F1×4 return-modes per-level (mirror switch `PurchaseEvaluationWorkflowService.cs:421-424`) · F3-analog sửa-Lines-lúc-duyệt · F2 skip-to-final (+gỡ ép-false `:387` + gỡ disable FE `:1292-1302`**CÙNG WAVE** — tiền lệ F5 @K3). Mỗi cờ = test RED→GREEN riêng. `CeoApprovalThreshold`**KHÔNG port** (OG-3 NĐUQ human-gate — owner đã chốt trước).
### W4 — test-specialist đóng suite (baseline 645 → +N per W1/W3)
**D3 (ANH CHỐT — chặn scope W2d/W3):** 6/9 checkbox tick được mà KHKK-runtime KHÔNG nghe (#78 config-lie class):
- **A** — giữ 9 ô tick được (uniform tuyệt đối với ảnh; cờ lưu DB nằm chờ; risk: người cấu hình tưởng có hiệu lực).
- **B** — port cho sống thật (W3; đổi hành vi duyệt KHKK; nặng + cần test per-cờ).
- **C** — mờ ô chưa-wire + tooltip "chưa áp dụng cho KHKK" (tiền lệ CHÍNH TRANG NÀY: SkipToFinal đã disabled cho type-10 `:1292-1302`; + ô Ngưỡng CEO cùng cách; trung thực #78; port sau gỡ dần).
**D4 (lead quyết, reviewer chấm):** title panel = menu-label "Duyệt KHKK — Nhóm {g}" + phụ đề nghiệp vụ từ `khkkGroupMenuLabel(g)`.
> Trạng thái: ĐANG ĐỔ RUỘT — skeleton viết lúc spawn, Edit liên tục.
## VERDICT (điền cuối)
_(pending)_
## 1. Thứ tự wave + phụ thuộc
_(pending)_
## 2. Deploy-safety
_(pending)_
## 3. Seeder tương tác (wipe-durability #75/#76)
_(pending)_
## 4. Acceptance prod — đủ đo chưa
_(pending)_
## 5. Test coverage W1
_(pending)_
## 6. D3/D4 — chấm phương án
_(pending)_
## 7. Rollback + monitoring
_(pending)_
## 8. WAVE-PLAN FINAL
_(pending)_
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.