From 77464d6c833dd21fad95367cbc45681b23d9d6fd Mon Sep 17 00:00:00 2001 From: nns Date: Fri, 9 Oct 2026 19:19:10 +0500 Subject: [PATCH] =?UTF-8?q?feat(prod):=20=D1=84=D0=BB=D0=B0=D0=B3=20SEED?= =?UTF-8?q?=5FDEMO=5FDATA=20=E2=80=94=20=D0=BE=D1=82=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B8=D1=82=D1=8C=20=D0=B4=D0=B5=D0=BC=D0=BE-=D0=BE?= =?UTF-8?q?=D1=80=D0=B3=20=C2=ABDemo=20Market=C2=BB=20=D0=B8=20demo-admin?= =?UTF-8?q?=20=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B4=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DevDataSeeder по умолчанию (dev/stage) сидирует демо-орг; на проде SEED_DEMO_DATA=false отключает демо-орг/demo-admin/привязку, сохраняя SuperAdmin+роли+глобальные ед.изм.+SystemSettings. Нужно для чистого (пустого) старта реального магазина. Co-Authored-By: Claude Opus 5.5 --- src/food-market.api/Seed/DevDataSeeder.cs | 96 +++++++++++++---------- 1 file changed, 55 insertions(+), 41 deletions(-) diff --git a/src/food-market.api/Seed/DevDataSeeder.cs b/src/food-market.api/Seed/DevDataSeeder.cs index 7b80d7d..f5eb877 100644 --- a/src/food-market.api/Seed/DevDataSeeder.cs +++ b/src/food-market.api/Seed/DevDataSeeder.cs @@ -43,6 +43,13 @@ public async Task StartAsync(CancellationToken ct) if (string.IsNullOrWhiteSpace(seedPassword) && _env.IsDevelopment()) seedPassword = "Admin12345!"; + // Демо-организация «Demo Market» и demo-admin — для dev/stage. На ПРОДЕ их + // быть НЕ должно (чистый старт реального магазина): отключается флагом + // SEED_DEMO_DATA=false (или Seed:DemoData=false) в .env прода. По умолчанию + // (флаг не задан) демо сидируется — поведение dev/stage не меняется. + var seedDemoRaw = Environment.GetEnvironmentVariable("SEED_DEMO_DATA") ?? cfg["Seed:DemoData"]; + var seedDemo = !string.Equals(seedDemoRaw, "false", StringComparison.OrdinalIgnoreCase); + foreach (var role in new[] { SystemRoles.SuperAdmin, SystemRoles.Admin, SystemRoles.Cashier, SystemRoles.Storekeeper }) { if (!await roleMgr.RoleExistsAsync(role)) @@ -57,29 +64,33 @@ public async Task StartAsync(CancellationToken ct) await SeedGlobalUnitsAsync(db, ct); var kzt = await db.Currencies.FirstOrDefaultAsync(c => c.Code == "KZT", ct); - var demoOrg = await db.Organizations.FirstOrDefaultAsync(o => o.Name == "Demo Market", ct); - if (demoOrg is null) + Organization? demoOrg = null; + if (seedDemo) { - demoOrg = new Organization + demoOrg = await db.Organizations.FirstOrDefaultAsync(o => o.Name == "Demo Market", ct); + if (demoOrg is null) { - Name = "Demo Market", - CountryCode = "KZ", - Bin = "000000000000", - Address = "Алматы, ул. Пример 1", - Phone = "+7 (777) 000-00-00", - Email = "demo@food-market.local", - DefaultCurrencyId = kzt?.Id, - }; - db.Organizations.Add(demoOrg); - await db.SaveChangesAsync(ct); - } - else if (demoOrg.DefaultCurrencyId is null && kzt is not null) - { - demoOrg.DefaultCurrencyId = kzt.Id; - await db.SaveChangesAsync(ct); - } + demoOrg = new Organization + { + Name = "Demo Market", + CountryCode = "KZ", + Bin = "000000000000", + Address = "Алматы, ул. Пример 1", + Phone = "+7 (777) 000-00-00", + Email = "demo@food-market.local", + DefaultCurrencyId = kzt?.Id, + }; + db.Organizations.Add(demoOrg); + await db.SaveChangesAsync(ct); + } + else if (demoOrg.DefaultCurrencyId is null && kzt is not null) + { + demoOrg.DefaultCurrencyId = kzt.Id; + await db.SaveChangesAsync(ct); + } - await SeedTenantReferencesAsync(db, demoOrg.Id, ct); + await SeedTenantReferencesAsync(db, demoOrg.Id, ct); + } // SuperAdmin платформы — без OrganizationId, видит все организации const string superAdminEmail = "admin@food-market.local"; @@ -126,30 +137,33 @@ public async Task StartAsync(CancellationToken ct) } } - // Admin демо-организации — владелец/директор Demo Market - const string demoAdminEmail = "admin@demo-market.local"; - var demoAdmin = await userMgr.FindByEmailAsync(demoAdminEmail); - if (demoAdmin is null && !string.IsNullOrWhiteSpace(seedPassword)) + // Admin демо-организации — владелец/директор Demo Market (только dev/stage). + if (seedDemo && demoOrg is not null) { - demoAdmin = new User + const string demoAdminEmail = "admin@demo-market.local"; + var demoAdmin = await userMgr.FindByEmailAsync(demoAdminEmail); + if (demoAdmin is null && !string.IsNullOrWhiteSpace(seedPassword)) { - UserName = demoAdminEmail, - Email = demoAdminEmail, - EmailConfirmed = true, - FullName = "Demo Market Admin", - OrganizationId = demoOrg.Id, - }; - var result = await userMgr.CreateAsync(demoAdmin, seedPassword); - if (result.Succeeded) - await userMgr.AddToRoleAsync(demoAdmin, SystemRoles.Admin); - } - else if (demoAdmin is not null) - { - if (!await userMgr.IsInRoleAsync(demoAdmin, SystemRoles.Admin)) - await userMgr.AddToRoleAsync(demoAdmin, SystemRoles.Admin); - } + demoAdmin = new User + { + UserName = demoAdminEmail, + Email = demoAdminEmail, + EmailConfirmed = true, + FullName = "Demo Market Admin", + OrganizationId = demoOrg.Id, + }; + var result = await userMgr.CreateAsync(demoAdmin, seedPassword); + if (result.Succeeded) + await userMgr.AddToRoleAsync(demoAdmin, SystemRoles.Admin); + } + else if (demoAdmin is not null) + { + if (!await userMgr.IsInRoleAsync(demoAdmin, SystemRoles.Admin)) + await userMgr.AddToRoleAsync(demoAdmin, SystemRoles.Admin); + } - await SeedAdminEmployeeAsync(db, demoOrg.Id, superAdmin?.Id, ct); + await SeedAdminEmployeeAsync(db, demoOrg.Id, superAdmin?.Id, ct); + } // Глобальные SystemSettings — single-row. Сидируем дефолт 30 дней // retention если ещё нет записи.