Files
solution-erp/.claude/workflows/runs/2026-07-29-S160-khkk-dryrun-plan/spec-wave-w1-schema-designer-29-07-2026.md
2026-07-29 16:54:56 +07:00

7.7 KiB
Raw Blame History

SPEC WAVE-1 — Schema Mig 69 + Permission + Designer type-10 (GĐ2 KHKK)

Nguồn RATIFIED: spec cũ §2.2 (7 bảng) + §2.4 (menu/permission) + §③ WAVE-1 (spec-ke-hoach-ky-ket-hd-28-07-2026.md:266-308) + NOTE W1 @S160 (đầu §WAVE-1). Plan cha default #6 #12. File này = CÁCH-LÀM cụ thể + checklist; xung đột nào với spec cũ đã khai ở mục Δ.

① TÍNH NĂNG / ĐỀ BÀI

Đặt nền DB + quyền + cho admin dựng được quy trình duyệt type=10, để W2 tạo phiếu được ngay. Deploy riêng an toàn: menu skeleton Khkk_* đã public từ arc-2 (leaf ComingSoon — dark-launch nằm ở TRANG, không ở menu). Mig 69 = migration DUY NHẤT của toàn plan dry-run.

Δ so spec cũ (2 điểm, do thực địa arc-2 đổi tiền đề):

  1. KHÔNG thêm 4 const ContragSigningPlans*/menu 4 dòng như §2.4 — menu skeleton Khkk_G1+6 leaf ĐÃ SEED prod (CanRead 13/13). Thay bằng: All += KeHoachKyKet (const sẵn MenuKeys.cs:41) → policy KeHoachKyKet.{Read,Create,Update,Delete} tự sinh (Program.cs foreach All×Actions) + seeder grant 4-action cho role đích. Menu-key hiển thị (Khkk_*) ⟂ policy-key (KeHoachKyKet) — 2 lớp khác nhau, khai rõ để reviewer soi.
  2. Label VN = "Kế hoạch ký kết HĐ" (đời nhãn cuối @S159), KHÔNG phải "Đề xuất ký kết hợp đồng" còn trong spec cũ :223.

