[CLAUDE] Infra: go nhanh S92 khoi revoker (owner supersede: hien thi het) + skeleton menu GD2/GD4 + ComingSoonPage x2
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m56s

- RevokeTemporarilyHiddenModulesAsync: GO Contracts+Ct_*/Master-set khoi predicate (bai tra gia: grant SQL tay bi revoker lat o restart #423 - 447/494 row roi; regrant=447 da chay truoc commit nay). Hrm/Off/Personal GIU (y owner: vung dang-lam chi admin)
- reviewKeys += ContractMenuKeys + MasterMenuKeys + KhkkKeys + HdcKeys (CanRead-only all-role, fresh-env hoi tu)
- Seeder tree.Add: Khkk_G1 + 4 leaves (khuon Duyet NCC) + Hdc_x7 (tai dung nhan 01.-07.) - prod da INSERT truc tiep (perm=156)
- ComingSoonPage mirror x2 (md5-identical) + route /coming-soon x2 + staticMap 11 leaf x2 (gotcha #50)
- Test: AdminOnlyModulesRevokeTests tach StillHidden/Reopened + REGRESSION-GUARD S159 (re-add nhanh S92 => do); ProcurementMasterAccessSeedTests doc lai isolation bang CO CAO (spec-change S92->S159, update test + code chung commit)
- 562 test PASS - nghiem thu cuoi = restart THAT khi deploy run nay (khuon S91)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-07-29 12:34:15 +07:00
parent b5a7dd8a92
commit 2a7269581c
9 changed files with 234 additions and 27 deletions

View File

@ -1773,6 +1773,14 @@ public static class DbInitializer
// FE staticMap trỏ /dashboard. Prod đã INSERT trực tiếp cùng ngày (idempotent ở đây).
(MenuKeys.KeHoachKyKet, "Kế hoạch ký kết HĐ", null, 26, "FileSignature"),
(MenuKeys.HopDongCung, "Hợp đồng cứng", null, 32, "Stamp"),
// [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"),
("Khkk_List", "Danh sách", "Khkk_G1", 1, "List"),
("Khkk_Create", "Thao tác", "Khkk_G1", 2, "Plus"),
("Khkk_Pending", "Đang duyệt", "Khkk_G1", 3, "CheckCircle2"),
("Khkk_Approved", "Đã duyệt", "Khkk_G1", 4, "CheckCheck"),
(MenuKeys.Forms, "Biểu mẫu", null, 40, "FileSpreadsheet"),
(MenuKeys.Reports, "Báo cáo", null, 50, "BarChart3"),
(MenuKeys.System, "Hệ thống", null, 90, "Settings"),
@ -1847,9 +1855,13 @@ public static class DbInitializer
// Per-type sub-menu under Contracts: 1 group + 3 leaves each
// (Danh sách / Thao tác / Duyệt).
var order = 31;
var hdcOrder = 1;
foreach (var code in MenuKeys.ContractTypeCodes)
{
var label = typeLabels.GetValueOrDefault(code, code);
// [S159-đợt3] GĐ4 skeleton — 1 leaf/loại HĐ dưới root Hợp đồng cứng, tái dùng
// đúng nhãn đã đánh số 01.-07. (leaf → /coming-soon?stage=4).
tree.Add(("Hdc_" + code, label, MenuKeys.HopDongCung, hdcOrder++, "FileText"));
tree.Add((MenuKeys.ContractTypeGroup(code), label, MenuKeys.Contracts, order++, "FileText"));
tree.Add((MenuKeys.ContractTypeList(code), "Danh sách", MenuKeys.ContractTypeGroup(code), order++, "List"));
tree.Add((MenuKeys.ContractTypeCreate(code), "Thao tác", MenuKeys.ContractTypeGroup(code), order++, "Plus"));
@ -2115,6 +2127,31 @@ public static class DbInitializer
// → "PeWf_*"/"PeWorkflows" KHÔNG match (loại admin Designer).
static bool IsPeKey(string key) => key.StartsWith("Pe_");
// [S159] các bộ key grant CanRead-only mọi role (xem chú thích tại reviewKeys).
static IEnumerable<string> ContractMenuKeys()
{
yield return MenuKeys.Contracts;
foreach (var c in MenuKeys.ContractTypeCodes)
{
yield return MenuKeys.ContractTypeGroup(c);
yield return MenuKeys.ContractTypeList(c);
yield return MenuKeys.ContractTypeCreate(c);
yield return MenuKeys.ContractTypePending(c);
}
}
static IEnumerable<string> MasterMenuKeys() => new[]
{
MenuKeys.Master, MenuKeys.Catalogs, MenuKeys.CatalogUnits, MenuKeys.CatalogMaterials,
MenuKeys.CatalogServices, MenuKeys.CatalogWorkItems, MenuKeys.Departments,
MenuKeys.Projects, MenuKeys.Suppliers,
};
static IEnumerable<string> KhkkKeys() => new[]
{
"Khkk_G1", "Khkk_List", "Khkk_Create", "Khkk_Pending", "Khkk_Approved",
};
static IEnumerable<string> HdcKeys()
=> MenuKeys.ContractTypeCodes.Select(c => "Hdc_" + c);
// MenuKeys.All chứa root PurchaseEvaluations nhưng KHÔNG chứa Pe_* leaf
// (sinh động qua factory). Build leaf giống SeedPurchaseEvaluationPermissionDefaultsAsync
// để upgrade đúng row Pe_* thật trong DB (1 root + 5 leaf × 2 type).
@ -2137,6 +2174,14 @@ public static class DbInitializer
// [S159] 2 root placeholder GĐ2/GĐ4 — CanRead-only mọi role (IsPeKey=false
// ⇒ nhánh read-only). Prod đã INSERT trực tiếp; đây giữ fresh-DB hội tụ.
.Concat(new[] { MenuKeys.KeHoachKyKet, MenuKeys.HopDongCung })
// [S159] skeleton GĐ2 (Khkk_*) + GĐ4 (Hdc_*) — leaves trỏ /coming-soon.
.Concat(KhkkKeys()).Concat(HdcKeys())
// [S159] owner "hiển thị hết": HĐ (Contracts+Ct_*) + DANH MỤC (Master-set)
// CanRead-only mọi role — cặp với việc GỠ nhánh [S92] khỏi revoker ở trên.
// Lưu ý: nhánh grant key-thường là skip-existing ⇒ trên prod row false
// KHÔNG được nâng ở đây — re-grant prod đã chạy SQL trực tiếp cùng ngày;
// đây là đường hội tụ cho fresh-DB/env khác.
.Concat(ContractMenuKeys()).Concat(MasterMenuKeys())
.Distinct()
.ToArray();
var roles = await roleManager.Roles.ToListAsync();
@ -2214,14 +2259,16 @@ public static class DbInitializer
var rows = await db.Permissions
.Where(p => p.RoleId != adminRoleId
&& (p.MenuKey.StartsWith("Hrm") || p.MenuKey.StartsWith("Off")
|| p.MenuKey == MenuKeys.Personal
// [S92 2026-06-29] +Hợp đồng (Contracts + Ct_*) + Danh mục (Master +
// Suppliers + Projects + Departments + Catalog*) — anh chốt "chỉ Admin
// thấy". Pe_* (Duyệt NCC) KHÔNG nằm đây → module PE giữ nguyên cho user.
|| p.MenuKey == MenuKeys.Contracts || p.MenuKey.StartsWith("Ct_")
|| p.MenuKey == MenuKeys.Master || p.MenuKey == MenuKeys.Suppliers
|| p.MenuKey == MenuKeys.Projects || p.MenuKey == MenuKeys.Departments
|| p.MenuKey.StartsWith("Catalog"))
|| p.MenuKey == MenuKeys.Personal)
// [S159 2026-07-29] 🔴 GỠ nhánh [S92] (Contracts+Ct_* / Master+Suppliers+
// Projects+Departments+Catalog*) — owner SUPERSEDE chính quyết định S92
// "chỉ Admin thấy": nay "đang phát triển → cho hiển thị hết để mọi người
// góp ý; Duyệt NCC để như cũ". Bài trả giá cùng ngày: grant 38 key bằng
// SQL tay bị CHÍNH revoker này lật lại ở app-restart kế (Run #423 —
// 447/494 row rơi, 11/13 role về 0; cicd-verify-1a47a61.md mục 9).
// Đúng chiều-ngược gotcha #75/#76: seeder ungated thắng data-change tay
// ⇒ đổi trạng-thái bền = đổi CODE, nghiệm thu = restart THẬT.
// Hrm*/Off*/Personal GIỮ trong revoker (vùng đang-làm, ý ❸ owner).
&& (p.CanRead || p.CanCreate || p.CanUpdate || p.CanDelete))
.ToListAsync();