Files
solution-erp/.claude/workflows/runs/2026-08-08-S182-khkk-awf-mirror-ncc/spec-khkk-awf-mirror-ncc-DRAFT.md
2026-08-08 01:08:01 +07:00

8.7 KiB
Raw Blame History

SPEC DRAFT — YC-013: 8 panel "Duyệt KHKK — Nhóm 1..8" mirror trang Duyệt NCC (S182/L13)

Tổng hợp từ 3 Fable deep-pass: sub-invest-be-fable.md (§1-§5+VERDICT) · sub-invest-db-fable.md (§1-§7) · sub-invest-fe-fable.md (§1-§6). Trạng thái: DRAFT chờ 2 reviewer Fable + anh chốt D3.

MỤC 1 — Mục tiêu + phạm vi + tiền đề đã chứng

Mục tiêu (YC-013): 8 mục sidebar "Duyệt KHKK — Nhóm 1..8" ra ĐÚNG khuôn trang approval-workflows-v2/DuyetNcc: panel active-card + 4 nút (Sửa-tại-chỗ / Tạo-phiên-bản-mới / Ghim-Bỏ-ghim / Xoá-version) + Lịch sử versions + dialog Designer 9-checkbox per-NV + rule-box. UI không lệch.

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 gridTYPE_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.

W1 — BE-1: 4 fix, 2 file, 0-mig (ApprovalWorkflowV2AdminFeatures.cs + ContractSigningPlanFeatures.cs +1 helper)

# Fix Site Cách
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-486EnsureWorkflowGroupMatchAsync(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).

W2 — FE: 1 file chính fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx (~60-90 dòng diff)

# Chạm Site Cách
a Parse kind :164-172 match(/^KhkkN([1-8])$/)khkkGroup; selectedTypeInt = khkkGroup ? 10 : TYPE_CODE_TO_INT[typeCode] (query overview giữ applicableType=10)
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:357Designer:620/:650/:798/:927 prop lockedCode?: string; ô Mã `disabled={isEdit
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)

W5 — reviewer adversarial pre-commit → commit → cicd-monitor 3-chân (bundle admin rotate, eoffice giữ nguyên nếu chỉ W2a-d; +eoffice nếu e) → acceptance prod + 3 query SQL verify (DB §4 bàn giao)

MỤC 3 — Điểm quyết + acceptance + rollback

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).

Acceptance (đo được, từ FE §5):

  1. 8 leaf sidebar → 8 slice panel khác nhau (URL /KhkkN{n}, header đúng nhóm, card KHKK-N{n} v01 + badge + 3 Bước + 4 nút + Lịch sử) — hết landing grid.
  2. Dialog Sửa-tại-chỗ: title KHKK-N{n} v{NN} (giữ nguyên phiên bản), khối cam 9 checkbox đúng khuôn (theo D3), Drafter tick sẵn, rule-box.
  3. "Tạo phiên bản mới" nhóm N1 ⇒ v02 nằm ĐÚNG panel N1; badge "Đang áp dụng" 7 nhóm khác KHÔNG mất (W1a).
  4. Regression 4 route cũ + fe-user auto-pin + 645 test cũ xanh.

Rollback: 0 mig ⇒ revert commit là sạch; W1a có regression-test 2 chiều giữ hành vi cũ cho type ≠ 10.

Nợ NGOÀI scope (khai, không lặng): GET Overview 0-policy lộ roster+9-flag cho mọi user authenticated (BE §5.2 — information-disclosure mềm, owner ngó sau) · roster 8 nhóm = snapshot email lúc seed, KHÔNG tự sync theo QT-DN-V2-001 (BE §5.3) · Khkk_WfView panel aggregate giấu 7/8 nhóm (FE §6.1 — slice này vá cho 8 leaf mới; re-point mục cũ = việc riêng) · comment "7 bảng" stale :1120.