② CÁCH IMPLEMENT (thứ tự bắt buộc)

  1. Gate 5-anchor (§③-A) — trượt ≥1 ⇒ chấm lại hết rồi mới code.
  2. Domain (src/Backend/SolutionErp.Domain/ContractSigningPlans/): 7 entity đúng bảng spec cũ §2.2 (#1 header ContractSigningPlans [+DepartmentId Guid? C5] · #2 Lines [+ContractId Guid? C6, UNIQUE filtered (PlanId,SupplierId) WHERE IsDeleted=0] · #3 DossierItems · #4 LevelOpinions [UNIQUE (PlanId,LevelId), FK Cascade-Plan/Restrict-Level] · #5 Attachments · #6 Changelogs [ĐỦ 4 cột EntityType/EntityId/UserName/FieldChangesJson] · #7 Approvals). 2 enum: ContractSigningPlanPhase{DangSoanThao=1,ChoDuyet=2,DaDuyet=3,TraLai=98,TuChoi=99} · DossierItemStatus{ChuaNop=1,DaNop=2,TvgsDuyet=3,TvgsBac=4} (🔴 bắt đầu 1, KHÔNG 0 — falsy JS) + DossierItemKind{MauVatLieu=1,Shopdrawing=2,Khac=99}.
  3. ApprovalWorkflowApplicableType += ContractSigningPlan = 10 — re-verify slot 10 trống NGAY TRƯỚC khi viết (ApprovalWorkflow.cs:53-67 dừng ở 9; anchor #2).
  4. EF Configuration ×7 — khai độ dài MỌI cột chuỗi (spec cũ :134-137: MaKeHoach 50 · GhiChu/ContextNote 2000 · Name 500 · Note 1000 · TvgsName 200 · Summary 1000 · SignedByFullName 200 IsRequired · FileName 500/Path 1000/ContentType 200) + HasQueryFilter(!IsDeleted) header + loose-Guid (KHÔNG FK vật lý sang PE/Supplier — convention Mig 49).
  5. DbSets vào IApplicationDbContext + ApplicationDbContext.
  6. Mig 69 AddContractSigningPlans (3-file rule: migration + Designer + Snapshot; skill ef-core-migration): 7 CreateTable, 0 ALTER bảng cũ, Down = DropTable ×7. database-agent design-review TRƯỚC apply (per spec cũ W1 vai).
  7. MenuKeys.cs: All += KeHoachKyKet (chỉ 1 dòng — const đã có :41). KHÔNG key mới.
  8. 🔴 DbInitializer grant — UPGRADE-IF-EXISTS, KHÔNG INSERT (review F-S1/F-O3/F-O4 — 4 lane hội tụ, lead verify đĩa CONFIRMED): row Permission key KeHoachKyKet + Khkk_* ĐÃ tồn tại CanRead-only cho mọi role (DbInitializer.cs:2204-2213 nhánh read-only), và nhánh grant key-non-Pe là skip-existing continue (:2242-2245) ⇒ thêm grant kiểu insert = NO-OP im lặng ⇒ CanCreate/Update giữ falseW2/W3 lên prod 403 cho 13/13 role, chỉ Admin qua = GIẾT dry-run (gotcha #44). Fix: viết method mới khuôn SeedProcurementMasterAccessAsync:2367-2374 (if (existing.TryGetValue(key,out row)) { if(!row.CanCreate){row.CanCreate=true;…} }), chạy SAU RevokeTemporarilyHidden… (mirror :2098-2101) để thắng. Cấp CanCreate/CanUpdate cho 13/13 role (đúng O-A "hiển thị hết để góp ý") + CanDelete cho Drafter/Admin, trên KeHoachKyKet + 6 leaf Khkk_*. 🔴 CẤM SQL tay (gotcha #84 — vết DbInitializer.cs:2287-2296 Run #423 grant tay bị revoker lật 447/494). (b) KHÔNG đụng menu-row Khkk_* (đã seed). (c) label chỉnh = labelBackfill (gotcha #11).
  9. Mã phiếu: CodeGen service prefix "KHKK/{YYYY}" qua WorkflowAppCodeSequence (spec cũ #8-CẮT: bảng dùng chung 4 module Office, atomic = transaction SERIALIZABLE trong service, ContractCodeSequence.cs:5).
  10. fe-admin Designer type-10: ApprovalWorkflowsV2Page.tsx map TYPE_CODE_TO_INT (site thực :144-148, KHÔNG phải comment :143 — review chéo) + 3 site ApprovalWorkflowV2AdminFeatures.cs liệt-kê-thủ-công (:911/:929 merge chữ-ký-sống · :971/:992 RetainedOpinionRef · :1044/:1056 chữ ký mồ côi) — thiếu ⇒ admin xoá Level có chữ ký nổ FK 500. 🔴 Ẩn 2 checkbox early-finalize cho type=10 (review F-B3 — containment THẬT): Designer V2 render checkbox AllowApproverFinalize/AllowApproverSkipToFinal (ApprovalWorkflowsV2Page.tsx:1267-1268) = per-Level admin opt-in. Anh phán 2 đường này "PHÁ VỠ" (S155). W3 KHÔNG port code path ⇒ để checkbox sống mà backend không xử = cờ chết đánh lừa admin. Fix: ẩn/disable 2 checkbox khi typeCode==10 (hoặc render read-only + tooltip "chưa hỗ trợ cho quy trình KHKK"). Đây là cách làm default #1 ("đường THƯỜNG") thành containment thật thay vì "port-nhưng-không-kích-hoạt" (giả).
  11. Build + test + commit [CLAUDE] Domain+Infra+Admin: W1 KHKK schema Mig 69 + policy KeHoachKyKet + Designer type-10.

③ CHECKLIST

A. Gate 5-anchor (mở TRƯỚC): ApprovalWorkflow.cs:53-67 (slot 10 trống) · MenuKeys.cs:41 (const KeHoachKyKet + comment tái dùng) · MenuKeys.cs:163+ (All chưa có KeHoachKyKet) · AuthorizePolicyRegressionTests.cs:138-139 (lưới policy-ngoài-All ⇒ 500) · DbInitializer.cs:1779-1786 (Khkk_* 7 key đã seed). B. Acceptance (từ spec cũ W1 :281-300, giữ nguyên hiệu lực + bổ sung):

  • dotnet ef migrations list → migration cuối chứa AddContractSigningPlans (KHÔNG có tiền tố 69_).
  • sqlcmd local: SELECT COUNT(*) FROM sys.tables WHERE is_ms_shipped=089 → 96.
  • dotnet testAuthorizePolicyRegressionTests XANH (policy KeHoachKyKet.* hợp lệ — All đã chứa key).
  • Test mới tồn tại ĐÚNG TÊN: ContractSigningPlanSchemaTests.BayBang_MoiBang_CoAuditFields_VaQueryFilter + sàn N ≥ 2 test mới, PASS 0 fail (số-sau ≥ số-đo-ngay-trước + 2).
  • Admin tạo được quy trình type=10 3 Bước (PMH→CCM→CEO), pin IsUserSelectable; xoá 1 Level chưa chữ ký → OK.
  • dotnet ef migrations script + Down chạy sạch trên DB copy.
  • 🔴 Policy-grant ĐO CỜ, KHÔNG đếm ROW (review F-04: row đã có sẵn ⇒ đếm row = 0-bit): sau seed, sqlcmd/curl xác nhận Permission key KeHoachKyKetCanCreate=1 ∧ CanUpdate=1 cho ≥1 role non-Admin (vd Drafter). Row đã tồn tại từ trước ⇒ chỉ CỜ mới chứng upgrade ăn.
  • cicd 3-chân-kiềng sau deploy: CI PASS · __EFMigrationsHistory top = Mig 69 (curl API không đo được mig ⇒ dùng sqlcmd qua RDP-người hoặc chấp nhận CI-log làm chứng) · sys.tables 96 · menu KHÔNG đổi (142 giữ — W1 không thêm menu). C. Rủi ro tick trước khi đóng wave: [ ] không quên HasQueryFilter · [ ] UNIQUE filtered có WHERE IsDeleted=0 (gotcha #57) · [ ] 0 SQL tay (gotcha #84).