Compare commits

...

2 Commits

Author SHA1 Message Date
55494ad477 [CLAUDE] Infra: gate SeedDemoMasterData sau DemoSeed:Disabled (chống resurrect NCC demo go-live)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m10s
Sau wipe 18 NCC demo (scripts/s91-wipe-golive.sql, go-live anh Kiệt FDC 26/06), phát hiện
SeedDemoMasterDataAsync chạy UNGATED + per-code idempotent (skip-if-code-exists else Add) ->
mỗi restart / IIS recycle TỰ ADD lại 18 NCC demo (NCC-VLXD / CDT-VIN / Sun Group ...) ->
undo danh sách NCC sạch anh Kiệt vừa chốt.

Fix: gate SeedDemoMasterDataAsync (Supplier + Project DEMO) sau cờ DemoSeed:Disabled, mirror
cách Contracts/PE/Workflow demo đã gated. Prod hiệu lực Disabled=true (appsettings.json deployed;
appsettings.Production.json render từ .example KHÔNG có DemoSeed -> fallback appsettings.json=true,
đúng fallback đã giữ contracts/PE gated nhiều tháng). -> SKIP -> wipe BỀN qua restart. Dev
Disabled=false -> vẫn seed demo local. Master data THẬT (SeedRealMasterDataAsync: 62 dự án + 71
hạng mục + 3 NCC) ungated -> KHÔNG ảnh hưởng.

User test (38) đã an toàn từ S89 (gỡ khỏi mảng SeedDemoUsers). Build slnx OK 0 warn / 0 err.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 10:53:25 +07:00
ba42c59430 [CLAUDE] Scripts: S91 go-live wipe data UAT (prod-executed 26/06)
anh Kiệt FDC chỉ đạo "xóa data cũ" trước go-live Phase-01 (PRO+CCM) hôm nay 26/06.
Quy trình destructive-prod chuẩn S85/S89: recon -> AskUserQuestion chốt scope ->
backup -> wipe atomic (XACT_ABORT + 2 guard) -> verify exact.

Đã chạy prod (.\SQLEXPRESS / SolutionErp); backup SolutionErp_S91_pregolivewipe.bak (2705 pages):
- Xóa: 16 PE (+cascade child Suppliers/Quotes/Attachments/Changelogs -> 0) · 16 PeWorkItemBudgets
       · 94 Notifications · 19 NCC demo (CreatedAt < 2026-06-01)
- Giữ: 7 NCC thật (06-09 x3 + 06-23 x4) · 70 Projects · 71 WorkItems · 17 Users · 8 Workflows
- Reset PeSeq -> phiếu thật đầu tiên = PE/2026/A/001
- Guard A: PE > 16 -> ABORT (chống xóa phiếu thật mới tạo sau recon, go-live day)
- Guard B: NCC demo deleted <> 19 -> ROLLBACK toàn bộ

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 10:21:12 +07:00
2 changed files with 141 additions and 6 deletions

128
scripts/s91-wipe-golive.sql Normal file
View File

