Menu ve Permission List Seeder geliştirildi

This commit is contained in:
Sedat ÖZTÜRK 2026-09-17 20:54:23 +03:00
parent 0bc6336715
commit 93dd058f1d
21 changed files with 6936 additions and 7090 deletions

View file

@ -59,8 +59,8 @@ System nature:
component; backward-compatible additions to script recipes / editor options / tokens).
Anything beyond that — a new React component or page, a new toolbox family, core engine changes (ListForm
runtime, seeders, code generator, auth, DataSourceManager, dispatcher/compiler), new ABP
entity/module/migration, platform table schema changes, new NuGet/npm dependencies, `Routes`
in `MenusData.json`, new external integrations — is **out of frame**: finish everything that
entity/module/migration, platform table schema changes, new NuGet/npm dependencies, the
`App.Menus.Routes.json` seed data, new external integrations — is **out of frame**: finish everything that
fits inside the frame first, then ask the user with a single question (why configuration is
insufficient, the smallest change that works, files touched, rollback) and proceed **only with
explicit approval**. Approval is per request and does not carry over. Full lists:
@ -660,8 +660,6 @@ Platform-owned screens, menus, permissions and language texts. Changing them req
a deploy. AI must learn and teach implementation flow primarily from these assets:
- ListFormSeeder_Saas.cs / ListFormSeeder_Administration.cs / ListFormSeeder_{Modul}.cs
- MenusData.json
- PermissionsData.json
- HostData.json
- LanguagesData.json
- WizardDataSeeder.cs / CrudDataSeeder.cs — the seeders that read
@ -720,11 +718,11 @@ AI must prioritize metadata-based field behavior instead of suggesting custom Re
### 31.3 Step 3 - Add menu and route mapping
From `MenusData.json` patterns, AI must define both:
From the `configs/seeds/host/data/App.Menus.*.json` patterns, AI must define both:
- `Routes` entry:
- `key`, `path`, `componentPath`, `routeType`, `authority`
- `Menus` entry:
- `App.Menus.Routes.json` row:
- `Id`, `Key`, `Path`, `ComponentPath`, `RouteType`, `Authority`
- `App.Menus.Menu.json` row:
- `ParentCode`, `Code`, `DisplayName`, `Url`, `Icon`, `RequiredPermissionName`, `Order`
For dynamic list screens, base route pattern is:
@ -735,7 +733,7 @@ AI must ensure menu URL and route path point to same screen contract.
### 31.4 Step 4 - Add permissions
From `PermissionsData.json` patterns, AI must define:
From the `configs/seeds/host/data/Abp.Identity.Permission*.json` patterns, AI must define:
- Permission group (if missing)
- Permission definitions for feature root and actions

View file

@ -27,8 +27,8 @@ This document summarizes the rules, standards, and step-by-step instructions for
## Special File Handling Rules
- **MenusData.json:**
- Never modify the `Routes` section directly. Only `Modules` and `Menus` sections can be changed for menu additions or updates. All menu additions must use the platform's configuration mechanisms or be added to `Modules` and `Menus` as required by platform design.
- **configs/seeds/host/data/App.Menus.*.json:**
- Never modify `App.Menus.Routes.json` directly. Only `App.Menus.Module.json` and `App.Menus.Menu.json` can be changed for menu additions or updates. All menu additions must use the platform's configuration mechanisms or be added to those two files as required by platform design.
- **LanguagesData.json:**
- When adding a new key, always check if the key already exists. Only add the key if it does not exist to prevent duplicates.
@ -38,11 +38,11 @@ This document summarizes the rules, standards, and step-by-step instructions for
## File-by-File Change Summary
### 1. MenusData.json
- **{Modul} menu** added as a top-level menu with `ModuleId: {Modul}`.
### 1. configs/seeds/host/data/App.Menus.Menu.json
- **{Modul} menu** added as a top-level menu with `ModuleId: {Modul}`; the module row goes into `App.Menus.Module.json`.
- **{Liste}** added as a child menu under {Modul}.
### 2. PermissionsData.json
### 2. configs/seeds/host/data/Abp.Identity.Permissions.json
- **{Modul} permissions** grouped under `App.{Modul}`.
- **{Liste} permissions** nested under {Modul} group.
@ -58,7 +58,7 @@ This document summarizes the rules, standards, and step-by-step instructions for
- **Updated** all related constraints and references.
### 6. PlatformIdentityDataSeeder.cs
- **Removed** redundant {Modul} permission grant logic (now handled by PermissionsData.json).
- **Removed** redundant {Modul} permission grant logic (now handled by the permission seed data).
### 7. LanguagesData.json
- **Added** localization entries for:
@ -73,8 +73,8 @@ This document summarizes the rules, standards, and step-by-step instructions for
### 1. Add a New Module (e.g., {Modul})
```
Yeni bir modül ekle (ör: {Modul}):
- MenusData.json'a kök menü olarak ekle
- PermissionsData.json'da ayrı bir PermissionGroup oluştur
- configs/seeds/host/data/App.Menus.Menu.json'a kök menü, App.Menus.Module.json'a modül kaydı olarak ekle
- configs/seeds/host/data/Abp.Identity.PermissionGroups.json'da ayrı bir grup oluştur
- ListFormSeeder_{Modul}.cs dosyası oluştur ve list-form seed'ini buraya taşı
- SqlObjects.sql'de tabloyu {Modul}_T_{Entity} olarak adlandır
- LanguagesData.json'a menü, liste ve alan çevirilerini ekle
@ -86,7 +86,7 @@ Yeni bir liste ekle (ör: {Liste}):
- {Modul} ana menüsünün altına ekle
- ListFormSeeder_{Modul}.cs dosyasına seed kodunu ekle
- SqlObjects.sql'de tabloyu {Modul}_T_{Entity} olarak oluştur
- PermissionsData.json'da ilgili izinleri {Modul} grubuna ekle
- configs/seeds/host/data/Abp.Identity.Permissions.json'da ilgili izinleri {Modul} grubuna ekle
- LanguagesData.json'a liste ve alan çevirilerini ekle
```
@ -117,7 +117,7 @@ Yeni menü, liste veya alan eklediğinde LanguagesData.json'a şu şekilde ekle:
### 5. Remove Redundant or Incorrect Code
```
- Farklı modüllerde aynı izin veya seed kodu varsa, sadece ilgili modülde bırak
- PlatformIdentityDataSeeder.cs'de Permission grant kodunu kaldır, PermissionsData.json'dan yönet
- PlatformIdentityDataSeeder.cs'de Permission grant kodunu kaldır, Abp.Identity.Permissions.json'dan yönet
```
---

View file

@ -1253,11 +1253,11 @@ açılmaz:
### 12.4 ListForm olmayan (özel React) ekranlar
Bu ekranlar `Sas_H_Route` kayıtlarıyla yönetilir (seed: `MenusData.json` → `Routes`). Yenisini
eklemek **kod yazmak demektir** — karar sırasının son adımıdır.
Bu ekranlar `Sas_H_Route` kayıtlarıyla yönetilir (seed:
`configs/seeds/host/data/App.Menus.Routes.json`). Yenisini eklemek **kod yazmak demektir** — karar sırasının son adımıdır.
Bir route kaydının alanları: `key`, `path`, `componentType`, `componentPath` (`@/views/...`),
`routeType`, `authority[]`.
Bir route kaydının alanları: `Id`, `Key`, `Path`, `ComponentType`, `ComponentPath` (`@/views/...`),
`RouteType`, `Authority` (virgülle ayrılmış yetki listesi).
| `routeType` | Anlam |
| --- | --- |

View file

