Files
solution-erp/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-4gd-khkk-tong-quat-31-07-2026.md
2026-07-31 12:45:46 +07:00

13 KiB
Raw Blame History

SPEC TỔNG QUÁT v2 — Chuỗi 4 GĐ theo SOL-CCM-SP-002 (B1a + B1b review, lead kết tinh @S164)

v1 = kết tinh từ sub-invest-fable-b1a.md (spot-check 4/4). v2 = v1 + 14 vá từ B1b (b1b-review-synthesis.md — 3 lane reviewer 41 finding thô; lens2 xác nhận 6/6 claim chịu-lực ĐÚNG ⇒ nền giữ, vỏ vá). Yêu cầu gốc: draft-yeu-cau-owner.md.

① Tính năng / đề bài

Chuỗi 4 GĐ per-gói-thầu theo SOL-CCM-SP-002: GĐ1 Duyệt NCC (PE = CHA, đã chạy) → GĐ2 KHKK = duyệt HẠNG MỤC theo 8 NHÓM DUYỆT (trình ký số trạm-by-trạm y Duyệt NCC; ký nháy = mực trên bản cứng GĐ4) → GĐ3 điều khoản → GĐ4 bản cứng 1-mốc. Scope 5 mảnh: master-data danh mục · sidebar 8 nhóm × 6 leaf · cây mirror sidebar · admin thu gọn + 8 designer · dry-run E2E. 🔴 Luật khuôn: GIỐNG NHAU — CHỈ KHÁC FORM — ĐỪNG CHẾ THÊM. 🔸 Khai thẳng (B1b l3-F4): đợt này 8 nhóm = đơn vị HIỂN THỊ + luồng duyệt, KHÔNG phải đơn vị authz — mọi endpoint KHKK giữ 1 bộ policy KeHoachKyKet.{R,C,U,D} per-action (ContractSigningPlansController.cs:28+); authz-per-nhóm nếu anh muốn = wave riêng sau.