@ -0,0 +1,128 @@
-- ============================================================================
-- S91 (2026-06-26) — GO-LIVE wipe: xóa data UAT cũ trước khi vận hành thật
-- Chỉ đạo: anh Kiệt FDC (Zalo "em chưa xoá data cũ giúp anh" + "múc nó phát em").
-- Go-live chính thức HÔM NAY 26/06 — Phase 01 Phòng Mua hàng (PRO) +
-- Phòng Kiểm soát chi phí (CCM). Quy trình destructive-prod chuẩn S85/S89:
-- recon -> AskUserQuestion chốt scope -> script committed -> backup -> chạy -> verify.
--
-- Recon prod 2026-06-26 (read-only): PE=16 · PeWorkItemBudgets=16 · Contracts=0 ·
-- Notifications=94 · Suppliers=26 (19 demo tháng 4 + 3 thật 06-09 + 4 thật 06-23) ·
-- Users=17 · Projects=70 · WorkItems=71 · Workflows=8 · PeSeq=1 · CtSeq=0.
--
-- Anh chốt (AskUserQuestion S91):
-- - PeWorkItemBudgets (16) -> XÓA hết (start fresh; PRO/CCM nhập lại khi có phiếu thật).
-- - Suppliers -> GIỮ 7 NCC THẬT (CreatedAt >= 2026-06-01: 3 ngày 06-09 + 4 ngày 06-23),
-- XÓA 19 demo (CreatedAt < 2026-06-01: NCC-TEST-002 + 18 seed tên-giả Vingroup/SunGroup…).
-- (Lưu ý: S85 cắt theo 06-11 = SAI cho lần này — 4 NCC thật nằm SAU 06-11. Dùng mốc 06-01:
-- toàn bộ demo ở tháng 4, toàn bộ NCC thật ở tháng 6 -> cắt 06-01 sạch, không nhập nhằng.)
--
-- XÓA: 16 PurchaseEvaluations (cascade child: Suppliers/Details/Quotes/Approvals/
-- Changelogs/Attachments/LevelOpinions/DeptOpinions) · 16 PeWorkItemBudgets
-- (loose-Guid per Dự-án×Hạng-mục — KHÔNG cascade -> DELETE riêng) · 0 Contracts ·
-- 94 Notifications · 19 Suppliers demo (CreatedAt < 2026-06-01) · PeSeq + CtSeq reset
-- (DELETE row -> generator INSERT lại LastSeq=1 -> phiếu thật đầu = PE/2026/A/001).
-- GIỮ: 7 Suppliers thật · Projects 70 · WorkItems 71 · Users 17 · Permissions/MenuItems/
-- Roles · ApprovalWorkflows 8 (+Steps/Levels/Approvers — KHÔNG đụng config) ·
-- ContractTemplates · HRM/Office master · EmployeeCodeSequences · AuditLog (giữ trail).
-- FK: PE child ALL CASCADE (proven S59/S85). Suppliers xóa SAU PE (đã giải phóng
-- SelectedSupplierId/Quotes). 7 NCC giữ đều unreferenced sau khi PE bị xóa.
-- GUARD: (a) PE > 16 -> ABORT (go-live day: có thể có phiếu THẬT mới tạo sau recon —
-- dừng để check, KHÔNG xóa nhầm phiếu thật). (b) Suppliers xóa <> 19 -> ROLLBACK.
-- Safety: SET XACT_ABORT ON + BACKUP bước 0 ngoài tran + chạy sqlcmd -b (backup fail -> abort
-- TRƯỚC wipe). Atomic: mọi guard fail -> ROLLBACK toàn bộ. Resurrect-safe: DemoSeed:Disabled.
-- Run: scp -> VPS C:\temp\s91.sql ; sqlcmd -S .\SQLEXPRESS -d SolutionErp -E -i C:\temp\s91.sql -f 65001 -b
-- ============================================================================
SET QUOTED_IDENTIFIER ON;
SET ANSI_NULLS ON;
SET NOCOUNT ON;
SET XACT_ABORT ON;
GO
-- ===== 0. BACKUP insurance (NGOÀI transaction; -b -> fail thì abort trước wipe) =====
DECLARE @bkdir nvarchar(512), @bkfile nvarchar(600);
EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer', N'BackupDirectory', @bkdir OUTPUT;
SET @bkfile = @bkdir + N'\SolutionErp_S91_pregolivewipe.bak';
PRINT 'Backup device -> ' + @bkfile;
BACKUP DATABASE [SolutionErp] TO DISK = @bkfile WITH INIT, CHECKSUM, NAME = N'SolutionErp-S91-pre-golive-wipe';
GO
PRINT '=== BEFORE ===';
SELECT 'PE' AS T, COUNT(*) AS C FROM PurchaseEvaluations
UNION ALL SELECT 'PeWorkItemBudgets', COUNT(*) FROM PeWorkItemBudgets
UNION ALL SELECT 'Contracts', COUNT(*) FROM Contracts
UNION ALL SELECT 'Notifications', COUNT(*) FROM Notifications
UNION ALL SELECT 'Suppliers_total', COUNT(*) FROM Suppliers
UNION ALL SELECT 'Suppliers_demo(<06-01)', COUNT(*) FROM Suppliers WHERE CreatedAt < '2026-06-01'
UNION ALL SELECT 'Suppliers_real(>=06-01)', COUNT(*) FROM Suppliers WHERE CreatedAt >= '2026-06-01'
UNION ALL SELECT 'PeSeq', COUNT(*) FROM PurchaseEvaluationCodeSequences
UNION ALL SELECT 'CtSeq', COUNT(*) FROM ContractCodeSequences;
GO
BEGIN TRANSACTION;
-- GUARD A: go-live day — nếu có phiếu THẬT mới tạo sau recon (PE > 16) thì DỪNG, không xóa nhầm.
DECLARE @pe int = (SELECT COUNT(*) FROM PurchaseEvaluations);
IF @pe > 16
BEGIN
ROLLBACK TRANSACTION;
RAISERROR(N'GUARD-A FAIL: PE=%d > 16 (recon) — co the co phieu THAT moi tao sau recon. ABORT de check truoc khi xoa.', 16, 1, @pe);
RETURN;
END;
-- 1. Phiếu PE (cascade child)
DELETE FROM PurchaseEvaluations;
PRINT ' PurchaseEvaluations deleted : ' + CAST(@@ROWCOUNT AS varchar);
-- 2. Ngân sách per-gói-thầu (loose-Guid, KHÔNG cascade theo PE)
DELETE FROM PeWorkItemBudgets;
PRINT ' PeWorkItemBudgets deleted : ' + CAST(@@ROWCOUNT AS varchar);
-- 3. Hợp đồng (cascade child) — recon = 0
DELETE FROM Contracts;
PRINT ' Contracts deleted : ' + CAST(@@ROWCOUNT AS varchar);
-- 4. Thông báo
DELETE FROM Notifications;
PRINT ' Notifications deleted : ' + CAST(@@ROWCOUNT AS varchar);
-- 5. NCC demo (CreatedAt < 2026-06-01) — giữ 7 NCC thật (tháng 6)
DELETE FROM Suppliers WHERE CreatedAt < '2026-06-01';
DECLARE @supdel int = @@ROWCOUNT;
PRINT ' Suppliers demo deleted : ' + CAST(@supdel AS varchar);
-- GUARD B: phải xóa đúng 19 demo. Lệch -> rollback (chống xóa nhầm/sót).
IF @supdel <> 19
BEGIN
ROLLBACK TRANSACTION;
RAISERROR(N'GUARD-B FAIL: Suppliers demo deleted=%d <> 19. ROLLBACK toan bo.', 16, 1, @supdel);
RETURN;
END;
-- 6. Reset bộ đếm mã (DELETE row -> generator INSERT lại LastSeq=1 -> .../001)
DELETE FROM PurchaseEvaluationCodeSequences;
DELETE FROM ContractCodeSequences;
PRINT ' Code sequences reset (Pe+Ct)';
PRINT '=== AFTER (expect PE/budgets/notif/contracts=0, Suppliers=7, master giữ) ===';
SELECT 'PE' AS T, COUNT(*) AS C FROM PurchaseEvaluations
UNION ALL SELECT 'PeWorkItemBudgets', COUNT(*) FROM PeWorkItemBudgets
UNION ALL SELECT 'PeSuppliers', COUNT(*) FROM PurchaseEvaluationSuppliers
UNION ALL SELECT 'PeQuotes', COUNT(*) FROM PurchaseEvaluationQuotes
UNION ALL SELECT 'PeAttachments', COUNT(*) FROM PurchaseEvaluationAttachments
UNION ALL SELECT 'PeChangelogs', COUNT(*) FROM PurchaseEvaluationChangelogs
UNION ALL SELECT 'Contracts', COUNT(*) FROM Contracts
UNION ALL SELECT 'Notifications', COUNT(*) FROM Notifications
UNION ALL SELECT 'Suppliers_keep', COUNT(*) FROM Suppliers
UNION ALL SELECT 'PeSeq', COUNT(*) FROM PurchaseEvaluationCodeSequences
UNION ALL SELECT 'CtSeq', COUNT(*) FROM ContractCodeSequences
UNION ALL SELECT 'KEEP_Projects', COUNT(*) FROM Projects
UNION ALL SELECT 'KEEP_WorkItems', COUNT(*) FROM WorkItems
UNION ALL SELECT 'KEEP_Users', COUNT(*) FROM Users
UNION ALL SELECT 'KEEP_Workflows', COUNT(*) FROM ApprovalWorkflows;
PRINT '=== Suppliers GIỮ (7 NCC thật) ===';
SELECT Name, CreatedAt FROM Suppliers ORDER BY CreatedAt;
COMMIT TRANSACTION;
PRINT 'S91 go-live wipe COMMITTED.';
GO