@ -407,7 +407,7 @@ kullanıcıya sorulur ve yalnızca onayla yapılır.** "Yapılamaz" cevabı yokt
| Çekirdek motor | ListForm runtime, seeder'lar, `codeGenerator.ts`, yetki/kimlik altyapısı, `DataSourceManager`, dispatcher/derleyici (`CustomEndpointAppService`, `DynamicServiceCompiler`) |
| Backend şeması | Yeni ABP modülü/entity/migration, platform tablolarında (`{Önek}_{H\|T\|B}_{Ad}` — reference §12.1) kolon değişikliği, `TableNameEnum`/`TableNameResolver` değişikliği, DTO/JSON kolon sözleşmesini **bozan** değişiklik |
| Bağımlılık | Yeni NuGet/npm paketi, sürüm yükseltme |
| Sabit yapılar | `MenusData.json` → `Routes`, `PlatformConsts` içindeki mevcut değerlerin değişmesi |
| Sabit yapılar | `data/App.Menus.Routes.json`, `PlatformConsts` içindeki mevcut değerlerin değişmesi |
| Dış dünya | Yeni harici entegrasyon, yeni bağlantı tipi, üçüncü taraf servis |
**Sorma biçimi:** çerçeve içinde yapılabilen her şeyi **önce bitir**, sonra tek soruda
@ -1538,8 +1538,8 @@ olduğu sürece popup form açmaz. Diyalog kapanışı listeyi yenilediği için
yenileme çağrısı gerekmez. Canlı örnek: **Dynamic Services** (`App.DeveloperKit.DynamicServices`) —
liste, KPI şeridi ve Swagger butonu ListForm'da; kod yazma `DynamicServiceEditor` diyalogunda (§9.3).
> **Adres değişiminde veritabanı uyarısı:** `MenusData.json`'daki `Menus` ve `Routes` kayıtları
> **yalnızca yoksa** eklenir (`MenuDataSeeder`). Var olan bir menünün `Url`'ini ya da bir route'un
> **Adres değişiminde veritabanı uyarısı:** `data/App.Menus.Menu.json` ve `App.Menus.Routes.json`
> kayıtları **yalnızca yoksa** eklenir (`ListFormSeedDataApplier`). Var olan bir menünün `Url`'ini ya da bir route'un
> `Path`'ini değiştirdiğinde kurulu veritabanları eski adreste kalır; düzeltme
> `{sql|postgres}/execute/` altında bir prosedürle (§8.3) ya da elle yapılır. Yeni kurulumda
> sorun çıkmadığı için bu adım kolayca atlanır.
@ -3072,7 +3072,7 @@ Yönetim yetkileri:
`App.DeveloperKit.DynamicServices{,.Create,.Edit,.Delete,.Manage,.TestCompile,.Publish,.ViewCode}` —
`Manage` aktif/pasif ve toplu işlemler, `ViewCode` kaynak görüntüleme kapısıdır. Servisin
**kendi uçlarının** yetkisi ise koddaki `[Authorize(...)]` özniteliğidir; sınıfı yetkisiz
bırakma, gerekiyorsa `PermissionsData.json`'a yeni yetki tanımla (CLAUDE.md kesişen değişiklik
bırakma, gerekiyorsa `data/Abp.Identity.Permissions.json`'a yeni yetki tanımla (CLAUDE.md kesişen değişiklik
kuralı).
**Seed:** `DynamicService` kayıtları yalnızca veritabanında yaşar; hiçbir seed dosyası okunmaz.
@ -3277,8 +3277,9 @@ elle düzeltme ve wizard'ın kapsamadığı düzenlemeler içindir.
**Kurallar — prompt ile üretim yaparken:**
1. **Menüyü elle ekleme.** Yeni bir ekranın menüsü wizard seed dosyasından gelir; `MenusData.json`
yalnızca platformun kendi ekranları içindir ve orada da `Routes` bölümüne dokunulmaz.
1. **Menüyü elle ekleme.** Yeni bir ekranın menüsü wizard seed dosyasından gelir;
`data/App.Menus.Menu.json` yalnızca platformun kendi ekranları içindir ve
`App.Menus.Routes.json` dosyasına hiç dokunulmaz.
2. **Route kaydı üretme.** Dinamik liste ekranları statik `/admin/list/:listFormCode` route'unu
kullanır; custom component'lerin route'u `RoutePath` alanından türetilir. `Route` tablosu
yalnızca fiziksel React sayfaları içindir ve prompt ile ekran üretirken böyle bir sayfa

View file

@ -896,7 +896,8 @@ Route.Authority ──┘ └► Permission
dışındadır: `Pub` modülü altında tutulur ve uygulama konfigürasyonuyla taşınır (bkz. §10.4).
**Yetki kodları** `PlatformConsts.AppCodes` içinde merkezî olarak tanımlıdır ve
`PermissionsData.json` ile seed edilir. Ana gruplar: `App.Saas`, `App.Branches`, `App.Intranet.*`,
`configs/seeds/host/data/Abp.Identity.Permissions.json` ile seed edilir (gruplar:
`Abp.Identity.PermissionGroups.json`). Ana gruplar: `App.Saas`, `App.Branches`, `App.Intranet.*`,
`App.Definitions.*`, `App.Restrictions.*`, `App.Languages.*`, `App.Listforms.*`,
`App.Notifications.*`, `App.BackgroundWorkers.*`, `App.Menus.*`, `App.DeveloperKit.*`,
`App.SqlQueryManager.*`,
@ -977,7 +978,8 @@ react-icons adı, `Order` sıra, `IsDisabled` yayın anahtarı, `DisplayName` di
`[Authorize]` olduğu için menüler uygulama konfigürasyonunun `publicMenus` alanıyla taşınır
(`PlatformApplicationConfigurationContributor`), istemcide `usePublicMenu` okur. `Pub` modülü
yönetim navigasyonuna girmez (`abpConfig.model.ts` menüyü kurarken bu modülü eler; Menü Yönetimi
ekranı elemez, menüler oradan düzenlenir). Seed: `MenusData.json` → `Modules` + `Menus`.
ekranı elemez, menüler oradan düzenlenir). Seed: `configs/seeds/host/data/App.Menus.Module.json` ve
`App.Menus.Menu.json`.
**Sayfa.** Her public sayfa bir Custom Component'tir: `RoutePath` `/admin/` ile başlamadığı sürece
bileşen otomatik olarak public route olur ve `PublicLayout` altında yayınlanır. Tasarım yalnızca
@ -1593,8 +1595,6 @@ Platformun kendi ekranları, menüleri, yetkileri ve dil metinleri buradadır; d
derlenip yayınlanır. Yeni bir modülün nasıl kurulacağını öğrenmek için başvurulacak dosyalar:
- `ListFormSeeder_Saas.cs`, `ListFormSeeder_Administration.cs` — ListForm + alan tanımları
- `MenusData.json` — `Routes`, `Modules`, `Menus`
- `PermissionsData.json` — yetki grupları ve tanımları
- `HostData.json` — ayar/entegrasyon değerleri
- `LanguagesData.json` — dil anahtarları (EN/TR)
- `WizardDataSeeder.cs`, `CrudDataSeeder.cs` — aşağıdaki
@ -1613,6 +1613,8 @@ configs/seeds/
│ ├── wizard/ # {Ad}.json → WizardDataSeeder
│ ├── crud/ # {EntityName}.json → CrudEndpointSeedApplier
│ ├── data/ # {ListFormCode}.json → ListFormSeedDataApplier
│ │ # App.Menus.{Routes,Module,Menu}.json — route/modül/menü ağacı
│ │ # Abp.Identity.Permission{Groups,s}.json — yetki tanımları
│ ├── sql/{object,execute}/ # .sql (SQL Server)
│ └── postgres/{object,execute}/
├── tenants/{tenantId}/… # aynı düzen, tenant kapsamı

View file

