[CLAUDE] Contract: K4a+K4b SP-002 sidebar 8 nhom x 6 leaf + noi ?group= end-to-end (0-mig)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 6m23s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 6m23s
K4a (gate PASS-WITH-FLAGS 4, sub-reviewer-gate-k4a.md): 49 key Khkk_G{2-8} bo-sinh
by-construction 3-phia (All/seed/grant) MenuKeys.cs + DbInitializer 49 row + labelBackfill
G1 nhan A1 + site-2 Concat + va 7/10/11/13/15 (nhan N2 co "pha do"; comment 1893 -> mo-neo
grep). All 64->113, Policies 256->452 (test T2 khoa runtime). Test +7 KhkkGroupMenuSeedTests
(T7 revoker-khong-dung-Khkk: probe vi-phan 112->0, gotcha #84).
K4b (gate PASS-WITH-FLAGS 4M/5m 0-chan, sub-reviewer-gate-k4b.md): KhkkListPage x2 derive
phase+group tu searchParams (leaf->leaf khong F5, navKey reset) + queryKey {group,phase,
search,page,deletedView} + KhkkCreatePage preset ?group= + staticMap G1 6-leaf group=1 +
regex Khkk_G([1-8])_* fe-user (fe-admin GHI RANG BUOC isAdminHidden) + FLAG-1 lead-fix:
GET /deleted +group mirror List (Controller+Query+handler SAU-IDOR) + FE noi 2-nhanh.
2 wave 1 commit CO KHAI: Layout.tsx dinh ca 2 wave khong tach hunk phi-tuong-tac; moi dong
deu qua gate rieng. STATUS canonical 5-row dong bo (71/97/452/113/620->621) + bundle :479.
No K4c: MAJOR-A test /deleted+group filter + MAJOR-C WfView doc group. Suite 621/0
(45D+576I) + filter 41/41 + npm x2 + dotnet 0E.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@ -1953,7 +1953,11 @@ public static class DbInitializer
|
||||
// [S159-đợt3] skeleton menu GĐ2/GĐ4 (owner vẽ: "viết hoa + phân list như
|
||||
// Duyệt NCC" / "thêm Sub đánh số như Duyệt Hợp đồng"). Root CÓ CON ⇒ render
|
||||
// MenuGroup uppercase tự động. Leaves → /coming-soon (staticMap ×2 app).
|
||||
("Khkk_G1", "1. Kế hoạch ký kết HĐ (NCC-TP)", MenuKeys.KeHoachKyKet, 1, "FileCheck"),
|
||||
// [K4a — S166] Nhóm 1 trong 8 NHÓM DUYỆT (danh mục SP-002): nhãn skeleton S159
|
||||
// "1. Kế hoạch ký kết HĐ (NCC-TP)" → nhãn nhóm A1. Key `Khkk_G1` GIỮ NGUYÊN;
|
||||
// DB đang chạy hội tụ qua `labelBackfill` bên dưới (dòng này chỉ ăn với DB trống).
|
||||
// 7 nhóm còn lại (G2..G8) seed ở vòng lặp phía dưới (sau vòng `PeWf_*`).
|
||||
("Khkk_G1", "1. Thiết bị, máy móc, vật tư phụ (A1)", MenuKeys.KeHoachKyKet, 1, "FileCheck"),
|
||||
// [S159-đợt5 owner] đủ 6 leaf "y chang Duyệt NCC" (WfView đầu + Deleted cuối).
|
||||
("Khkk_WfView", "Luồng duyệt", "Khkk_G1", 1, "Network"),
|
||||
("Khkk_List", "Danh sách", "Khkk_G1", 2, "List"),
|
||||
@ -2092,8 +2096,8 @@ public static class DbInitializer
|
||||
tree.Add((MenuKeys.PurchaseEvaluationList(code), "Danh sách", MenuKeys.PurchaseEvaluationGroup(code), peOrder++, "List"));
|
||||
tree.Add((MenuKeys.PurchaseEvaluationCreate(code), "Thao tác", MenuKeys.PurchaseEvaluationGroup(code), peOrder++, "Plus"));
|
||||
// [S155 đợt 2] Nhãn ở đây CHỈ có tác dụng cho DB TRỐNG. Với DB đang chạy, upsert
|
||||
// `:1893-1905` gặp key đã tồn tại thì chỉ update `Order` rồi `continue` — KHÔNG
|
||||
// đụng Label ⇒ rename "Duyệt" → "Đang duyệt" phải qua `labelBackfill` bên dưới.
|
||||
// `:2162-2179` (grep `existingItems.TryGetValue`) gặp key đã tồn tại thì chỉ update
|
||||
// `Order` rồi `continue` ⇒ rename "Duyệt" → "Đang duyệt" phải qua `labelBackfill`.
|
||||
tree.Add((MenuKeys.PurchaseEvaluationPending(code), "Đang duyệt", MenuKeys.PurchaseEvaluationGroup(code), peOrder++, "CheckCircle2"));
|
||||
// 2 mục MỚI (owner chốt 2026-07-27) — key mới ⇒ đi nhánh INSERT bình thường.
|
||||
tree.Add((MenuKeys.PurchaseEvaluationApproved(code), "Đã duyệt", MenuKeys.PurchaseEvaluationGroup(code), peOrder++, "CheckCheck"));
|
||||
@ -2108,6 +2112,50 @@ public static class DbInitializer
|
||||
tree.Add((MenuKeys.PeWorkflowTypeLeaf(code), label, MenuKeys.PeWorkflows, peWfOrder++, "FileCheck"));
|
||||
}
|
||||
|
||||
// [K4a — S166] Sidebar KHKK 8 NHÓM DUYỆT × 6 leaf — 49 row MỚI cho nhóm 2..8
|
||||
// (nhóm 1 = 7 row CŨ KHÔNG-infix nằm trong tree initializer trên: `Khkk_G1` +
|
||||
// `Khkk_WfView`…`Khkk_Deleted`, key GIỮ NGUYÊN — đổi = mồ côi permission-row, S155).
|
||||
// Nhãn 8 nhóm = bảng owner đã soát `danh-muc-sp002-transcribe.md:22-29` (nguồn: danh
|
||||
// mục SOL-CCM-SP-002 Mig 70 chia 86 dòng thành 8 nhóm duyệt). Nhãn/icon/Order của 6
|
||||
// leaf MIRROR Y nhóm 1 (Luồng duyệt/Danh sách/Thao tác/Đang duyệt/Đã duyệt/Đã xóa).
|
||||
// 🔴 Key sinh bằng CHÍNH `MenuKeys.KhkkGroup/KhkkLeaf` + duyệt CHÍNH `KhkkGroupNumbers`/
|
||||
// `KhkkLeafActions` ⇒ mọi key trong `MenuKeys.All` đều có menu-row by-construction
|
||||
// (thiếu row = Permission FK nổ lần boot đầu — invariant T6 K1). Thêm nhóm/action mà
|
||||
// quên nhãn ⇒ KeyNotFoundException NGAY lúc seed (fail-fast, hơn là FK nổ về sau).
|
||||
// ⚠️ Đổi NHÃN sau khi đã seed: BẮT BUỘC thêm entry vào `labelBackfill` bên dưới +
|
||||
// restart — sửa chữ tại đây VÔ TÁC DỤNG trên DB đang chạy (upsert chỉ re-set Order).
|
||||
var khkkGroupLabels = new Dictionary<int, string>
|
||||
{
|
||||
[2] = "2. Kết cấu, hạ tầng, phá dỡ & DV hỗ trợ thi công (A2-A3)",
|
||||
[3] = "3. Hoạt động văn phòng (A4)",
|
||||
[4] = "4. Vật tư (B1)",
|
||||
[5] = "5. Thầu phụ xây dựng (B2)",
|
||||
[6] = "6. Thầu phụ MEP (B3)",
|
||||
[7] = "7. BCH công trường (C1-C3)",
|
||||
[8] = "8. HĐ chưa ủy quyền — CEO (5.2)",
|
||||
};
|
||||
var khkkLeafMeta = new Dictionary<string, (string Label, string Icon)>
|
||||
{
|
||||
["WfView"] = ("Luồng duyệt", "Network"),
|
||||
["List"] = ("Danh sách", "List"),
|
||||
["Create"] = ("Thao tác", "Plus"),
|
||||
["Pending"] = ("Đang duyệt", "CheckCircle2"),
|
||||
["Approved"] = ("Đã duyệt", "CheckCheck"),
|
||||
["Deleted"] = ("Đã xóa", "Trash2"),
|
||||
};
|
||||
foreach (var n in MenuKeys.KhkkGroupNumbers)
|
||||
{
|
||||
var groupKey = MenuKeys.KhkkGroup(n);
|
||||
// Order nhóm = n (nhóm 1 đang Order 1 ⇒ 8 nhóm xếp 1..8 dưới root KeHoachKyKet).
|
||||
tree.Add((groupKey, khkkGroupLabels[n], MenuKeys.KeHoachKyKet, n, "FileCheck"));
|
||||
var khkkLeafOrder = 1;
|
||||
foreach (var action in MenuKeys.KhkkLeafActions)
|
||||
{
|
||||
var (leafLabel, leafIcon) = khkkLeafMeta[action];
|
||||
tree.Add((MenuKeys.KhkkLeaf(n, action), leafLabel, groupKey, khkkLeafOrder++, leafIcon));
|
||||
}
|
||||
}
|
||||
|
||||
var existingItems = await db.MenuItems.ToDictionaryAsync(m => m.Key);
|
||||
var added = 0;
|
||||
var reordered = 0;
|
||||
@ -2146,7 +2194,7 @@ public static class DbInitializer
|
||||
[MenuKeys.PeWorkflowTypeLeaf("DuyetNccPhuongAn")] = "Duyệt NCC và Giải pháp",
|
||||
// [S155 đợt 2] 🔴 Rename "Duyệt" → "Đang duyệt" (owner, ảnh menu 2026-07-27).
|
||||
// BẮT BUỘC đi qua đây: sửa chữ trong `tree.Add(...)` là VÔ TÁC DỤNG trên DB đang
|
||||
// chạy vì upsert `:1893-1905` chỉ update `Order` cho key đã tồn tại.
|
||||
// chạy vì upsert `:2162-2179` (grep `existingItems.TryGetValue`) chỉ re-set `Order`.
|
||||
[MenuKeys.PurchaseEvaluationPending("DuyetNcc")] = "Đang duyệt",
|
||||
[MenuKeys.PurchaseEvaluationPending("DuyetNccPhuongAn")] = "Đang duyệt",
|
||||
// [S159] 🔴 UAT anh Kiệt: đánh số 01.-07. nhóm HĐ (verbatim "01 . HĐ thầu phụ").
|
||||
@ -2180,6 +2228,11 @@ public static class DbInitializer
|
||||
[MenuKeys.ContractTypeGroup("MuaBan")] = "05. HĐ Mua bán",
|
||||
[MenuKeys.ContractTypeGroup("NguyenTacNcc")] = "06. HĐ Nguyên tắc NCC",
|
||||
[MenuKeys.ContractTypeGroup("NguyenTacDv")] = "07. HĐ Nguyên tắc Dịch vụ",
|
||||
// [K4a — S166] Nhóm 1 KHKK đổi nhãn skeleton S159 ("1. Kế hoạch ký kết HĐ
|
||||
// (NCC-TP)") → nhãn nhóm duyệt A1, khớp bảng 8 nhãn owner đã soát. CHỈ đổi
|
||||
// Label, KHÔNG đổi key ⇒ 0 row mới, 0 permission-row mồ côi. 7 nhóm G2..G8 là
|
||||
// key MỚI nên đi nhánh INSERT của upsert, không cần entry backfill.
|
||||
["Khkk_G1"] = "1. Thiết bị, máy móc, vật tư phụ (A1)",
|
||||
};
|
||||
var updatedLabels = 0;
|
||||
foreach (var (key, expectedLabel) in labelBackfill)
|
||||
@ -2282,6 +2335,9 @@ public static class DbInitializer
|
||||
// Cá nhân (Personal) khỏi MỌI role TRỪ Admin. Menu tự ẩn cả 2 app
|
||||
// (GetMyMenuTree lọc CanRead). Chạy SAU grant seed để revoke thắng.
|
||||
// Mở lại sau golive: gỡ prefix khỏi revoke + thêm lại vào InReviewScope.
|
||||
// [K4a — S166] Đã soi revoker cho 49 key KHKK mới: filter chỉ bắt prefix `Hrm*`/`Off*`
|
||||
// + key `Personal` ⇒ **0 match `Khkk_*`** ⇒ 49 row CanRead vừa cấp KHÔNG bị lật. Phép
|
||||
// thử của khẳng định này = restart API ×2 rồi đếm lại row `Khkk%` (acceptance A5).
|
||||
await RevokeTemporarilyHiddenModulesAsync(db, roleManager, logger);
|
||||
|
||||
// [S118 2026-07-14 — anh Kiệt FDC] CHẠY SAU revoke để THẮNG: NGOẠI-LỆ role Procurement
|
||||
@ -2370,11 +2426,24 @@ public static class DbInitializer
|
||||
MenuKeys.CatalogServices, MenuKeys.CatalogWorkItems, MenuKeys.Departments,
|
||||
MenuKeys.Projects, MenuKeys.Suppliers,
|
||||
};
|
||||
// [S159] 7 key nhóm 1 (không-infix) + [K4a S166] 49 key nhóm 2..8 (7 group + 42 leaf,
|
||||
// sinh từ `MenuKeys.KhkkGroupMenuKeys` — CÙNG bộ sinh với `MenuKeys.All` và vòng seed
|
||||
// menu-row ⇒ không mirror tay). CanRead mọi role, skip-existing.
|
||||
// 🔴 LÝ DO GIỮ site này (đính chính lý-do sai đang lưu hành "group-key cần row để
|
||||
// render"): group KHÔNG cần row CanRead của chính nó — `GetMyMenuTreeQuery.cs:96`
|
||||
// `HasAccess(n) = n.CanRead || n.Children.Any(HasAccess)`. Cái BẮT BUỘC là 42 LEAF
|
||||
// phải có row CanRead cho non-Admin: site-1 (loop MenuKeys.All) CHỈ cấp Admin, còn
|
||||
// site-3 `SeedKeHoachKyKetAccessAsync` CHỈ đụng root + 6 leaf nhóm 1. Group vẫn liệt
|
||||
// kê ở đây để có hàng tường minh trên ma trận Phân quyền (admin tự bật/tắt).
|
||||
// ⚠️ CanRead là ĐỦ cho 42 leaf mới, KHÔNG cần nhét chúng vào site-3: mọi endpoint KHKK
|
||||
// gate bằng policy `KeHoachKyKet.{Read,Create,Update,Delete}` (gotcha #85 — gate FE
|
||||
// cũng phải dùng đúng key đó, KHÔNG OR key con), và cờ GHI của root do site-3 phát
|
||||
// (13/13 role C+U, Delete = Drafter+Admin). Leaf chỉ là điểm điều hướng.
|
||||
static IEnumerable<string> KhkkKeys() => new[]
|
||||
{
|
||||
"Khkk_G1", "Khkk_WfView", "Khkk_List", "Khkk_Create", "Khkk_Pending",
|
||||
"Khkk_Approved", "Khkk_Deleted",
|
||||
};
|
||||
}.Concat(MenuKeys.KhkkGroupMenuKeys);
|
||||
static IEnumerable<string> HdcKeys()
|
||||
=> MenuKeys.ContractTypeCodes.Select(c => "Hdc_" + c);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user