wal: flush 20260729T1843
This commit is contained in:
@ -72,7 +72,7 @@ W8: GỠ (O-A — anh chốt để mở @S160)
|
||||
| 5 | O-Q2 checkbox per-phòng | comment tự do LevelOpinions (W4 DEFERRED, 0 dev) | số hoá checkbox (wave riêng) | lane-1 F-18 |
|
||||
| 6 | Mã phiếu KHKK | `KHKK/{YYYY}/{Seq:D3}` qua `WorkflowAppCodeSequence` (RG-001 v02 CÂM về phiếu) | đổi format 1 chỗ CodeGen | lane-1 F-07 + spec cũ `:128` |
|
||||
| 7 | Viết tắt "MB" (Mua bán) — codegen tự chế, KHÔNG có trong RG-001 v02 | **GIỮ hiện trạng** + flag (đổi codegen giữa dry-run = rủi ro) | map MuaBan→NCC hoặc loại type khỏi dry-run | lane-1 F-06/F-21, verify `ContractCodeGenerator.cs:25` |
|
||||
| 8 | GĐ4 vật mang | **Option A: 0-mig DERIVE** từ `phase=9` + attachment (SealedCopy/ScannedSigned/+InitialSigned enum-extend) | Option B: +`HardCopyStatus/Note` 1 mig AddColumn | lane-2 §3 |
|
||||
| 8 | GĐ4 vật mang | **Option A: 0-mig DERIVE** từ `phase=9` + attachment (SealedCopy/+InitialSigned enum-extend — KHÔNG `ScannedSigned`, F-C6/gotcha #71: =2 là chữ ký NCC ở DangInKy) | Option B: +`HardCopyStatus/Note` 1 mig AddColumn | lane-2 §3 |
|
||||
| 9 | Số bộ gốc / nơi lưu / ngày giao | ghi vào **note khi upload SealedCopy** (option A không có field) | option B field tường minh | lane-1 F-13/F-14 (nguồn câm) |
|
||||
| 10 | Thời điểm gán mã HĐ (QT đòi b.17, máy gen ở create + terminal) | **GIỮ máy hiện trạng** (create-time `ContractFeatures.cs:113-118` — có mã TRƯỚC khi in, sớm hơn cả QT đòi) + khai lệch trình tự so QT | dời site gen | lane-1 F-16 + lane-2 §1-b.13 |
|
||||
| 11 | Authz Contract | ✅ **RESOLVED — anh chốt O-A @S160: ĐỂ MỞ, không siết. W8 GỠ.** Rủi ro disclose §4.7 | (anh đổi ý lúc nào cũng kịp — bật lại W8 = 1-2 file) | owner @S160 |
|
||||
|
||||
@ -32,18 +32,16 @@
|
||||
| # | Stage | Vai / cách | Trạng thái |
|
||||
|---|---|---|---|
|
||||
| 1 | Scaffold + extract RG-001 v02 | lead | [x] |
|
||||
| 2 | invest lane-1: NGUỒN/QUY-TRÌNH GĐ3-GĐ4 (b.13→21 chi tiết + RG-001 v02 diff + FO-002.01 checklist-map + "hợp đồng cứng" = gì cụ thể) | `/fable-real investigator-codebase` #1 | [ ] |
|
||||
| 3 | invest lane-2: CODEBASE dry-run map (PE→KHKK→Contract→Hdc gap-map + reuse Contract V2 + authz khoanh vùng + dry-run mode + wave structure đề xuất) | `/fable-real investigator-codebase` #2 | [ ] |
|
||||
| 4 | Plan cha + spec-chi-tiết + checklist per-wave | lead (từ 2 invest + spec cũ) | [ ] |
|
||||
| 2 | invest lane-1: NGUỒN/QUY-TRÌNH GĐ3-GĐ4 (b.13→21 chi tiết + RG-001 v02 diff + FO-002.01 checklist-map + "hợp đồng cứng" = gì cụ thể) | `/fable-real investigator-codebase` #1 | [x] |
|
||||
| 3 | invest lane-2: CODEBASE dry-run map (PE→KHKK→Contract→Hdc gap-map + reuse Contract V2 + authz khoanh vùng + dry-run mode + wave structure đề xuất) | `/fable-real investigator-codebase` #2 | [x] |
|
||||
| 4 | Plan cha + spec-chi-tiết + checklist per-wave | lead (từ 2 invest + spec cũ) | [x] |
|
||||
| 5 | Review ensemble — 6 lane reviewer `tier:'opus'` (run `wf_0eb994aa-a63`) | `/fable-clone reviewer` | [x] |
|
||||
| 5b | Synthesis + lead-verify 5 claim (5/5 CONFIRMED đĩa) → `review-synthesis-clone-s160.md`; disposition: 2 owner-gate + ~18 fix | lead | [x] |
|
||||
| 5c | Owner-decision (AskUser): **W8=O-A để mở** + **đổi tên test khớp repo** | anh @S160 | [x] |
|
||||
| 5d | Fix NHÓM-2 (13 spec-edit: W8→O-A biên bản · seeder UPGRADE · W3 2-write-path+changelog-KHKK+bỏ-port · W6 view-per-HĐ-3-site · W7 param-type · tên test khuôn repo · dựng WF 3-trạm · disclose §4.7) | lead | [x] |
|
||||
| 6 | `/fable-real reviewer` chốt cuối — **VERDICT GO-WITH-FIXES** (reviewer #53 chết sau Trục-1+Trục-2; lead finalize on-behalf từ đĩa: 12/13 fix landed-đúng + 30 anchor CONFIRMED + 0 HIGH leftover; 3 dư-lượng nhỏ DR-1..3 + 1 check DR-4) | `/fable-real` | [x] |
|
||||
| 6b | Vá 3 dư-lượng DR-1 (W7 badge bảng §①) · DR-2 (W3 anchor#5 →:356-360) · DR-3 (W1 anchor +:1256-1257) + check DR-4 (W6 admin-inbox) | lead | [ ] |
|
||||
| 6b | Vá 3 dư-lượng DR-1 (W7 badge bảng §①) · DR-2 (W3 anchor#5 →:356-360) · DR-3 (W1 anchor +:1256-1257) + check DR-4 (W6 admin-inbox) | lead | [x] @S161 — 4/4 xong + 1 site CÙNG-LỚP lòi thêm `plan-cha:75` (gỡ `ScannedSigned` khỏi bộ derive option-A, F-C6); DR-4 chốt = spec-hoá nhánh ADMIN (mirror PE `:731-748`) vào W6 §②-4 + 1 vế acceptance admin-inbox |
|
||||
| 7 | hmw Opus-5-MAX thi công từng wave + kiểm (SAU vá DR) | hmw | [ ] |
|
||||
| 6 | Review chốt cuối | `/fable-real reviewer` | [ ] |
|
||||
| 7 | hmw Opus-5-MAX chạy dry-run từng wave theo Plan cha + kiểm | hmw (worker-tier-pin) | [ ] |
|
||||
|
||||
## Ràng buộc mang theo (từ sổ bền)
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
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ữ `false` ⇒ **W2/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ả).
|
||||
🔴 **Ẩn 2 checkbox early-finalize cho type=10 (review F-B3 — containment THẬT):** Designer V2 render checkbox `AllowApproverFinalize`/`AllowApproverSkipToFinal` (`ApprovalWorkflowsV2Page.tsx:1256-1257` SkipToFinal + `:1267-1268` Finalize) = 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
|
||||
|
||||
@ -23,7 +23,7 @@ Phiếu KHKK chạy trọn `DangSoanThao → ChoDuyet → (PMH → CCM → CEO)
|
||||
|
||||
## ③ CHECKLIST
|
||||
|
||||
**A. Gate 5-anchor:** `ContractWorkflowService.cs:217-394` (nguồn copy) · `:259-260` (OR-of-N) · `:292-316` (UPSERT) · `ApprovalWorkflow.cs:95+:116-125` (return-mode cờ, class trong file này) · `PurchaseEvaluationWorkflowService.cs:1008` (RULE choke-point).
|
||||
**A. Gate 5-anchor:** `ContractWorkflowService.cs:217-394` (nguồn copy) · `:259-260` (OR-of-N) · `:292-316` (UPSERT) · `ApprovalWorkflow.cs:95+:116-125` (return-mode cờ, class trong file này) · `ContractFeatures.cs:356-360` (khuôn RULE choke-point — LUẬT + `grep -rn` + "không đếm số"; thay `PEWS:1008` per F-B4, khớp §②-3(a)).
|
||||
**B. Acceptance (spec cũ W3 `:348-384` — SÀN 6 test, thiếu 1 tên = TRƯỢT):**
|
||||
- [ ] 🔴 OR-of-N 4 vế: (a) 2 phiếu song sinh — phiếu-1 A duyệt → tiến; phiếu-2 B duyệt → CŨNG tiến; (b) ca ÂM: người ngoài cấp → 403; (c) `LevelOpinions WHERE PlanId=@id` = 1 row; (d) KHÔNG đòi cả A và B.
|
||||
- [ ] Con-trỏ đôi: workflow 3 Bước → StepIndex 1→2→3, LevelOrder reset về 1 mỗi Bước mới.
|
||||
|
||||
@ -15,7 +15,7 @@ Wave này = 0 UI mới, 0 mig; sau deploy: approver thấy + mở + duyệt đư
|
||||
1. **Gate 5-anchor** (§③-A).
|
||||
2. **Test-before** 3 test (§③-B) RED.
|
||||
3. 🔴 **View — ĐÚNG CÁCH per-HĐ, KHÔNG role-blanket (review F-S3/F-C2/F-01):** `GetEligiblePhases(userRoles)` (`ContractFeatures.cs:334-350`) chữ ký **chỉ nhận role** ⇒ nếu chỉ nhét `ChoDuyet`/`DaPhatHanh` vào tập role thì mở toang cho MỌI user mang role đó (kể cả HĐ xóa mềm ở `:381`). **Fix:** thêm nhánh V2 **membership-theo-HĐ** ở CẢ 3 call-site của `GetEligiblePhases` (`:301` List · `:381` ListDeleted · `:486` Detail — review F-S3 chỉ ra gate cũ thiếu 2 site) — user thấy HĐ `ChoDuyet` **nếu là `ApproverUserId` của Level trong workflow pin CỦA CHÍNH HĐ đó**, và HĐ `DaPhatHanh` **nếu thuộc workflow HĐ đó HOẶC mang vai bản-cứng** (Director/AuthorizedSigner/HrAdmin/CostControl — actor b.19/20/21, cho GĐ4/W7). Admin giữ thấy-hết. KHÔNG mở toang: user ngoài cả hai điều kiện → 403 y cũ. *(Đây là điều kiện W7 phụ thuộc — F-C2.)*
|
||||
4. **Inbox**: mirror khuôn PE `ResolveV2InboxIdsAsync` (precompute id-set các HĐ mà con-trỏ Step/Level hiện tại chứa `ApproverUserId==actor`) — GHÉP vào inbox query hiện có thay vì chỉ `PhaseActorRoles` legacy. Giữ nhánh legacy cho HĐ V1 (nếu prod xuất hiện lại data V1).
|
||||
4. **Inbox**: mirror khuôn PE `ResolveV2InboxIdsAsync` (precompute id-set các HĐ mà con-trỏ Step/Level hiện tại chứa `ApproverUserId==actor`) — GHÉP vào inbox query hiện có thay vì chỉ `PhaseActorRoles` legacy. Giữ nhánh legacy cho HĐ V1 (nếu prod xuất hiện lại data V1). 🔴 **Nhánh ADMIN (F-B13, DR-4 chốt @S161):** admin hiện lấy `eligiblePhases = PhaseActorRoles.Keys` (`ContractFeatures.cs:440-441`) mà dict `:421-430` KHÔNG có `ChoDuyet` ⇒ ghép v2InboxIds xong admin VẪN mù HĐ ChoDuyet. Mirror TRỌN khuôn PE `PurchaseEvaluationFeatures.cs:731-748`: admin dùng danh-sách phase liệt TƯỜNG MINH **+ `ChoDuyet`** (admin thấy mọi HĐ chờ duyệt qua nhánh PHASE; `v2InboxIds` để rỗng cho admin đúng như PE `:746-748`).
|
||||
5. **Guard trình** (`ContractWorkflowService.cs:73-78`): nới thành `Drafter ∨ DeptManager ∨ CreatedBy==actor ∨ Procurement` (dòng tối thiểu đóng lớp 403-PMH; giữ 403 cho role ngoài).
|
||||
6. (Nếu DTO cần) thêm `currentApproval` info vào detail DTO cho FE panel — chỉ khi FE thiếu dữ liệu hiển thị.
|
||||
7. Build + test GREEN + commit `[CLAUDE] Contract: W6 duong ong V2 view+inbox+trinh`. cicd verify.
|
||||
@ -26,7 +26,7 @@ Wave này = 0 UI mới, 0 mig; sau deploy: approver thấy + mở + duyệt đư
|
||||
**B. Acceptance (lane-2 §7-W6):**
|
||||
- [ ] 5 test ĐÚNG TÊN (khuôn repo) trong `ContractV2PipelineTests`: `Inbox_PendingLevelApprover_SeesChoDuyetContract` · `Inbox_OtherLevel_DoesNotSeeContract` (ca ÂM) · `View_V2Approver_NotDrafter_CanSeeChoDuyetContract` · `List_HardCopyActor_NotAdmin_SeesDaPhatHanhContract` (🔴 review F-01: LIST test cho actor bản-cứng — không wave nào đo LIST trước) · `View_UserOutsideWorkflow_WithUnrelatedRole_Gets403` (🔴 review F-S4: ca ÂM **pin ROLE cụ thể** như CostControl/Procurement, KHÔNG chọn HrAdmin cho pass dễ).
|
||||
- [ ] `dotnet test` PASS 0 fail, số-sau ≥ baseline + 5.
|
||||
- [ ] Prod ③: login approver-V2 KHÔNG-admin → `GET /api/contracts/inbox` ≥1 HĐ ChoDuyet mà mình là Level hiện tại + `GET /{id}` 200; login actor bản-cứng non-admin (vd Director) → `GET /api/contracts?type=1&phase=9` ≥1 dòng (trước W6: 0 dòng + 403).
|
||||
- [ ] Prod ③: login approver-V2 KHÔNG-admin → `GET /api/contracts/inbox` ≥1 HĐ ChoDuyet mà mình là Level hiện tại + `GET /{id}` 200; login **admin** → `/api/contracts/inbox` ≥1 HĐ ChoDuyet (🔴 F-B13 — trước W6: admin 0 dòng vì `PhaseActorRoles.Keys` không có ChoDuyet); login actor bản-cứng non-admin (vd Director) → `GET /api/contracts?type=1&phase=9` ≥1 dòng (trước W6: 0 dòng + 403).
|
||||
- [ ] Ca ÂM giữ (pin role): user role KHÔNG liên quan + không thuộc workflow HĐ nào → `GET /{id}` vẫn 403 (chứng KHÔNG mở toang qua role-blanket).
|
||||
- [ ] 🔴 Kiểm hở xóa-mềm: HĐ `ChoDuyet` đã soft-delete → user V2 KHÔNG thấy ở `:381` ListDeleted (fix membership không được rò sang màn Đã-xóa).
|
||||
- [ ] CI run PASS; 0 mig (diff `*Migrations*` = 0 — khuôn M2 đợt-5).
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
Mapping trạm → bằng chứng upload (đảo được sang option B nếu anh muốn field tường minh):
|
||||
| Trạm (QT) | Ai | Bằng chứng hệ thống | Derive badge |
|
||||
|---|---|---|---|
|
||||
| b.19 Ký GĐ/NĐUQ | BOD | upload `ScannedSigned` (scan bản có chữ ký GĐ) | "Đã ký GĐ" = has(ScannedSigned) |
|
||||
| b.19 Ký GĐ/NĐUQ | BOD | upload scan bản có chữ ký GĐ (purpose: KHÔNG `ScannedSigned` — F-C6/gotcha #71, =2 nghĩa "scan chữ ký NCC ở DangInKy") | "Đã ký GĐ" = derive từ `InitialSigned`/`SealedCopy` (2 cờ DTO, khớp §②-2(c)) |
|
||||
| b.20 Đóng dấu | HRA/ISO | (gộp vào b.21 — option A không tách được 2 mốc; khai lệch so 4-mốc lane-1 F-14) | — |
|
||||
| b.21 Phát hành + Lưu | PB/BCH + CCM | upload `SealedCopy` (scan bộ đóng dấu) + **note bắt buộc: số bộ gốc · đã giao CCM/NTP · nơi lưu/Filing path** (plan cha default #9) + upload scan cover FO-002.01 (luật (c) lane-1) | "Đã lưu bản cứng" = has(SealedCopy) |
|
||||
Readonly từ GĐ3 (F-11): khối "Ký nháy & cover b.17-18" hiển thị từ attachments (`InitialSigned` mới) + LevelOpinions HĐ.
|
||||
|
||||
Reference in New Issue
Block a user