@ -3,8 +3,8 @@
namespace Sozsoft.Platform.Permissions;
/// <summary>
/// Uygulama yetkileri kod içinde tanımlanmaz; <c>Migrations/PermissionsData.json</c>
/// dosyasından <c>PermissionDataSeeder</c> ile veritabanına seed edilir ve
/// Uygulama yetkileri kod içinde tanımlanmaz; <c>configs/seeds/host/data/Abp.Identity.Permissions.json</c>
/// dosyasından <c>ListFormSeedDataApplier</c> ile veritabanına seed edilir ve
/// oradan dinamik olarak yönetilir. Bu sağlayıcı yalnızca kullanılmayan
/// ABP modül gruplarını kaldırmak için vardır.
/// </summary>

View file

@ -57,23 +57,6 @@ public class NotificationRuleSeedDto
public bool IsCustomized { get; set; }
}
public class PermissionGroupDefinitionRecordSeedDto
{
public string Name { get; set; }
public string DisplayName { get; set; }
}
public class PermissionDefinitionRecordSeedDto
{
public string GroupName { get; set; }
public string Name { get; set; }
public string ParentName { get; set; }
public string DisplayName { get; set; }
public bool IsEnabled { get; set; }
public int MultiTenancySide { get; set; }
public string Modules { get; set; }
}
public class CurrencySeedDto
{
public string Id { get; set; }

View file

@ -27945,8 +27945,8 @@
{
"resourceName": "Platform",
"key": "App.Menus.Routes.Description",
"en": "Routes — the route records of custom React screens. Table: Sas_H_Route · host scope · list screen.\nUsage: needed only when a page written in code is added — this is the last step of the decision order. Screens produced with a ListForm do not get a route record; they use the ready dynamic routes /admin/list/{code}, /admin/form/{code}, /admin/form/{code}/{id}, /admin/chart/{code}.\nFields:\n• Key → the unique key of the route; the menu record binds to the page over this value\n• Path → the url; parameters are written in the /admin/foo/:id form\n• ComponentType → how the component is resolved (normal)\n• ComponentPath → the component path, e.g. @/views/admin/foo/Foo. The file must exist in the repository\n• RouteType → who may open it: public (no login), authenticated (any logged in user), protected (permission required)\n• Authority → the permissions that may open it; on a protected route this field is mandatory\nCaution: a route whose ComponentPath does not exist breaks the whole menu load, not just that page. In Migrations/MenusData.json the Routes section is managed by the platform — while adding a menu only the Modules and Menus sections are touched.",
"tr": "Route'lar — özel React ekranlarının route kayıtları. Tablo: Sas_H_Route · host kapsamlı · liste ekranı.\nKullanım: yalnızca kod ile yazılmış bir sayfa eklenirken gerekir — karar sırasının son adımıdır. ListForm ile üretilen ekranlara route kaydı açılmaz; hazır dinamik rotalar kullanılır: /admin/list/{kod}, /admin/form/{kod}, /admin/form/{kod}/{id}, /admin/chart/{kod}.\nAlanlar:\n• Key → route'un benzersiz anahtarı; menü kaydı sayfaya bu değerle bağlanır\n• Path → url; parametreler /admin/foo/:id biçiminde yazılır\n• ComponentType → bileşenin nasıl çözüleceği (normal)\n• ComponentPath → bileşen yolu, örn. @/views/admin/foo/Foo. Dosyanın depoda bulunması zorunludur\n• RouteType → kimin açabileceği: public (oturumsuz), authenticated (oturum açmış herkes), protected (yetki gerekir)\n• Authority → açabilecek yetkiler; protected route'ta bu alan zorunludur\nDikkat: ComponentPath karşılığı olmayan route yalnızca o sayfayı değil menünün tamamının yüklenmesini bozar. Migrations/MenusData.json içindeki Routes bölümü platform tarafından yönetilir — menü eklerken yalnızca Modules ve Menus bölümlerine dokunulur."
"en": "Routes — the route records of custom React screens. Table: Sas_H_Route · host scope · list screen.\nUsage: needed only when a page written in code is added — this is the last step of the decision order. Screens produced with a ListForm do not get a route record; they use the ready dynamic routes /admin/list/{code}, /admin/form/{code}, /admin/form/{code}/{id}, /admin/chart/{code}.\nFields:\n• Key → the unique key of the route; the menu record binds to the page over this value\n• Path → the url; parameters are written in the /admin/foo/:id form\n• ComponentType → how the component is resolved (normal)\n• ComponentPath → the component path, e.g. @/views/admin/foo/Foo. The file must exist in the repository\n• RouteType → who may open it: public (no login), authenticated (any logged in user), protected (permission required)\n• Authority → the permissions that may open it; on a protected route this field is mandatory\nCaution: a route whose ComponentPath does not exist breaks the whole menu load, not just that page. The seed file configs/seeds/host/data/App.Menus.Routes.json is managed by the platform — while adding a menu only App.Menus.Module.json and App.Menus.Menu.json are touched.",
"tr": "Route'lar — özel React ekranlarının route kayıtları. Tablo: Sas_H_Route · host kapsamlı · liste ekranı.\nKullanım: yalnızca kod ile yazılmış bir sayfa eklenirken gerekir — karar sırasının son adımıdır. ListForm ile üretilen ekranlara route kaydı açılmaz; hazır dinamik rotalar kullanılır: /admin/list/{kod}, /admin/form/{kod}, /admin/form/{kod}/{id}, /admin/chart/{kod}.\nAlanlar:\n• Key → route'un benzersiz anahtarı; menü kaydı sayfaya bu değerle bağlanır\n• Path → url; parametreler /admin/foo/:id biçiminde yazılır\n• ComponentType → bileşenin nasıl çözüleceği (normal)\n• ComponentPath → bileşen yolu, örn. @/views/admin/foo/Foo. Dosyanın depoda bulunması zorunludur\n• RouteType → kimin açabileceği: public (oturumsuz), authenticated (oturum açmış herkes), protected (yetki gerekir)\n• Authority → açabilecek yetkiler; protected route'ta bu alan zorunludur\nDikkat: ComponentPath karşılığı olmayan route yalnızca o sayfayı değil menünün tamamının yüklenmesini bozar. configs/seeds/host/data/App.Menus.Routes.json seed dosyası platform tarafından yönetilir — menü eklerken yalnızca App.Menus.Module.json ve App.Menus.Menu.json dosyalarına dokunulur."
},
{
"resourceName": "Platform",
@ -27957,8 +27957,8 @@
{
"resourceName": "Platform",
"key": "App.Menus.Menu.Description",
"en": "Menu — menu items. Table: Sas_H_Menu · host scope · tree layout. The menu comes from the database, not from code.\nUsage: the tree of the left menu is built here. The produced screen becomes visible to the user only after its menu record is opened.\nFields:\n• Code → the unique code of the menu item; the child items reference it through ParentCode\n• ParentCode → the parent menu; the tree structure is formed over this field\n• DisplayName → the language key of the displayed name; the text is written on Language Text\n• ModuleId → the module the root menu belongs to; it references the Module record and the module cannot be deleted while a menu points at it\n• Url → the address it opens; for a produced screen /admin/list/{ListFormCode}\n• Icon, CssClass → the icon and additional style\n• Order → the ordering among siblings\n• Target → does it open in the same tab or a new one\n• ElementId → the dom id used for tests and guided tours\n• RequiredPermissionName → a menu whose permission the user does not hold is not rendered at all\n• IsDisabled → a disabled item does not appear in the menu; the record is preserved\nRule: the menu item, the route it opens and the permission must show the same contract. A visible menu leading to a screen the user cannot open is a design error.\nCaution: a menu added only from the interface disappears on a database reset; the same record is also written into Migrations/MenusData.json (Modules and Menus sections only).",
"tr": "Menü — menü öğeleri. Tablo: Sas_H_Menu · host kapsamlı · ağaç düzeni. Menü koddan değil veritabanından gelir.\nKullanım: sol menünün ağacı burada kurulur. Üretilen ekran, menü kaydı açılmadan kullanıcıya görünmez.\nAlanlar:\n• Code → menü öğesinin benzersiz kodu; alt öğeler ParentCode ile buna referans verir\n• ParentCode → üst menü; ağaç yapısı bu alan üzerinden kurulur\n• DisplayName → görünen adın dil anahtarı; metin Language Text ekranına yazılır\n• ModuleId → kök menünün bağlı olduğu modül; Modül kaydına referans verir, menü bağlıyken modül silinemez\n• Url → açtığı adres; üretilen ekran için /admin/list/{ListFormCode}\n• Icon, CssClass → ikon ve ek stil\n• Order → kardeşleri arasındaki sıra\n• Target → aynı sekmede mi yeni sekmede mi açılacağı\n• ElementId → test ve rehberli tur için kullanılan dom kimliği\n• RequiredPermissionName → kullanıcının yetkisi olmayan menü hiç basılmaz\n• IsDisabled → pasif öğe menüde görünmez, kaydı korunur\nKural: menü öğesi, açtığı route ve yetki aynı sözleşmeyi göstermelidir. Görünen ama açılamayan ekrana götüren menü tasarım hatasıdır.\nDikkat: yalnızca arayüzden eklenen menü veritabanı sıfırlandığında kaybolur; aynı kayıt Migrations/MenusData.json dosyasına da yazılır (yalnızca Modules ve Menus bölümleri)."
"en": "Menu — menu items. Table: Sas_H_Menu · host scope · tree layout. The menu comes from the database, not from code.\nUsage: the tree of the left menu is built here. The produced screen becomes visible to the user only after its menu record is opened.\nFields:\n• Code → the unique code of the menu item; the child items reference it through ParentCode\n• ParentCode → the parent menu; the tree structure is formed over this field\n• DisplayName → the language key of the displayed name; the text is written on Language Text\n• ModuleId → the module the root menu belongs to; it references the Module record and the module cannot be deleted while a menu points at it\n• Url → the address it opens; for a produced screen /admin/list/{ListFormCode}\n• Icon, CssClass → the icon and additional style\n• Order → the ordering among siblings\n• Target → does it open in the same tab or a new one\n• ElementId → the dom id used for tests and guided tours\n• RequiredPermissionName → a menu whose permission the user does not hold is not rendered at all\n• IsDisabled → a disabled item does not appear in the menu; the record is preserved\nRule: the menu item, the route it opens and the permission must show the same contract. A visible menu leading to a screen the user cannot open is a design error.\nCaution: a menu added only from the interface disappears on a database reset; the same record is also written into configs/seeds/host/data/App.Menus.Menu.json (and the module row into App.Menus.Module.json).",
"tr": "Menü — menü öğeleri. Tablo: Sas_H_Menu · host kapsamlı · ağaç düzeni. Menü koddan değil veritabanından gelir.\nKullanım: sol menünün ağacı burada kurulur. Üretilen ekran, menü kaydı açılmadan kullanıcıya görünmez.\nAlanlar:\n• Code → menü öğesinin benzersiz kodu; alt öğeler ParentCode ile buna referans verir\n• ParentCode → üst menü; ağaç yapısı bu alan üzerinden kurulur\n• DisplayName → görünen adın dil anahtarı; metin Language Text ekranına yazılır\n• ModuleId → kök menünün bağlı olduğu modül; Modül kaydına referans verir, menü bağlıyken modül silinemez\n• Url → açtığı adres; üretilen ekran için /admin/list/{ListFormCode}\n• Icon, CssClass → ikon ve ek stil\n• Order → kardeşleri arasındaki sıra\n• Target → aynı sekmede mi yeni sekmede mi açılacağı\n• ElementId → test ve rehberli tur için kullanılan dom kimliği\n• RequiredPermissionName → kullanıcının yetkisi olmayan menü hiç basılmaz\n• IsDisabled → pasif öğe menüde görünmez, kaydı korunur\nKural: menü öğesi, açtığı route ve yetki aynı sözleşmeyi göstermelidir. Görünen ama açılamayan ekrana götüren menü tasarım hatasıdır.\nDikkat: yalnızca arayüzden eklenen menü veritabanı sıfırlandığında kaybolur; aynı kayıt configs/seeds/host/data/App.Menus.Menu.json dosyasına da yazılır (modül satırı App.Menus.Module.json içine)."
},
{
"resourceName": "Platform",
@ -28023,14 +28023,14 @@
{
"resourceName": "Platform",
"key": "Abp.Identity.PermissionGroups.Description",
"en": "Permission Groups — the top level of the permission tree. Table: AbpPermissionGroups · list screen.\nUsage: every permission belongs to a group and the group determines the heading under which the permission appears in the role and user permission dialogs. The groups also carry the module division: App.Saas, App.Administration, a project module.\nFields:\n• Name → the group code; permission rows reference it through GroupName\n• DisplayName → the language key of the displayed name\n• ExtraProperties → additional information kept by ABP on the record\nCaution: permissions and their groups are produced by the platform — by the Wizard, by the seeder and by Migrations/PermissionsData.json. Do not open a group by hand for a screen you produce; the wizard creates the group and the permissions together and keeps the codes consistent.",
"tr": "Yetki Grupları — yetki ağacının en üst seviyesi. Tablo: AbpPermissionGroups · liste ekranı.\nKullanım: her yetki bir gruba bağlıdır ve grup, yetkinin rol ve kullanıcı yetki diyaloglarında hangi başlık altında görüneceğini belirler. Gruplar aynı zamanda modül ayrımını taşır: App.Saas, App.Administration, proje modülü.\nAlanlar:\n• Name → grup kodu; yetki satırları GroupName alanıyla buna referans verir\n• DisplayName → görünen adın dil anahtarı\n• ExtraProperties → ABP'nin kayıt üzerinde tuttuğu ek bilgi\nDikkat: yetkiler ve grupları platform tarafından üretilir — Wizard, seeder ve Migrations/PermissionsData.json. Ürettiğin ekran için elle grup açma; sihirbaz grubu ve yetkileri birlikte oluşturur, kodları tutarlı tutar."
"en": "Permission Groups — the top level of the permission tree. Table: AbpPermissionGroups · list screen.\nUsage: every permission belongs to a group and the group determines the heading under which the permission appears in the role and user permission dialogs. The groups also carry the module division: App.Saas, App.Administration, a project module.\nFields:\n• Name → the group code; permission rows reference it through GroupName\n• DisplayName → the language key of the displayed name\n• ExtraProperties → additional information kept by ABP on the record\nCaution: permissions and their groups are produced by the platform — by the Wizard, by the seeder and by the configs/seeds/host/data/Abp.Identity.Permission*.json seed files. Do not open a group by hand for a screen you produce; the wizard creates the group and the permissions together and keeps the codes consistent.",
"tr": "Yetki Grupları — yetki ağacının en üst seviyesi. Tablo: AbpPermissionGroups · liste ekranı.\nKullanım: her yetki bir gruba bağlıdır ve grup, yetkinin rol ve kullanıcı yetki diyaloglarında hangi başlık altında görüneceğini belirler. Gruplar aynı zamanda modül ayrımını taşır: App.Saas, App.Administration, proje modülü.\nAlanlar:\n• Name → grup kodu; yetki satırları GroupName alanıyla buna referans verir\n• DisplayName → görünen adın dil anahtarı\n• ExtraProperties → ABP'nin kayıt üzerinde tuttuğu ek bilgi\nDikkat: yetkiler ve grupları platform tarafından üretilir — Wizard, seeder ve configs/seeds/host/data/Abp.Identity.Permission*.json seed dosyaları. Ürettiğin ekran için elle grup açma; sihirbaz grubu ve yetkileri birlikte oluşturur, kodları tutarlı tutar."
},
{
"resourceName": "Platform",
"key": "Abp.Identity.Permissions.Description",
"en": "Permissions — the permission definitions of the application. Table: AbpPermissions · tree layout.\nUsage: the permission contract of every screen is visible here. A list screen normally has a root permission plus the .Create, .Update, .Delete, .Export, .Import and .Note sub-permissions; the ListForm PermissionJson maps these codes onto the buttons.\nFields:\n• Name → the permission code, e.g. App.Definitions.Currency.Create. It is the same value referenced from the code (PlatformConsts.AppCodes) and from the UI\n• ParentName → the parent permission; the tree is formed over this field and granting a parent does not automatically grant the children\n• GroupName → the permission group it belongs to\n• DisplayName → the language key of the displayed name\n• MultiTenancySide → on which side it is valid: host, tenant or both. A permission defined only for host is not offered to a tenant role\n• Modules → which modules the permission belongs to; it drives the module based filtering of the permission dialogs\n• IsEnabled → a disabled permission is not offered to anyone; it is the fastest way to close a capability across the system\nCaution: a permission added only from the interface is lost on a database reset. The same record is also written into PlatformConsts.AppCodes, Migrations/PermissionsData.json, LanguagesData.json and, if it is used in the interface, into permission.constant.ts.",
"tr": "Yetkiler — uygulamanın yetki tanımları. Tablo: AbpPermissions · ağaç düzeni.\nKullanım: her ekranın yetki sözleşmesi burada görünür. Liste ekranı normalde bir kök yetki ile birlikte .Create, .Update, .Delete, .Export, .Import ve .Note alt yetkilerini taşır; ListForm PermissionJson bu kodları butonlara eşler.\nAlanlar:\n• Name → yetki kodu, örn. App.Definitions.Currency.Create. Koddan (PlatformConsts.AppCodes) ve arayüzden referans verilen değerle aynıdır\n• ParentName → üst yetki; ağaç bu alan üzerinden kurulur ve üst yetkiyi vermek alt yetkileri otomatik vermez\n• GroupName → bağlı olduğu yetki grubu\n• DisplayName → görünen adın dil anahtarı\n• MultiTenancySide → hangi tarafta geçerli olduğu: host, tenant veya ikisi. Yalnızca host için tanımlı yetki kiracı rolüne sunulmaz\n• Modules → yetkinin hangi modüllere ait olduğu; yetki diyaloglarının modül bazlı süzülmesini sağlar\n• IsEnabled → pasif yetki kimseye sunulmaz; bir yeteneği sistem genelinde kapatmanın en hızlı yoludur\nDikkat: yalnızca arayüzden eklenen yetki veritabanı sıfırlandığında kaybolur. Aynı kayıt PlatformConsts.AppCodes, Migrations/PermissionsData.json, LanguagesData.json ve arayüzde kullanılacaksa permission.constant.ts dosyalarına da yazılır."
"en": "Permissions — the permission definitions of the application. Table: AbpPermissions · tree layout.\nUsage: the permission contract of every screen is visible here. A list screen normally has a root permission plus the .Create, .Update, .Delete, .Export, .Import and .Note sub-permissions; the ListForm PermissionJson maps these codes onto the buttons.\nFields:\n• Name → the permission code, e.g. App.Definitions.Currency.Create. It is the same value referenced from the code (PlatformConsts.AppCodes) and from the UI\n• ParentName → the parent permission; the tree is formed over this field and granting a parent does not automatically grant the children\n• GroupName → the permission group it belongs to\n• DisplayName → the language key of the displayed name\n• MultiTenancySide → on which side it is valid: host, tenant or both. A permission defined only for host is not offered to a tenant role\n• Modules → which modules the permission belongs to; it drives the module based filtering of the permission dialogs\n• IsEnabled → a disabled permission is not offered to anyone; it is the fastest way to close a capability across the system\nCaution: a permission added only from the interface is lost on a database reset. The same record is also written into PlatformConsts.AppCodes, configs/seeds/host/data/Abp.Identity.Permissions.json, LanguagesData.json and, if it is used in the interface, into permission.constant.ts.",
"tr": "Yetkiler — uygulamanın yetki tanımları. Tablo: AbpPermissions · ağaç düzeni.\nKullanım: her ekranın yetki sözleşmesi burada görünür. Liste ekranı normalde bir kök yetki ile birlikte .Create, .Update, .Delete, .Export, .Import ve .Note alt yetkilerini taşır; ListForm PermissionJson bu kodları butonlara eşler.\nAlanlar:\n• Name → yetki kodu, örn. App.Definitions.Currency.Create. Koddan (PlatformConsts.AppCodes) ve arayüzden referans verilen değerle aynıdır\n• ParentName → üst yetki; ağaç bu alan üzerinden kurulur ve üst yetkiyi vermek alt yetkileri otomatik vermez\n• GroupName → bağlı olduğu yetki grubu\n• DisplayName → görünen adın dil anahtarı\n• MultiTenancySide → hangi tarafta geçerli olduğu: host, tenant veya ikisi. Yalnızca host için tanımlı yetki kiracı rolüne sunulmaz\n• Modules → yetkinin hangi modüllere ait olduğu; yetki diyaloglarının modül bazlı süzülmesini sağlar\n• IsEnabled → pasif yetki kimseye sunulmaz; bir yeteneği sistem genelinde kapatmanın en hızlı yoludur\nDikkat: yalnızca arayüzden eklenen yetki veritabanı sıfırlandığında kaybolur. Aynı kayıt PlatformConsts.AppCodes, configs/seeds/host/data/Abp.Identity.Permissions.json, LanguagesData.json ve arayüzde kullanılacaksa permission.constant.ts dosyalarına da yazılır."
},
{
"resourceName": "Platform",

View file

@ -69,6 +69,10 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
SelectCommand = "AbpPermissionGroups",
KeyFieldName = "Id",
KeyFieldDbSourceType = DbType.Guid,
SeedFilePath = SeedPathResolver.GetDataFilePath(listFormName),
SeedSyncInsert = true,
SeedSyncUpdate = true,
SeedSyncDelete = true,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
@ -79,7 +83,9 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
PermissionJson = DefaultPermissionJson(AbpIdentity.PermissionGroups.Create, AbpIdentity.PermissionGroups.Default, AbpIdentity.PermissionGroups.Update, AbpIdentity.PermissionGroups.Delete, AbpIdentity.PermissionGroups.Export, AbpIdentity.PermissionGroups.Import, AbpIdentity.PermissionGroups.Note),
PagerOptionJson = DefaultPagerOptionJson,
InsertFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
new() { FieldName = "Id", FieldDbType = DbType.Guid, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
new() { FieldName = "Id", FieldDbType = DbType.Guid, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey },
// ExtraProperties bos birakilirsa ABP kaydi okurken sozlugu kuramaz; bos JSON nesnesi yazilir.
new() { FieldName = "ExtraProperties", FieldDbType = DbType.String, Value = "{}", CustomValueType = FieldCustomValueTypeEnum.Value }
}),
EditingOptionJson = DefaultEditingOptionJson(listFormName, 600, 350, true, true, true, true, false),
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>()
@ -204,6 +210,10 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
SelectCommand = "AbpPermissions",
KeyFieldName = "Id",
KeyFieldDbSourceType = DbType.Guid,
SeedFilePath = SeedPathResolver.GetDataFilePath(listFormName),
SeedSyncInsert = true,
SeedSyncUpdate = true,
SeedSyncDelete = true,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
@ -215,7 +225,9 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
PagerOptionJson = DefaultPagerOptionJson,
TreeOptionJson = DefaultTreeOptionJson("Name", "ParentName", true),
InsertFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
new() { FieldName = "Id", FieldDbType = DbType.Guid, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
new() { FieldName = "Id", FieldDbType = DbType.Guid, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey },
// ExtraProperties bos birakilirsa ABP kaydi okurken sozlugu kuramaz; bos JSON nesnesi yazilir.
new() { FieldName = "ExtraProperties", FieldDbType = DbType.String, Value = "{}", CustomValueType = FieldCustomValueTypeEnum.Value }
}),
EditingOptionJson = DefaultEditingOptionJson(listFormName, 600, 600, true, true, true, true, false),
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>()

View file

@ -6219,6 +6219,10 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.Route)),
KeyFieldName = "Id",
KeyFieldDbSourceType = DbType.Guid,
SeedFilePath = SeedPathResolver.GetDataFilePath(listFormName),
SeedSyncInsert = true,
SeedSyncUpdate = true,
SeedSyncDelete = true,
DefaultFilter = DefaultFilterJson,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
@ -6446,6 +6450,10 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.Module)),
KeyFieldName = "Id",
KeyFieldDbSourceType = DbType.String,
SeedFilePath = SeedPathResolver.GetDataFilePath(listFormName),
SeedSyncInsert = true,
SeedSyncUpdate = true,
SeedSyncDelete = true,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
@ -6537,6 +6545,10 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.Menu)),
KeyFieldName = "Code",
KeyFieldDbSourceType = DbType.String,
SeedFilePath = SeedPathResolver.GetDataFilePath(listFormName),
SeedSyncInsert = true,
SeedSyncUpdate = true,
SeedSyncDelete = true,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
@ -6551,7 +6563,10 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>() {
new() { Order=1, ColCount=2, ColSpan=1, ItemType="group" },
}),
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(DbType.String, "Code"),
// Menu tablosunda audit kolonu yok; varsayilan olarak yalnizca anahtar uretilir.
InsertFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
new() { FieldName = "Id", FieldDbType = DbType.Guid, Value = DefaultValues.NewId, CustomValueType = FieldCustomValueTypeEnum.CustomKey }
}),
FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
new() { FieldName = "IsDisabled", FieldDbType = DbType.Boolean, Value = "false", CustomValueType = FieldCustomValueTypeEnum.Value }
})
@ -6592,8 +6607,6 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
Visible = true,
IsActive = true,
SortIndex = 1,
SortDirection = GridColumnOptions.SortOrderAsc,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
@ -6644,6 +6657,8 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
ListOrderNo = 4,
Visible = true,
IsActive = true,
SortIndex = 1,
SortDirection = GridColumnOptions.SortOrderAsc,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,