② Cách implement — 8 quyết định (v2)

  1. [OG-1] Cardinality "đưa vào loại HĐ" default GỘP theo cặp (NCC × dòng-danh-mục) — N line chung ContractId (hợp khuôn ContractSigningPlanLine.cs:25, index không-unique Configuration:26); đảo 1-1 được cùng máy.
  2. Phiếu KHKK = per NHÓM (1 phiếu = 1 nhóm, N hạng mục). Lines per-hạng-mục: Mig +CatalogEntryId Guid? +TenHangMuc, UNIQUE → (PlanId, SupplierId, CatalogEntryId) filtered. 🔴 +2 vá B1b: (a) đổi rào 1-PE-1-phiếu (ContractSigningPlanFeatures.cs:342-347 + picker :1201-1202) → (PeId, ApprovalGroup) [OG-7] — FE tree đã chịu N-phiếu/PE (usePipelineStages.ts:110-121); (b) bất-biến tiền: PeReferenceAmount = snapshot per-NCC-toàn-phiếu (Line.cs:6,:16-20) — repurpose per-hạng-mục PHẢI định nghĩa lại semantics + Σ trước == Σ sau mig, acceptance rà 16 consumer (10 BE .Lines + 6 file FE — danh sách l3-F18).
  3. Workflow = 1 type-10 + 8 Code KHKK-N1..N8; only-ONE-active VÔ HẠI (chứng 2 mắt xích l2: create chỉ check type :209-220; overview không lọc IsActive :117-134, POST không đụng IsUserSelectable :341-353). 🔴 Cột ApprovalGroup K2 là CHỦ DUY NHẤT (l3-F6) — K3 chỉ đọc (map Code↔group + validator phiếu-pin-đúng-nhóm).
  4. Vai catalog = 2 tầng: danh mục lưu chuỗi vai TEXT (in khối ký GĐ4) ⟂ workflow Levels lưu NGƯỜI THẬT. 🔸 Khai limitation (l1-F12): TEXT không ràng buộc máy với người-duyệt-thật — chấp nhận đợt này, khai trong doc K1.
  5. NĐUQ = cột THAM KHẢO text [OG-3]; enforce (CeoApprovalThreshold) = wave opt-in sau (0 consumer CỐ Ý — WorkflowService.cs:44).
  6. Menu: GIỮ Khkk_G1 + 6 leaf cũ, đổi LABEL = nhóm 1 (labelBackfill khuôn S155). Nhóm 2-8 = 42 leaf MỚI + 7 group-key mới (49 row menu mới; 48 leaf TỔNG) — sửa số l1-F8/l2-F5. 🔴 Phiếu cũ: backfill ApprovalGroup = 1 (l3-F5 — mirror bài EvaluationType không rỗng; acceptance đếm COUNT(phiếu) == Σ COUNT 8 folder).
  7. Admin ẩn = fe-admin isAdminHidden MỞ RỘNG TẬP KEY TƯỜNG MINH (giữ blacklist — KHÔNG đảo whitelist, tránh đổi default menu-mới; vá hội tụ l1-F2 l3-F1/F2): ẩn thêm {Dashboard?→giữ, các root nghiệp vụ: DuyetNcc-root keys, KeHoachKyKet, HR/Office/Personal, Contracts(đã ẩn Ct_*), HardCopies, Forms, Reports, Catalogs/Master, Workflows (:1795), PeWorkflows (:1798)} — CHỪA {System + 4 leaf quản trị + ApprovalWorkflowsV2 (:1801, con System) + subtree}. Danh sách key CHÍNH XÁC = việc B2-cụm-2 liệt từ DbInitializer seed; acceptance = liệt kê đúng N mục lá còn thấy (l3-F2).
  8. Nguồn danh mục: file đĩa QUY_TRINH/QT TRINH KY HOP DONG TP-NCC.docx = ĐÚNG SOL-CCM-SP-002.v01 (mã ở word/header1.xml) NHƯNG bản 6-trang KHÔNG chứa bảng (lead đo). Nguồn bảng = 7 ảnh anh gửi @S164 (trang 5-9, trọn 5.1 A/B/C + 5.2 CEO) → transcribe → [OG-6] anh soát bảng seed trước land (hoặc anh gửi file 15-trang). "/" trong ô vai = OR-of-N.
  9. 🆕 KHÓA BUDGET TẠI FINALIZE (owner @S164, verbatim: "Cái tính năng chuyển CEO và duyệt kết thúc hợp đồng -> Là khóa luôn cái budget rồi, người quyết sẽ là a Chương, Trưởng phòng CCM"): khi phiếu KHKK được duyệt-kết-thúc tại CCM (a Chương finalize) HOẶC CEO duyệt finalfreeze số (ApprovedAmount/giá chốt/NS tham chiếu) — phiếu DaDuyet đọc SNAPSHOT, không đọc live. Mirror nguyên khuôn PE Mig 67 (AddPeApprovedBudgetSnapshot S133): snapshot chốt tại finalize choke-point + display-gate frozen + 🔴#81-EXT: grep MỌI Phase-assignment-site (kể cả admin-override + seeder) kẻo bypass hook — bài đã trả giá 1 lần bên PE. Người quyết finalize-hay-CEO = TP.CCM Phan Văn Chương (cấp 2 CCM đội hình QT-DN-V2-001). ⚠️ MERGE-PENDING: B2-cụm-1 lane phóng TRƯỚC lời này — lead merge vào spec chi tiết khi lane về (schema cột snapshot → K2, hook finalize → K3).

③ Wave K1-K8 (v2 — PRE-gate + acceptance có răng)