View File

@ -71,11 +71,11 @@ public static class DbInitializer
// - SeedDemoPurchaseEvaluationsAsync ([DEMO] PE 4 sample)
// - SeedSampleApprovalWorkflowsV2Async (V2 sample mẫu UAT cho type B)
// - SeedSampleContractWorkflowV2Async (V2 sample mẫu UAT cho Contract — Mig 32 Plan B Chunk A2)
// GIỮ: SeedRoles, SeedAdmin, SeedDepartments, SeedDemoUsers (30 user UAT),
// SeedMenuTree, SeedAdminPermissions, SeedDemoMasterData (Supplier/Project
// master), SeedContractTemplates (file template), SeedCatalogs, backfill
// helpers. Production UAT clean slate: bro toàn quyền setup workflow mới
// qua Designer.
// GIỮ (ungated): SeedRoles, SeedAdmin, SeedDepartments, SeedDemoUsers (chỉ user THẬT
// — S89 đã gỡ user test khỏi mảng), SeedMenuTree, SeedAdminPermissions,
// SeedContractTemplates (file template), SeedCatalogs, SeedRealMasterData (62 dự án +
// 71 hạng mục + 3 NCC thật). [S91 2026-06-26] SeedDemoMasterData (Supplier/Project
// DEMO) ĐÃ chuyển sang GATED — prod skip để không resurrect 18 NCC demo đã wipe go-live.
var config = sp.GetRequiredService<IConfiguration>();
var demoSeedDisabled = config.GetValue<bool>("DemoSeed:Disabled");
if (demoSeedDisabled)
@ -108,7 +108,14 @@ public static class DbInitializer
await SeedMeetingRoomsAsync(db, logger);
await SeedMenuTreeAsync(db, logger);
await SeedAdminPermissionsAsync(db, roleManager, logger);
await SeedDemoMasterDataAsync(db, logger);
// [S91 2026-06-26 — anh Kiệt FDC go-live] GATE demo master (Supplier/Project demo)
// sau cờ DemoSeed:Disabled. Trước đây ungated → SeedDemoMasterDataAsync per-code
// idempotent RESURRECT 18 NCC demo (NCC-VLXD/CDT-VIN/Sun Group…) mỗi restart sau khi
// đã wipe (scripts/s91-wipe-golive.sql). Prod Disabled=true → SKIP → giữ wipe BỀN;
// Dev Disabled=false → vẫn seed demo local. Master data THẬT (62 dự án + 71 hạng mục
// + 3 NCC) đến từ SeedRealMasterDataAsync (ungated, dưới) — KHÔNG ảnh hưởng.
if (!demoSeedDisabled)
await SeedDemoMasterDataAsync(db, logger);
await SeedContractTemplatesAsync(db, logger);
if (!demoSeedDisabled)
{