View file

@ -1,148 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Sozsoft.Platform.Entities;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
namespace Sozsoft.Platform.Data.Seeds;
public class RouteSeedDto
{
public string Key { get; set; }
public string Path { get; set; }
public string ComponentType { get; set; }
public string ComponentPath { get; set; }
public string RouteType { get; set; }
public string[] Authority { get; set; }
}
public class ModuleSeedDto
{
public string Name { get; set; }
}
public class MenuSeedDto
{
public string ParentCode { get; set; }
public string Code { get; set; }
public string DisplayName { get; set; }
public int Order { get; set; }
public string Url { get; set; }
public string Icon { get; set; }
public string CssClass { get; set; }
public string RequiredPermissionName { get; set; }
public bool IsDisabled { get; set; }
public string ModuleId { get; set; }
}
public class MenuSeederDto
{
public List<RouteSeedDto> Routes { get; set; }
public List<ModuleSeedDto> Modules { get; set; }
public List<MenuSeedDto> Menus { get; set; }
}
public class MenuDataSeeder : IDataSeedContributor, ITransientDependency
{
private readonly IRepository<Route, Guid> _routeRepository;
private readonly IRepository<Menu, Guid> _menuRepository;
private readonly IRepository<Module, string> _moduleRepository;
public MenuDataSeeder(
IRepository<Route, Guid> routeRepository,
IRepository<Menu, Guid> menuRepository,
IRepository<Module, string> moduleRepository
)
{
_routeRepository = routeRepository;
_menuRepository = menuRepository;
_moduleRepository = moduleRepository;
}
public async Task SeedAsync(DataSeedContext context)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile(Path.Combine("Migrations", "MenusData.json"))
.Build();
var items = configuration.Get<MenuSeederDto>();
foreach (var item in items.Routes)
{
var exists = await _routeRepository.AnyAsync(x => x.Key == item.Key);
if (!exists)
{
await _routeRepository.InsertAsync(new Route(
item.Key,
item.Path,
item.ComponentType,
item.ComponentPath,
item.RouteType,
item.Authority ?? []
), autoSave: true);
}
}
foreach (var item in items.Modules)
{
var exists = await _moduleRepository.AnyAsync(x => x.Name == item.Name);
if (!exists)
{
await _moduleRepository.InsertAsync(new Module(item.Name)
{
Name = item.Name
}, autoSave: true);
}
}
foreach (var item in items.Menus)
{
var exists = await _menuRepository.AnyAsync(x => x.Code == item.Code);
if (!exists)
{
// Menunun bagli oldugu modul Modules bolumunde tanimli degilse burada olusturulur;
// aksi halde ModuleId yabanci anahtari seed sirasinda hata verir.
await EnsureModuleAsync(item.ModuleId);
await _menuRepository.InsertAsync(new Menu
{
ParentCode = string.IsNullOrWhiteSpace(item.ParentCode) ? null : item.ParentCode,
Code = item.Code,
DisplayName = item.DisplayName,
Order = item.Order,
Url = item.Url,
Icon = item.Icon,
CssClass = item.CssClass,
RequiredPermissionName = item.RequiredPermissionName,
IsDisabled = item.IsDisabled,
ModuleId = item.ModuleId
}, autoSave: true);
}
}
}
private async Task EnsureModuleAsync(string moduleId)
{
var cleaned = moduleId?.Trim();
if (string.IsNullOrWhiteSpace(cleaned))
{
return;
}
if (await _moduleRepository.AnyAsync(x => x.Id == cleaned))
{
return;
}
await _moduleRepository.InsertAsync(new Module(cleaned) { Name = cleaned }, autoSave: true);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,79 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Sozsoft.Platform.Extensions;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement;
namespace Sozsoft.Platform.Data.Seeds;
public class PermissionSeederDto
{
public List<PermissionGroupDefinitionRecordSeedDto> PermissionGroupDefinitionRecords { get; set; }
public List<PermissionDefinitionRecordSeedDto> PermissionDefinitionRecords { get; set; }
}
public class PermissionDataSeeder : IDataSeedContributor, ITransientDependency
{
private readonly IRepository<PermissionGroupDefinitionRecord, Guid> _permissionGroupRepository;
private readonly IRepository<PermissionDefinitionRecord, Guid> _permissionRepository;
public PermissionDataSeeder(
IRepository<PermissionGroupDefinitionRecord, Guid> permissionGroupRepository,
IRepository<PermissionDefinitionRecord, Guid> permissionRepository)
{
_permissionGroupRepository = permissionGroupRepository;
_permissionRepository = permissionRepository;
}
public async Task SeedAsync(DataSeedContext context)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile(Path.Combine("Migrations", "PermissionsData.json"))
.Build();
var items = configuration.Get<PermissionSeederDto>();
foreach (var item in items.PermissionGroupDefinitionRecords)
{
var exists = await _permissionGroupRepository.AnyAsync(x => x.Name == item.Name);
if (!exists)
{
await _permissionGroupRepository.InsertAsync(new PermissionGroupDefinitionRecord
{
Name = item.Name,
DisplayName = item.DisplayName
}, autoSave: true);
}
}
foreach (var item in items.PermissionDefinitionRecords)
{
var exists = await _permissionRepository.AnyAsync(x => x.Name == item.Name);
if (!exists)
{
var perm = new PermissionDefinitionRecord
{
GroupName = item.GroupName,
Name = item.Name,
ParentName = string.IsNullOrWhiteSpace(item.ParentName) ? null : item.ParentName,
DisplayName = item.DisplayName,
IsEnabled = item.IsEnabled,
MultiTenancySide = (MultiTenancySides)item.MultiTenancySide,
};
perm.SetModules(item.Modules);
await _permissionRepository.InsertAsync(perm, autoSave: true);
}
}
}
}

