Md dosyaları düzenleme ve ölü kodlar kaldırıldı

This commit is contained in:
Sedat ÖZTÜRK 2026-09-29 09:14:07 +03:00
parent ae226d359b
commit 677a62bd79
11 changed files with 148 additions and 118 deletions

View file

@ -362,8 +362,10 @@ MCP (`/mcp`, `Sozsoft.Mcp` module) — expose ListForm data/queries to an extern
(Claude, ChatGPT, or an OAuth-registered MCP client) without new code: configure a server row
on the **MCP Servers** screen (`App.DeveloperKit.McpServers`, §12.2 of
`lowcode-reference.instructions.md`) with its allowed tools and tenant scope; queries always run
on the calling tenant's own database. Tenant users are read-only over MCP (schema tools,
`query_list`, `run_select`); writing and development tools are host-only. A
on the calling tenant's own database. Tenant users read and write data over MCP but cannot develop
(`McpToolNames.TenantTools`: schema tools, `query_list`, `run_select`, `insert_row`/`update_row`/`delete_row`
— row writes go through the screen's C/U/D contract and need `.Write`); development tools,
`list_queries` and `run_query` are host-only. A
request to "let an agent query/update X" is a Decision Flow §1 (ListForm) request first — MCP
only gates which of the existing screens/queries an already-authorized client may reach; it
never grants access beyond the calling user's own ListForm/query permissions. Ayrıntı:
@ -879,7 +881,7 @@ Default is `List`, so older seed files that lack it keep working.
| Kind | Produces | Menu URL | Child permissions |
| --- | --- | --- | --- |
| `List` | ListForm + ListFormFields + Route + Menu + Permissions + language keys | `/admin/list/{ListFormCode}` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
| `List` | ListForm + ListFormFields + Menu + Permissions + language keys (no Route record; the generic `/admin/list/{code}` route serves it) | `/admin/list/{ListFormCode}` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
| `Custom` | Menu + Permissions + language keys; the screen is the selected Custom Component | the component's `RoutePath` | `.Create`, `.Update`, `.Delete` only |
`Export` / `Import` / `Note` exist only in the ListForm ecosystem. Never propose them on the
@ -891,7 +893,7 @@ embedded elsewhere as a SubGrid/part. Default is `true`.
### 32.4 Permission group selection
The wizard's permission group comes from a select list backed by `GetWizardPermissionGroups`.
The wizard's permission group comes from a select list backed by `ListFormWizardAppService.GetPermissionGroups` (`/api/app/list-form-wizard/permission-groups`).
Display names are read from the language key whose name equals the group name.
- Selecting an existing group fills `PermissionGroupEn/Tr` (seed file: `Language.PermissionGroupEn/Tr`);

View file

@ -31,7 +31,7 @@ Kural:
- Nullable, proje bazında ve bilinçli olarak açılır (`<Nullable>enable</Nullable>`).
Şu an açık olanlar: `Sozsoft.Platform.Application`, `Sozsoft.Notifications.*`,
test projeleri.
`Sozsoft.Mcp.*`, test projeleri.
- **Entity taşıyan projelerde** (`*.Domain`) nullable açılacaksa, aynı PR'da
`dotnet ef migrations add` çıktısı gözden geçirilir; şema değişikliği isteniyorsa
kabul edilir, istenmiyorsa kolon zorunluluğu `PlatformDbContext` içinde

View file

@ -482,7 +482,8 @@ ya da ziyaretçiye açık yeni bir fiziksel sayfa ürettiğinde.
**Genel varsayılanlar kayıtta değil ayardadır:** site adresi, site adı, varsayılan başlık ve
açıklama, paylaşım görseli, Twitter hesabı, diller, robots yönergesi, Google doğrulaması,
sosyal hesaplar ve sitemap anahtarı `App.SiteManagement.Seo.*` ayarlarındadır
sosyal hesaplar, varsayılan anahtar kelimeler (`DefaultKeywords`), sitemap anahtarı (`SitemapEnabled`) ve
sitemap dışı yollar (`SitemapExcludePaths`) `App.SiteManagement.Seo.*` ayarlarındadır
(`configs/seeds/host/data/App.SettingDefinitions.json`). Bir değer bütün site için geçerliyse
oraya yazılır, her yola tekrarlanmaz. Site kökü (`/`) hiçbir kayıt taşımaz; doğrudan bu
varsayılanlardan beslenir.
@ -605,7 +606,8 @@ talebin metnini döndürür. Başlık birden fazla talebe uyuyorsa Id ister. `St
- `Timesheets` — **sunucu yazar, model hiçbir şey yapmaz.** `get_dev_request` / `start_dev_request`
talebi kullanıcının etkin talebi yapar; ardından yapılan her MCP yazma işlemi (`create_table`,
`deploy_wizard`, `delete_wizard`, `save_component`, `delete_component`, `insert_row` /
`update_row` / `delete_row`, `save_dev_request_analysis`) o talebe bir satır ekler
`update_row` / `delete_row`, `save_dev_request_analysis`, `append_dev_request_note`,
`add_dev_request_subtasks`) o talebe bir satır ekler
(`IMcpDevRequestTimesheetRecorder`). Açıklama `App.Mcp.Timesheet.*` dil anahtarından **Türkçe**
üretilir ("Hr_T_Doctor tablosu oluşturuldu"), süre önceki satırdan ya da talebin açıldığı andan bu
yana ölçülür (en az 1 dakika, saat olarak), çalışan bağlanan kullanıcı, tarih bugündür.
@ -901,7 +903,7 @@ hiçbir şey silmez**. Tek çıktısı seed dosyalarıdır:
| `wizard/{WizardName}.json` | Ekranın `ListForm`/`Fields` sözleşmesi, wizard cevapları, `InsertedRecords`, `Pending` |
| `data/App.Menus.Module.json`, `data/App.Menus.Menu.json` | Modül, üst menü, ekranın menüsü |
| `data/Abp.Identity.PermissionGroups.json`, `data/Abp.Identity.Permissions.json` | İzin grubu, okuma yetkisi ve alt yetkileri |
| `data/App.Languages.LanguageText.json` | Menü, başlık, açıklama, grup ve alan başlıklarının EN + TR metinleri (`Id` iş anahtarından v5 GUID, `SeedRowIds.LanguageText`) |
| `data/App.Languages.LanguageText.json` | Menü, başlık, açıklama, grup, alan başlıkları ve `Language.Texts` anahtarlarının (widget başlıkları) EN + TR metinleri (`Id` iş anahtarından v5 GUID, `SeedRowIds.LanguageText`) |
Satırları `WizardSeedRowStore` yazar; anahtarlar `WizardSeedRowKeys`'ten gelir (export aynı
listeyle toplar). **Sahiplik:** bir satır ne veritabanında ne dosyada varsa ya da önceki sürüm ona
@ -942,7 +944,8 @@ sürümünü taşır.
"Menu": { "MenuCode": "…", "MenuOrder": 2, "MenuUrl": "…", "MenuIcon": "…",
"MenuParentPath": [ { "Code": "…", "Icon": "…", "En": "…", "Tr": "…" } ], // yalnızca derin yolda
"MenuParentCode": "…", "MenuParentIcon": "…" }, // "CreateMenu": false ise eklenir
"Language": { "MenuEn": "…", /* Menu/Title/Desc/MenuParent/PermissionGroup · EN + TR */ },
"Language": { "MenuEn": "…", /* Menu/Title/Desc/MenuParent/PermissionGroup · EN + TR */
"Texts": [ { "Key": "…", "En": "…", "Tr": "…" } ] }, // Texts yalnızca doluysa
"Groups": [ { "Items": [ { "FieldName": "…", "CaptionName": "…",
"En": "…", "Tr": "…" } ] } ] // grup Caption/ColCount yok
},
@ -993,7 +996,7 @@ düzenleme izinleri, görünüm option blokları, alt formlar, widget'lar, iş a
Dosyada wizard alanları üç başlık altında toplanır — `Menu` (menü kaydı), `Language` (dil
metinleri), `Groups` (alan başlıklarının dil karşılıkları); geri kalanı kök seviyededir.
Gruplama ile `ListFormCode → WizardCode` ve `MenuParentModuleId → ModuleId` adlandırmaları
Gruplama ile `ListFormCode → WizardCode`, `MenuParentModuleId → ModuleId` ve `LanguageTexts → Language.Texts` adlandırmaları
yalnızca **dosya biçimidir**; C#
sözleşmesi (`ListFormWizardDto`) düzdür ve dosya okunurken düzleştirilir
(`WizardSeedFileDto.FromSeedJson` ↔ `ToSeedJson`). Aşağıdaki tablolar C# alan adlarını kullanır.
@ -1671,8 +1674,9 @@ Silme ucu (`DeleteFile`) her kaydın akıbetini (`Deleted` / `Kept` + kullananla
Düzenleme (`EditFileName`) bu sınıfı çağırmaz; önceki sürümün kayıtlarını migrate kaldırır (§4.0).
Wizard'ın yarattığı modül `InsertedRecords.ModuleIds` ile izlenir.
Silme yolunda ekranın veri aynası (`ListForm.SeedFilePath` → `data/{ListFormCode}.json` ya da
klasörü) ekranla birlikte silinir; ekransız uygulanamaz.
Kurulu wizard silinirken ekranın veri aynası (`ListForm.SeedFilePath` → `data/{ListFormCode}.json` ya da
klasörü) ekranla birlikte silinir; ekransız uygulanamaz. Migrate bekleyen wizard'da ayna yalnızca ekran
hiç kurulmamışsa silinir (MCP demo satırları); kurulu ekranın aynası veritabanındaki satırların kaydıdır, kalır.
**Ekranın tablosu** wizard'ın ürettiği bir kayıt değildir (tasarımcı ya da `create_table` ile
ayrıca kurulur, `InsertedRecords`'ta yoktur) ve **kendiliğinden silinmez**. Silme onayı önce
@ -2124,8 +2128,9 @@ opsiyonel `ApprovalDateFieldName`, `ApprovalDescriptionFieldName`, `ApprovalIsFi
dönsün). Onay düğümleri (`Criteria`) görsel akış tasarımcısında kurulur ve `ListFormWorkflow`
kayıtlarına gider (§4.7).
**Adım 12 — Deploy.** Sol tarafta tüm adımların özeti, sağda üretim log'u. Üretim sırası —
seed dosyası uygulanırken `WizardDataSeeder`'ın izlediği sıranın aynısıdır:
**Adım 12 — Deploy.** Sol tarafta tüm adımların özeti, sağda üretim log'u. Log, deploy'un seed
dosyalarına yazdığı bölümleri sırayla gösterir; migrate'te `WizardDataSeeder` ekrana özgü kayıtları,
ardından `ListFormSeedDataApplier` menü/yetki/dil satırlarını kurar (§4.0):
1. Konfigürasyon doğrulama
2. Menü kaydı (`CreateMenu: false` ise atlanır)
@ -2134,10 +2139,11 @@ seed dosyası uygulanırken `WizardDataSeeder`'ın izlediği sıranın aynısıd
5. List yolunda: veri kaynağı → ListForm → alan grupları · Custom yolunda: bileşen bağlama
6. Deploy + tamamlandı
Başarıda sihirbaz `/admin/list/{ListFormCode}`'a yönlendirir ve seed dosyası
`configs/seeds/{kapsam}/wizard/` altına yazılmış olur. **Düzenleme modu** Wizard Manager'dan
`EditFileName` ile açılır: aynı adımlar dolu gelir, kaydetmede önce eski dosya ve
`InsertedRecords` kayıtları silinir (§4.5).
Başarıda sihirbaz "Migrate bekliyor" bildirimiyle Wizard Manager'a döner (ekran henüz kurulu
değildir; DB Migrate ile kurulur) ve seed dosyası `configs/seeds/{kapsam}/wizard/` altına yazılmış
olur. **Düzenleme modu** Wizard Manager'dan `EditFileName` ile açılır: aynı adımlar dolu gelir,
kaydetmede dosyalar cevaptan yeniden yazılır; önceki sürümün kayıtları `Pending.Replaced`'a alınır,
veritabanına dokunulmaz — kaldırma ve yeniden kurulum DB Migrate'tedir (§4.0).
---
@ -2471,7 +2477,7 @@ Preset mevcut JSON ile **birleşir**, diğer ayarları silmez; aynı anahtar var
| TagBox anında seçim | `showSelectionControls`, `applyValueMode:instantly`, `searchEnabled` |
| GridBox tek/çok seçim | `columns`, `selectionMode`, `filterRowVisible`, `height`, `width` |
| Çoklu görsel | `width`, `height`, `multiple`, `accept:image/*` |
| HTML tam araç çubuğu | `toolbar.items` (tam liste), `toolbar.multiline`, `mediaResizing`, `imageUpload` |
| HTML tam araç çubuğu | `htmlEditorOptions.ts` varsayılanı: `toolbar.items` (tam liste), `toolbar.multiline`, `mediaResizing`, `imageUpload` (`tabs: file/url`, base64), `tableResizing`, `tableContextMenu` — boş `editorOptions` da aynı varsayılanı alır |
| Yükseklik 100 / 200 | `{"height":100}` · `{"height":200}` |
| Barkod okutma butonu | `buttons[]` — kamera ikonlu buton; `onClick` = `"@SCAN_BARCODE"` token'ı. Yalnız `dxTextBox`. Token'ı `editingForm.ts` kamera diyaloğuna bağlar, okunan kod alana yazılır. HTTPS şart. |
| Kamerayla foto çek | `{"accept":"image/*","capture":"environment"}` — yalnız `dxImageUpload`. Mobilde dosya seçici yerine **yalnızca** kamera açılır (`user` = ön kamera); masaüstünde yok sayılır. Ayarlanmazsa dokunmatik cihazda dosya seçicinin yanına ayrı bir kamera butonu gelir, yani ikisi birden kullanılabilir — bu kalıp kamerayı **zorunlu** kılmak içindir. |
@ -2489,7 +2495,7 @@ Preset mevcut JSON ile **birleşir**, diğer ayarları silmez; aynı anahtar var
| Telefon | `EditorOptions.Phone()` | global format + maske + örnek |
| Kaydırıcı | `EditorOptions.Slider()` | `{"tooltip":{"enabled":true}}` |
| Görsel yükleme | `EditorOptions.ImageUpload(multiple: true, 80, 80)` | |
| Zengin metin | `EditorOptions.Html(240)` | tam araç çubuğu + `encodeHtml` |
| Zengin metin | `EditorOptions.Html(240)` | `htmlEditorOptions.ts` varsayılanıyla aynı bloklar (tam araç çubuğu, `imageUpload`, `mediaResizing`, `tableResizing`, `tableContextMenu`; biri değişirse diğeri de değişir) + `encodeHtml` + `elementAttr` `min-height:240px` (sabit yükseklik değil; içerikle büyür) |
Akıcı ekler: `.Placeholder()`, `.MaxLength()`, `.Height(int\|string)`, `.Width(int\|string)`,
`.Format()`, `.FixedPointFormat(p)`, `.DisplayFormat()`, `.DateSerializationFormat()`,

