Files
solution-erp/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum3-chi-tiet-31-07-2026.md
2026-07-31 14:08:16 +07:00

7.1 KiB
Raw Blame History

SPEC CỤM-3 FINAL — K7 + K8 (lead kết tinh sau B2-r cụm-3, @S164)

① Đề bài

K7 cầu KHKK→HĐ (bridge 8v/8test — đường ống S156 ĐÃ vá @W6-S161, verified 3 chân) · K8 dry-run E2E 17 bước. NỀN = sub-invest-fable-b2-cum3.md (22.9KB; L1 chấm 7/7 claim ĐÚNG) — 16 VÁ dưới thắng khi xung đột (từ sub-reviewer-c3-l{1,2,3}.md: L1 PWF 4M · L2 FAIL 5H · L3 FAIL 4H).

② 16 vá

Trục AUTHZ bridge (3-lane hội tụ — nặng nhất):

  1. 🔴 [L1-F2 L2-H1 L3-H1/H2] Gate nút bridge = HỘI 2 policy (KeHoachKyKet.Read class-level ∧ Contracts.Create action-level) — spec/FE phải khai ĐỦ 2 vế; và 🔴 Contracts.Create hiện CHƯA CẤP vai nào (seeder CanCreate=isPe ⇒ false cho Contracts) ⇒ thêm việc: grant Contracts.Create cho vai được bấm (đề xuất: Drafter + Procurement + Admin — [chờ câu III anh; default người-có-quyền-tạo-HĐ]) + test authz 2 chiều (vai có quyền → 201 · vai thiếu 1 trong 2 vế → 403) + FE gate đúng hội-2-khóa (không lỏng hơn server). Ghi chú: endpoint POST /api/contracts hiện [Authorize] trần (#82 treo chủ-đích — KHÔNG sửa đợt này, chỉ khai).
  2. [L1-F9] B0 pre-flight picker đủ 2 vế: workflow type-3 phải IsActive IsUserSelectable (dropdown lọc cả 2 — ContractCreatePage.tsx:334-341); B0 thêm SQL check cả 2 cờ kẻo dialog rỗng.
  3. [L1-F11] Guard bridge re-check IsActive/IsUserSelectable của workflow được pin (khuôn ContractFeatures.cs:74-88 chỉ check tồn-tại+type — forge POST pin được quy trình retired; thêm 2 điều kiện, rẻ).

Trục dữ liệu/cây: 4. 🔴 [L1-F6] pe.ContractId ??= có chiều NGƯỢC — bridge-PE-cũ chạy trước thì ??= no-op im lặng ⇒ HĐ mới vô hình trên cây (cây đi qua pe.contractId ĐƠN usePipelineStages.ts:214-218). Vá 2 tầng: (a) K7 ghi Line.ContractId luôn (nguồn thật) + pe.ContractId ??= chỉ là fallback hiển thị; (b) K5-liên-đới: builder GĐ3/GĐ4 nối qua TẬP lines[].contractId của các phiếu KHKK thuộc gói ( pe.contractId legacy) — không thì OG-1 UI-1-1 (N HĐ/PE) chỉ hiện HĐ đầu. 5. [L3-H3] T2 (gộp 2 line cùng NCC) phụ thuộc Mig 71 DROP-unique — thêm vào danh sách phụ-thuộc K7←K2 (hiện sót); test T2 chạy SAU K2. 6. [L1-F7] Bridge bổ sung theo tiền lệ: nạp Project.Code + Supplier.Code (+2 guard NotFound, khuôn bridge-cũ :63-66/:85-86) cho codegen GenerateAsync · field-map += SlaDeadline · WorkflowDefinitionId pin như 2 tiền lệ (ContractFeatures.cs:105-109 "Cả 2 set ok") — không để null rơi về policy hardcode :647-662. 7. [L1-F10] Acceptance B6 đổi neo: EndedByLevelFinalize phía KHKK là vật K3 MỚI ĐẺ (hiện 0 hit) — B6 neo vào {phase DaDuyet + ApprovedAmount frozen per-line + K3-cột-runtime} tùy nhánh; khai rõ bảng nào cột nào. 8. [L1-F8] Sửa nhãn "7 case" → 8 (bảng T1-T8).

Trục K8 dry-run (L2 — "chưa chạy được như viết"): 9. 🔴 [L2-H5] B0 = FORM NGƯỜI THẬT fail-closed: bảng 14 dòng {bước · người · email · tài khoản} PHẢI ĐIỀN ĐỦ trước giờ-G (12/14 bước đang trống); nguồn = K3-acceptance LIVE; thiếu 1 dòng = KHÔNG chạy. 10. 🔴 [L2-H2] Phép đo QĐ9 phải TRƯỢT ĐƯỢC: sau finalize → sửa NS/giá nguồn (PE hoặc catalog) → reload phiếu → số KHÔNG đổi = PASS (đổi = FAIL); đo CẢ 2 nhánh (a-Chương finalize-CCM VÀ lên-CEO-Trường duyệt) — hiện phép đo 0-bit. 11. 🔴 [L2-H3] Dấu ZZTEST cho phiếu KHKK: mã phiếu auto-gen (KHKK/2026/xxx) KHÔNG mang ZZTEST — bản ghi sống-vĩnh-viễn lại không dấu. Vá: nhét ZZTEST vào field hiển thị được trên list (tên kế hoạch/ghi chú — soi DTO chọn field) + rollback theo DANH SÁCH ID ghi lại từng bước, không theo prefix. 12. [CHỐT @S164 — câu V] "Phiếu đã duyệt không xóa" = THIẾT KẾ ĐÚNG, owner ratified (verbatim: "đồng ý luôn, hiện tất cả các phiếu nếu đã duyệt gần như ko xóa đc. Đồng ý cái này đúng với thiết kế ERP.") ⇒ (i) delete allow-list {DangSoanThao, TuChoi} GIỮ NGUYÊN — CẤM B4 "sửa" nó (nó không phải bug); (ii) hệ quả vận hành: phiếu test đã duyệt BẤT TỬ ⇒ K8 CHỐT dùng bộ PE TEST RIÊNG — owner ratified @S164 (verbatim: "tạo 1 cái PE Test SOLUTION-PE-1, 2, 3 j đó để test, cái này đúng ko test trên phiếu thật"): dựng gói thầu/hạng mục test đặt tên SOLUTION-PE-1..n (dưới dự án test — tái dùng convention ZZTEST-project S160 hoặc dự án test sẵn có), phiếu PE tạo trên gói đó đi trọn vòng từ GĐ1; ⚠️ note kỹ thuật: MÃ phiếu vẫn auto-gen theo RG-001 (không nhét chữ test vào mã được) — nhận diện test qua TÊN GÓI SOLUTION-PE-{n} hiện trên list + cây, và danh-sách-ID ghi lại từng bước (vá-11); (iii) 🆕 BACKLOG giai-đoạn-sau (lời anh): tính năng "phiếu điều chỉnh/thay thế" — cập nhật chứng từ đã duyệt bằng chứng từ điều chỉnh, KHÔNG xóa gốc (khuôn amendment ERP; áp được cả PE/KHKK/HĐ) — ghi nhận, KHÔNG làm đợt này. 13. [L3-H4] B16 rollback HĐ = NO-OP hiện tại (numeric guard chặn xóa cả khi TuChoi) — rollback plan ghi rõ: HĐ test dọn bằng sqlcmd soft-delete (lệnh cụ thể per bảng: Contracts + ContractApprovals + Changelogs + Line.ContractId=NULL + pe.ContractId=NULL), thứ tự ngược. 14. [L2-M10] Câu III treo → acceptance "ai bấm" để [CHỜ-ANH] — không chốt trong DoD tới khi anh trả; default dialog + người-có-quyền. 15. [L2-M12] DoD cardinality đo được: sau bridge UI-1-1 — đếm SELECT COUNT(DISTINCT ContractId) FROM Lines WHERE PlanId=X AND ContractId IS NOT NULL == số lần bấm; gộp (sau này) = N line 1 ContractId. 16. [L3-Q5] Dialog bridge tái dùng khuôn sẵn (dialog confirm shadcn/ui đã dùng ở Xóa-phiếu S155 + select khuôn ContractCreatePage picker) — 0 khuôn mới (lời 9).

③ Checklist final cụm-3

  • K7 (SAU cụm-1 K2+K3): bridge 8v nền + vá 1-8 · test 8+2-authz+idempotency-double-click · acceptance 7 nền + hội-2-khóa 403-path + cây hiện HĐ qua lines[].contractId + giaTri == Σ ApprovedAmount line chọn (null → message) · baseline ≥590+k.
  • K8 (CUỐI, sau MỌI wave land + câu V anh chốt): B0-FORM 14 người fail-closed + pre-flight SQL (workflow LIVE 2-cờ + KHKK-N4 + catalog N-row) · 17 bước mỗi bước {người thật · hành động · kỳ vọng · chụp} · QĐ9 đo 2 nhánh trượt-được · ZZTEST field-hiển-thị + rollback theo ID (sqlcmd cả HĐ lẫn phiếu) · notification dặn team trước.

END spec-cum3-final — nền 7/7-claim-đúng + 16 vá · authz-hội-2-khóa đóng · K8 từ "kịch bản" thành "chạy được".