View file

@ -67,16 +67,6 @@
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<None Remove="Migrations\MenusData.json" />
<Content Include="Migrations\MenusData.json">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<None Remove="Migrations\PermissionsData.json" />
<Content Include="Migrations\PermissionsData.json">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>

View file

@ -180,7 +180,7 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
paylaştığı dönüşüm `Application.Contracts`'ta DTO metodudur; entity'ye yazma Domain.Shared'deki
`IListFormArtifact` / `IListFormFieldArtifact` sözleşmeleri üzerinden yapılır.
Ayrıntı: `dotnet.instructions.md` §5.
- **Yeni bir yetki** → `PlatformConsts.AppCodes` + `PermissionsData.json` + (UI'da kullanılacaksa)
- **Yeni bir yetki** → `PlatformConsts.AppCodes` + `data/Abp.Identity.Permissions.json` + (UI'da kullanılacaksa)
`permission.constant.ts` + `LanguagesData.json`.
- **`/mcp` ucuna yeni bir araç** → üç yer birlikte değişir: `McpToolNames` (ad kayıt defteri),
ilgili `Mcp*Tools` sınıfı (`Sozsoft.Mcp.HttpApi`) ve arkasındaki AppService sözleşmesi
@ -260,7 +260,11 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
kaydın `LastModificationTime`/`CreationTime` değerinden yeniyse güncellenir/silinir. Migrate
kullanıcının runtime revizyonunu ezmez. Yeni bir seeder yazarken bu kuralı taklit et: **migrate
varsayılanı eklemektir, ezmek değil.**
- **`MenusData.json`** → `Routes` bölümüne dokunma; yalnızca `Modules` ve `Menus`.
- **Menü ağacı ve yetkiler** → `configs/seeds/host/data/App.Menus.{Routes,Module,Menu}.json` ve
`Abp.Identity.Permission{Groups,s}.json`; platformun kendi menü/yetki kayıtları da diğer liste
verisiyle aynı mekanizmadan (`ListFormSeedDataApplier`) geçer, ayrı bir seeder yoktur. `Order`
alanı bağımlılık sırasını kurar: route → modül → menü, yetki grubu → yetki.
`App.Menus.Routes.json` dosyasına dokunma.
- **Public site** → menü `Menu` tablosunda `ModuleId = "Pub"` altında (`PlatformConsts.PublicSite`);
`App.Public.Header` hem üst menüyü hem alt bilgideki hızlı bağlantıları besler (ikisi de
`PublicNav` düğümü) ve ziyaretçiye uygulama konfigürasyonunun `publicMenus` alanıyla taşınır

View file

@ -0,0 +1,16 @@
{
"ListFormCode": "Abp.Identity.PermissionGroups",
"KeyFieldName": "Name",
"GeneratedAt": "2026-09-17T14:53:28.356299Z",
"Order": 1,
"Rows": [
{
"Name": "App.Saas",
"DisplayName": "App.Saas"
},
{
"Name": "App.Administration",
"DisplayName": "App.Administration"
}
]
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,20 @@
{
"ListFormCode": "App.Menus.Module",
"KeyFieldName": "Id",
"GeneratedAt": "2026-09-17T14:39:36.191548Z",
"Order": 2,
"Rows": [
{
"Id": "Sas",
"Name": "Sas"
},
{
"Id": "Adm",
"Name": "Adm"
},
{
"Id": "Pub",
"Name": "Pub"
}
]
}

View file

@ -0,0 +1,413 @@
{
"ListFormCode": "App.Menus.Routes",
"KeyFieldName": "Id",
"GeneratedAt": "2026-09-17T14:39:36.191548Z",
"Order": 1,
"Rows": [
{
"Id": "93c31491-52c2-5079-88ed-2f960f729a50",
"Key": "products",
"Path": "/products",
"ComponentType": "normal",
"ComponentPath": "@/views/public/Products",
"RouteType": "public",
"Authority": ""
},
{
"Id": "5c071295-f626-5e41-93fc-b4462a7a0528",
"Key": "checkout",
"Path": "/checkout",
"ComponentType": "normal",
"ComponentPath": "@/views/public/Checkout",
"RouteType": "public",
"Authority": ""
},
{
"Id": "f88f7222-42e6-5bef-b2aa-a8db81d11383",
"Key": "payment",
"Path": "/payment",
"ComponentType": "normal",
"ComponentPath": "@/views/public/Payment",
"RouteType": "public",
"Authority": ""
},
{
"Id": "c4c17ec7-8423-513a-863a-6065816efe0a",
"Key": "success",
"Path": "/success",
"ComponentType": "normal",
"ComponentPath": "@/views/public/Success",
"RouteType": "public",
"Authority": ""
},
{
"Id": "d3529321-2f70-5965-8e2d-7e4dc9e56dca",
"Key": "blog",
"Path": "/blog",
"ComponentType": "normal",
"ComponentPath": "@/views/public/Blog",
"RouteType": "public",
"Authority": ""
},
{
"Id": "037dc714-77fc-5b0c-840c-0cdeca22df19",
"Key": "blogDetail",
"Path": "/blog/:id",
"ComponentType": "normal",
"ComponentPath": "@/views/public/BlogDetail",
"RouteType": "public",
"Authority": ""
},
{
"Id": "d170f3e3-b0bd-5ed0-8394-601b51f5666f",
"Key": "demo",
"Path": "/demo",
"ComponentType": "normal",
"ComponentPath": "@/views/public/Demo",
"RouteType": "public",
"Authority": ""
},
{
"Id": "e4d6f040-ad8a-523f-bd4f-211329c651cf",
"Key": "access-denied",
"Path": "/access-denied",
"ComponentType": "normal",
"ComponentPath": "@/views/AccessDenied",
"RouteType": "public",
"Authority": ""
},
{
"Id": "bf6d30a3-03cf-5475-9daa-730023459bb0",
"Key": "login",
"Path": "/login",
"ComponentType": "normal",
"ComponentPath": "@/views/auth/Login",
"RouteType": "authenticated",
"Authority": ""
},
{
"Id": "df9b57fd-37f7-5377-b84c-70257295261a",
"Key": "register",
"Path": "/register",
"ComponentType": "normal",
"ComponentPath": "@/views/auth/Register",
"RouteType": "authenticated",
"Authority": ""
},
{
"Id": "bb282d0d-062b-51b7-87d7-22545c6f0c4d",
"Key": "forgotPassword",
"Path": "/forgot-password",
"ComponentType": "normal",
"ComponentPath": "@/views/auth/ForgotPassword",
"RouteType": "authenticated",
"Authority": ""
},
{
"Id": "7be57172-a75d-5f03-8a7a-566523dc5acc",
"Key": "resetPassword",
"Path": "/reset-password",
"ComponentType": "normal",
"ComponentPath": "@/views/auth/ResetPassword",
"RouteType": "authenticated",
"Authority": ""
},
{
"Id": "2e78c334-4e75-586b-9c14-f5b5169bd895",
"Key": "sendConfirmationCode",
"Path": "/confirm",
"ComponentType": "normal",
"ComponentPath": "@/views/auth/SendConfirmationCode",
"RouteType": "authenticated",
"Authority": ""
},
{
"Id": "d5f0773b-dece-5b55-beea-db2547ff9293",
"Key": "sendExtendLogin",
"Path": "/extend-login",
"ComponentType": "normal",
"ComponentPath": "@/views/auth/ExtendLogin",
"RouteType": "authenticated",
"Authority": ""
},
{
"Id": "f639b8fd-a462-5af5-b230-d2e5bd8a8eaf",
"Key": "verifyConfirmationCode",
"Path": "/confirm/:userId/:token",
"ComponentType": "normal",
"ComponentPath": "@/views/auth/VerifyConfirmationCode",
"RouteType": "authenticated",
"Authority": ""
},
{
"Id": "56ecf681-cf6b-5968-9acc-754e3026231c",
"Key": "admin.dashboard",
"Path": "/admin/dashboard",
"ComponentType": "normal",
"ComponentPath": "@/views/Dashboard",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "f5d4a187-ef76-5010-bb2f-14844722875d",
"Key": "admin.menuManager",
"Path": "/admin/menuManager",
"ComponentType": "normal",
"ComponentPath": "@/views/menu/MenuManager",
"RouteType": "protected",
"Authority": "App.Menus.Manager"
},
{
"Id": "43285584-09c7-52cb-83ae-a35cb69bfced",
"Key": "admin.listFormManagement.wizard",
"Path": "/admin/listform/wizard",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/listForm/wizard/Wizard",
"RouteType": "protected",
"Authority": "App.Listforms.Wizard"
},
{
"Id": "e87db52d-25cd-5c0f-9aa8-01dc2dc5b032",
"Key": "admin.listFormManagement.wizardManager",
"Path": "/admin/listform/wizardManager",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/listForm/wizard/WizardFileManager",
"RouteType": "protected",
"Authority": "App.Listforms.Wizard"
},
{
"Id": "8ce5dfc6-8795-5d5e-b815-447f08292900",
"Key": "admin.listFormManagement.edit",
"Path": "/admin/listform/edit/:listFormCode",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/listForm/edit/FormEdit",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "4e380430-9661-55ff-9c6b-270823b14401",
"Key": "admin.ai",
"Path": "/admin/ai",
"ComponentType": "normal",
"ComponentPath": "@/views/ai/Assistant",
"RouteType": "protected",
"Authority": "App.Definitions.AiBot.Asistant"
},
{
"Id": "ad21c21d-84c2-5f73-9eff-5bdd4d6754eb",
"Key": "admin.profile.general",
"Path": "/admin/profile/general",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/profile/Profile",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "43df2816-075a-5fb0-8d75-07041acedf60",
"Key": "admin.profile.password",
"Path": "/admin/profile/password",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/profile/Profile",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "5bf4ec7d-09fa-57bc-a832-915f0bd9a424",
"Key": "admin.profile.notificationSettings",
"Path": "/admin/profile/notification-settings",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/profile/Profile",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "c64d7bd0-e884-55a6-915a-7a43e0c5e684",
"Key": "admin.activityLog",
"Path": "/admin/activityLog",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/activityLog/ActivityLog",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "012f714f-fb86-5292-a2f1-c11c4bf88a06",
"Key": "admin.changeLog",
"Path": "/admin/changeLog",
"ComponentType": "normal",
"ComponentPath": "@/views/version/ChangeLog",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "507adc62-0ffd-51f0-a9d2-165eccbfc225",
"Key": "admin.settings",
"Path": "/admin/settings",
"ComponentType": "normal",
"ComponentPath": "@/views/settings/Settings",
"RouteType": "protected",
"Authority": "App.Setting"
},
{
"Id": "9cae5316-b620-5100-9726-bd638cd71517",
"Key": "admin.identity.user.detail",
"Path": "/admin/users/detail/:userId",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/user-management/Details",
"RouteType": "protected",
"Authority": "AbpIdentity.Users.Update"
},
{
"Id": "f44286f9-e9d8-5478-80c1-3643eb848078",
"Key": "admin.identity.ous",
"Path": "/admin/ous",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/organization-unit/OrganizationUnits",
"RouteType": "protected",
"Authority": "Abp.Identity.OrganizationUnits"
},
{
"Id": "dc18c096-b996-51f6-b774-14a90e74f137",
"Key": "admin.hr.organization",
"Path": "/admin/organization",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/hr/OrgChart",
"RouteType": "protected",
"Authority": "App.Definitions.Department"
},
{
"Id": "53d4baee-8360-523a-8470-26eaaaa54371",
"Key": "admin.forum",
"Path": "/admin/forum",
"ComponentType": "normal",
"ComponentPath": "@/views/forum/Forum",
"RouteType": "protected",
"Authority": "App.ForumManagement.Publish"
},
{
"Id": "094842eb-fc95-51ea-bd57-6284f377c199",
"Key": "admin.list",
"Path": "/admin/list/:listFormCode",
"ComponentType": "normal",
"ComponentPath": "@/views/list/List",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "c2230e57-183d-56b5-8e7b-e6fde917b335",
"Key": "admin.formNew",
"Path": "/admin/form/:listFormCode",
"ComponentType": "normal",
"ComponentPath": "@/views/form/FormNew",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "62e585e8-7393-5749-8281-ba94f7fdd43e",
"Key": "admin.formView",
"Path": "/admin/form/:listFormCode/:id",
"ComponentType": "normal",
"ComponentPath": "@/views/form/FormView",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "fddafca0-a6ad-51fb-85b0-ccdf1cfed1d6",
"Key": "admin.formEdit",
"Path": "/admin/form/:listFormCode/:id/edit",
"ComponentType": "normal",
"ComponentPath": "@/views/form/FormEdit",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "35d0b346-fe04-5a5a-896f-5e2b87e90bc3",
"Key": "admin.chart",
"Path": "/admin/chart/:listFormCode",
"ComponentType": "normal",
"ComponentPath": "@/views/list/Chart",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "76a3f75e-11db-560a-b749-989f2ca579d7",
"Key": "admin.sqlQueryManager",
"Path": "/admin/sqlQueryManager",
"ComponentType": "normal",
"ComponentPath": "@/views/developerKit/SqlQueryManager",
"RouteType": "protected",
"Authority": "App.SqlQueryManager"
},
{
"Id": "08891b2a-5d2e-54c5-b12a-e0e8c2547b55",
"Key": "admin.developerkit.components.design",
"Path": "/admin/developerkit/components/design/:id",
"ComponentType": "normal",
"ComponentPath": "@/views/developerKit/ComponentCodeLayout",
"RouteType": "protected",
"Authority": "App.DeveloperKit.CustomComponents"
},
{
"Id": "cdbfdea5-ea04-5537-bb5c-1dd964c675fe",
"Key": "admin.intranet.documents",
"Path": "/admin/intranet-documents",
"ComponentType": "normal",
"ComponentPath": "@/views/intranet/documents/IntranetDocuments",
"RouteType": "protected",
"Authority": "App.Intranet.Document"
},
{
"Id": "ea5acaee-a479-5daf-b4e6-2999578fd78d",
"Key": "admin.fileManagement",
"Path": "/admin/files",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/files/FileManager",
"RouteType": "protected",
"Authority": "App.Files"
},
{
"Id": "c074e5cc-ab9c-51e9-a89c-d9f662316ab5",
"Key": "admin.devexpressDynamicReportView",
"Path": "/admin/reports/:report/view/:id?/:listFormCode?",
"ComponentType": "normal",
"ComponentPath": "@/views/report/DevexpressReportViewer",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "57520752-8f21-5d81-aaf7-fa8089b83e1c",
"Key": "admin.devexpressDynamicReportDesigner",
"Path": "/admin/reports/:report/design/:id?/:listFormCode?",
"ComponentType": "normal",
"ComponentPath": "@/views/report/DevexpressReportDesigner",
"RouteType": "protected",
"Authority": ""
},
{
"Id": "16917407-a912-53ab-ab96-d14e7ef6abd2",
"Key": "admin.videoroom",
"Path": "/admin/videoroom/dashboard",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/videoroom/Dashboard",
"RouteType": "protected",
"Authority": "App.Videoroom"
},
{
"Id": "7cfef810-4738-577e-88aa-ca32f9d15ccc",
"Key": "admin.videoroom.list",
"Path": "/admin/videoroom/list",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/videoroom/RoomList",
"RouteType": "protected",
"Authority": "App.Videoroom.List"
},
{
"Id": "b6af134c-95b8-5453-915a-4cf5d84cb600",
"Key": "admin.videoroom.detail",
"Path": "/admin/videoroom/room/:id",
"ComponentType": "normal",
"ComponentPath": "@/views/admin/videoroom/RoomDetail",
"RouteType": "protected",
"Authority": "App.Videoroom.Detail"
}
]
}