Cụm 1 (nền):

  • K1 Master-data danh mục — PRE: [OG-6]. BE entity+config+CQRS+controller per-action policy; Mig 70 (3-file rule) filtered-unique Code #57; seed per-Code idempotent; FE leaf Catalogs ×2 app. DoD: N dòng khớp ~85±5, lệch giải trình từng dòng (đối chứng ảnh) · tên VN+EN đủ · CRUD 200 · seed ×2 không nhân row · test ≥590+k, khai k.
  • K2 Phiếu mang hạng-mục + nhóm — PRE: [OG-1] + [OG-7]. Mig 71 (3-file): plan +ApprovalGroup int backfill=1; Lines +2 cột + đổi UNIQUE; đổi rào (PeId)→(PeId,ApprovalGroup) 2 site :342-347/:1201-1202; list-query +param group (ListContractSigningPlansQuery :622-625K2 chủ, l3-F3) + DTO ContractSigningPlanListItemDto:34 +approvalGroup (sửa citation l2-F4) + FE types. DoD: phiếu nhóm 2 CÙNG PE → 201 · line khác nhóm → 409 · phiếu cũ ở folder nhóm 1, COUNT == Σ 8 folder · Σ tiền trước == sau mig · bảng rà 16 consumer ĐÃ-XỬ/KHÔNG-ĐỔI · test ≥590+k.
  • K3 8 workflow nhóm + designer — PRE: [OG-2] gật roster + verify đội hình LIVE (không phải archived). Seed 8 workflow KHKK-N1..N8 type-10 (khuôn :171) + validator pin-đúng-nhóm; 8 menu-con dưới ApprovalWorkflowsV2 + mở resolvePath fe-admin Layout.tsx:166-172 nhận code mới (leaf lạ rớt im lặng #50) + route designer per-workflow. DoD: API trả 8 · sidebar admin đếm được 8 designer, mở designer nhóm n load đúng KHKK-N{n} (l3-F10) · phiếu nhóm 3 pin workflow nhóm 5 → 409 · duyệt trọn trạm 1 phiếu → DaDuyet · test ≥590+k.

Cụm 2 (UI): (l3-F8: tách phụ thuộc thật — K4a chạy song song cụm 1 được)

  • K4a Menu+grant (0 phụ thuộc): 49 row menu + grant 3 SITE (:1780 seed · SeedKeHoachKyKetAccessAsync:2415 · KhkkKeys():2185 — site-3 l2-F6, comment :2204 "quên 1 bên = quyền lệch"). K4b 4 leaf list + Thao tác (chờ K2 param). K4c leaf WfView/Create (chờ K3): WfView mang ?group= lọc theo workflow Code nhóm (hiện WorkflowMatrixViewPage:52-71 chỉ lọc type — l2-F3). DoD: 48 leaf render đúng · leaf lọc đúng group kể cả WfView/Create · 2 chiều theo bảng kỳ-vọng 13 role (seeder hiện phủ 7 vai :2671-2675 — 6 vai còn lại khai kỳ vọng TRƯỚC, l3-F13) · key cũ 0 mồ côi.
  • K5 Cây sub-folder: GĐ2 group-by approvalGroup · GĐ3/4 group-by c.type (đã có :240); thêm tầng groups vào PipelineStage (mở rộng khuôn — bẫy content phải truyền count tay :74-75). DoD: sub-folder khớp sidebar · 2 file đích danh SHA-identical ×2 app (usePipelineStages.ts + PipelineTreePanel.tsx — l3-F19) · build ×2 PASS.
  • K6 Admin thu gọn (độc lập NHƯNG l3-F9: kéo sớm TRƯỚC K3 thì 8 designer chưa tồn tại — nếu kéo sớm, acceptance "đếm 8 designer" dời sang sau K3): QĐ7 tập-key tường minh. DoD: liệt kê đúng N mục lá còn thấy (đủ tên, dư/thiếu 1 = FAIL) · fe-user KHÔNG đổi = git diff --stat <base>..<head> -- fe-user/src = 0 file (KHÔNG đo bundle-hash #69 — l3-F12).

Cụm 3 (nối + chạy):

  • K7 Cầu KHKK→HĐ — RE-ĐO 3 NẤC (l3-F11): (a) cột/index ✓ có (Line.cs:25+Config:26); (b) write-site gán ContractId = 0 hiện tại (lead xác nhận grep); (c) test E2E — ⇒ trạng thái NỬA-LAND, K7 build phần (b)+(c). Bridge đọc ApprovedAmount per-Line + gộp theo OG-1 + pin workflow V2 + chọn ContractType lúc bắc cầu (ai chọn = câu nghiệp vụ, mặc định người bấm chọn trong dialog — l1-F15). DoD: KHKK DaDuyet → HĐ đúng số lượng OG-1 · giaTri == Σ ApprovedAmount phạm-vi-gộp khai rõ, null → chặn với message (l1-F6) · approver V2 thấy + inbox · test bridge ≥590+k.
  • K8 DRY-RUN E2E từ PE/2026/A/049. DoD (+3 dòng l3-F16): mọi bản ghi mới mang tiền tố ZZTEST · danh sách bản-ghi-không-xoá-được + cách sống chung (HĐ DaPhatHanh guard numeric) · tắt/dặn-team notification trước khi chạy · toàn trình hết trạm → HĐ · cây đủ 4 GĐ · screenshot + mã phiếu thật.

Mọi wave: cicd PASS; byte-verify #77 CHỈ wave có FE-ship — wave BE-only = smoke API (l3-F17); mig = 3-file rule.

④ [OWNER-GATE] — 4 cũ + 2 mới (nối vào PRE từng wave ở trên)

OG Câu hỏi Trạng thái Chặn wave
OG-1 Gộp HĐ CHỐT @S164 (verbatim: "thiết kế gộp nhưng giao diện thì cho 1-1 (Khi user đổi ý thì mình làm luôn)") ⇒ schema GỘP-capable (N line chung ContractId) + UI default 1-1 (bridge = 1 hàm nhận list-line, UI truyền 1 line; bung gộp = FE sau, 0 đổi máy) K2, K7
OG-2 Roster 8 workflow CHỐT @S164 ("Đúng đội hình cũ") — map đội hình QT-DN-V2-001, verify bản LIVE (không archived) trước seed K3
OG-7 1 PE → N phiếu CHỐT @S164 ("PE cho nhiều, nhưng… rào hiển thị 1-1 lại — User cần thì bung ra") ⇒ BE mở N-phiếu/PE (đổi rào 2 site :342/:1201 → (PeId, ApprovalGroup)) + UI default hướng-1: PE có phiếu rồi → hiện phiếu + nút phụ "Tạo thêm cho nhóm khác" (thay 409 chặn hẳn) K2
OG-3 NĐUQ CHỐT @S164 ("Đồng ý. Vẫn như trước - các quyền kiểu chuyển CEO các thứ y chang vậy luôn, thì ko cần quan tâm mức duyệt, vì a Chương sẽ quyết định là cái đó cần CEO ko hay là anh ấy đc duyệt.") ⇒ NĐUQ = ghi chú tham khảo; cơ chế lên-CEO = TÁI DÙNG level-finalize sẵn có của V2 (người trạm CCM — Phan Văn Chương — tự chọn "kết thúc tại cấp" hay trình tiếp, y PE đang chạy: EndedByLevelFinalize runtime + checkbox opt-in S97) — 🔄 SỬA @B2c1 (mâu thuẫn spec↔code, evidence fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx:151-152 KHKK_EARLY_FINALIZE_NOTE "backend chưa xử lý đường duyệt sớm"): cơ chế = tái dùng KHUÔN level-finalize NHƯNG BE KHKK CHƯA port nhánh ⇒ K3 có 3 việc code: (a) port nhánh finalize vào ContractSigningPlanWorkflowService (b) cột runtime EndedByLevelFinalize né #78 (forward-provision vào Mig 71 ⇒ K3 0-mig) (c) gỡ khóa 2 ô Designer FE. Seed AllowApproverFinalize=true cấp CCM-Chương CHỈ SAU khi (a) land — kẻo config-lie #78
OG-6 Soát bảng transcribe 86 dòng (gõ tay từ ảnh; 4 ô ⚠️ cuối file) HOẶC anh gửi file 15-trang đã giải thích, chờ anh soát K1 (seed)
OG-8 Authz per-nhóm CHỐT @S164 ("Đúng chính xác. Cho hiển thị, phân quyền tính sau.") — đợt này 8 nhóm = hiển thị + luồng duyệt; XEM/TẠO chung bộ khóa module; authz-per-nhóm = wave sau khi anh gọi
OG-5 Extract mơ hồ → hỏi khi gặp mở K1

END spec v2 — 8 wave · 8 quyết định · 6 OG · 14 vá B1b áp đủ.