wal: flush 20260729T1903
This commit is contained in:
@ -7,12 +7,14 @@ chain:
|
|||||||
- [x] (S160 window-2: pipeline 4/5 + chốt-cuối GO-WITH-FIXES — xem `_context` PAUSE-2 + `sub-reviewer-chot-cuoi-s160.md`)
|
- [x] (S160 window-2: pipeline 4/5 + chốt-cuối GO-WITH-FIXES — xem `_context` PAUSE-2 + `sub-reviewer-chot-cuoi-s160.md`)
|
||||||
- [x] vá 4 dư-lượng @S161: DR-1 (W7 bảng §① b.19 → derive `InitialSigned`/`SealedCopy`, `has(ScannedSigned)`=0) · DR-2 (W3 anchor#5 → `ContractFeatures.cs:356-360`, verify đĩa đúng khuôn) · DR-3 (W1 + `:1256-1257` SkipToFinal, verify đĩa 2 dải đúng) · DR-4 CHỐT (spec-hoá nhánh ADMIN mirror PE `:731-748` vào W6 §②-4 + 1 vế acceptance admin-inbox — F-B13 verify đĩa: dict `:421-430` 0 ChoDuyet THẬT) + 1 site CÙNG-LỚP `plan-cha:75` (gỡ ScannedSigned khỏi derive option-A)
|
- [x] vá 4 dư-lượng @S161: DR-1 (W7 bảng §① b.19 → derive `InitialSigned`/`SealedCopy`, `has(ScannedSigned)`=0) · DR-2 (W3 anchor#5 → `ContractFeatures.cs:356-360`, verify đĩa đúng khuôn) · DR-3 (W1 + `:1256-1257` SkipToFinal, verify đĩa 2 dải đúng) · DR-4 CHỐT (spec-hoá nhánh ADMIN mirror PE `:731-748` vào W6 §②-4 + 1 vế acceptance admin-inbox — F-B13 verify đĩa: dict `:421-430` 0 ChoDuyet THẬT) + 1 site CÙNG-LỚP `plan-cha:75` (gỡ ScannedSigned khỏi derive option-A)
|
||||||
- [x] ctx-verifier @tiep-2 CO-CO 10 cờ (biên-nhận `_tiep-2.md`) → vá ngay run.md ledger (hàng 2/3/4/6b flip [x] + xoá 2 dòng duplicate stale); còn lại → housekeeping
|
- [x] ctx-verifier @tiep-2 CO-CO 10 cờ (biên-nhận `_tiep-2.md`) → vá ngay run.md ledger (hàng 2/3/4/6b flip [x] + xoá 2 dòng duplicate stale); còn lại → housekeeping
|
||||||
- [!] CHỜ ANH 3 quyết trước W1 (report S161 đánh số): (1) mã phiếu KHKK `KHKK/{YYYY}/{Seq:D3}` · (2) viết tắt "MB" codegen · (3) GĐ4 option A (0-mig, default) / B (1-mig)
|
- [x] 3 quyết owner @S161: (1) mã phiếu OK `KHKK/{YYYY}/{Seq:D3}` · (2) "Bỏ cái MB đi" → dry-run cấm HĐ MuaBan + codegen = nợ tuyên án · (3) GĐ4 = 1-MỐC (verbatim "Upload file cứng lên -> Là xem như xong") — khắc vào plan-cha #6/#7/#8/#9 + W1/W2/W5/W7 (16 edit)
|
||||||
- [ ] hmw Opus-5-MAX thi công từng wave theo Plan cha (W1 đầu, mig 69) + gate 5-anchor mỗi wave + cicd 3-chân-kiềng
|
- [x] gate 5-anchor W1 PASS 5/5 (mở tươi @S161 — slot 10 trống · :41 const · ∉All · :138-139 lưới · :1779-1786 seed)
|
||||||
|
- [!] wf: hmw W1 đợt-1 `wf_7d6fb81b-640` ĐANG CHẠY NỀN — 2 lane {implementer-backend: 7 entity+Mig 69+seeder UPGRADE+CodeGen+3 site AWV2Admin · implementer-frontend: Designer type-10 + ẩn 2 checkbox} — run-folder `.claude/workflows/runs/2026-07-29-S161-khkk-w1-schema/` (taskList 7 stage trong run.md)
|
||||||
|
- [ ] đợt-2 SAU khi wf về: test-specialist + database-agent (song song) → lead acceptance §③-B (build·test·sqlcmd 96·Down sạch·đo CỜ) → reviewer → commit/push → cicd-monitor 3-chân-kiềng
|
||||||
- [ ] setup thủ công TRƯỚC W5 (SAU W1 vì type=10 cần mig 69): dựng workflow type=3 + type=10 3-trạm qua Designer (seed chỉ 1 trạm)
|
- [ ] setup thủ công TRƯỚC W5 (SAU W1 vì type=10 cần mig 69): dựng workflow type=3 + type=10 3-trạm qua Designer (seed chỉ 1 trạm)
|
||||||
- [ ] housekeeping @pause/closeout kế: nén MIND-1 5.447B (trần `_mind` 83,2% — MIND-5 chắc vượt) · re-carry 2 ý D rơi (vá-GỐC-Phase-3.5-refresh {mới-nêu} CÒN SỐNG + khuôn-5-đợt→sổ bền {gần-chốt}) · STATUS:6 bổ arc dry-run S160 (mù có lý do — land 15:27 trước pipeline) · hạ nhãn DR/WF-3-trạm đã-định-đoạt · E đếm 7 sub-file (không 6) · mở lại slot-45 trần `_mind` (tiền-đề lật: file SỐNG 83,2%) · quyết bookkeeping OVERDUE:light (cặp H24 chạy @S159 bookend mà `last_audit` đứng 27)
|
- [ ] housekeeping @pause/closeout kế: nén MIND-1 5.447B (trần `_mind` 83,2% — MIND-5 chắc vượt) · re-carry 2 ý D rơi (vá-GỐC-Phase-3.5-refresh {mới-nêu} CÒN SỐNG + khuôn-5-đợt→sổ bền {gần-chốt}) · STATUS:6 bổ arc dry-run S160 (mù có lý do — land 15:27 trước pipeline) · hạ nhãn DR/WF-3-trạm đã-định-đoạt · E đếm 7 sub-file (không 6) · mở lại slot-45 trần `_mind` (tiền-đề lật: file SỐNG 83,2%) · quyết bookkeeping OVERDUE:light (cặp H24 chạy @S159 bookend mà `last_audit` đứng 27)
|
||||||
|
|
||||||
next: chờ anh trả lời (1)(2)(3) → hmw wave W1 (mig 69). Anh gật default hết ⇒ W1 chạy được ngay.
|
next: đợi wf_7d6fb81b-640 về (task-notification) → verify đĩa (sub-md + git status, ĐỪNG chỉ tin return #53) → đợt-2 theo run.md stage 3-7. Phiên chết giữa wf ⇒ /tiep §4 relaunch-cắt-gọt từ run-folder.
|
||||||
|
|
||||||
verify:
|
verify:
|
||||||
- `grep -c "has(ScannedSigned)" .claude/workflows/runs/2026-07-29-S160-khkk-dryrun-plan/spec-wave-w7-ban-cung-hdc-29-07-2026.md` = 0 (DR-1)
|
- `grep -c "has(ScannedSigned)" .claude/workflows/runs/2026-07-29-S160-khkk-dryrun-plan/spec-wave-w7-ban-cung-hdc-29-07-2026.md` = 0 (DR-1)
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
- **GĐ1** Duyệt NCC = PE (live) · **GĐ2** Kế hoạch ký kết HĐ = b.7→12 (b.7 email BỎ — Q8 ĐÓNG) · **GĐ3** Duyệt hợp đồng = **b.13→18** (tận dụng Contract V2) · **GĐ4** Hợp đồng cứng = **b.19→21, ký cứng UPLOAD-ONLY**.
|
- **GĐ1** Duyệt NCC = PE (live) · **GĐ2** Kế hoạch ký kết HĐ = b.7→12 (b.7 email BỎ — Q8 ĐÓNG) · **GĐ3** Duyệt hợp đồng = **b.13→18** (tận dụng Contract V2) · **GĐ4** Hợp đồng cứng = **b.19→21, ký cứng UPLOAD-ONLY**.
|
||||||
- Khúc b.13→21 = span verdict-LAI (toàn bộ tái dùng Contract), KHÔNG phải span GĐ3 (lane-1 F-09 bắt drift này trong chính run.md).
|
- Khúc b.13→21 = span verdict-LAI (toàn bộ tái dùng Contract), KHÔNG phải span GĐ3 (lane-1 F-09 bắt drift này trong chính run.md).
|
||||||
- **Nhãn GĐ2 2 đời:** "Đề xuất ký kết hợp đồng" (sáng @S159, còn trong spec cũ `:27`) → **superseded "Kế hoạch ký kết HĐ"** (chốt cuối @S159, prod `Khkk_G1` seeder). Mọi label VN mới = **"Kế hoạch ký kết HĐ"**; class/bảng English `ContractSigningPlan*` GIỮ.
|
- **Nhãn GĐ2 2 đời:** "Đề xuất ký kết hợp đồng" (sáng @S159, còn trong spec cũ `:27`) → **superseded "Kế hoạch ký kết HĐ"** (chốt cuối @S159, prod `Khkk_G1` seeder). Mọi label VN mới = **"Kế hoạch ký kết HĐ"**; class/bảng English `ContractSigningPlan*` GIỮ.
|
||||||
- Nuance lane-1 F-11: **bản cứng vật lý SINH ở b.17-18 (∈GĐ3)** — trang GĐ4 hiển thị readonly metadata b.17-18, thao tác thật của GĐ4 chỉ là 3 trạm b.19/20/21.
|
- Nuance lane-1 F-11: **bản cứng vật lý SINH ở b.17-18 (∈GĐ3)**. 🔄 **@S161 anh rút GĐ4 còn 1 MỐC hệ-thống** (default #8): b.19/20/21 làm trên giấy, hệ thống chỉ ghi nhận **upload scan bộ cứng = xong**; khối readonly GĐ3 chỉ còn LevelOpinions (duyệt điện tử), KHÔNG attachment ký nháy.
|
||||||
|
|
||||||
## 2. BỨC TRANH WAVE (hợp nhất 2 lane — đánh số GIỮ W1-W5 của spec ratified, nối W6-W8)
|
## 2. BỨC TRANH WAVE (hợp nhất 2 lane — đánh số GIỮ W1-W5 của spec ratified, nối W6-W8)
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ W8: GỠ (O-A — anh chốt để mở @S160)
|
|||||||
|
|
||||||
## 4. CHIẾN LƯỢC DATA DRY-RUN (lane-2 §4 + đo mới)
|
## 4. CHIẾN LƯỢC DATA DRY-RUN (lane-2 §4 + đo mới)
|
||||||
|
|
||||||
1. **Dự án test `ZZTEST` + 1-2 NCC test** tạo qua UI (0 code): mã HĐ dry-run ăn sequence per-prefix riêng (`ContractCodeGenerator.cs:33,:40-53`) — không đụng chuỗi số dự án thật; NGOÀI seed-list ⇒ xóa mềm không bị re-seed (#75/#76). **CẤM đặt Code trùng seed-list** (twin FLOCK-01).
|
1. **Dự án test `ZZTEST` + 1-2 NCC test** tạo qua UI (0 code): mã HĐ dry-run ăn sequence per-prefix riêng (`ContractCodeGenerator.cs:33,:40-53`) — không đụng chuỗi số dự án thật; NGOÀI seed-list ⇒ xóa mềm không bị re-seed (#75/#76). **CẤM đặt Code trùng seed-list** (twin FLOCK-01). 🔴 **CẤM tạo HĐ loại `HopDongMuaBan`** (anh bỏ "MB" @S161 — default #7).
|
||||||
2. **PE side có data THẬT** — phiếu KHKK dry-run tạo từ PE test mới (mỗi vòng thử cần PE mới vì idempotency `pe.ContractId` `:59-60,:145`).
|
2. **PE side có data THẬT** — phiếu KHKK dry-run tạo từ PE test mới (mỗi vòng thử cần PE mới vì idempotency `pe.ContractId` `:59-60,:145`).
|
||||||
2-bis. 🔴 **DỰNG WORKFLOW type=3 3-TRẠM (review F-02 — bắt buộc E2E):** seed prod chỉ có `QT-HD-V2-001` = **1 trạm CCM** (`DbInitializer.cs:239-265`, approver binh.le). E2E hứa 3 trạm (PRO→CCM→CEO) + b.19 BOD ⇒ **admin phải tự dựng 1 ApprovalWorkflow `ApplicableType=3` 3 Bước qua Designer** (0 code — Designer type-3 đã có) TRƯỚC khi chạy W5. Tương tự KHKK type=10 cần 1 workflow 3-trạm (W1 Designer). Ghi là **bước setup thủ công**, không phải code wave.
|
2-bis. 🔴 **DỰNG WORKFLOW type=3 3-TRẠM (review F-02 — bắt buộc E2E):** seed prod chỉ có `QT-HD-V2-001` = **1 trạm CCM** (`DbInitializer.cs:239-265`, approver binh.le). E2E hứa 3 trạm (PRO→CCM→CEO) + b.19 BOD ⇒ **admin phải tự dựng 1 ApprovalWorkflow `ApplicableType=3` 3 Bước qua Designer** (0 code — Designer type-3 đã có) TRƯỚC khi chạy W5. Tương tự KHKK type=10 cần 1 workflow 3-trạm (W1 Designer). Ghi là **bước setup thủ công**, không phải code wave.
|
||||||
3. **KHÔNG cờ IsDryRun** (blast cardinality mọi list/inbox — bài S87/S88).
|
3. **KHÔNG cờ IsDryRun** (blast cardinality mọi list/inbox — bài S87/S88).
|
||||||
@ -70,10 +70,10 @@ W8: GỠ (O-A — anh chốt để mở @S160)
|
|||||||
| 3 | Q11 tạo HĐ khi chưa có KH | **cảnh báo mềm** — 2 đường song song (PE→HĐ tắt vẫn sống) | nâng 409 chặn cứng | lane-2 §2(d) |
|
| 3 | Q11 tạo HĐ khi chưa có KH | **cảnh báo mềm** — 2 đường song song (PE→HĐ tắt vẫn sống) | nâng 409 chặn cứng | lane-2 §2(d) |
|
||||||
| 4 | O-Q1 căn cứ thiếu TvgsDuyet | cảnh báo mềm khi trình | 409 | spec cũ W4 |
|
| 4 | O-Q1 căn cứ thiếu TvgsDuyet | cảnh báo mềm khi trình | 409 | spec cũ W4 |
|
||||||
| 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 |
|
| 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` |
|
| 6 | Mã phiếu KHKK | ✅ **RESOLVED — anh OK @S161:** `KHKK/{YYYY}/{Seq:D3}` qua `WorkflowAppCodeSequence` (RG-001 v02 CÂM về phiếu); phép đo format thêm @W1 §③-B + W2 §③-B (review A6: quyết owner-visible phải có acceptance) | đổi format 1 chỗ CodeGen | lane-1 F-07 + spec cũ `:128` + owner @S161 |
|
||||||
| 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` |
|
| 7 | Viết tắt "MB" (Mua bán) — codegen tự chế, KHÔNG có trong RG-001 v02 | ✅ **RESOLVED — anh chốt @S161 (verbatim): "Bỏ cái MB đi"** ⇒ (i) dry-run **CẤM tạo HĐ `HopDongMuaBan`** — không mã MB nào được sinh (guard W5 §③-C); (ii) `ContractCodeGenerator.cs:25` "MB" = **nợ đã tuyên án**, format thay thế (PO-format theo comment `:18` hay khác) làm CHUNG đợt sửa Contract service — O-3 "cứ từ từ" còn hiệu lực, KHÔNG đổi codegen giữa dry-run | đổi 1 case switch khi anh chốt format thay | lane-1 F-06/F-21 + owner @S161 |
|
||||||
| 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 |
|
| 8 | GĐ4 vật mang | ✅ **RESOLVED — anh chốt @S161 (verbatim):** *"trình ký sẽ hiển thị full form doc có sẵn trong mục FORM -> điền đầy đủ vào luôn -> Duyệt qua (Nếu có) -> Upload file cứng lên -> Là xem như xong"* ⇒ **A-RÚT-GỌN 1-MỐC**: 0-mig **+ 0 enum-extend** — badge duy nhất "Đã lưu bản cứng" = has(`SealedCopy` SẴN); ~~InitialSigned=4/CoverChecklist=5~~ BỎ; b.19/b.20 diễn ra NGOÀI hệ thống (vẫn KHÔNG `ScannedSigned` — F-C6/gotcha #71). Option B RETIRED | nâng field 4-mốc nếu vận hành thật đòi — backfill từ attachment sẵn | lane-2 §3 + owner @S161 |
|
||||||
| 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) |
|
| 9 | Số bộ gốc / nơi lưu / ngày giao | note **TÙY CHỌN** khi upload SealedCopy (hạ từ "bắt buộc" theo 1-mốc @S161 — "upload = xong", không chặn thao tác) | 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 |
|
| 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 |
|
| 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 |
|
||||||
| 12 | Grant quyền KHKK (W1) | 🔴 **UPGRADE-if-exists** (`SeedProcurementMasterAccessAsync:2367-2374` khuôn), chạy SAU revoke — **KHÔNG insert** (row `KeHoachKyKet`/`Khkk_*` seed CanRead-only sẵn ⇒ insert = skip-existing no-op ⇒ 403 giết dry-run, review F-S1/F-O3/F-O4). Cấp CanCreate/CanUpdate cho **13/13 role** (đúng O-A "hiển thị hết") + Delete cho Drafter/Admin | siết nhóm hẹp hơn nếu muốn | review 4-lane hội tụ |
|
| 12 | Grant quyền KHKK (W1) | 🔴 **UPGRADE-if-exists** (`SeedProcurementMasterAccessAsync:2367-2374` khuôn), chạy SAU revoke — **KHÔNG insert** (row `KeHoachKyKet`/`Khkk_*` seed CanRead-only sẵn ⇒ insert = skip-existing no-op ⇒ 403 giết dry-run, review F-S1/F-O3/F-O4). Cấp CanCreate/CanUpdate cho **13/13 role** (đúng O-A "hiển thị hết") + Delete cho Drafter/Admin | siết nhóm hẹp hơn nếu muốn | review 4-lane hội tụ |
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
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).
|
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.
|
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ữ `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).
|
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`).
|
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`). ✅ **Format `KHKK/{YYYY}/{Seq:D3}` anh OK @S161** (default #6 RESOLVED).
|
||||||
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.
|
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: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ả).
|
🔴 **Ẩ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`.
|
11. Build + test + commit `[CLAUDE] Domain+Infra+Admin: W1 KHKK schema Mig 69 + policy KeHoachKyKet + Designer type-10`.
|
||||||
@ -33,6 +33,7 @@
|
|||||||
- [ ] `sqlcmd` local: `SELECT COUNT(*) FROM sys.tables WHERE is_ms_shipped=0` → **89 → 96**.
|
- [ ] `sqlcmd` local: `SELECT COUNT(*) FROM sys.tables WHERE is_ms_shipped=0` → **89 → 96**.
|
||||||
- [ ] `dotnet test` → `AuthorizePolicyRegressionTests` XANH (policy `KeHoachKyKet.*` hợp lệ — All đã chứa key).
|
- [ ] `dotnet test` → `AuthorizePolicyRegressionTests` 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).
|
- [ ] 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).
|
||||||
|
- [ ] Phép đo mã phiếu (review A6 — quyết owner-visible phải có acceptance): test `SigningPlanCodeGenerator_Format_KhkkYearSeqD3` — mã match `^KHKK/\d{4}/\d{3}$` + 2 lần gọi liên tiếp seq tăng dần (format anh OK @S161).
|
||||||
- [ ] 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.
|
- [ ] 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**.
|
- [ ] `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 `KeHoachKyKet` có **CanCreate=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.
|
- [ ] 🔴 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 `KeHoachKyKet` có **CanCreate=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.
|
||||||
|
|||||||
@ -24,7 +24,7 @@ BCH tạo được **phiếu nháp "Kế hoạch ký kết HĐ"** từ PE `DaDuy
|
|||||||
|
|
||||||
**A. Gate 5-anchor:** `ProposalFeatures.cs:427-439` (bẫy flatten — để BIẾT mà né) · `CreateContractFromEvaluationFeatures.cs:53-62` (guard+phép tính snapshot) · `ProposalFeatures.cs:258-267` (guard workflow-type trọn) · `DbInitializer.cs:2207` khu staticMap comment `Khkk_*` (leaf đang ComingSoon) · `MenuKeys.cs` All (KeHoachKyKet ĐÃ vào từ W1).
|
**A. Gate 5-anchor:** `ProposalFeatures.cs:427-439` (bẫy flatten — để BIẾT mà né) · `CreateContractFromEvaluationFeatures.cs:53-62` (guard+phép tính snapshot) · `ProposalFeatures.cs:258-267` (guard workflow-type trọn) · `DbInitializer.cs:2207` khu staticMap comment `Khkk_*` (leaf đang ComingSoon) · `MenuKeys.cs` All (KeHoachKyKet ĐÃ vào từ W1).
|
||||||
**B. Acceptance (spec cũ W2 `:322-337` + Δ):**
|
**B. Acceptance (spec cũ W2 `:322-337` + Δ):**
|
||||||
- [ ] `POST /api/contract-signing-plans` từ PE DaDuyet → 201; DB N Lines = số winner (đếm đối chiếu `PurchaseEvaluationSuppliers WHERE IsWinner=1`).
|
- [ ] `POST /api/contract-signing-plans` từ PE DaDuyet → 201; DB N Lines = số winner (đếm đối chiếu `PurchaseEvaluationSuppliers WHERE IsWinner=1`); `maKeHoach` trả về match `^KHKK/\d{4}/\d{3}$` (format anh OK @S161 — phép đo A6).
|
||||||
- [ ] `PeReferenceAmount` mỗi Line == SUM Quotes IsSelected đúng NCC (2 câu đếm so khớp).
|
- [ ] `PeReferenceAmount` mỗi Line == SUM Quotes IsSelected đúng NCC (2 câu đếm so khớp).
|
||||||
- [ ] Tạo lần 2 cùng PE → 409. · [ ] PE chưa DaDuyet → 400/409, KHÔNG 500.
|
- [ ] Tạo lần 2 cùng PE → 409. · [ ] PE chưa DaDuyet → 400/409, KHÔNG 500.
|
||||||
- [ ] 🔴 Authz 2 tầng: user thiếu quyền POST → **403** (không 200/401/500); có quyền → 201. Gate rẻ: `grep -c "Authorize(Policy" ContractSigningPlansController.cs` ≥ 4.
|
- [ ] 🔴 Authz 2 tầng: user thiếu quyền POST → **403** (không 200/401/500); có quyền → 201. Gate rẻ: `grep -c "Authorize(Policy" ContractSigningPlansController.cs` ≥ 4.
|
||||||
|
|||||||
@ -27,4 +27,4 @@ Từ phiếu KHKK `DaDuyet`, tạo HĐ per-winner với **giá = `ApprovedAmount
|
|||||||
- [ ] 🔴 Prod curl (ZZTEST) — CHẠY TỚI LƯỢT DUYỆT, KHÔNG dừng ở trình (review F-B5: nhánh trình `ContractWorkflowService.cs:70-89` KHÔNG đọc workflow ⇒ "204 KHÔNG 409" PASS SẴN, 0-bit): HĐ tạo với `ApprovalWorkflowId` V2 → `GET /{id}` có **`currentApprovalLevelOrder=1`** (vế có răng — chứng pin V2 ăn); → Cấp-1 approver `POST /{id}/transitions` duyệt → tiến Bước 2. HĐ tạo KHÔNG workflow → trình vẫn 204 (đường cũ) nhưng `currentApprovalLevelOrder=null`.
|
- [ ] 🔴 Prod curl (ZZTEST) — CHẠY TỚI LƯỢT DUYỆT, KHÔNG dừng ở trình (review F-B5: nhánh trình `ContractWorkflowService.cs:70-89` KHÔNG đọc workflow ⇒ "204 KHÔNG 409" PASS SẴN, 0-bit): HĐ tạo với `ApprovalWorkflowId` V2 → `GET /{id}` có **`currentApprovalLevelOrder=1`** (vế có răng — chứng pin V2 ăn); → Cấp-1 approver `POST /{id}/transitions` duyệt → tiến Bước 2. HĐ tạo KHÔNG workflow → trình vẫn 204 (đường cũ) nhưng `currentApprovalLevelOrder=null`.
|
||||||
- [ ] Changelog có ContextNote chứa CẢ 2 số khi giá KH ≠ SUM-PE.
|
- [ ] Changelog có ContextNote chứa CẢ 2 số khi giá KH ≠ SUM-PE.
|
||||||
- [ ] FE build ×2 · cicd 3-chân-kiềng.
|
- [ ] FE build ×2 · cicd 3-chân-kiềng.
|
||||||
**C. Rủi ro:** [ ] KHÔNG sửa lệch phép SUM cũ cho PE-không-plan (đường cũ phải y nguyên — test #2 canh) · [ ] body record lệch count controller↔command (silent 400).
|
**C. Rủi ro:** [ ] KHÔNG sửa lệch phép SUM cũ cho PE-không-plan (đường cũ phải y nguyên — test #2 canh) · [ ] body record lệch count controller↔command (silent 400) · [ ] 🔴 dry-run CẤM tạo HĐ `HopDongMuaBan` — không mã "MB" nào được sinh (anh bỏ MB @S161, plan cha default #7; codegen giữ nguyên chờ format thay).
|
||||||
|
|||||||
@ -4,21 +4,19 @@
|
|||||||
|
|
||||||
## ① TÍNH NĂNG / ĐỀ BÀI
|
## ① TÍNH NĂNG / ĐỀ BÀI
|
||||||
|
|
||||||
7 leaf `Hdc_<Code>` ("01. HĐ Thầu phụ - Bảng cứng" … "07.") hết ComingSoon → trang **theo dõi bản cứng** per loại HĐ: list HĐ `phase=9 DaPhatHanh` + trạng thái bản cứng + thao tác 3 trạm b.19/20/21 dạng **upload-only** (ký GĐ → đóng dấu HRA/ISO → phát hành/lưu/scan). **Option A: 0-migration** — trạng thái DERIVE từ attachment; GĐ4 nằm SAU terminal nên KHÔNG thêm phase, KHÔNG hồi sinh `DangDongDau=8 [LEGACY]`.
|
7 leaf `Hdc_<Code>` ("01. HĐ Thầu phụ - Bảng cứng" … "07.") hết ComingSoon → trang **theo dõi bản cứng** per loại HĐ: list HĐ `phase=9 DaPhatHanh` + **1 MỐC** hệ-thống. 🔄 **Anh chốt @S161 (verbatim, default #8 plan cha):** *"trình ký sẽ hiển thị full form doc có sẵn trong mục FORM -> điền đầy đủ vào luôn -> Duyệt qua (Nếu có) -> Upload file cứng lên -> Là xem như xong"* ⇒ ký GĐ (b.19) + đóng dấu (b.20) + thủ tục lưu (b.21) diễn ra **NGOÀI hệ thống trên giấy**; hệ thống chỉ ghi nhận bằng chứng cuối: **upload scan bộ HĐ cứng (đã ký + đóng dấu) → badge "Đã lưu bản cứng" = has(`SealedCopy`) → XONG**. **Option A-RÚT-GỌN: 0-migration + 0 enum-extend** — GĐ4 nằm SAU terminal nên KHÔNG thêm phase, KHÔNG hồi sinh `DangDongDau=8 [LEGACY]`.
|
||||||
|
|
||||||
Mapping trạm → bằng chứng upload (đảo được sang option B nếu anh muốn field tường minh):
|
Mô hình bằng chứng (1-mốc — supersede bảng 3-trạm bản trước @S161):
|
||||||
| Trạm (QT) | Ai | Bằng chứng hệ thống | Derive badge |
|
| Việc | Ai | Bằng chứng hệ thống | Derive badge |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 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.19+b.20+b.21 (ký GĐ · đóng dấu · phát hành/lưu — làm trên GIẤY) | BOD · HRA/ISO · PB/BCH+CCM | upload `SealedCopy` (scan bộ cứng đã ký+đóng dấu) + note **tùy chọn** {số bộ gốc · đã giao CCM/NTP · nơi lưu} (default #9 hạ mức @S161) — 🔴 KHÔNG dùng `ScannedSigned` (F-C6/gotcha #71: =2 là "scan chữ ký NCC ở DangInKy") | "Đã lưu bản cứng" = has(`SealedCopy`) |
|
||||||
| 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) | — |
|
Readonly từ GĐ3: **LevelOpinions HĐ** (chữ ký duyệt điện tử — khớp "Duyệt qua (nếu có)" @S161). Khối attachment ký nháy `InitialSigned` **BỎ** theo 1-mốc.
|
||||||
| 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Đ.
|
|
||||||
|
|
||||||
## ② CÁCH IMPLEMENT
|
## ② CÁCH IMPLEMENT
|
||||||
|
|
||||||
1. **Gate 5-anchor** (§③-A).
|
1. **Gate 5-anchor** (§③-A).
|
||||||
2. **BE nhỏ**: (a) enum-extend `AttachmentPurpose` += `InitialSigned = 4` (ký nháy b.17-18) **+ `CoverChecklist = 5`** (scan cover FO-002.01, luật (c) — review F-09: thiếu purpose cho cover) — int column, 0-mig (tiền lệ PE `ComparisonTable=4`; `ContractAttachment.cs:5-11`); (b) 🔴 **thêm param `type` vào `ListContractsQuery` + controller (review F-C1/F-05 — `GET /api/contracts` HIỆN 0 CÓ `type`, `ContractsController.cs:16-24` chỉ phase/supplierId/projectId):** thêm `[FromQuery] ContractType? type` + filter handler `ContractFeatures.cs:305-307` — KHÔNG lọc client-side `pageSize:100` (trần 100/loại). (c) `ContractListItemDto` +2 cờ derive `hasSealedCopy`/`hasInitialSigned` trong projection (DTO hiện 12 field `:323-327` KHÔNG trả attachments; 🔴 badge "Đã ký GĐ" derive từ **`InitialSigned`/`SealedCopy`**, KHÔNG từ `ScannedSigned` — review F-C6: `ScannedSigned=2` nghĩa "scan có chữ ký NCC ở DangInKy", proxy-predicate sai vai b.19 GĐ, gotcha #71).
|
2. **BE nhỏ**: (a) 🔄 **0 enum-extend (@S161 — supersede bản trước):** dùng `SealedCopy` CÓ SẴN (`ContractAttachment.cs:5-11`); ~~`InitialSigned=4` + `CoverChecklist=5`~~ **BỎ** theo 1-mốc (slot 4/5 vẫn trống cho tương lai; F-09 cover moot — cover FO-002.01 thuộc bộ hồ sơ giấy); (b) 🔴 **thêm param `type` vào `ListContractsQuery` + controller (review F-C1/F-05 — `GET /api/contracts` HIỆN 0 CÓ `type`, `ContractsController.cs:16-24` chỉ phase/supplierId/projectId):** thêm `[FromQuery] ContractType? type` + filter handler `ContractFeatures.cs:305-307` — KHÔNG lọc client-side `pageSize:100` (trần 100/loại). (c) `ContractListItemDto` **+1 cờ derive `hasSealedCopy`** trong projection (DTO hiện 12 field `:323-327` KHÔNG trả attachments; ~~hasInitialSigned~~ BỎ @S161 — 1-mốc; 🔴 vẫn KHÔNG derive từ `ScannedSigned` — review F-C6: =2 nghĩa "scan có chữ ký NCC ở DangInKy", gotcha #71).
|
||||||
3. **FE ×2 app**: page `HardCopiesPage` (khuôn `MyContractsPage.tsx` — ĐÃ đọc đủ `type`/`phase` params `:29,:34-35`): route `/hard-copies?type=N` → list `GET /api/contracts?type=N&phase=9` + cột mã HĐ/NCC/dự án/giá trị + 2 badge derive + panel upload (3 purpose) + note theo default #9 + khối readonly GĐ3. 4-place mirror ×2 app: page + `App.tsx` route + `Layout.tsx` staticMap **re-point 7 dòng `Hdc_`** (`fe-user Layout.tsx:63-69`, mirror fe-admin) khỏi `/coming-soon?stage=4&t=NN` + types. Empty-state khi loại chưa có HĐ phát hành.
|
3. **FE ×2 app**: page `HardCopiesPage` (khuôn `MyContractsPage.tsx` — ĐÃ đọc đủ `type`/`phase` params `:29,:34-35`): route `/hard-copies?type=N` → list `GET /api/contracts?type=N&phase=9` + cột mã HĐ/NCC/dự án/giá trị + **1 badge derive** (`hasSealedCopy`) + panel upload (**1 purpose `SealedCopy`** + note tùy chọn default #9) + khối LevelOpinions readonly (@S161 1-mốc). 4-place mirror ×2 app: page + `App.tsx` route + `Layout.tsx` staticMap **re-point 7 dòng `Hdc_`** (`fe-user Layout.tsx:63-69`, mirror fe-admin) khỏi `/coming-soon?stage=4&t=NN` + types. Empty-state khi loại chưa có HĐ phát hành.
|
||||||
4. **Authz**: 🔴 anh chốt **O-A (để mở)** ⇒ Contract giữ `[Authorize]` trần, **KHÔNG gắn policy mới** cho trang Hdc/upload — mọi user auth thao tác được (đúng "hiển thị hết để góp ý"; rủi ro attachment-IDOR disclose plan §4.7). *(Nếu sau này anh bật O-B thì mới dùng `Contracts.{Read,Update}` — Contracts ∈ All `:168`, policy sống sẵn.)*
|
4. **Authz**: 🔴 anh chốt **O-A (để mở)** ⇒ Contract giữ `[Authorize]` trần, **KHÔNG gắn policy mới** cho trang Hdc/upload — mọi user auth thao tác được (đúng "hiển thị hết để góp ý"; rủi ro attachment-IDOR disclose plan §4.7). *(Nếu sau này anh bật O-B thì mới dùng `Contracts.{Read,Update}` — Contracts ∈ All `:168`, policy sống sẵn.)*
|
||||||
5. Build ×2 + test + commit. cicd: byte-marker + menu KHÔNG đổi (142 giữ — chỉ re-point staticMap FE, seeder không đụng).
|
5. Build ×2 + test + commit. cicd: byte-marker + menu KHÔNG đổi (142 giữ — chỉ re-point staticMap FE, seeder không đụng).
|
||||||
|
|
||||||
@ -32,5 +30,5 @@ Readonly từ GĐ3 (F-11): khối "Ký nháy & cover b.17-18" hiển thị từ
|
|||||||
- [ ] 🔴 Prod ③ — 2 loại KHÁC NHAU ra 2 danh sách KHÁC NHAU (chứng `type` lọc, review F-C1): `GET /api/contracts?type=1&phase=9` ≠ `?type=2&phase=9` (khi có ≥1 HĐ mỗi loại); mọi item `phase==9`. Byte-marker bundle #77.
|
- [ ] 🔴 Prod ③ — 2 loại KHÁC NHAU ra 2 danh sách KHÁC NHAU (chứng `type` lọc, review F-C1): `GET /api/contracts?type=1&phase=9` ≠ `?type=2&phase=9` (khi có ≥1 HĐ mỗi loại); mọi item `phase==9`. Byte-marker bundle #77.
|
||||||
- [ ] 🔴 Prod ③ — VAI THẬT thấy được (review F-C2/F-01, phụ thuộc W6): login actor bản-cứng non-admin (Director b.19 / HrAdmin b.20 / CostControl b.21) → trang Bảng cứng ≥1 dòng, KHÔNG rỗng/403.
|
- [ ] 🔴 Prod ③ — VAI THẬT thấy được (review F-C2/F-01, phụ thuộc W6): login actor bản-cứng non-admin (Director b.19 / HrAdmin b.20 / CostControl b.21) → trang Bảng cứng ≥1 dòng, KHÔNG rỗng/403.
|
||||||
- [ ] Ca ÂM: leaf loại 0 HĐ phát hành → empty-state, KHÔNG 500.
|
- [ ] Ca ÂM: leaf loại 0 HĐ phát hành → empty-state, KHÔNG 500.
|
||||||
- [ ] Upload 3 purpose trên HĐ ZZTEST DaPhatHanh → 2 badge lật đúng; note b.21 có đủ {số bộ, giao CCM/NTP, nơi lưu}.
|
- [ ] Upload `SealedCopy` trên HĐ ZZTEST DaPhatHanh → badge "Đã lưu bản cứng" lật đúng (1 badge — @S161); note tùy chọn lưu + hiển thị lại được.
|
||||||
**C. Rủi ro:** [ ] mirror mù 6-leaf (grounding cũ) — menu Hdc là 7-leaf-per-type owner vẽ, KHÔNG tự đẻ key (gotcha #84) · [ ] upload không phase-guard là HÀNH VI HIỆN TRẠNG (up được mọi phase) — W7 không siết (đó là W8-authz nếu chọn) · [ ] khai lệch b.20 gộp b.21 trong UI (tooltip/label) để user không tưởng thiếu trạm.
|
**C. Rủi ro:** [ ] mirror mù 6-leaf (grounding cũ) — menu Hdc là 7-leaf-per-type owner vẽ, KHÔNG tự đẻ key (gotcha #84) · [ ] upload không phase-guard là HÀNH VI HIỆN TRẠNG (up được mọi phase) — W7 không siết (đó là W8-authz nếu chọn) · [ ] UI ghi rõ ký GĐ/đóng dấu là bước NGOÀI hệ thống — chỉ nhận scan cuối (anh chốt 1-mốc @S161), tránh user tưởng thiếu trạm.
|
||||||
|
|||||||
26
.claude/workflows/runs/2026-07-29-S161-khkk-w1-schema/run.md
Normal file
26
.claude/workflows/runs/2026-07-29-S161-khkk-w1-schema/run.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# RUN — W1 KHKK: Schema Mig 69 + Permission + Designer type-10 (S161, 2026-07-29)
|
||||||
|
|
||||||
|
> **Wave đầu tiên của DRY-RUN TOÀN TRÌNH** (plan cha `../2026-07-29-S160-khkk-dryrun-plan/plan-cha-dry-run-toan-trinh-29-07-2026.md`).
|
||||||
|
> Spec thi công: `../2026-07-29-S160-khkk-dryrun-plan/spec-wave-w1-schema-designer-29-07-2026.md` (+ spec cũ `../2026-07-28-S157-ke-hoach-ky-ket-hd/spec-ke-hoach-ky-ket-hd-28-07-2026.md` §2.2 bảng chi tiết).
|
||||||
|
> **Gate 5-anchor: PASS 5/5 @S161** (slot 10 trống `ApprovalWorkflowsV2/ApprovalWorkflow.cs:53-67` · `MenuKeys.cs:41` const+comment · KeHoachKyKet ∉ All · `AuthorizePolicyRegressionTests.cs:138-139` lưới sống · `DbInitializer.cs:1779-1786` Khkk 7 key).
|
||||||
|
> **3 quyết owner @S161:** (1) mã phiếu `KHKK/{YYYY}/{Seq:D3}` OK · (2) "Bỏ MB" — dry-run cấm HĐ MuaBan, codegen giữ chờ format thay · (3) GĐ4 1-mốc (không đụng W1).
|
||||||
|
|
||||||
|
## taskList snapshot
|
||||||
|
|
||||||
|
| # | Stage | Vai / cách | Trạng thái |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | Đợt-1a BE: Domain 7 entity + 3 enum + ApplicableType=10 + EF Config ×7 + DbSets + **Mig 69** 3-file (apply 2 DB) + MenuKeys All+= + DbInitializer UPGRADE-if-exists (13/13 role) + CodeGen KHKK + 3 site AWV2AdminFeatures | hmw `implementer-backend` | [ ] |
|
||||||
|
| 2 | Đợt-1b FE: Designer type-10 `ApprovalWorkflowsV2Page.tsx` (TYPE_CODE_TO_INT + option + ẩn 2 checkbox early-finalize khi type=10) | hmw `implementer-frontend` | [ ] |
|
||||||
|
| 3 | Đợt-2a: schema test + codegen format test (`ContractSigningPlanSchemaTests` + `SigningPlanCodeGenerator_Format_KhkkYearSeqD3`, N ≥ 2) | hmw `test-specialist` | [ ] |
|
||||||
|
| 4 | Đợt-2b: design-review Mig 69 TRƯỚC deploy (reversible Down · snapshot drift · FK/index) | hmw `database-agent` | [ ] |
|
||||||
|
| 5 | Lead: build ×2 + `dotnet test` + sqlcmd 89→96 + Down-script sạch + acceptance §③-B sweep | lead | [ ] |
|
||||||
|
| 6 | Reviewer adversarial diff (schema mig >50 LOC — bắt buộc trước commit) | `reviewer` | [ ] |
|
||||||
|
| 7 | Commit + push + cicd-monitor 3-chân-kiềng (CI PASS · mig 69 prod · menu 142 giữ) | lead + `cicd-monitor` | [ ] |
|
||||||
|
|
||||||
|
## Ràng buộc mang theo
|
||||||
|
- 🔴 Seeder = **UPGRADE-if-exists khuôn `SeedProcurementMasterAccessAsync:2367-2374` + mở rộng vế CanDelete**, chạy SAU revoke (mirror `:2098-2101`) — KHÔNG insert (F-S1, 403 giết dry-run) · CẤM SQL tay (#84).
|
||||||
|
- 🔴 Acceptance đo CỜ không đếm ROW (F-04) · UNIQUE filtered WHERE IsDeleted=0 (#57) · enum bắt đầu 1 không 0 (falsy JS) · loose-Guid không FK vật lý sang PE/Supplier (convention Mig 49).
|
||||||
|
- 🔴 Lead commit SAU reviewer — worker KHÔNG commit/push.
|
||||||
|
|
||||||
|
## Stages
|
||||||
|
(cập nhật theo tiến độ)
|
||||||
Reference in New Issue
Block a user