View file

@ -533,7 +533,7 @@ eskisi gibi çalışır.
| `ComponentKind` | Üretilen | Menü URL'i | Yetkiler |
| --- | --- | --- | --- |
| `List` | ListForm + ListFormField + Route + Menu + Permission + dil anahtarları | `/admin/list/{ListFormCode}` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
| `List` | ListForm + ListFormField (+ iş akışı) + Menu + Permission + dil anahtarları (rota üretilmez; genel `/admin/list/{ListFormCode}` rotası kullanılır) | `/admin/list/{ListFormCode}` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
| `Custom` | Menü + Permission + dil anahtarları; ekran seçilen Custom Component'tir | Component'in `RoutePath` değeri | Yalnızca `.Create`, `.Update`, `.Delete` (Export/Import/Note ListForm'a özgüdür) |
**Menüsüz wizard (`CreateMenu = false`).** Menü (ve gerekiyorsa üst menü) kaydı hiç üretilmez;
@ -542,7 +542,7 @@ ekranda SubGrid/parça olarak kullanılmak üzere tanımlanır. Alan varsayılan
alanı taşımayan eski seed dosyaları etkilenmez.
**İzin grubu seçimi.** Menü adımında izin grubu bir seçim listesinden gelir
(`GetWizardPermissionGroups`). Görünen adlar, grup adıyla aynı olan dil anahtarının metinlerinden
(`ListFormWizardAppService.GetPermissionGroups`, `/api/app/list-form-wizard/permission-groups`). Görünen adlar, grup adıyla aynı olan dil anahtarının metinlerinden
okunur; seçim yapıldığında `PermissionGroupEn/Tr` forma doldurulur. Yeni bir grup
tanımlanırsa grup adıyla aynı dil anahtarına bu metinler yazılır; mevcut grup seçilip alanlar boş
bırakılırsa sunucu veritabanındaki değeri geri yazar. Böylece seed dosyası her durumda iki dilli
@ -556,12 +556,15 @@ Var olan bir ekranı düzenlemek için `/admin/listform/edit/{listFormCode}` —
yapılandırması sekmeli bir editörde yönetilir (Veritabanı, Sütunlar, Filtreler, Düzenleme,
Yetkiler, Alt Form, Pivot, Tree, Gantt, Scheduler, Todo, Widget, Workflow, Durum, Grafik sekmeleri).
**Wizard File Manager** (`/admin/listform/wizard` liste ekranı) üretilmiş seed dosyalarını yönetir:
**Wizard File Manager** (`/admin/listform/wizardManager`; sihirbazın kendisi `/admin/listform/wizard`) üretilmiş seed dosyalarını yönetir:
liste/kart görünümü arasında geçiş (tercih diğer listelerle aynı yerde, `admin.lists.states`
altında saklanır), arama, düzenleme (dosyanın yerine geçen yeni bir çalıştırma), silme, veritabanı
migrate tetikleme, dışa aktarma ve içe aktarma. Liste, wizard'ın ilk deploy damgasına
(`Wizard.SeededAt`) göre **tersine** sıralıdır — en son üretilen ekran en üstte durur; damgası
okunamayan dosyalar sona düşer. Butonlar `App.Listforms.Wizard.*` yetkileriyle gizlenir; asıl
okunamayan dosyalar sona düşer. Silme, bağlı wizard'ı olan dosyada reddedilir; onay diyaloğu önce
`DeleteAnalysis` ile düşürülebilecek tabloyu sorar, sonuç her kaydın akıbetiyle (`Deleted` / `Kept` +
kullananlar / `NotFound`) rapor olarak gösterilir (`WizardRecordCleaner`, `WizardTableCleaner`;
`lowcode.instructions.md` §4.5). Butonlar `App.Listforms.Wizard.*` yetkileriyle gizlenir; asıl
kontrol `ListFormWizardAppService` üzerindedir.
### 7.7. İçe/dışa aktarma
@ -869,8 +872,8 @@ tıklamak seçim yapar, sayfayı değiştirmez — tıklama yakalama evresinde d
**Diğer notlar.** `PlatformIcon` tasarımcı dokümanındaki ikon adını çözer; `selectComponents.ts`
`Select.componentAs` için saklanan adı (`ReactSelect`, `CreatableSelect`, `AsyncSelect`) gerçek
bileşene çevirir — kanvas ve üretilen bileşenin aynı adı aynı şekilde yorumlamasını sağlayan tek
nokta budur. Yeni bileşen `configs/seeds/host/data/App.DeveloperKit.CustomComponents/{Id}.json`
içindeki bir satır olarak başlar.
nokta budur. Yeni bileşen `configs/seeds/host/data/App.DeveloperKit.CustomComponents/` klasöründe
kendi `{Id}.json` satır dosyası olarak başlar.
**Dinamik servis yaşam döngüsü:** `DynamicServiceCompiler` kodu derler →
`DynamicAssemblyRegistrationService` assembly'yi tenant bağlamıyla kaydeder →
@ -917,8 +920,9 @@ kendi aralarında 1'den. `PlatformPermissionAppService` sıralama anahtarını k
zincirinden kurar, böylece çocuk her zaman ebeveyninin altında kalır. Değerler seed dosyalarındaki
`Order` alanında tutulur ve Permissions / Permission Groups ekranlarından düzenlenebilir.
Wizard deploy'u yeni grubu ve grubun yeni kök yetkisini (seed satırı olarak) veritabanı ile seed
dosyasındaki kardeşlerin en büyük sırasının bir fazlasıyla, alt yetkileri Create/Update/Delete/Export/Import/Note dizilimiyle
1'den yazar (`NextPermissionOrder`, `AbpPermissionsExtensions`).
dosyasındaki kardeşlerin en büyük sırasının bir fazlasıyla, alt yetkileri `WizardSeedRowKeys.ChildPermissions` dizilimiyle
(List: Create/Update/Delete/Export/Import/Note, Custom: Create/Update/Delete) 1'den yazar
(`ListFormWizardAppService.WritePermissionGroupAsync` / `WritePermissionRowsAsync`).
Aksiyon yetkisi olan alt gruplar (UI tarafındaki karşılıkları `constants/permission.constant.ts`
içindedir; oradaki kontroller yalnızca butonları gizler, asıl kontrol AppService'lerdedir):
@ -948,7 +952,7 @@ içindedir; oradaki kontroller yalnızca butonları gizler, asıl kontrol AppSer
| **Sozsoft.MailQueue** | Şablon (Scriban) tabanlı gövde üretimi, ek dosya yaşam döngüsü, kuyruk çalıştırma ve günlükleme. |
| **Sozsoft.Sender** | Amazon SES (mail), Posta Güvercini (SMS), WhatsApp Cloud API, Rocket.Chat göndericileri. |
| **Sozsoft.SqlQueryManager** | SQL nesne yönetimi, sorgu çalıştırma, tablo/kolon metadata'sı. |
| **Sozsoft.Mcp** | MCP (Model Context Protocol) sunucusu: `/mcp` Streamable HTTP ucu, kiracı bazlı araç seti, şema keşfi, sorgu, veri yazma ve (host) tablo/ekran/bileşen geliştirme. Kiracı kullanıcısı yalnızca veri okur. Bkz. §13.9. |
| **Sozsoft.Mcp** | MCP (Model Context Protocol) sunucusu: `/mcp` Streamable HTTP ucu, kiracı bazlı araç seti, şema keşfi, sorgu, veri yazma ve (host) tablo/ekran/bileşen geliştirme. Kiracı kullanıcısı veri okur ve ekranın C/U/D sözleşmesinden geçerek satır yazar; geliştirme araçları yalnızca host'tadır. Bkz. §13.9. |
### 10.2. Uygulama servisleri (`api/src/Sozsoft.Platform.Application`)
@ -1003,7 +1007,7 @@ DeveloperKit > Custom Components (Visual Designer) üzerinden değişir. Aynı y
ile paylaşan custom component kazanır; karşılığı olan dosyası bulunmayan rota kaydı ise hiç
yüklenmez (`hasPhysicalComponent`) — seeder yalnızca eklediği için eski kayıtlar veritabanında
kalsa bile ekran patlamaz. Seed: `configs/seeds/host/data/App.DeveloperKit.CustomComponents/{Id}.json`;
bileşenin ayrı dosyası yoktur, her bileşen bu dosyada bir satırdır.
ekran klasör modundadır, her bileşen kendi satır dosyasındadır (dosya adı satırın `Id`'si).
Runtime kapsamı sınırlıdır: bileşen kodundaki `import` satırları derlemede temizlenir,
kullanılabilenler `React`, `ui` kit, `PlatformViewHost`, `apiService`, `axios`, `DOMPurify`,
@ -1089,7 +1093,7 @@ Veriden beslenen public sayfalar (`/products`, `/checkout`, `/payment`, `/succes
| Parça | Nerede | Ne taşır |
| --- | --- | --- |
| Genel varsayılanlar | `App.SiteManagement.Seo.*` ayarları (Ayarlar ekranı, yetki `App.SiteManagement.Seo`) | Site adresi, site adı, varsayılan başlık/açıklama/paylaşım görseli, Twitter hesabı, diller, robots yönergesi, Google doğrulaması, sosyal hesaplar, sitemap anahtarı |
| Genel varsayılanlar | `App.SiteManagement.Seo.*` ayarları (Ayarlar ekranı, yetki `App.SiteManagement.Seo`) | Site adresi, site adı, varsayılan başlık/açıklama/paylaşım görseli, Twitter hesabı, diller, robots yönergesi, Google doğrulaması, sosyal hesaplar, varsayılan anahtar kelimeler (`DefaultKeywords`), sitemap anahtarı (`SitemapEnabled`), sitemap dışı yollar (`SitemapExcludePaths`) |
| Yol bazlı alanlar | Yolu tanımlayan kaydın `Seo*` kolonları: `Route` (`Sas_H_Route`, ekran **Menü Yönetimi › Route**) ve `CustomComponent` (`Sas_H_CustomComponent`, ekran **DeveloperKit › Custom Components**) | Yolun başlığı, açıklaması, anahtar kelimeleri, paylaşım görseli, kanonik adresi, `SeoNoIndex`, sitemap davranışı ve ek JSON-LD |
| İstemci | `components/shared/SeoHead.tsx` | `title`, `description`, `robots`, `canonical`, `og:`/`twitter:` kartı, `og:locale:alternate` ve JSON-LD |
@ -1109,7 +1113,11 @@ Sayfanın kendi `SeoHead`'i, kabuğun (`PublicLayout`) `fallback` kaydını her
`sitemap.xml` ve `robots.txt` aynı servisten üretilir (`SeoController`, anonim). Sitemap'in
kaynakları: `Pub` menüleri, aktif custom component rotaları, yayınlanmış blog yazıları ve
yolu tanımlayan kayıtların `Seo*` alanları; `/admin` yolları, parametreli rotalar (`/blog/:id`) ve
`SeoNoIndex` işaretli yollar elenir. Arama motorları bu iki dosyayı **sitenin** kök dizininde aradığı için UI sunucusu her iki
`SeoNoIndex` işaretli ya da `SeoIncludeInSitemap = false` olan yollar elenir.
`App.SiteManagement.Seo.SitemapExcludePaths` (satır başına bir yol, sonu `*` ise önek) hem sitemap'ten
düşer hem `robots.txt`'e `Disallow` olarak yazılır; `robots.txt` ayrıca `/admin/`, `/auth/`,
`/checkout`, `/payment`, `/success` yollarını her zaman kapatır. `SitemapEnabled` kapalıyken
`sitemap.xml` 404 döner ve robots'a `Sitemap:` satırı yazılmaz. Arama motorları bu iki dosyayı **sitenin** kök dizininde aradığı için UI sunucusu her iki
yolu da API'ye geçirir (`vite.config.ts` > `seoProxy`, hem `server` hem `preview`); ayrı bir ters
vekil kuralı gerekmez. `VITE_API_URL` tanımlı değilse proxy kurulmaz ve `ui/public/robots.txt`
içindeki statik varsayılan geçerli kalır.
@ -1276,21 +1284,23 @@ Bildirimin tamamı Administration menüsünde `App.Administration.Notifications`
**Bildirim Türleri**, **Bildirim Kuralları**, **Bildirimler**, **Bildirim Şablonları**. Grup
Agenda'nın üstündedir; Saas altında bildirim ekranı **yoktur**.
Tablolar kiracı kapsamındadır (`Adm_T_NotificationType`, `Adm_T_NotificationRule`,
`Adm_T_Notification`; üçü de `IMultiTenant`). Her kiracı kendi türünü, kuralını ve kuyruğunu
Tablolar kiracı kapsamındadır (`Adm_T_NotificationTemplate`, `Adm_T_NotificationType`,
`Adm_T_NotificationRule`, `Adm_T_Notification`; dördü de `IMultiTenant`). Her kiracı kendi türünü, kuralını ve kuyruğunu
görür; host kaydı (`TenantId = null`) yalnızca host oturumunda görünür. Yeni bir kiracı
oluşturulduğunda varsayılan tür ve kural kümesi o kiracıya kopyalanır
(`NotificationTenantDefaultsSeedContributor`): kaynak host kapsamındaki
`data/App.Notifications.Notification{Types,Rules}.json` dosyalarıdır, satırlar **yeni
kimliklerle** yazılır ve eşleşme ad üzerinden yapıldığı için ikinci çalıştırma bir şey eklemez.
kimliklerle** yazılır ve eşleşme ad üzerinden yapıldığı için ikinci çalıştırma bir şey eklemez;
şablonlar kopyalanmaz.
**Bildirimler** ekranı (`App.Notifications.Notification`) hem kuyruk günlüğü hem gönderim
ekranıdır: liste kural motorunun ürettiklerini de gösterir, ekleme formu ise elle gönderimdir.
Ayrı bir manuel gönderim kaydı yoktur — gönderimin kaydı bildirimin kendisidir. Ekleme anında
yazma işi `list-form-dynamic-api/notification-insert` ucuna gider (`InsertServiceAddress`); uç
seçilen alıcı × kanal açılımını `INotificationManager.SendManualNotificationAsync` ile kuyruğa
yazar — yani Bildirim Kuralları ekranındaki elle gönderimle **aynı yol**, tek fark alıcı
kümesinin kurallardan değil ekrandan gelmesi. Güncelleme kapalıdır, silme kaydı kaldırır.
yazar. Bildirim Kuralları ekranındaki `CreateNotification` diyaloğu ise aynı yöneticinin
`SendNotificationAsync` yolunu kullanır: türün kurallarını işletir ve kullanıcı tercihini dikkate
alır; bu uç alıcıyı ekrandan alır ve tercihi okumaz. Güncelleme kapalıdır, silme kaydı kaldırır.
Formdaki `NotificationChannel` ve `UserId` alanları listede tek değerlidir (her satır bir
alıcı × kanal), formda `dxTagBox` ile çoklu seçilir; tipli DTO yolunda çoklu değeri
@ -1414,12 +1424,14 @@ liste süzgeci ve çağrı kapısı aynı kuralı kullanır.
| `save_dev_request_analysis` | `Backlog` ya da `Analysis` durumundaki talebin analizini (HTML) `Analysis` kolonuna yazar — var olanı değiştirir — ve talebi `Analysis` durumuna alır; diğer durumları reddeder. `Description`'a dokunmaz. Analizin standardı `lowcode.instructions.md` §0.12. `.Write` + `App.DevRequests.Update` ister. |
| `add_dev_request_subtasks` | Talebin `SubTasks` listesine tamamlanmış satırlar ekler: model yalnızca başlığı verir, atanan kişi bağlanan kullanıcının adı (`userName`), bitiş tarihi bugün (`yyyy-MM-dd`) olarak sunucuda yazılır; var olan satırlar korunur. `.Write` + `App.DevRequests.Update` ister. |
| `append_dev_request_note` | Talebin `Analysis` kolonunun sonuna HTML ekler (üretim sonuç notu); `Description` talebin yazıldığı hâliyle kalır. İkisi de `update_row` ile yazılmaz — açıklama base64 görsel taşır. `.Write` + `App.DevRequests.Update` ister. |
| `list_components` / `get_component` / `save_component` / `delete_component` | Custom component'ler `ICustomComponentAppService` üzerinden; seed senkronu ve `DataSources` çözümü aynen çalışır. `save_component` ada göre ekler/günceller, tasarımcı belgesi (`Props.visualDesigner`, `sourceMode ≠ code`) taşıyan bileşene kod yazmayı reddeder — kod belgeden üretildiği için tasarımcıdaki ilk kayıtta ezilirdi. |
**Timesheets.** Talebin `Timesheets` listesini sunucu doldurur (`IMcpDevRequestTimesheetRecorder`):
`get_dev_request` / `start_dev_request` talebi kullanıcının etkin talebi yapar (dağıtık önbellek,
`McpDevRequestActivityCacheItem`, 12 saat); sonraki her MCP yazma işlemi (`create_table`,
`deploy_wizard`, `delete_wizard`, `save_component`, `delete_component`, satır araçları,
`save_dev_request_analysis`) o talebe bir satır ekler. Açıklama `App.Mcp.Timesheet.*` anahtarından
`save_dev_request_analysis`, `append_dev_request_note`, `add_dev_request_subtasks`) o talebe bir satır
ekler; talebi açan `start_dev_request` yazmaz. Açıklama `App.Mcp.Timesheet.*` anahtarından
Türkçe üretilir, süre önceki satırdan ya da talebin açıldığı andan ölçülür (en az 1 dakika, saat
olarak), çalışan bağlanan kullanıcı, tarih bugündür. Etkin talep yoksa satır yazılmaz; bozuk bir
`Timesheets` değeri işlemi geri almaz, yalnızca satır atlanır ve log'a düşer.
@ -1454,7 +1466,6 @@ değilse sunucu reddeder ve hiçbir şey üretilmez.
başlıkta komut yerine Id ya da düz metin kullan. Başlık birden fazla talebe uyuyorsa sunucu Id ister.
- Düz metin de aynı yoldan geçer: sunucu talimatları modeli `start_dev_request`'e yönlendirir,
durum şartı yine sunucuda uygulanır.
| `list_components` / `get_component` / `save_component` / `delete_component` | Custom component'ler `ICustomComponentAppService` üzerinden; seed senkronu ve `DataSources` çözümü aynen çalışır. `save_component` ada göre ekler/günceller, tasarımcı belgesi (`Props.visualDesigner`, `sourceMode ≠ code`) taşıyan bileşene kod yazmayı reddeder — kod belgeden üretildiği için tasarımcıdaki ilk kayıtta ezilirdi. |
**Yetki modeli: MCP yetki vermez.** Kullanıcı MCP'de uygulamadaki yetkisini taşır; MCP'nin iki
yetkisi yalnızca kapıdır. Bir çağrı üç katmandan geçer ve her katman ayrı reddeder:
@ -1471,7 +1482,7 @@ yetkisi yalnızca kapıdır. Bir çağrı üç katmandan geçer ve her katman ay
| Yetki | Kim alabilir | Ne açar | Açmadığı / sınırı |
| --- | --- | --- | --- |
| `App.DeveloperKit.McpServers` | Host, kiracı | MCP Servers ekranını görme (`.Create/.Update/.Delete/.Export/.Import` ekran işlemleri) | `/mcp` ucuna erişim vermez |
| `App.DeveloperKit.McpServers.Invoke` | Host, kiracı | `/mcp` bağlantısı ve bütün okuma araçları: `server_info`, `list_lists`, `describe_list`, `search_schema`, `query_list`; host'ta ayrıca `get_dev_guide`, `list_wizards`, `get_wizard`, `verify_wizard`, `list_components`, `get_component` | Hiçbir şey yazmaz. Okuma da ekran yetkisine bağlıdır: `R` yetkisi olmayan liste görünmez, sorgulanamaz. Ham SQL (`run_select`, `list_queries`, `run_query`) ayrıca `App.SqlQueryManager` ister |
| `App.DeveloperKit.McpServers.Invoke` | Host, kiracı | `/mcp` bağlantısı ve bütün okuma araçları: `server_info`, `list_lists`, `describe_list`, `search_schema`, `query_list`; host'ta ayrıca `get_dev_guide`, `list_wizards`, `get_wizard`, `verify_wizard`, `get_dev_request`, `list_components`, `get_component` | Hiçbir şey yazmaz. Okuma da ekran yetkisine bağlıdır: `R` yetkisi olmayan liste görünmez, sorgulanamaz. Ham SQL (`run_select`, `list_queries`, `run_query`) ayrıca `App.SqlQueryManager` ister |
| `App.DeveloperKit.McpServers.Write` | Host, kiracı | MCP üzerinden her değişiklik. **Kiracıda:** `insert_row`, `update_row`, `delete_row`. **Host'ta:** bunlara ek olarak `create_table`, `deploy_wizard`, `delete_wizard`, `save_component`, `delete_component`, `start_dev_request`, `save_dev_request_analysis`, `append_dev_request_note`, `add_dev_request_subtasks` | Kendi başına bir şey yazdırmaz: satır araçları ekranın `C`/`U`/`D` yetkisini, geliştirme araçları Wizard / Custom Components / SQL Query Manager / `App.DevRequests.Update` yetkisini ayrıca ister. Kiracıda geliştirme araçlarını **açmaz** — kiracı bağlamında bu araçlar yetkiden bağımsız kapalıdır (`McpToolNames.TenantTools`). `Invoke` olmadan işe yaramaz |
**Araç → gereken yetkiler** (Invoke hepsinde aranır, tabloda tekrar yazılmadı)
@ -1960,7 +1971,7 @@ configs/seeds/
│ │ # Abp.Identity.Permission{Groups,s}.json — yetki tanımları
│ │ # App.Definitions.{CountryGroup,Country,City,District}.json — adres zinciri
│ │ # App.Definitions.{Currency,ContactTitle,AiBot}.json — para birimi, hitap, AI bot
│ │ # App.Notifications.Notification{Types,Rules}.json — bildirim tipi → kuralı
│ │ # App.Notifications.Notification{Templates,Types,Rules}.json — bildirim şablonu, tipi → kuralı
│ │ # App.Languages.{Language,LanguageText}.json — dil → metin (eksik LanguageKey metinle üretilir)
│ │ # App.SettingDefinitions.json, App.BackgroundWorkers.RecurringJobs.json — ayar tanımları, zamanlanmış işler
│ ├── sql/{object,execute}/ # .sql (SQL Server)
@ -1970,8 +1981,9 @@ configs/seeds/
```
> Bu dosyalar elle de düzenlenebilir; ilgili ekrandan tekrar kaydedildiğinde yeniden üretilirler.
> Wizard dosyası `EditFileName` ile güncellenirse sunucu önce eski dosyayı ve ürettiği kayıtları
> siler, sonra yenisini üretir. Wizard'ın ürettiği ekran **ListForm detayından** düzenlendiğinde
> Wizard dosyası `EditFileName` ile güncellenirse deploy veritabanına dokunmaz: dosyalar cevaptan
> yeniden yazılır (ad değiştiyse eski dosya silinir), önceki sürümün kayıtları `Pending.Replaced`'a
> alınır ve DB Migrate onları kaldırıp ekranı yeniden kurar (`lowcode.instructions.md` §4.0). Wizard'ın ürettiği ekran **ListForm detayından** düzenlendiğinde
> de aynı dosya güncellenir (`WizardSeedSynchronizer`): `ListForm`/`Fields` bölümleri ve
> `Wizard` bölümündeki karşılıkları veritabanındaki güncel haliyle değiştirilir.

View file

@ -448,6 +448,7 @@ public class McpDevelopAppService(
var devRequest = await FindDevRequestAsync(request);
devRequest.Analysis = string.Concat(devRequest.Analysis, html.Trim());
await devRequestRepository.UpdateAsync(devRequest, autoSave: true);
await timesheetRecorder.RecordAsync(McpTimesheetTexts.AppendNote);
}
/// <summary>
@ -497,6 +498,7 @@ public class McpDevelopAppService(
devRequest.SubTasks = subTasks.ToJsonString();
await devRequestRepository.UpdateAsync(devRequest, autoSave: true);
await timesheetRecorder.RecordAsync(McpTimesheetTexts.AddSubTasks, items.Count);
}
private static McpDevRequestDto ToDto(DevRequest devRequest)

View file

@ -9,6 +9,8 @@ public static class McpTimesheetTexts
private const string Prefix = "App.Mcp.Timesheet.";
public const string Analysis = Prefix + "Analysis";
public const string AppendNote = Prefix + "AppendNote";
public const string AddSubTasks = Prefix + "AddSubTasks";
public const string CreateTable = Prefix + "CreateTable";
public const string DeployWizard = Prefix + "DeployWizard";
public const string DeleteWizard = Prefix + "DeleteWizard";

View file

@ -80,71 +80,57 @@ public static class EditorOptions
/// <remarks>
/// <c>height</c> verilirse editor sabitlenir ve icerik kaydirilir; <c>min-height</c> ise
/// en az yuksekligi korurken yeni satirlarla buyumesine izin verir.
/// Bloklar UI'daki <c>htmlEditorOptions.ts</c> varsayilaniyla birebir aynidir: istemci ic ice
/// bloklari tek seviye birlestirdigi icin buradaki <c>toolbar</c> varsayilanin yerine gecer.
/// </remarks>
public static EditorOptionsBuilder Html(int minHeight = 200)
=> New()
.Raw("mediaResizing", "{\"enabled\":true}")
.Raw("imageUpload", "{\"tabs\":[\"file\",\"url\"],\"fileUploadMode\":\"base64\"}")
.Raw("toolbar", "{\"multiline\":true,\"items\":[" + string.Join(",", HtmlToolbarItems()) + "]}")
.Raw("imageUpload", "{\"tabs\":[\"file\",\"url\"],\"fileUploadMode\":\"base64\"}")
.Raw("mediaResizing", "{\"enabled\":true}")
.Raw("tableResizing", "{\"enabled\":true}")
.Raw("tableContextMenu", "{\"enabled\":true}")
.Flag("encodeHtml", true)
.Raw("elementAttr", "{\"style\":\"min-height:" + EditorJson.Number(minHeight) + "px\"}");
private static IEnumerable<string> HtmlToolbarItems()
{
var fontSizes = new[] { "8pt", "10pt", "12pt", "14pt", "18pt", "24pt", "36pt" };
var fontFamilies = new[]
{
"Arial", "Courier New", "Georgia", "Impact",
"Lucida Console", "Tahoma", "Times New Roman", "Verdana"
};
private static readonly string[] HtmlToolbarNames =
[
"undo", "redo", "separator",
"header", "size", "font", "separator",
"bold", "italic", "underline", "strike", "superscript", "subscript", "separator",
"color", "background", "separator",
"alignLeft", "alignCenter", "alignRight", "alignJustify", "separator",
"orderedList", "bulletList", "decreaseIndent", "increaseIndent", "separator",
"blockquote", "codeBlock", "link", "image", "separator",
"insertTable", "insertHeaderRow", "insertRowAbove", "insertRowBelow", "deleteRow",
"insertColumnLeft", "insertColumnRight", "deleteColumn", "cellProperties", "tableProperties", "deleteTable",
"separator", "clear"
];
yield return Item("undo");
yield return Item("redo");
yield return Item("separator");
yield return Picker("size", fontSizes, "Font size");
yield return Picker("font", fontFamilies, "Font family");
yield return Item("separator");
yield return Item("bold");
yield return Item("italic");
yield return Item("strike");
yield return Item("underline");
yield return Item("separator");
yield return Item("alignLeft");
yield return Item("alignCenter");
yield return Item("alignRight");
yield return Item("alignJustify");
yield return Item("separator");
yield return Item("orderedList");
yield return Item("bulletList");
yield return Item("separator");
yield return "{\"name\":\"header\",\"acceptedValues\":[false,1,2,3,4,5]}";
yield return Item("separator");
yield return Item("color");
yield return Item("background");
yield return Item("separator");
yield return Item("link");
yield return Item("image");
yield return Item("separator");
yield return Item("clear");
yield return Item("codeBlock");
yield return Item("blockquote");
yield return Item("separator");
yield return Item("insertTable");
yield return Item("deleteTable");
yield return Item("insertRowAbove");
yield return Item("insertRowBelow");
yield return Item("deleteRow");
yield return Item("insertColumnLeft");
yield return Item("insertColumnRight");
yield return Item("deleteColumn");
yield return Item("cellProperties");
yield return Item("tableProperties");
}
private static readonly string[] HtmlFontSizes = ["8pt", "10pt", "12pt", "14pt", "18pt", "24pt", "36pt"];
private static readonly string[] HtmlFontFamilies =
[
"Arial", "Courier New", "Georgia", "Impact",
"Lucida Console", "Segoe UI", "Tahoma", "Times New Roman", "Verdana"
];
private static readonly string[] HtmlHeaderValues = ["false", "1", "2", "3", "4", "5", "6"];
private static IEnumerable<string> HtmlToolbarItems()
=> HtmlToolbarNames.Select(name => name switch
{
"size" => Picker(name, HtmlFontSizes.Select(EditorJson.Quote), "Font size"),
"font" => Picker(name, HtmlFontFamilies.Select(EditorJson.Quote), "Font family"),
"header" => Picker(name, HtmlHeaderValues, "Header"),
_ => Item(name)
});
private static string Item(string name) => "{\"name\":" + EditorJson.Quote(name) + "}";
/// <summary><paramref name="values"/> JSON olarak yazilmis degerlerdir (metin tirnakli, sayi/bool ciplak).</summary>
private static string Picker(string name, IEnumerable<string> values, string ariaLabel)
=> "{\"name\":" + EditorJson.Quote(name) +
",\"acceptedValues\":[" + string.Join(",", values.Select(EditorJson.Quote)) + "]" +
",\"acceptedValues\":[" + string.Join(",", values) + "]" +
",\"options\":{\"inputAttr\":{\"aria-label\":" + EditorJson.Quote(ariaLabel) + "}}}";
}

View file

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Volo.Abp.Data;
using Volo.Abp.PermissionManagement;
@ -49,20 +48,5 @@ public static class AbpPermissionsExtensions
.Distinct()
.ToArray();
}
/// <summary>
/// Yetki ekranindaki sira (<see cref="PlatformConsts.Permissions.Order"/>) kardesler arasindadir;
/// yeni kayit en buyuk kardes sirasinin bir fazlasini alir, kardes yoksa 1. Bos birakilan sira
/// 0 olur ve kayit listenin en ustune cikar.
/// </summary>
public static int NextPermissionOrder(this IEnumerable<IHasExtraProperties> siblings)
{
return siblings.Select(s => s.GetProperty<int>(PlatformConsts.Permissions.Order)).DefaultIfEmpty(0).Max() + 1;
}
public static void SetPermissionOrder(this IHasExtraProperties record, int order)
{
record.SetProperty(PlatformConsts.Permissions.Order, order);
}
}

View file

@ -176,14 +176,19 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
- **`scriptRecipes.ts` (TS) ↔ `Domain.Shared/Editors/*.cs`** — biri değişirse diğeri de değişir.
İkisinin çıktısı **birebir aynı** olmak zorundadır; aksi hâlde seeder ile basılan script
dialogda "elle düzenlenmiş" sayılır ve kural editörü kapanır.
- **`htmlEditorOptions.ts` ↔ `EditorOptions.Html`** — HtmlEditor varsayılanı iki yerde yazılır ve
bloklar birebir aynıdır. İstemci iç içe blokları tek seviye birleştirdiği için seed edilen
`toolbar` varsayılanın yerine geçer; biri değişip diğeri değişmezse seed'li ekranlar eski araç
çubuğunu gösterir.
- **Wizard seed dosyasında tekrar yok** → `Wizard` bölümü yalnızca ekrandan üretilemeyen bilgileri
taşır. `ListForm`/`Fields` içinde karşılığı olan her alan (veri kaynağı, select, anahtar alan,
kırılım/düzen/düzenleme bayrakları, görünüm option blokları, alt form, widget, iş akışı, alan
tanımları) dosyaya yazılmadan çıkarılır (`WizardSeedFileDto.ToSeedJson`) ve okurken geri
doldurulur (`FromSeedJson`). Wizard'a yeni bir alan eklerken karşılığı ListForm'da varsa listeye ekle.
Dosyada kalan wizard alanları üç başlık altında toplanır — `Menu`, `Language`, `Groups` — ve
`ListFormCode` → `WizardCode`, `MenuParentModuleId` → `ModuleId` adıyla yazılır; varsayılanı olan
alanlar (`CreateMenu: true`, boş `DataSourceConnectionString`) hiç yazılmaz. Bu yalnızca dosya biçimidir; C#
`ListFormCode` → `WizardCode`, `MenuParentModuleId` → `ModuleId`, `LanguageTexts` → `Language.Texts`
adıyla yazılır; varsayılanı olan alanlar (`CreateMenu: true`, boş `DataSourceConnectionString`, boş
`MenuParentPath` / `LanguageTexts`) hiç yazılmaz. Bu yalnızca dosya biçimidir; C#
sözleşmesi düzdür, dönüşüm `WizardSeedFileDto.ToSeedJson` / `FromSeedJson` içindedir. **Wizard
seed dosyası her zaman bu iki metotla okunup yazılır**; düz `JsonSerializer` çağrısı bloklu
bölümleri sessizce düşürür.
@ -264,8 +269,10 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
`add_dev_request_subtasks` ile yazılır: atanan kişi bağlanan kullanıcı, bitiş tarihi bugün —
sunucu doldurur, modele bırakılmaz. `Timesheets`'i tamamen sunucu yazar
(`IMcpDevRequestTimesheetRecorder`): `get_dev_request`/`start_dev_request` talebi etkin talep yapar,
sonraki her MCP yazma işlemi ona `App.Mcp.Timesheet.*` anahtarından Türkçe açıklama ve ölçülen
süreyle bir satır ekler. Yeni bir MCP yazma aracı eklenirse kaydedici çağrısı ve dil anahtarı da eklenir.
sonraki her üretim/veri yazma işlemi (`create_table`, `deploy_wizard`, `delete_wizard`,
`save_component`, `delete_component`, satır araçları, `save_dev_request_analysis`,
`append_dev_request_note`, `add_dev_request_subtasks`) ona `App.Mcp.Timesheet.*` anahtarından Türkçe
açıklama ve ölçülen süreyle bir satır ekler; yalnızca talebi açan `start_dev_request` satır yazmaz. Yeni bir üretim/veri yazma aracı eklenirse kaydedici çağrısı ve dil anahtarı da eklenir.
- **Talep analizi** → `Description` talebin yazıldığı hâliyle kalır; MCP ona yazmaz. Analiz ve
üretim notları `Analysis` kolonundadır (Todo panosunda `AnalysisExpr`, Açıklama yanında sekme).
Durum sırası `Backlog → Analysis → Ready to Start → …`: "Analiz et" `save_dev_request_analysis`
@ -289,8 +296,8 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
karşılık gelen yetkiyle eklenir. `create_table` bu yüzden `.Write`'a ek olarak `App.SqlQueryManager`
ister; tablo scriptini tasarımcının `generateCreateTableSql` çıktısıyla aynı biçimde üretir
(`McpTableCreator`) — tasarımcının şablon kolonları ya da script biçimi değişirse o da değişir.
- **Bildirim kapsamı** → bildirim tipi, kuralı ve kuyruğu kiracıya aittir (`Adm_T_NotificationType`,
`Adm_T_NotificationRule`, `Adm_T_Notification`; üçü de `IMultiTenant`) ve ekranların tamamı
- **Bildirim kapsamı** → bildirim tipi, kuralı ve kuyruğu kiracıya aittir (`Adm_T_NotificationTemplate`,
`Adm_T_NotificationType`, `Adm_T_NotificationRule`, `Adm_T_Notification`; dördü de `IMultiTenant`) ve ekranların tamamı
Administration › Bildirimler altındadır. Ayrı bir manuel gönderim tablosu yoktur: **Bildirimler**
ekranının ekleme formu elle gönderimdir, uç alıcı × kanal açılımını kuyruğa yazar
(`list-form-dynamic-api/notification-insert`). Yeni kiracıya varsayılan tür/kural kümesi

View file

@ -67428,6 +67428,34 @@
"Key": "App.Mcp.Timesheet.DeleteRow",
"Value": "{0} ekranından satır silindi"
},
{
"Id": "02d139fc-753d-567a-b672-8aa0a0212ad0",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Mcp.Timesheet.AppendNote",
"Value": "Production note added to the analysis"
},
{
"Id": "9e9cc3eb-557b-5a02-8730-29347f4f77b4",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Mcp.Timesheet.AppendNote",
"Value": "Analize üretim notu eklendi"
},
{
"Id": "eb67cbd2-c6b3-57d6-ab44-ee7e79636553",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Mcp.Timesheet.AddSubTasks",
"Value": "{0} completed subtasks added"
},
{
"Id": "ec94c375-713b-51f8-8db8-5e58b9e4ce7b",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Mcp.Timesheet.AddSubTasks",
"Value": "{0} tamamlanmış alt görev eklendi"
},
{
"Id": "a5e491f7-a85c-572f-bf66-4245cb84fa36",
"CultureName": "en",

View file

@ -3,6 +3,7 @@
* `<HtmlEditor {...htmlEditorDefaults}>` ile, dinamik formlar `mergeHtmlEditorOptions` ile
* aynı yetenek setini alır; ListForm'daki "HTML toolbar" kalıbı da buradan beslenir.
* Değerler JSON'a yazılabilir kalmalıdır — kalıp editorOptions kolonuna olduğu gibi kaydedilir.
* Seed'li ekranlar aynı blokları C# `EditorOptions.Html` ile yazar; biri değişirse diğeri de değişir.
*/
import type { Properties as HtmlEditorProperties } from 'devextreme/ui/html_editor'