sozsoft-platform/.github/instructions/lowcode-reference.instructions.md
2026-08-28 10:47:17 +03:00

1373 lines
92 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Low-Code Genişletilmiş Referans (JSON Kolon ve Modül Sözleşmeleri)
`lowcode.instructions.md` **nasıl üretileceğini** anlatır; bu dosya **neyin ayarlanabildiğini**
tek tek listeler. Orada "bunun bir JSON kolonu var" denen her şeyin alan alan karşılığı burada
durur: ListForm/ListFormField'ın tüm JSON kolonları, grafik sözleşmesi, Visual Designer envanteri
ve zamanlanmış e-posta modülü. Son bölüm (§12) Saas ve Administration menülerindeki **hazır
gelen bütün ekranları** ve bunların yeni bir komponentte nasıl kullanılacağını listeler.
**Kullanım sırası:** `ai.instructions.md``lowcode.instructions.md`**bu dosya**`README.md`.
Bir istek geldiğinde önce ana dosyadaki karar sırasını işlet; "hangi anahtarı yazacağım?"
sorusunda buraya bak.
**Kaynak:** Buradaki her tablo `api/src/Sozsoft.Platform.Application.Contracts/ListForms/**` ve
`api/src/Sozsoft.Platform.Domain/Entities/Tenant/ListForm/ListForm.cs` dosyalarından çıkarılmıştır.
Çelişki hâlinde **kod esastır**; bu dosya güncellenir.
**Ortak kurallar**
- Bütün `*Json` kolonları veritabanında **tek satır JSON string** olarak durur; wizard seed
dosyasına yazarken kaçışlanır.
- Varsayılan değeri olan bir alanı tekrar yazmak zorunda değilsin; yalnızca farklı olanı yaz.
- `Accepted Values` yazan yerlerde değer birebir eşleşmelidir (büyük/küçük harf dahil).
- **Bilinmeyen anahtar sessizce düşer — tarayıcıya hiç ulaşmaz.** `GridOptionsDto` bu 47
kolonun ham metnini `[JsonIgnore]` ile gizler ve istemciye yalnızca tipli DTO'ya
(`SchedulerOptionJson` → `SchedulerOptionDto`) çözülmüş hâlini yollar. Dolayısıyla:
- DTO'da olmayan bir DevExtreme seçeneğini `*Json`'a yazmak **işe yaramaz**; kalıcı olarak
gerekiyorsa önce ilgili DTO'ya alan eklenir (ve bu dosya güncellenir).
- Yanlış **tipte** yazılan değer (`"3"` yerine `3`, dizi yerine metin) `JsonSerializer`
tarafında `JsonException` fırlatır ve ekranın metadata isteği tamamen düşer — sessiz
değil, gürültülü bir hatadır. Tipleri tablodaki gibi yaz.
- Bu kural yalnızca alan seviyesindeki `ListFormField.EditorOptions` için geçmez: orası
ham metin olarak taşınır, tanımadığı anahtarı doğrudan editöre geçirir (§9.8).
---
## 0. Üretim yetenek envanteri — bir komponent üretirken tara
Bir ekran/komponent üretirken **her katmanı sırayla geç**. Cevabı "gerekmiyor" olan katmanı atla,
ama hiçbirini görmeden bırakma; kullanıcı "şunu da yapabilir miydik?" dediğinde cevap
"kod yazmamız gerekir" olmasın.
| # | Katman | Sorulacak soru | Nerede |
| --- | --- | --- | --- |
| 0 | **Hazır yetenek** | Bu talebin karşılığı Saas/Administration menüsünde zaten var mı? | §12.5 |
| 1 | **Veri** | Tablo/view var mı, join gerekiyor mu, anahtar ve tipi ne? | `lowcode` §8 · §9.6 |
| 2 | **Ekran türü** | Liste mi, tek kayıt formu mu, serbest yerleşim mi? Kaç görünüm açılacak? | `lowcode` §0.6.1 · §9.8 · §5.4 |
| 3 | **Sütunlar** | Editör tipi, biçim, hizalama, genişlik, band, gizli/aktif | `lowcode` §4.3 · §9.7 |
| 4 | **Lookup** | Sabit liste mi, sorgu mu, servis mi? Cascade var mı? | `lowcode` §4.3.4 |
| 5 | **Varsayılanlar** | Kullanıcı/tarih/tenant/sequence/sorgu ile otomatik dolacak alanlar | `lowcode` §4.3.5 · §9.9 |
| 6 | **Alan davranışı** | Hesap, kopyalama, temizleme, koşullu kilit, uyarı, servis çağrısı | `lowcode` §5 |
| 7 | **Editör görünümü** | Maske, ondalık, tarih biçimi, arama, çoklu seçim, görsel yükleme | `lowcode` §6 |
| 8 | **Doğrulama** | Zorunluluk, aralık, desen, karşılaştırma + sunucu tarafı kontrol | `lowcode` §4.3.6 · §4 |
| 9 | **Filtre/arama** | Filtre satırı, başlık filtresi, arama paneli, ek filtre çubuğu, grup paneli | §2.6 · `lowcode` §4.3.8 |
| 10 | **Özet** | Toplam/adet satırı, grup özetleri, pivot | §9.5 · §6 |
| 11 | **Biçimlendirme** | Koşullu satır/hücre rengi, CSS sınıfı | `lowcode` §4.3.7 |
| 12 | **Düzenleme deneyimi** | Popup/satır/hücre/batch, form grupları, kopyalama, toplu silme | §3 |
| 13 | **Aksiyonlar** | Toolbar ve satır butonları: adres, diyalog, script, yetki, koşullu görünürlük | `lowcode` §4.9 |
| 14 | **Yazma mantığı** | Özel SQL, before/after kancaları, farklı servis adresi | §4 |
| 15 | **Ana-detay** | Alt form sekmeleri ve ilişki alanları | §5.2 |
| 16 | **Gösterge** | Üstte KPI kartları, grafik | §5.3 · §8 |
| 17 | **Süreç** | Onay akışı, bilgilendirme, durum alanları | `lowcode` §4.7 |
| 18 | **Otomasyon** | Zamanlanmış iş, zamanlanmış e-posta, bildirim kuralı | `lowcode` §9.10§9.11 · §11 |
| 19 | **Çıktı** | Hazır grid raporu ya da rapor şablonu | `lowcode` §9.12 |
| 20 | **Yetki** | Ekran, alan, komut ve buton yetkileri; menü görünürlüğü | §5.1 · `lowcode` §4.2 |
| 21 | **Tenant/şube** | `IsTenant`, `IsBranch`, `IsOrganizationUnit`, sorgularda kırılım | `lowcode` §4.2 |
| 22 | **Dil** | Menü, başlık, alan, buton, mesaj metinleri EN + TR | `lowcode` §4.2 |
| 23 | **Kullanıcı tercihi** | Grid durumunun saklanması, kullanıcı/rol/dil varyantı | §2.5 · §5.7 |
| 24 | **Seed** | Üretilen her artefaktın dosyası + yalnızca DB'de yaşayan kayıtların geri getirici script'i | `lowcode` §0.2 · §9.14 |
Serbest yerleşimli bir komponent (Visual Designer) üretiyorsan 02 ve 1324 aynen geçerlidir;
312 yerine tasarımcı envanteri (§10.1), `Form` sözleşmesi (§10.2), veri kaynağı/filtre
sözleşmesi (§10.4), bileşen prop sözleşmeleri (§10.5§10.9), olay yükleri (§10.10) ve event
script'leri (`lowcode` §7.8) kullanılır. 20. katman (yetki) orada
iki yerdedir: düğüm başına `designerPermission` ve `Form`'un dört komut yetkisi.
Katmanların çoğunda cevap yeni bir artefakt değil, platformun **hazır bir ekranıdır**: numaratör,
bildirim, zamanlanmış iş, rapor, ayar, dil, yetki, şube, kısıt, dosya. Hepsinin envanteri §12'de —
"kod yazmamız gerekir" demeden önce §12.5'e bak.
---
## 1. ListForm JSON kolon haritası
Bir List ekranının bütün davranışı bu kolonlardadır. "Şunu yapabilir miyiz?" sorusunun cevabı
önce bu tabloda aranır.
Aşağıdaki tablo `*Json` bloklarını listeler. Bunların **öncesinde** ekranın düz kolonları gelir
ve çoğu isteğin cevabı aslında oradadır:
| Kolon | Varsayılan | Ne yapar |
| --- | --- | --- |
| `ListFormCode` | — | Ekranın kimliği; route, metadata ve varyantlar bu koda bağlanır |
| `DataSourceCode` | `"Default"` | Hangi bağlantıdan okunacağı (`Sas_H_DataSource`) |
| `SelectCommandType` | `1` Table | `1` Table · `2` View · `3` TableValuedFunction · `4` Query · `5` StoredProcedure |
| `SelectCommand` | — | Tablo/view adı, fonksiyon çağrısı ya da sorgu metni |
| `TableName` | `SelectCommand` | Üretilen `SELECT`'te kolonların ve join'lerin önüne yazılan **alias**. Boşsa `SelectCommand` kullanılır; `SelectCommand` bir sorgu metni ya da fonksiyon çağrısıysa buraya kısa bir ad yaz |
| `KeyFieldName` · `KeyFieldDbSourceType` | — · `16` String | Anahtar kolon ve `System.Data.DbType` karşılığı |
| `SelectFieldsDefaultValueJson` | — | **Okuma** sorgusuna parametre olarak katılan değerler (`FieldsDefaultValueDto[]`) — `@USERID`, `@TENANTID` gibi |
| `DefaultFilter` | — | Her sorgunun sonuna `AND` ile eklenen sabit `WHERE` koşulu. `DefaultValueHelper` üzerinden geçer, yani `@USERID`/`@TENANTID`/`@NOW` gibi token'lar çözülür. Soft delete'li tabloda (`IsDeletedField: true`) wizard buraya `"IsDeleted" = 'false'` yazar |
| `SortMode` | — | `UiGridSortModeEnum`: `1` Single · `2` Multiple · `3` None |
| `PageSize` | — | Sayfa başına kayıt; `0` = tümü |
| `Name` · `Title` · `Description` | — | Ekran adı, başlığı, açıklaması**dil anahtarı** yazılır |
| `IsTenant` · `IsBranch` · `IsOrganizationUnit` | `IsMultiTenant` · `false` · `false` | Otomatik kırılım filtresi |
| Kolon | Ne yapılandırır | Bölüm |
| --- | --- | --- |
| `ColumnOptionJson` | Grid genel görünümü (kenarlık, satır rengi, kolon seçici, sabitleme) | §2.1 |
| `CommandColumnJson` | Toolbar ve satır butonları | `lowcode` §4.9 |
| `RowJson` | Satır yüksekliği ve metin kaydırma | §2.2 |
| `PagerOptionJson` | Sayfalama şeridi | §2.3 |
| `SelectionJson` | Seçim modu ve checkbox davranışı | §2.4 |
| `StateStoringJson` | Kullanıcının grid tercihlerinin saklanması | §2.5 |
| `FilterRowJson` · `HeaderFilterJson` · `FilterPanelJson` · `SearchPanelJson` · `GroupPanelJson` | Filtre/arama/gruplama panelleri | §2.6 |
| `ExtraFilterJson` | Ekran üstü ek filtre çubuğu | `lowcode` §4.3.8 |
| `EditingOptionJson` | Düzenleme modu, izinler, popup ayarları | §3.1 |
| `EditingFormJson` | Düzenleme formunun grup/sekme yerleşimi | §3.2 |
| `InsertCommand` · `UpdateCommand` · `DeleteCommand` (+ `*Before`/`*After`) | Özel SQL komutları ve kancalar | §4 |
| `*FieldsDefaultValueJson` | Otomatik doldurulan alanlar | `lowcode` §4.3.5 |
| `*ServiceAddress` | Yazma işlemini karşılayan uç | §4.3 |
| `PermissionJson` | Ekran yetkileri | §5.1 |
| `SubFormsJson` | Alt form sekmeleri | §5.2 |
| `WidgetsJson` | KPI kartları | §5.3 |
| `WorkflowJson` | Onay akışı | `lowcode` §4.7 |
| `LayoutJson` | Açık görünümler ve varsayılan | §5.4 |
| `PivotOptionJson` | Pivot görünümü | §6 |
| `TreeOptionJson` · `GanttOptionJson` · `SchedulerOptionJson` · `TodoOptionJson` | Ağaç/Gantt/Takvim/Kanban eşlemeleri | §7 |
| `SeriesJson` ve diğer 21 grafik kolonu | Chart görünümü | §8 |
| `CustomJsSourcesJson` · `CustomStyleSourcesJson` | Sayfaya enjekte edilen JS/CSS | §5.5 |
| `AdaptiveLayoutJson` | Dar ekranda öğe gizleme (grafik) | §8.4 |
| `CommonJson` · `DataSourceJson` | Grafik geneli ve grafik sorgusu | §8.2 · §8.3 |
| `Width` · `Height` · `FullHeight` | Ekran boyutu | — |
| `ListFormType` · `IsSubForm` · `SubFormsListFormType` · `ShowNote` | Ekranın türü ve alt form davranışı | §5.6 |
| `CultureName` · `UserId` · `RoleId` | Aynı ekranın dil/kullanıcı/rol varyantı | §5.7 |
---
## 2. Grid görünümü
### 2.1 `ColumnOptionJson` (`GridColumnOptionDto`)
| Anahtar | Varsayılan | Anlam |
| --- | --- | --- |
| `ShowBorders` | `true` | Dış kenarlık |
| `ShowRowLines` | `true` | Satır çizgileri |
| `ShowColumnLines` | `false` | Kolon çizgileri |
| `RowAlternationEnabled` | `true` | Tek/çift satır renklendirme |
| `AllowColumnReordering` | `true` | Kullanıcı kolon sırasını değiştirebilir |
| `AllowColumnResizing` | `true` | Kolon genişliği değiştirilebilir |
| `ColumnResizingMode` | `"widget"` | `nextColumn` \| `widget` |
| `ColumnAutoWidth` | `false` | İçeriğe göre genişlik |
| `ColumnFixingEnabled` | `false` | Kolon sabitleme menüsü |
| `ColumnChooserEnabled` | `false` | Kolon seçici düğmesi |
| `ColumnChooserMode` | `"dragAndDrop"` | `dragAndDrop` \| `select` |
| `ColumnHidingEnabled` | `true` | Dar ekranda kolon gizleme |
| `HoverStateEnabled` | `false` | Satır üzerine gelince vurgulama |
| `FocusedRowEnabled` | `true` | Odaklı satır |
| `ShowColumnHeaders` | `true` | Başlık satırı |
| `RtlEnabled` | `false` | Sağdan sola |
### 2.2 `RowJson` (`GridRowDto`)
| Anahtar | Varsayılan | Anlam |
| --- | --- | --- |
| `RowHeight` | `"auto"` | Satır yüksekliği (CSS) |
| `WhiteSpace` | `"normal"` | Uzun metnin kaydırılması |
| `OverflowWrap` | `"break-word"` | Kelime kırma |
### 2.3 `PagerOptionJson` (`GridPagerOptionDto`)
Adı yalnızca sayfalamayı çağrıştırsa da bu blok **kaydırma ve yükleniyor panelini** de taşır.
| Anahtar | Varsayılan | Anlam |
| --- | --- | --- |
| `Visible` | `true` | Sayfalama şeridi |
| `ShowPageSizeSelector` | `false` | Sayfa boyu seçici |
| `ShowInfo` | `false` | "Page 1 of 4 (37 items)" bilgisi |
| `ShowNavigationButtons` | `true` | İleri/geri düğmeleri |
| `AllowedPageSizes` | `"10,20,50,100"` | **Virgüllü metin**, dizi değil |
| `InfoText` | `"Page {0} of {1} ({2} items)"` | `{0}` sayfa · `{1}` toplam sayfa · `{2}` kayıt |
| `DisplayMode` | `"adaptive"` | `adaptive` \| `compact` \| `full` |
| `ScrollingMode` | `"standard"` | `standard` \| `virtual` \| `infinite` — uzun listelerde `virtual` |
| `LoadPanelEnabled` | `"auto"` | **Metin** alanıdır: `"auto"` \| `"true"` \| `"false"` |
| `LoadPanelText` | `"Loading..."` | Yükleniyor metni |
Sayfa başına kayıt sayısı ekranın `PageSize` alanındadır; `0` = tümü. `ScrollingMode` ile
`PageSize` birlikte düşünülür: `virtual`/`infinite` seçilip `PageSize: 0` yazılırsa sayfalama
devre dışı kalır ve tüm küme tek istekte çekilir.
### 2.4 `SelectionJson` (`SelectionDto`)
| Anahtar | Varsayılan | Değerler |
| --- | --- | --- |
| `Mode` | `"none"` | `single` \| `multiple` \| `none` |
| `AllowSelectAll` | `false` | |
| `SelectAllMode` | `"allPages"` | `allPages` \| `page` |
| `ShowCheckBoxesMode` | `"always"` | `always` \| `none` \| `onClick` \| `onLongTap` |
Toolbar butonları seçili satırlarla çalışır (`lowcode` §4.9); onay akışı varsa wizard `single` yazar.
### 2.5 `StateStoringJson` (`StateStoringDto`)
| Anahtar | Varsayılan | Anlam |
| --- | --- | --- |
| `Enabled` | `true` | Kullanıcının kolon/filtre/sıralama tercihleri saklansın mı |
| `Type` | `"custom"` | `custom` (sunucuda kullanıcı bazlı) \| `localStorage` \| `sessionStorage` |
| `StorageKey` | — | Anahtar; boşsa ekran kodundan türer |
| `SavingTimeout` | `5000` | Değişiklikten kaç ms sonra yazılacağı**`[Range(1500, 5000)]`**, dışına çıkan değer doğrulamada reddedilir |
`Type: "custom"` tercih edilir: tercih sunucuda `ListFormCustomization` kaydı olarak
(`ListFormCustomizationTypeEnum.GridState = 2`) kullanıcı bazlı saklanır, bu yüzden başka
tarayıcıdan girildiğinde de korunur. `localStorage`/`sessionStorage` yalnızca o tarayıcıdadır.
### 2.6 Filtre, arama ve gruplama panelleri
**`FilterRowJson`** (`GridFilterRowDto`): `Visible` (`false`), `ApplyFilter` (`auto` \| `onClick`),
`AllowUserUiFilterSave` (varsayılan `true` — kullanıcı kendi filtresini kaydedebilir;
kayıt `ListFormCustomizationTypeEnum.UserUiFilter = 1` olarak tutulur).
**`HeaderFilterJson`** (`GridHeaderFilterDto`): `Visible` (`false`), `AllowSearch` (`false`),
`Height` (`325`), `Width` (`252`), `SearchTimeout` (`500`).
**`FilterPanelJson`** (`FilterPanelDto`): `Visible` (`false`), `FilterEnabled` (`false`),
`Texts.ClearFilter` (`"Clear"`) / `Texts.CreateFilter` (`"Create Filter"`) /
`Texts.FilterEnabledHint` (`"Enable the filter"`), `CustomizeText` (serbest JSON; filtre
metnini biçimlendirmek için — sözlükte tipi yoktur, olduğu gibi bileşene geçer).
**`SearchPanelJson`** (`SearchPanelDto`): `Visible` (`false`), `Width` (`160`).
**`GroupPanelJson`** (`GroupPanelDto`): `Visible` (`false`), `AutoExpandAll` (`false`).
`AutoExpandAll: true` **fazladan bir sorgu daha** çalıştırır.
---
## 3. Düzenleme
### 3.1 `EditingOptionJson` (`GridEditingDto`)
| Anahtar | Varsayılan | Anlam |
| --- | --- | --- |
| `Mode` | `"popup"` | `batch` \| `cell` \| `row` \| `form` \| `popup` |
| `RefreshMode` | `"full"` | `full` \| `reshape` \| `repaint` |
| `AllowAdding` / `AllowUpdating` / `AllowDeleting` | `false` | Aksiyon izinleri (yetki ayrıca `PermissionJson`) |
| `AllowAllDeleting` | `false` | Toplu silme düğmesi |
| `AllowDuplicate` | `false` | Kaydı kopyalayarak yeni kayıt |
| `AllowDetail` | `false` | Satırda Detay düğmesi |
| `ConfirmDelete` | `true` | Silme onayı |
| `UseIcons` | `false` | Aksiyonlar ikon olarak |
| `NewRowPosition` | `"viewportTop"` | `first` \| `last` \| `pageTop` \| `pageBottom` \| `viewportTop` \| `viewportBottom` |
| `StartEditAction` | `"click"` | `click` \| `dblClick` |
| `SelectTextOnEditStart` | `false` | Düzenlemeye girince metni seç |
| `EditColumnName` | — | Aksiyon sütununun başlığı |
| `SendOnlyChangedFormValuesUpdate` | `false` | Update'te yalnızca değişen alanları gönder |
| `AddPageUrl` | — | Yeni kayıt popup yerine bu adreste açılır |
| `Popup` | — | Aşağıdaki alt nesne |
`Popup` (`GridEditingPopupDto`): `Title`, `ShowTitle` (`true`), `Width` (`700`), `Height` (`500`),
`FullScreen` (`false`), `HideOnOutsideClick` (`true`), `ResizeEnabled` (`true`),
`DragEnabled` (`true`), `RestorePosition` (`true`),
`Position` (`center` \| `top` \| `bottom` \| `left` \| `right`).
### 3.2 `EditingFormJson` (`EditingFormDto[]`)
Düzenleme formundaki grupların listesi. Alanların hangi gruba düştüğü `ListFormField` üzerindeki
`EditGroupOrderNo` / `EditOrderNo` ile belirlenir.
| Anahtar | Varsayılan | Anlam |
| --- | --- | --- |
| `Order` | `1` | Grubun sırası (`EditGroupOrderNo` ile eşleşir) |
| `ItemType` | `"group"` | `group` (kullanılan) \| `tabbed` \| `simple` \| `empty` \| `button` |
| `Caption` | — | Grup başlığı (dil anahtarı) |
| `ColCount` | `2` | Grup içi kolon sayısı |
| `ColSpan` | `2` | Grubun formda kapladığı kolon |
Wizard bu listeyi `Groups` bloğundan üretir; anahtar alan ve `IncludeInEditingForm: false`
olanlar dışarıda kalır.
---
## 4. Yazma komutları ve kancalar
### 4.1 Komutlar
| Kolon | Ne zaman |
| --- | --- |
| `InsertCommand` / `UpdateCommand` / `DeleteCommand` | Boşsa platform komutu kendi üretir; doluysa **bu SQL** çalışır |
| `InsertBeforeCommand` / `InsertAfterCommand` | Insert'ten önce/sonra |
| `UpdateBeforeCommand` / `UpdateAfterCommand` | Update'ten önce/sonra |
| `DeleteBeforeCommand` / `DeleteAfterCommand` | Delete'ten önce/sonra |
**Kancalar, kod yazmadan iş mantığı çalıştırmanın yeridir**: stok düşme, hareket kaydı, durum
güncelleme, log, bildirim kuyruğuna satır ekleme. Karmaşıklaşınca gövdeyi bir stored procedure'e
taşı ve kancadan onu çağır (`EXEC Wms_S_AfterOrderInsert @Id, @USERID`).
### 4.2 Komut içinde kullanılabilen anahtarlar
| Token | Değer |
| --- | --- |
| `@ID` | Kaydın anahtarı (Delete'te seçili anahtar kümesi) |
| `@USERID` · `@USERNAME` · `@ROLES` | Oturumdaki kullanıcı |
| `@FieldName` | Ekrandan gelen o alanın değeri — tablodaki her kolon için geçerlidir (`@OrderNo`, `@Amount`) |
`*FieldsDefaultValueJson` ile üretilen değerler (`@NOW`, `@NEWID`, `@TENANTID`, Sequence…)
komuta parametre olarak katılır (`lowcode` §4.3.5). **String birleştirme ile sorgu kurma.**
### 4.3 `*ServiceAddress`
`InsertServiceAddress` / `UpdateServiceAddress` / `DeleteServiceAddress` varsayılan olarak
`list-form-data/insert|update|delete` uçlarıdır. Yazma işini bir Custom Endpoint ya da Dynamic
Service'e devretmek istiyorsan bu alanı o ucun adresiyle değiştirirsin — ekranın geri kalanı
(form, doğrulama, yetki) aynı kalır.
---
## 5. Ekran seviyesindeki diğer bloklar
### 5.1 `PermissionJson` (`PermissionCrudDto`)
Tek harfli anahtarlar: `R` (read), `C` (create), `U` (update), `D` (delete), `E` (export),
`I` (import), `N` (note). Değerler **yetki adıdır**, boolean değil:
```json
{ "R": "App.Mrp.Orders", "C": "App.Mrp.Orders.Create", "U": "App.Mrp.Orders.Update",
"D": "App.Mrp.Orders.Delete", "E": "App.Mrp.Orders.Export", "I": "App.Mrp.Orders.Import",
"N": "App.Mrp.Orders.Note" }
```
Alan seviyesindeki karşılığı `ListFormField.PermissionJson`'dır ve **şeması farklıdır**
(`ListFormFieldPermissionDto`) — ekran seviyesindeki yedi harfli sözleşmeyi buraya kopyalama:
| Anahtar | Tip | Anlam |
| --- | --- | --- |
| `Deny` | bool | `true` ise alan **hiç dönmez**; diğer anahtarlara bakılmaz |
| `C` · `R` · `U` | string | Yaratma / okuma / güncelleme yetkisinin **adı**. Boşsa ekranın kendi Create/Read/Update yetkisi kullanılır |
| `E` | bool | Alan dışa aktarımda yer alsın mı |
| `I` | bool | Alan içe aktarımda kabul edilsin mi |
```json
{ "C": "App.Mrp.Orders.Create", "R": "App.Mrp.Orders", "U": "App.Mrp.Orders.Update",
"E": true, "I": true, "Deny": false }
```
`ListFormField` üzerindeki `CanRead` / `CanCreate` / `CanUpdate` / `CanExport` kolonları
**veritabanında yoktur** (`[NotMapped]`); `ListFormFieldManager.SetPermissionsAsync` bu
JSON'u oturumdaki yetkilerle karşılaştırarak istek başına hesaplar. Üçü de `false` çıkan alan
metadata'dan tamamen düşer — yani okuma yetkisi olmayan bir kolon sorguya bile girmez.
Wizard varsayılan olarak `DefaultFieldPermissionJson(permissionName)` üretir.
### 5.2 `SubFormsJson` (`SubFormDto[]`)
| Anahtar | Anlam |
| --- | --- |
| `TabType` | Sekmenin görünümü — `ListFormTabTypeEnum`: `List` \| `Card` \| `Tree` \| `Gantt` \| `Scheduler` \| `Todo` \| `Form` \| `Chart` \| `Pivot` |
| `TabTitle` | Dil anahtarı |
| `Code` | Hedef `ListFormCode` |
| `IsRefresh` | Ana kayıt değişince yenilensin |
| `Relation[]` | `ParentFieldName``ChildFieldName` + `DbType` (`System.Data.DbType`, **sayı**; bileşik anahtarda birden çok satır) |
Alt formun kendisi de bir ListForm'dur: `IsSubForm = true` olmalı ve genellikle `CreateMenu:
false` ile menüsüz üretilir (`lowcode` §4.2). `TabType`, hedef ekranın `LayoutJson`'ında açık
olan bir görünüm olmalıdır; kapalı bir görünüm sekmede boş çizilir.
### 5.3 `WidgetsJson` (`WidgetEditDto[]`)
Ekranın üstündeki KPI şeridi. **Sözleşmesi sezgisel değildir, dikkatle oku:**
| Anahtar | Ne yazılır |
| --- | --- |
| `SqlQuery` | Kartları besleyen sorgu. **Zorunludur** — boş olan widget hiç çizilmez |
| `Title` · `SubTitle` · `Value` · `Color` · `Icon` · `OnClick` | **Sorgu sonucundaki kolon adları** — sabit metin değil. Sunucu her satırda bu adlı kolonu okur; kolon yoksa boş string döner |
| `ColSpan` · `ColGap` · `ClassName` | Şeritteki yerleşim (widget başına, karta değil) |
| `ValueClassName` | Değerin CSS sınıfı, varsayılan `text-3xl` |
| `IsActive` | `false` ise sorgu hiç çalıştırılmaz |
**Bir widget, sorgunun döndürdüğü her satır için bir kart çizer.** Yani tek bir widget kaydıyla
"Bekleyen / Onaylı / Reddedilen" üçlüsü tek sorgudan üretilebilir:
```sql
SELECT 'Bekleyen' AS Baslik, COUNT(*) AS Deger, 'amber' AS Renk, 'FaClock' AS Ikon
FROM Mrp_T_Order WHERE Status = 1
UNION ALL
SELECT 'Onaylı', COUNT(*), 'green', 'FaCheck' FROM Mrp_T_Order WHERE Status = 2
```
```json
{ "Title": "Baslik", "Value": "Deger", "Color": "Renk", "Icon": "Ikon", "ColSpan": 4, "IsActive": true }
```
Sorgu ekranın `DataSourceCode` bağlantısında, **olduğu gibi** çalıştırılır:
- Ekranın otomatik tenant/şube/OU filtresi **uygulanmaz**.
- `@USERID` / `@TENANTID` gibi token'lar **çözülmez** — bunlar `*FieldsDefaultValueJson` ve
`DefaultFilter` yolunun sözleşmesidir. Widget sorgusuna yazılırsa bağlanmamış parametre
hatası verir. Kiracı kırılımı gerekiyorsa ya kiracıya özel bir `DataSource` kullan, ya da
kırılımı sorgunun okuduğu view'ın içine göm.
### 5.4 `LayoutJson` (`LayoutDto`)
| Anahtar | Varsayılan |
| --- | --- |
| `Grid` · `Card` · `Pivot` · `Chart` · `Tree` · `Gantt` · `Scheduler` | `true` |
| `Todo` | `false` |
| `DefaultLayout` | `"grid"` |
Wizard'daki görünüm bayraklarının karşılığıdır. **DTO varsayılanları yanıltıcıdır:** blok
yazılmazsa yedi görünüm birden açık gelir; ekranın üstünde çalışmayan görünüm düğmeleri
çıkmasın diye wizard bu bloğu her zaman açıkça yazar. `DefaultLayout`, `true` olan bir görünümü
göstermelidir (§7'deki zorunlu `*Expr` alanları boşsa o görünümün JSON'u hiç yazılmaz).
### 5.5 `CustomJsSourcesJson` / `CustomStyleSourcesJson`
Her ikisi de **string dizisidir**. Bir eleman `http` ya da `/` ile başlıyorsa dosya olarak
sayfaya eklenir (`<script src>` / `<link rel=stylesheet>`); aksi hâlde içerik olarak çalıştırılır
(JS'te `eval`, CSS'te inline `<style>`).
```json
["/assets/custom/orders.js", "console.log('orders ekranı yüklendi')"]
```
**Son çaredir.** Önce `EditorScript`, `EditorOptions`, `ColumnStylingJson` ve `CommandColumnJson`
denenir. Buraya yazılan kod ekran her açıldığında çalışır ve hiçbir yerde denetlenmez.
### 5.6 Ekranın türü
| Kolon | Varsayılan | Anlam |
| --- | --- | --- |
| `ListFormType` | `"List"` | `ListFormTypeEnum`: `List` (ızgara) \| `Form` (tek kayıt) \| `Chart` (yalnız grafik). Route karşılıkları: `/admin/list/{kod}` · `/admin/form/{kod}[/{id}[/edit]]` · `/admin/chart/{kod}` |
| `IsSubForm` | `false` | Ekran alt form olarak da kullanılıyor mu |
| `SubFormsListFormType` | `"Form"` | Alt form olarak açıldığında hangi görünümle geleceği |
| `ShowNote` | `true` | Not paneli (alt form ya da iş akışı varsa wizard açar) |
`ListFormType = "Form"` listesiz, tek kayıtlık kart ekrandır; canlı örneği Administration
Licence'tır (§12.6). `Pivot` bir `ListFormType` **değildir** — pivot, `LayoutJson.Pivot`
bayrağıyla açılan bir görünümdür ve `/admin/pivot/...` diye bir route yoktur.
### 5.7 Varyantlar
Aynı `ListFormCode` ile ikinci bir `ListForm` kaydıılıp `CultureName`, `UserId` ya da `RoleId`
doldurulursa o dil/kullanıcı/rol için **farklı sütun düzeni ve ayarlar** verilebilir. Aynı şey
`ListFormField` ve `Menu` kayıtları için de geçerlidir. Wizard bunu üretmez; ihtiyaç varsa
ListForm editöründen açılır ve seed karşılığı elle yazılır.
---
## 6. Pivot
### 6.1 `PivotOptionJson` (`GridPivotOptionDto`)
| Anahtar | Varsayılan |
| --- | --- |
| `ShowFieldPanel` | `true` |
| `AllowFieldDragging` | `true` |
| `ShowDataFields` / `ShowColumnFields` / `ShowRowFields` / `ShowFilterFields` | `true` |
| `ColumnChooserEnabled` | `false` |
| `ShowChart` | `false` |
| `ChartHeight` | `320` |
| `ChartCommonSeriesType` | `"bar"` |
### 6.2 Alan başına `PivotSettingsJson` (`ListFormFieldPivotSettingsDto`)
| Anahtar | Varsayılan | Değerler |
| --- | --- | --- |
| `IsPivot` | `true` | Alan pivotta kullanılsın mı |
| `Area` | `filter` | `row` \| `column` \| `data` \| `filter` |
| `SummaryType` | — | `sum` \| `avg` \| `count` \| `min` \| `max` |
| `GroupInterval` | `none` | `day` \| `dayOfWeek` \| `month` \| `quarter` \| `year` |
| `SortOrder` | `asc` | `asc` \| `desc` |
| `Format` | — | DevExtreme format adı |
| `Expanded` | `false` | Başlangıçta açık |
| `WordWrapEnabled` | `false` | |
Pivot ekranı ayrı bir sorgu istemez; ızgarayla aynı `SelectCommand` üzerinden çalışır.
---
## 7. Ağaç, Gantt, Takvim, Kanban
### 7.1 `TreeOptionJson` (`TreeOptionDto`)
`KeyExpr`*, `ParentIdExpr`*, `HasItemsExpr`, `RootValue` (varsayılan `null`),
`ExpandedRowKeys[]`, `AutoExpandAll` (`false`), `RecursiveSelection` (`false`),
`TitleExpr`, `StartExpr`, `EndExpr`, `ProgressExpr`.
### 7.2 `GanttOptionJson` (`GanttOptionDto`)
Ağaç alanlarının tamamı + `TitleExpr`*, `StartExpr`*, `EndExpr`*, `ProgressExpr`,
`ScaleType` (varsayılan `weeks`; tam küme `GanttScaleTypeEnum`: `auto` \| `minutes` \| `hours` \|
`sixHours` \| `days` \| `weeks` \| `months` \| `quarters` \| `years`) ve izin bayrakları:
`AllowEditing`, `AllowTaskAdding`, `AllowTaskUpdating`, `AllowTaskResourceUpdating`,
`AllowTaskDeleting`, `AllowDependencyAdding`, `AllowDependencyDeleting`, `AllowResourceAdding`,
`AllowResourceUpdating`, `AllowResourceDeleting` (hepsi `false`).
### 7.3 `SchedulerOptionJson` (`SchedulerOptionDto`)
| Anahtar | Varsayılan | Anlam |
| --- | --- | --- |
| `TextExpr`* · `StartDateExpr`* · `EndDateExpr`* | — | Başlık ve zaman kolonları |
| `UserNameExpr` · `DescriptionExpr` | — | Kaynak/kişi ve açıklama |
| `AllDayExpr` | — | Tüm gün bayrağı kolonu |
| `RecurrenceRuleExpr` · `RecurrenceExceptionExpr` | — | Tekrar kuralı kolonları |
| `StartDayHour` / `EndDayHour` | `8` / `20` | Görünen saat aralığı |
| `DefaultView` | `"week"` | Ekranın çizdiği sekiz görünüm: `day` \| `week` \| `workWeek` \| `month` \| `timelineDay` \| `timelineWeek` \| `timelineMonth` \| `agenda` |
| `ShowAllDayPanel` | `true` | |
| `CellDuration` | `30` | Hücre dakikası |
| `FirstDayOfWeek` | `1` | 0 = Pazar |
| `CrossScrollingEnabled` | `false` | Kaynak (resource) görünümünde yatay+dikey kaydırma |
| `AllowAdding` / `AllowEditing` / `AllowDeleting` / `AllowDragging` / `AllowResizing` | `false` | |
| `Resources[]` | — | Randevuları renklendiren kaynak eşlemesi (`FieldExpr`, `DataSource[]`, `Label`, `UseColorAsDefault`) |
`Resources` C# `SchedulerOptionDto`'da **tanımlı değildir**; yalnızca UI modelinde (`proxy/form/
models.ts`) vardır. Yani seed'den yazılabilir (bilinmeyen anahtar korunur ve bileşene geçer) ama
ListForm editöründeki tipli formdan düzenlenemez; kalıcı kullanılacaksa C# DTO'suna eklenmelidir.
### 7.4 `TodoOptionJson` (`TodoOptionDto`) — Kanban
`TitleExpr`*, `StatusExpr`*, `DescriptionExpr`, `DueDateExpr`, `TagExpr`, `AssigneeExpr`,
`PriorityExpr`, `CompletedExpr`, `OrderExpr`, `TimesheetExpr`, `SubTaskExpr`,
`StatusOrder` (kolon sırası, virgüllü), `AllowDragging` (varsayılan `true`).
> `*` işaretli alan boşsa seeder o görünümün JSON'unu **yazmaz**; bayrağı açmak yetmez.
---
## 8. Chart (grafik) sözleşmesi
Grafik, ListForm üzerindeki **22 ayrı JSON kolonuyla** yapılandırılır. Hepsi DevExtreme
`dxChart` yapılandırmasının karşılık gelen bölümüne geçer — ama tipli DTO'dan süzülerek
(girişteki "bilinmeyen anahtar düşer" kuralı grafik kolonları için de geçerlidir).
Grafik iki yoldan açılır: ekranın `LayoutJson.Chart` bayrağıyla bir görünüm olarak, ya da
`ListFormType = "Chart"` ile yalnız grafikten oluşan bir ekran (`/admin/chart/{kod}`) olarak.
| Kolon | Karşılığı |
| --- | --- |
| `SeriesJson` | `series[]`**zorunlu**, §8.1 |
| `DataSourceJson` | Grafiğin kendi sorgusu, §8.2 |
| `CommonJson` | Grafik geneli (palet, tema), §8.3 |
| `CommonSeriesSettingsJson` | Tüm serilere ortak ayarlar |
| `ArgumentAxisJson` · `ValueAxisJson` · `CommonAxisSettingsJson` | Eksenler, §8.5 |
| `LegendJson` | Açıklama kutusu, §8.6 |
| `TooltipJson` | İpucu balonu, §8.7 |
| `PanesJson` · `CommonPaneSettingsJson` | Bölmeler (çok panelli grafik) |
| `AnnotationsJson` · `CommonAnnotationsSettingsJson` | Ek açıklamalar |
| `CrosshairJson` | Artı imleç çizgileri |
| `ScrollBarJson` | Kaydırma çubuğu |
| `ZoomAndPanJson` | Yakınlaştırma/kaydırma |
| `SizeJson` · `MarginJson` · `AdaptiveLayoutJson` | Boyut, kenar boşluğu, dar ekran davranışı |
| `TitleJson` | Başlık/alt başlık |
| `AnimationJson` | Animasyon |
| `ExportJson` | Dışa aktarma/yazdırma |
Ayrıca grafiğe **kullanıcı/rol kısıtı**: ListForm kaydındaki `UserId` / `RoleId` alanları boşsa
grafik herkese açıktır.
### 8.1 `SeriesJson` (`ChartSeriesDto[]`)
| Anahtar | Varsayılan | Anlam |
| --- | --- | --- |
| `Name` | — | Açıklamada görünen seri adı |
| `Type` | `line` | `line` \| `bar` \| `spline` \| `area` \| `scatter` \| `bubble` \| `stackedbar` \| `fullstackedbar` \| `stackedline` \| `stackedarea` \| `steparea` \| `stepline` \| `rangebar` \| `rangearea` \| `candlestick` \| `stock` ve stacked/fullstacked varyantları |
| `ArgumentField` | `"arg"` | X ekseni kolonu |
| `ValueField` | — | Y ekseni kolonu |
| `SummaryType` | `"sum"` | `sum` \| `avg` \| `count` \| `min` \| `max` \| `custom` |
| `Color` | — | Seri rengi |
| `Axis` · `Pane` | — | Hangi eksen/bölme |
| `Visible` | `true` | |
| `ShowInLegend` | `true` | |
| `Width` | `2` | Çizgi kalınlığı |
| `DashStyle` | `"solid"` | `solid` \| `dash` \| `dot` \| `longDash` |
| `BarWidth` · `BarPadding` · `BarOverlapGroup` · `CornerRadius` | — | Çubuk serileri |
| `IgnoreEmptyPoints` | `false` | |
| `SelectionMode` | `"none"` | `onlyPoint` \| `allSeriesPoints` \| `allArgumentPoints` \| `includePoints` \| `excludePoints` \| `none` |
| `RangeValue1Field` / `RangeValue2Field` | `val1` / `val2` | Aralık serileri |
| `Label` | — | `ChartLabelDto`: `Visible`, `Format`, `Font`, `BackgroundColor`, `CustomizeText` |
| `UserId` | — | Seriyi yalnızca bu kullanıcıya göster |
### 8.2 `DataSourceJson` (`ChartDataSourceDto`)
```json
{ "Query": "SELECT Status AS arg, SUM(Amount) AS val FROM Mrp_T_Order GROUP BY Status" }
```
Grafik, ızgaranın `SelectCommand`'ından **ayrı** bir sorgu kullanabilir. Sorgu kolonları
`ArgumentField` / `ValueField` adlarıyla eşleşmelidir. Ekranın filtresi grafik isteğine
`Filter` parametresi olarak taşınır.
### 8.3 `CommonJson` (`ChartCommonDto`)
| Anahtar | Varsayılan | Anlam |
| --- | --- | --- |
| `Palette` | `"Material"` | `Bright` \| `Harmony Light` \| `Ocean` \| `Pastel` \| `Soft` \| `Soft Pastel` \| `Vintage` \| `Violet` \| `Carmine` \| `Dark Moon` \| `Dark Violet` \| `Green Mist` \| `Soft Blue` \| `Material` \| `Office` |
| `PaletteExtensionMode` | `"blend"` | `alternate` \| `blend` \| `extrapolate` |
| `Theme` | `"generic.light"` | `generic.*` ve `material.*.light` varyantları |
| `ContainerBackgroundColor` | `"#FFFFFF"` | |
| `AdjustOnZoom` | `true` | |
| `DefaultPane` | — | |
| `Disabled` | `false` | |
### 8.4 Boyut ve yerleşim
- `SizeJson` (`ChartSizeDto`): `UseSize` (`false`), `Width` (`400`), `Height` (`200`).
`UseSize: false` iken grafik kapsayıcıya yayılır.
- `MarginJson` (`ChartMarginDto`): `Top`, `Bottom`, `Left`, `Right`.
- `AdaptiveLayoutJson` (`ChartAdaptivelayoutDto`): `Width`/`Height` eşiği (`80`/`80`),
`KeepLabels` (`true`).
- `TitleJson` (`ChartTitleDto`): `Text`, `Subtitle`, `HorizontalAlignment` (`center`),
`VerticalAlignment` (`top`), `TextOverflow` (`ellipsis`), `WordWrap`.
- `AnimationJson` (`ChartAnimationDto`): `Enabled` (`true`), `Duration` (`1000`),
`Easing` (`easeOutCubic` \| `linear`), `MaxPointCountSupported` (`300`).
- `ExportJson` (`ChartExportDto`): `Enabled`, `PrintingEnabled` (`true`),
`AllowExportSelectedData`, `BackgroundColor` (`#ffffff`), `Margin` (`10`).
### 8.5 Eksenler
`ArgumentAxisJson` (`ChartArgumentAxisDto`): `ArgumentType` (`datetime` \| `numeric` \| `string`),
`AggregationInterval` (`day` \| `hour` \| `minute` \| `month` \| `quarter` \| `second` \| `week` \| `year`),
`Position` (`bottom` \| `left` \| `right` \| `top`), `HoverMode` (`none` \| `allArgumentPoints`),
`Grid`, `Label``DisplayMode` (`standard` \| `rotate` \| `stagger`), `RotationAngle` (`90`),
`OverlappingBehavior` (`hide` \| `rotate` \| `stagger` \| `none`).
`ValueAxisJson` (`ChartValueAxisDto`): `Name`, `Title`, `ValueType` (`numeric`),
`Position` (`left`), `Type` (`continuous` \| `discrete` \| `logarithmic`), `Visible` (`true`),
`Width` (`1`), `Grid`, `Breaks[]`, `BreakStyle`, `AutoBreaksEnabled` (`true`),
`MaxAutoBreakCount` (`2`).
`CommonAxisSettingsJson` iki eksene birden uygulanır; **eksene özel ayar varsa yok sayılır.**
### 8.6 `LegendJson` (`ChartLegendDto`)
`Visible` (`true`), `Position` (`outside` \| `inside`), `Orientation` (`vertical` \| `horizontal`),
`ColumnCount`, `RowCount`, `Title`, `BackgroundColor`, `Border`.
### 8.7 `TooltipJson` (`ChartTooltipDto`)
`Enabled`, `Shared`, `Format` / `ArgumentFormat` (DevExtreme format adları),
`Color` (`#ffffff`), `ArrowLength` (`10`), `Location` (`center` \| `edge`),
`PaddingLeftRight` (`18`), `PaddingTopBottom` (`15`), `Border`, `Font`.
### 8.8 Diğerleri
- `PanesJson` (`ChartPanesDto[]`): `Name`, `Height` (`250`), `BackgroundColor`.
Seriler `Pane` alanıyla bir bölmeye bağlanır.
- `CrosshairJson` (`ChartCrosshairDto`): `Enabled`, `Color` (`#f05b41`), `Width` (`1`),
`DashStyle` (`dot`), `HorizontalLine`, `VerticalLine`, `Label`.
- `ScrollBarJson` (`ChartScrollBarDto`): `Visible`, `Position` (`top`), `Color` (`gray`),
`Width` (`10`), `Offset` (`5`).
- `ZoomAndPanJson` (`ChartZoomAndPanDto`): `ArgumentAxis` / `ValueAxis`
(`none` \| `pan` \| `zoom` \| `both`), `AllowMouseWheel` (`true`), `AllowTouchGestures` (`true`),
`DragToZoom` (`false`), `PanKey` (`shift`), `DragBoxStyle`.
- `AnnotationsJson` (`ChartAnnotationDto[]`): `Name`, `Text`, `Image`, `Series`, `Argument`,
`OffsetX`/`OffsetY`, `Color`, `Font`, `Border`, `TooltipEnabled`, `Description`.
---
## 9. Alan (`ListFormField`) JSON kolonları
`lowcode` §4.3.44.3.7'de anlatılan `LookupJson`, `ValidationRuleJson`, `ColumnStylingJson`
dışında kalanlar:
### 9.1 `ColumnFilterJson` (`ColumnFilterDto`)
| Anahtar | Anlam |
| --- | --- |
| `AllowFiltering` | Bu sütun filtrelenebilsin mi (`true`) |
| `FilterOperations[]` | İzin verilen operatörler; boş bırakılırsa tipe göre otomatik. Değerler: `=`, `<>`, `<`, `<=`, `>`, `>=`, `contains`, `notcontains`, `startswith`, `endswith`, `isblank`, `isnotblank`, `between`, `anyof`, `noneof` |
| `SelectedFilterOperation` | Varsayılan seçili operatör |
| `FilterValue` | Ekran açılırken uygulanan filtre değeri |
### 9.2 `ColumnHeaderJson` (`ColumnHeaderDto`)
`AllowHeaderFiltering` (`true`), `AllowSearch` (`false`) ve **özel başlık filtresi listesi**:
```json
{ "AllowHeaderFiltering": true,
"DataSource": [ { "text": "3000 altı", "value": ["Amount", "<", 3000] },
{ "text": "3000 üstü", "value": ["Amount", ">=", 3000] } ] }
```
### 9.3 `GroupingJson` (`ColumnGroupingDto`)
`AllowGrouping` (`true`), `GroupIndex` (kaçıncı seviyeden gruplanacağı), `AutoExpandGroup` (`false`).
`GroupIndex` verilen sütun ekran açılışında gruplanmış gelir.
### 9.4 `ColumnCustomizationJson` (`ColumnCustomizationDto`)
`Fixed` (`false`), `FixedPosition` (`left` \| `right`), `AllowReordering` (`false`).
Sol/sağa sabitlenmiş kolon yatay kaydırmada sabit kalır.
### 9.5 `TotalSummaryJson` / `GroupSummaryJson` (`ColumnTotalSummaryDto`)
| Anahtar | Anlam |
| --- | --- |
| `SummaryType` | `sum` \| `avg` \| `count` \| `min` \| `max` \| `custom` |
| `ValueFormat` | DevExtreme format adı (`fixedPoint`, `currency`, `percent`, `shortDate`…) |
| `DisplayFormat` | Metin şablonu: `{0}` biçimlenmiş değer, `{1}` `ShowInColumn`'daki sütunun başlığı |
| `ShowInColumn` | Özetin hangi sütunun altında görüneceği (kolon adı). `DisplayFormat`'taki `{1}` bunun başlığıdır |
| `ShowInGroupFooter` | `false` — grup alt bilgisinde göster (yalnızca `GroupSummaryJson`) |
| `AlignByColumn` | `false` — grup satırında ilgili sütunun altına hizala; `false` iken özet grup başlığının yanında parantez içinde çıkar |
`TotalSummaryJson` listenin altındaki toplam satırını, `GroupSummaryJson` grup kırılımındaki
özeti üretir; ikisi de **aynı DTO'yu** kullanır, fark yazıldıkları kolondur.
"Listenin altında toplam görünsün" isteği budur; ayrı sorgu ya da widget gerekmez.
### 9.6 `JoinTableJson` (`JoinTableDto`)
Bir kolonu **başka bir tablodan** çekmek için; view yazmadan tek alanlık join kurar.
| Anahtar | Anlam |
| --- | --- |
| `JoinType` | `INNER JOIN` \| `LEFT JOIN` \| `RIGHT JOIN` |
| `TableName` | Join kurulacak tablo |
| `BaseTableJoinFieldName` | Ana tablonun join alanı |
| `JoinFieldName` | Join kurulan tablonun ilişkili alanı |
| `SelectFieldName` | Ekranda gösterilecek alan |
| `FieldNameAlias` | Alanın takma adı |
| `JoinCondition2` | İkinci koşulun bağlacı (`AND` \| `OR`) |
| `JoinFieldName2` | İkinci koşulun alanı**tablo adıyla birlikte** (`Def_T_City.CultureName`) |
| `BaseTableJoinFieldName2_OrValue` | İkinci koşulun karşı tarafı: tablo adlı bir alan ya da `'en'` gibi sabit |
Üç-dört join'i geçen ihtiyaçta view tasarımcısı tercih edilir (`lowcode` §8.2).
### 9.7 Diğer alan kolonları
| Kolon | Varsayılan | Anlam |
| --- | --- | --- |
| `FieldName` | — | Kaynaktaki sütun adı; SQL'deki adıyla birebir |
| `CaptionName` | — | Sütun başlığı**dil anahtarı** |
| `PlaceHolder` | — | Editörün placeholder metni |
| `Alignment` | `"left"` | `left` \| `center` \| `right` |
| `Format` | — | Hücre biçimi (DevExtreme format adı ya da desen) |
| `BandName` | — | Sütunu bir başlık bandının altına toplar |
| `Width` · `ListOrderNo` | — | Genişlik ve grid'deki sıra |
| `Visible` | — | Sütun grid'de görünür mü; `false` ise kolon seçicide durur ama **sorguya girer** |
| `IsActive` | `true` | `false` olan alan **sorguya bile girmez** |
| `SortIndex` · `SortDirection` | — | Açılıştaki sıralama (`asc` \| `desc`); çok sütunlu sıralamada `SortIndex` sırası belirler |
| `AllowSearch` · `AllowEditing` · `AllowAdding` | `true` | Arama paneline dâhil olma, güncellemede ve yeni kayıtta düzenlenebilirlik |
| `ColumnCssClass` · `ColumnCssValue` | — | Koşulsuz stil (sınıf adı + sınıfın içeriği); koşullu olan `ColumnStylingJson` |
| `SourceDbType` | `16` String | Kolonun `System.Data.DbType` karşılığı |
| `EditorType2` · `EditorOptions` · `EditorScript` | — | Editör tipi ve davranışı (`lowcode` §5, §6) |
| `ColSpan` · `EditOrderNo` · `EditGroupOrderNo` | — | Düzenleme formundaki yeri; `EditGroupOrderNo` `EditingFormJson`'daki `Order` ile eşleşir |
| `PermissionJson` | — | Alan yetkileri (§5.1) |
| `CultureName` · `UserId` · `RoleId` | — | Alan varyantı (§5.7) |
> **`DefaultValue` / `DefaultValueType` / `ReadOnly` diye bir alan kolonu yoktur.**
> Varsayılan değerler ekran seviyesindeki `Insert/Update/Delete/Form/SelectFieldsDefaultValueJson`
> bloklarında, alan adıyla eşleşen `FieldsDefaultValueDto` satırları olarak durur
> (`lowcode` §4.3.5); salt okunurluk ise `EditorOptions.readOnly` ya da `EditorScript`'in
> `readOnly` tarifidir (`lowcode` §6.6).
### 9.8 Tipli editör seçenekleri
`EditorOptions` JSON'unun bazı anahtarları backend'de **tipli DTO'ya** çözülür; yanlış tip
sessizce yok sayılır:
| DTO | Hangi `EditorType2` | Anahtarlar (varsayılan) |
| --- | --- | --- |
| `GridBoxOptionsDto` | `dxGridBox` | `Columns[]` (ilk kolon `Key` ile aynı adda olmalı), `SelectionMode` (`"single"`), `FilterRowVisible` (`false`), `AcceptCustomValue` (`false`), `ShowClearButton` (`true`), `Height` (`250`), `Width` (`500`) |
| `TagBoxOptionsDto` | `dxTagBox` | `ShowSelectionControls` (`true`), `MaxDisplayedTags` (`3`), `ShowMultiTagOnly` (`false`), `ApplyValueMode` (`"useButtons"`), `SearchEnabled` (`true`), `AcceptCustomValue` (`false`), `ShowClearButton` (`true`) |
| `ImageUploadOptionsDto` | `dxImageUpload` · `dxImageViewer` | `UploadUrl`, `Accept`, `Multiple`, `MaxFileSize` (bayt), `Width`, `Height` — hepsi nullable, varsayılanı yok |
Çözüm **yalnızca alanın `EditorType2` değeri eşleşiyorsa** yapılır: `dxTextBox` bir alana
`columns` yazmak `GridBoxOptions`'ı doldurmaz. Ayrıca `ListFormField.EditorOptions`'ın ham
metni istemciye **her hâlükârda** gider; tipli DTO'lar onun yanında ek bir kolaylıktır ve
`JsonException` durumunda sessizce `null` döner — yani bozuk JSON burada ekranı düşürmez, ama
tipli okumaya bağlı davranış (GridBox kolonları, TagBox etiket sayısı) çalışmaz.
---
## 10. Visual Designer envanteri
`lowcode` §7 tasarımcı dokümanının şemasını anlatır; burada **kutuda ne olduğu** listelenir.
### 10.1 Toolbox aileleri
Kutunun içeriği tek bir yerden, `getDesignerCatalog()` (`components/visualDesigner/catalog.ts`)
tarafından üretilir: elle yazılmış tanımlar + `components/ui` altındaki bileşenlerden
otomatik çıkarılan metadata (`generated/componentProps.json`).
| Aile | Bileşenler |
| --- | --- |
| `layout` | `PageContainer` (maxWidth, padding, gap, className), `FlexRow` (columns, firstColumnWidth, gap, wrap, align, className), `Table` |
| `data` | `Form` (§10.2) ve veri bağlanabilen UI bileşenleri: `Select`, `AutoComplete`, `Dropdown`, `Menu`, `Pagination`, `Radio.Group`, `Tabs`, `Grid` |
| `platform` | `ListView`, `DataGridView`, `TreeView`, `GanttView`, `TodoBoard`, `CardView`, `SchedulerView`, `PivotView`, `ChartView` — hepsi aynı üç prop'u alır: `listFormCode` (**zorunlu**), `height` (varsayılan `520px`, `ChartView`'da `420px`), `className` |
| `html` | `div`, `p`, `span`, `h1`, `h2`, `h3`, `h4`, `h5`, `img`**yalnız bu dokuz etiket** |
| `ui` | `Avatar`, `Badge`, `Button`, `Calendar`, `Card`, `Checkbox`, `Chips`, `ColorPicker`, `DatePicker`, `ImageViewer`, `Input`, `Knob`, `Marquee`, `Notification`, `Progress`, `Radio`, `RangeCalendar`, `Rate`, `ScrollBar`, `Skeleton`, `Slider`, `Spacer`, `Spinner`, `Switcher`, `Tag`, `TimeInput`, `Tooltip`, `Upload` |
| `custom` | Kayıtlı diğer custom component'ler (`Dependencies`'e eklenir) |
**`input`, `button`, `textarea`, `select`, `checkbox` HTML etiketleri kutuda yoktur**
(`HTML_UI_DUPLICATES`): karşılıkları `ui` ailesindeki `Input`, `Button`, `Select`, `Checkbox`
bileşenleridir; ham etiket bırakmaya çalışma, tema ve doğrulama onlardan gelir.
Kutu dışında tutulanlar (`EXCLUDED_COMPONENTS`): `Alert`, `Breadcrumb`, `Dialog`, `Drawer`,
`FormContainer`, `FormItem`, `InputGroup`, `MenuItem`, `Segment`, `Steps`. Bunlara ihtiyaç
duyan bir yerleşim, tasarımcı yerine **Code modunda** yazılır (`lowcode` §7.1.1) — orada
`components/ui`'nin tamamı kapsamdadır.
Çocuk düğüm kabul edenler: `PageContainer`, `FlexRow`, `Form`, `div`, `Card`, `Table`, `Tabs`
ve **her custom component**. Diğer düğümlerin içine bırakma; kanvas kabul etse de üretilen kod
çocukları çizmez.
Düğüm başına iki ortak prop, hangi ailede olursa olsun geçerlidir:
| Prop | Anlam |
| --- | --- |
| `designerPermission` | Boş değilse düğüm yalnızca bu yetki verilmişse **çizilir**; verisini göremeyeceği bir grid hiç oluşturulmaz |
| `className` | Tailwind sınıfları |
> **Önce yeniden kullan:** İstenen şey bir ListForm ekranının verdiği liste/ağaç/pano/grafikse
> primitiflerden kurma; `platform` düğümünü `listFormCode` ile bırak.
>
> **Eksik olan = var olan bileşene ekle, yeni bileşen yazma:** İstenen komponent bu
> envanterle büyük ölçüde kuruluyor ama bir bileşende **olay, prop ya da küçük bir yetenek**
> eksikse komponent yine üretilir: eksik parça `components/ui/{Name}`'e geriye dönük uyumlu
> eklenir, `componentProps.json` elle güncellenir, olaysa `catalog.ts` `DESIGNER_PRIMARY_EVENTS`,
> değer kümesiyse `NAMED_UNION_OPTIONS`/`PROPERTY_OVERRIDES`, sonra §10.9/§10.10 tabloları
> tamamlanır (`lowcode` §7.3 notu). Yeni `ui` bileşeni, yeni toolbox ailesi, Developer Kit
> menüsüne yeni komponent ya da var olan bileşenin davranışını değiştiren ekleme **yapılmaz** —
> bunlar çerçeve dışıdır ve onay ister (`lowcode` §0.8).
### 10.2 `Form` düğümü
Dört CRUD ucunu sahiplenen kapsayıcı. İçine bırakılan her bileşen kaydın bir kolonuna bağlanır.
| Prop | Varsayılan | Anlam |
| --- | --- | --- |
| `title` | `""` | Kart başlığı; boşsa Card başlığı hiç çizilmez (`::` önekli değer dil anahtarıdır) |
| `selectEndpoint` / `insertEndpoint` / `updateEndpoint` / `deleteEndpoint` | — | GET / POST / PUT / DELETE uçları |
| `selectPermission` / `insertPermission` / `updatePermission` / `deletePermission` | — | Komut yetkileri; boşsa dokümanın `permissionCode` değeri + `""`/`.Create`/`.Update`/`.Delete` **otomatik** çözülür (`FORM_AUTO_SUFFIXES`), o da yoksa komut açıktır |
| `keyFieldName` | `"id"` | Anahtar kolon |
| `collectionPath` | `""` | Select yanıtındaki liste yolu; boşsa yanıtın kendisi |
| `keySource` | `"query"` | `query` \| `route` — anahtarın URL'de nereden okunacağı |
| `keyParamName` | `""` | Parametre/segment adı; boşsa `route`'ta son segment kullanılır |
| `previewKeyValue` | `""` | Yalnızca tasarımcı önizlemesi; üretilen koda girmez |
| `autoLoad` | `true` | Açılışta veriyi çek |
| `showToolbar` | `true` | Kaydet/Sil/Gezinme çubuğu |
| `columnCount` | `1` | Form içindeki alanların kaç kolona diziliceği |
| `gap` | `16` | Alanlar arası boşluk (px) |
| `className` | `""` | Ek sınıflar |
Olayları ve script API'si `lowcode` §7.8'dedir. Bir sayfada birden fazla `Form` olabilir;
ana-detay için detay tarafının veri kaynağına `source: "record"` filtresi verilir ve değeri
`<anaFormRef>.<kolon>` biçiminde yazılır (§10.4).
### 10.3 Veri bileşenleri
`DESIGNER_DATA_COMPONENTS` iki tür tanır:
| Tür | Bileşenler | Koleksiyon prop'u |
| --- | --- | --- |
| `option` (etiket/değer) | `Select`, `AutoComplete`, `Dropdown`, `Menu`, `Pagination`, `Radio.Group`, `Tabs` | `options` (Select/AutoComplete) ya da `items` |
| `tabular` (satır) | `Grid` | `items` |
`option` bileşenlerinde binding'e `columns` eklenirse, ekranda görünmeyen kolonlar script'ten
`refs.<ad>.getColumn('kolon')` ile okunabilir. Bu, "müşteri seçilince vergi numarası da gelsin"
isteğinin tasarımcı tarafındaki karşılığıdır — ikinci bir istek atılmaz.
### 10.4 Veri kaynakları ve filtreler
Doküman seviyesindeki `dataSources` listesi, düğümlerin `bindings.sourceId` ile bağlandığı
uçlardır. Şeması `lowcode` §7.2'de; burada **filtre sözleşmesi**ılır.
| `source` | `value` ne demek | Ne zaman |
| --- | --- | --- |
| `static` | Değerin kendisi | Sabit kırılım (`IsActive = true`) |
| `query` | Sayfa adresindeki query parametresinin **adı** (`?id=…`) | Adresle taşınan bağlam |
| `route` | Yol segmentinin adı; boşsa **son segment** | `/admin/order/123` gibi rotalar |
| `record` | `<formRef>.<kolon>` — başka bir `Form` düğümünün aktif kaydının kolonu | Ana-detay; tek satır kod yazmadan |
| `operator` | Query string'e nasıl çıkar |
| --- | --- |
| `eq` | Çıplak parametre: `?RoleId=5` |
| `ne` `contains` `startswith` `endswith` `gt` `gte` `lt` `lte` `in` `isnull` `notnull` | Adını son ek olarak taşır: `?Name.contains=abc` |
`isnull` / `notnull` değer almaz (`DESIGNER_VALUELESS_FILTER_OPERATORS`); değer kutuları gizlenir.
`required` **varsayılan olarak `true`'dur ve bilinçlidir**: değeri henüz gelmemiş bir filtre
isteği tutar. Aksi hâlde filtresiz koleksiyon yüklenir ve bu, kullanıcıya "filtre çalışmıyor"
diye görünür. `previewValue` yalnızca tasarımcı kanvasında kullanılır, üretilen koda girmez.
Bu sözleşme CRUD Endpoint `GetList` ucunun okuduğu sözleşmenin aynısıdır (`lowcode` §9.1) —
yani tasarımcıdan kurulan filtre, sunucu tarafında ek bir şey yazmadan çalışır.
### 10.5 Property Panel — nasıl çalışır
Kanvasta seçili düğümün sağ paneli üç sekmedir ve her prop bir **kategoriye** aittir:
| Kategori | Nerede görünür | Ne taşır |
| --- | --- | --- |
| `properties` | Properties sekmesi | Davranış ve içerik prop'ları |
| `styling` | Properties sekmesi (stil grubu) | `className`, boyut, boşluk, hizalama |
| `events` | **JavaScript sekmesi** | `function` tipli prop'lar — değer değil **script** olarak düzenlenir (§7.8 · `lowcode`) |
Panelin kuralları:
- **Değer kümesi bilinen prop yazılmaz, seçilir.** `options` taşıyan (ya da tsType'ı bilinen bir
union olan) her string prop panelde açılır listeye döner (`withPickableOptions`); listede
olmayan mevcut değer korunur.
- **Olay listesi süzülür:** `DESIGNER_PRIMARY_EVENTS`'te kaydı olan bileşende yalnızca o olaylar
JavaScript sekmesinde görünür (aşağıda §10.10); kaydı olmayan bileşende bütün `function`
prop'ları listelenir.
- `field` ve `form` prop'ları panelde **hiç görünmez** (Formik'in runtime nesneleridir).
- Her düğümün panel-üstü iki ortak alanı vardır: **`ref`** (script adresi — `refs.<ad>`) ve
**`designerPermission`** (boş değilse düğüm yalnızca o yetkiyle çizilir).
- Seed dosyasına yalnızca **varsayılandan farklı** prop'ları yaz; panel dokunulmayan prop'u
dokümana koymaz.
### 10.6 `layout` bileşenleri — prop sözleşmesi
**`PageContainer`** — sayfanın dış kabı; çocuk kabul eder:
| Prop | Varsayılan | Anlam |
| --- | --- | --- |
| `maxWidth` | `"1280px"` | İçerik genişliği (CSS değeri) |
| `padding` | `24` | İç boşluk (px) |
| `gap` | `16` | Çocuklar arası dikey boşluk (px) |
| `className` | `""` | |
**`FlexRow`** — yatay bölme; çocuk kabul eder:
| Prop | Varsayılan | Anlam |
| --- | --- | --- |
| `columns` | `1` | `1` = serbest akan flex satırı; `2+` = o kadar **eşit grid kolonu** |
| `firstColumnWidth` | `""` | Yalnız kolon modunda: ilk kolonu sabitler → kenar çubuğu düzeni (`"320px"`) |
| `gap` | `16` | Kolonlar arası boşluk |
| `wrap` | `true` | Taşan çocuk alta insin mi (yalnız flex modunda) |
| `align` | `"stretch"` | `stretch` \| `start` \| `center` \| `end` |
| `className` | `""` | |
**`Table`** (`ui` kitinden, `layout` grubunda; çocuk kabul eder) — statik tablo:
`borderlessRow` (—), `compact` (`false`), `hoverable` (`true`), `overflow` (`true`),
`rowCount` (`2`), `columnCount` (`3`), `className`. `columns`/`data` prop'ları panelden
kaldırılmıştır — hücreler kanvasta çocuk düğüm olarak doldurulur. Veri bağlanabilir tablo
istiyorsan `Grid` (data) ya da `DataGridView` (platform) kullan.
**`Spacer`** (`ui` grubunda listelenir) — dikey boşluk: `height` (`24`).
### 10.7 `platform` bileşenleri — prop sözleşmesi
Dokuzu da aynı üç prop'u alır; başka prop'ları **yoktur** (görünümün tüm davranışı gömülen
ListForm ekranının kendi tanımından gelir):
| Prop | Varsayılan | Anlam |
| --- | --- | --- |
| `listFormCode` | `""` | **Zorunlu.** Gömülecek ekranın kodu |
| `height` | `"520px"` (`ChartView`: `"420px"`) | Kapsayıcı yüksekliği |
| `className` | `""` | |
`ListView` · `DataGridView` · `TreeView` · `GanttView` · `TodoBoard` · `CardView` ·
`SchedulerView` · `PivotView` · `ChartView`. Bileşen, kullanıcının o ekranda yetkisi yoksa
ekranın kendi yetki hatasını gösterir; ayrıca gizlemek istiyorsan `designerPermission` yaz.
Gömülen görünüm, hedef ekranın `LayoutJson`'ında açık olmalıdır.
### 10.8 `html` elemanları — prop sözleşmesi
| Eleman | Prop'lar | Olaylar |
| --- | --- | --- |
| `div` (çocuk kabul eder) | `children`, `className`, `style` | `onClick`, `onMouseEnter`, `onMouseLeave` |
| `p` · `span` | `children`, `className` | `onClick` |
| `h1``h5` | `children`, `className` — başlıklar hazır Tailwind sınıfıyla düşer (`h1`: `text-4xl font-bold``h5`: `text-lg font-semibold`); Tailwind reset'i yüzünden sınıfı silersen başlık paragraf boyutuna iner | `onClick` |
| `img` | `src` (yeni düşen eleman gömülü SVG yer tutucusuyla gelir; herhangi bir URL/data-URI yazılabilir), `alt`, `width`, `height`, `className` (`max-w-full rounded-md`) | `onClick`, `onLoad` |
`input`/`button`/`textarea`/`select`/`checkbox` etiketleri kutuda yoktur — `ui` karşılıklarını
kullan (§10.1).
### 10.9 `data` ve `ui` bileşenleri — Property Panel sözleşmeleri
Kaynak: `generated/componentProps.json` + `catalog.ts` düzeltmeleri. Her tabloda yalnızca
karar gerektiren prop'lar listelenir; `className`, `children`, `style` her bileşende vardır ve
tekrarlanmaz. `(z)` = zorunlu.
**Veri bileşenleri** (koleksiyon prop'u §10.3'e göre statik değer ya da data source binding'i
alır):
| Bileşen | Koleksiyon | Diğer prop'lar (varsayılan) |
| --- | --- | --- |
| `Select` | `options[]` (`{label, value}`) | `size` (`sm/md/lg`), `componentAs` (`''` \| `ReactSelect` \| `CreatableSelect` \| `AsyncSelect`), `value`, `isDisabled` (`false`), `isMulti` (`false`), `isClearable` (`false`), `isSearchable` (`true`) — tasarımcı `disabled/multiple/clearable/searchable` adlarını react-select karşılıklarına çevirir |
| `AutoComplete` | `options[]` | `value`, `defaultValue`, `placeholder`, `disabled` (`false`), `invalid` (`false`), `size`, `debounce`, `minChars` (`1`), `clearable` (`true`), `noOptionsText`, `loadingText`, `name` |
| `Dropdown` | `items[]` (`{eventKey, children, to}`) | `title` (`'Dropdown'`), `trigger` (`click` \| `hover` \| `context`), `placement` (`bottom-start`; 10 değerli liste), `disabled`, `activeKey`, `menuClass`, `menuStyle` |
| `Menu` | `items[]` (`{eventKey, icon, children/label}`) | `menuItemHeight` (`30`), `sideCollapsed` (`false`), `variant` (`light` \| `dark` \| `themed` \| `transparent`), `defaultActiveKeys[]`, `defaultExpandedKeys[]` |
| `Pagination` | `items[]` | `currentPage` (`1`), `pageSize` (`1`), `total` (`5`), `displayTotal` (`false`) |
| `Radio.Group` | `items[]` (`{value, label, disabled}`) | `name` (`'radioGroup'`), `value`, `vertical` (`false`), `disabled`, `readOnly`, `color` |
| `Tabs` | `items[]` (`{label, value}`) — **her sekme değeri bir çocuk yuvasıdır** (`slot: "tab:<value>"`), içine bileşen bırakılır | `defaultValue`, `value`, `variant` (`underline` \| `pill`) |
| `Grid` | `items[]` (satır nesneleri; kolonlar binding'den seçilir) | `cols` (`3`), `rows` (`2`), `gap`/`colGap`/`rowGap` (`4`), `responsive` (`true`), `smCols`/`mdCols`/`lgCols`/`xlCols` (`1/2/3/4`), `autoFit` (`false`), `minColWidth` (`'200px'`), `height` (`'auto'`) |
**Form/giriş bileşenleri:**
| Bileşen | Prop'lar (varsayılan) |
| --- | --- |
| `Input` | `type` (`text`; `HTMLInputTypeAttribute` listesi: `text/password/email/number/tel/url/search/date/time/…`), `value`, `placeholder` (`'Metin girin...'`), `textArea` (`false`) + `rows` (`3`), `prefix`/`suffix`, `size`, `disabled`, `invalid`, `readOnly`, `required`, `maxLength`/`minLength`, `pattern`, `autoComplete` (`off`), `autoFocus`, `name`, `unstyle` |
| `Checkbox` | `checked`, `defaultChecked`, `value`, `name`, `color`, `disabled`, `readOnly` |
| `Switcher` | `checked`, `defaultChecked`, `checkedContent`/`unCheckedContent`, `color`, `disabled`, `readOnly`, `isLoading` (`false`), `name` |
| `Radio` | `checked`, `defaultChecked`, `value`, `name`, `color`, `vertical`, `disabled`, `readOnly` — tekil düğme; seçenek grubu için `Radio.Group` |
| `DatePicker` | `value`/`defaultValue` (ISO string olarak saklanır, render'da `Date`'e çevrilir), `inputFormat`, `closePickerOnChange` (`true`), `defaultOpen` (`false`), `openPickerOnClear` (`false`), `inputtableBlurClose` |
| `TimeInput` | `value`/`defaultValue`, `format` (`24` \| `12`), `showSeconds` (`false`), `clearable` (`true`), `amLabel`/`pmLabel`, `timeFieldPlaceholder` (`'--'`), `prefix`/`suffix`, `size` (`md`), `disabled`, `invalid`, `name` |
| `Calendar` · `RangeCalendar` | `value` (`Date` \| `Date[]`), `multipleSelection` · `value` (`[Date, Date]`), `singleDate` (`false`) |
| `ColorPicker` | `value`/`defaultValue` (`'#6366f1'`), `presets[]`, `showAlpha`, `showInput` (`true`), `showRgb` (`false`), `size` (`md`), `disabled`, `name` |
| `Chips` | `value`/`defaultValue` (string dizisi; örnek `['Deneme','Deneme2']`), `max` (`0` = sınırsız), `allowDuplicate` (`false`), `separator`, `placeholder`, `size`, `disabled`, `invalid`, `name` |
| `Slider` | `value`/`defaultValue`, `min` (`0`), `max` (`100`), `step` (`1`), `range` (`false`), `orientation` (`horizontal` \| `vertical`), `marks`, `tooltip` (`false`), `trackSize` (`4`), `handleSize` (`18`), `disabled`, `readOnly`, `name` |
| `Knob` | `value`/`defaultValue` (`0`), `min`/`max` (`0/100`), `step` (`1`), `size` (`100`), `strokeWidth` (`14`), `valueColor`/`rangeColor`/`textColor`, `valueTemplate` (`'{value}'`), `showValue` (`true`), `readOnly`, `disabled`, `name` |
| `Rate` | `count` (`5`), `value`/`defaultValue`, `allowHalf` (`false`), `allowClear` (`true`), `color` (`amber`), `size` (`20`), `gap` (`4`), `tooltips[]`, `disabled`, `readOnly` |
| `Upload` | `accept`, `multiple`, `draggable` (`false`), `uploadLimit`, `showList` (`true`), `tip`, `fileList[]`, `disabled` — dosyanın **gerçek** yüklenmesi `beforeUpload`/`onChange` script'inde `api.post` ile yapılır |
**Gösterim/geri bildirim bileşenleri:**
| Bileşen | Prop'lar (varsayılan) |
| --- | --- |
| `Button` | `variant` (`default` \| `solid` \| `twoTone` \| `plain`), `color`, `size` (`sm`), `shape` (`round` \| `circle` \| `none`), `icon`, `block` (`false`), `active` (`false`), `loading` (`false`), `disabled` |
| `Card` (çocuk kabul eder) | `header`/`headerExtra`/`footer`, `headerBorder`/`footerBorder` (`true`), `bordered`, `clickable` (`false`), `bodyClass`/`headerClass`/`footerClass` |
| `Avatar` | `src`/`srcSet`, `icon`, `alt`, `size` (`md`), `shape` (`circle`; `round` \| `circle` \| `square`) |
| `Badge` | `content`, `maxCount` (`99`), `innerClass`, `badgeStyle` |
| `Tag` | `children`, `prefix`/`suffix` (+ `prefixClass`/`suffixClass`), `title` |
| `Progress` | `variant` (`line` \| `circle`), `percent` (`0`), `color`, `showInfo` (`true`), `customInfo`, `strokeWidth` (`6`), `strokeLinecap` (`round` \| `square`), `width` (`120`; circle), `gapDegree`/`gapPosition` (circle) |
| `Skeleton` | `variant` (`block` \| `circle`), `animation` (`true`), `width`/`height`, `asElement` |
| `Spinner` | `size` (`20`), `color`, `isSpining` (`true`), `enableTheme` (`true`), `indicator` |
| `Notification` | `title`, `type` (`success` \| `warning` \| `danger` \| `info`), `closable` (`false`), `duration` (`3000`), `customIcon`, `width` (`350`) — sayfada sabit kutu olarak durur; olaya bağlı geçici bildirim için script'te `notify()` kullan |
| `Tooltip` | `title`, `placement` (`top`; 12 değerli `ArrowPlacement` listesi), `isOpen`, `wrapperClass` |
| `ImageViewer` | `images[]` (`{src, alt, caption}` — yeni düşen bileşen iki örnek görselle gelir), `children` (`'Galeri'` tetikleyici), `defaultIndex` (`0`), `loop` (`true`), `showToolbar`/`showThumbnails` (`true`), `zoomStep` (`0.25`), `minZoom`/`maxZoom` (`0.5/4`), `keyboard` |
| `Marquee` | `speed` (`100`), `direction` (`left` \| `right` \| `up` \| `down`), `pauseOnHover`/`pauseOnClick` (`false`), `loop` (`0` = sonsuz), `gradient` (`false`), `gradientColor`/`gradientWidth`, `delay` (`0`), `play` (`true`), `autoFill` (`false`) |
| `ScrollBar` | `direction` (`ltr` \| `rtl`) |
### 10.10 Olaylar — bileşen başına `event` yükü
JavaScript sekmesinde görünen olaylar ve handler'a gelen tek argümanın (`event`) içeriği.
Script kapsamındaki her şey (`refs`, `api`, `notify`, `translate`, `checkPermission`) ve
`Form` yaşam döngüsü olayları `lowcode` §7.8'dedir; buradaki tablo bileşen olaylarının yüküdür.
| Bileşen | Olay(lar) | `event` |
| --- | --- | --- |
| `Button` | `onClick` | DOM tıklama olayı |
| `Input` | `onChange` | DOM olayı → değer `event.target.value` |
| `Checkbox` | `onChange` | `event.checked` |
| `Select` | `onChange` | Seçilen `{label, value}` nesnesi; temizlenince `null``event?.value ?? null` |
| `AutoComplete` | `onInputChange` · `onSelect` | Yazılan metin · seçilen option nesnesi |
| `Dropdown` | `onSelect` | Seçilen öğenin `eventKey` değeri |
| `Menu` | `onSelect` | Seçilen öğenin `eventKey` değeri |
| `Pagination` | `onChange` | Seçilen sayfa numarası |
| `Radio.Group` | `onChange` | Seçilen öğenin `value` değeri |
| `Tabs` | `onChange` | Aktif sekmenin `value` değeri |
Bu on bileşen `DESIGNER_PRIMARY_EVENTS` kaydıdır — panel yalnızca bu olayları gösterir.
Kayıtta olmayan bileşenlerde bütün `function` prop'ları listelenir; işe yarayanlar:
| Bileşen | Olaylar |
| --- | --- |
| `Switcher` · `ColorPicker` · `Knob` · `Slider` (+`onAfterChange`) · `Rate` (+`onHoverChange`) · `TimeInput` · `DatePicker` · `RangeCalendar` | `onChange` — yeni değer |
| `Chips` | `onChange`, `onAdd`, `onRemove` |
| `Upload` | `beforeUpload` (false → dosya reddedilir), `onChange` (dosya listesi), `onFileRemove` |
| `Card` · `Avatar` · `p` · `span` · `h1``h5` | `onClick` |
| `div` | `onClick`, `onMouseEnter`, `onMouseLeave` |
| `img` | `onClick`, `onLoad` |
| `Notification` · `ImageViewer` | `onClose` (`ImageViewer` ayrıca `onIndexChange`) |
| `Marquee` | `onFinish`, `onCycleComplete` |
Sayfa düzeyinde tek yaşam döngüsü kancası vardır: **`lifecycle.onMount`** — sayfa açıldığında
bir kez çalışır; açılış verisi çekme ve `refs` üzerinden ilk durumu kurma buraya yazılır.
> Olay davranışı kurarken önce Script Builder tarifleri (`lowcode` §7.8 tablosu) denenir;
> serbest kod `custom` tarifiyle eklenir ki sihirbaz açık kalsın.
---
## 11. Zamanlanmış e-posta (MailQueue modülü)
`BackgroundWorker` kaydı `WorkerType: 1` (MailQueueWorker) ise gövde bu modüldür
(`api/modules/Sozsoft.MailQueue`).
### 11.1 Worker `Options` (`MailQueueWorkerOptions`)
| Anahtar | Anlam |
| --- | --- |
| `MailType` | Şablon tipi etiketi |
| `MailSubject` | Mail konusu |
| `MailTemplate` | Razor ile render edilen HTML gövde (`EmailLayout` düzeni içinde) |
| `TableName` | Maildeki tabloların tarifi (§11.2) |
### 11.2 `TableName` biçimi
Her tablo `{index:TabloAdi:DosyaTipi:MailEkAdi:Korumalimi:DosyaAciklama}` altılısıdır;
birden fazlası `};{` ile birleştirilir:
```
{0:MT3_GECIKEN_SIPARIS:IN:Order Delay Notification:0:};{1:MT7_SIPARIS_DURUM:PDF:Durum.pdf:0:BRU,3,1}
```
- `TabloAdi` bir **tablo/view adıdır**; `SELECT * FROM {TabloAdi} WHERE ...` olarak parametreli
çalıştırılır (parametreler kuyruk satırındaki `TableParameter` alanından gelir).
- `DosyaTipi` = `IN` ise tablo mail gövdesine gömülür; `PDF` / `XLS` / `TXT` ise ek dosya olur.
- Sütun başlıkları, sırası, CSS'i ve alt toplamları `BackgroundWorker_MailQueueTableFormat`
kayıtlarından okunur: `TableName`, `Order`, `ColumnName`, `Caption`, `HeaderCss`, `Css`,
`FooterCss`, `DataType`, `DataFormat`, `IsHidden`, `IsProtected`, `SubTotal`, `Width`.
### 11.3 Kuyruk satırı (`BackgroundWorker_MailQueue`)
`TemplateId` (worker), `From`, `To`, `MailParameter`, `TableName`, `TableParameter`,
`Attachment`, `AttachmentParameter`, `RelatedRecordId`, `SendStatus`, `SendTime`, `AwsMessageId`.
Gönderim sonuçları `BackgroundWorker_MailQueueEvents` tablosunda izlenir.
Kuyruğa satır yazma işi genellikle worker'ın `BeforeSp` prosedüründe ya da ekranın
`InsertAfterCommand` kancasında yapılır — yani "kayıt onaylanınca mail çıksın" isteği kod
gerektirmez.
---
## 12. Saas ve Administration menüleri — platform yetenek kataloğu
Bu iki menü, platformun **hazır gelen tüm yeteneklerinin** girişidir. Bir komponent üretirken
buradaki her ekran üç rolden birindedir:
- **Yeniden kullanılacak yetenek** — numaratör, bildirim, zamanlanmış iş, rapor, dosya, yetki,
dil, ayar. Talebin bu kısmı için yeni artefakt üretilmez; ilgili ekrana kayıt girilir.
- **Veri kaynağı** — ülke/il/ilçe, para birimi, ölçü birimi, departman, ünvan, şube, kullanıcı,
rol. Yeni ekranın lookup'ı bu tablolara bağlanır; aynı listeyi tekrar tanımlama.
- **Referans uygulama** — istenen davranışın bu uygulamada zaten çalışan bir örneği. Aynı JSON'u
oradan alıp uyarlamak, sıfırdan yazmaktan hem hızlı hem güvenlidir (§12.6).
### 12.1 Tablo adlandırma sözleşmesi
Platform tablolarının adı `TableNameResolver` tarafından üretilir:
```
{ModülÖnEki}_{H|T|B}_{TableNameEnum} view'ler: V_{aynı ad}
```
| Parça | Değerler |
| --- | --- |
| Modül ön eki (`MenuPrefix`) | `Sas` Saas · `Adm` Administration · `Crm` · `Crd` Coordinator · `Scp` SupplyChain · `Mnt` Maintenance · `Str` Store · `Prj` Project · `Hr` · `Mrp` · `Acc` Accounting |
| Kapsam | `H` host (tüm tenant'lar için ortak) · `T` tenant · `B` şube |
| Ad | `TableNameEnum` üyesi |
Örnek: `Sas_H_Currency` (host — tüm kiracılar aynı para birimlerini görür), `Adm_T_Department`
(kiracı başına), `V_Sas_H_Order` (view). Özel view'ler
`TableNameResolver.GetFullSpecialViewName` ile `V_{Önek}_{Prefix}_{Ad}` biçiminde üretilir.
> Yeni bir platform tablosu eklenecekse `TableNameEnum` + `TableNameResolver._map` birlikte
> güncellenir; eşlemesi olmayan ad `KeyNotFoundException` fırlatır. Proje tabloları için
> `lowcode.instructions.md` §2'deki `{Modul}_T_{Entity}` kuralı geçerlidir.
### 12.2 Saas menüsü
Kök menü `App.Saas`. Yetki adı her satırda menünün `RequiredPermissionName` değeridir; ListForm
ekranlarında alt yetkiler `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note`
soneklerini alır.
| Ekran | Kod / route | Tablo | Kapsam | Komponent üretirken ne işe yarar |
| --- | --- | --- | --- | --- |
| **Tenants** | `AbpTenantManagement.Tenants` | `AbpTenants` | host | Kiracı kaydı, bağlantı dizesi diyaloğu (`TenantsConnectionString`), alt form olarak şubeler. Ekranların `IsTenant` davranışının kaynağı. |
| **Branches** | `App.Branches` | `Sas_T_Branch` | tenant | Şube listesi. Ekranı `IsBranch = true` yaparsan filtre bu tablodan gelir; `BranchSeed` diyaloğu şube verisini kurar. |
| **Definitions AiBot** | `App.Definitions.AiBot` | `Sas_H_AiBot` | host | Yapay zekâ asistanı tanımı (`Name`, `ApiUrl`, `Tenants`); `/admin/ai` bu kayıtları kullanır. |
| **Definitions Global Search** | `App.Definitions.GlobalSearch` | `Sas_T_GlobalSearch` | tenant | Üretilen ekranın üst aramada çıkması için kayıt: `System`, `Group`, `Term`, `Weight`, `Url`. |
| **Definitions Contact Title** | `App.Definitions.ContactTitle` | `Sas_H_ContactTitle` | host | Ünvan lookup'ı (`Title`, `Abbreviation`). |
| **Definitions Currency** | `App.Definitions.Currency` | `Sas_H_Currency` | host | Para birimi + `Rate`. Tutar alanı olan ekranın kur lookup'ı ve `DbQuery` varsayılanı buradan beslenir. |
| **Definitions Country Group / Country / City / District** | `App.Definitions.CountryGroup` · `.Country` · `.City` · `.District` | `Sas_H_CountryGroup` · `Sas_H_Country` · `Sas_H_City` · `Sas_H_District` | host | Adres alanlarının hazır cascade zinciri. `Country` ayrıca `PhoneCode`, `PhoneNumberFormat`, `ZipRequired`, `StateRequired`, `TaxLabel` taşır — adres doğrulaması için kullan. |
| **Definitions Skill Type / Skill / Skill Level** | `App.Definitions.SkillType` (+ alt kayıtlar) | `Sas_H_SkillType` · `Sas_H_Skill` · `Sas_H_SkillLevel` | host | Yetkinlik ağacı; `SkillType` kendi kendine ebeveyn olan alt form örneğidir. |
| **Definitions UoM Category / UoM** | `App.Definitions.UomCategory` | `Sas_H_UomCategory` · `Sas_H_Uom` | host | Ölçü birimi, `Ratio`/`Rounding` — miktar alanı olan ekranlarda birim lookup'ı ve çevrim. |
| **Definitions Sequence** | `App.Definitions.Sequence` | `Adm_T_Sequence` | tenant | Belge numarası üretimi (`lowcode.instructions.md` §9.9); alan varsayılanında `CustomValueType: 5` ile bağlanır. |
| **Public Home / About / Services / Contact** | `App.Home` · `App.About` · `App.Services` · `App.Contact``/admin/public/{ad}/designer` | `Sas_H_Home` · `Sas_H_About` · `Sas_H_Service` · `Sas_H_Contact` | host | Genel siteye açık sayfalar; tasarımcıdan düzenlenir. Public sayfa isteği kod değil bu tasarımcıdır. |
| **Public Products / Payment Methods / Installment Options** | `App.Orders.Products` · `.PaymentMethods` · `.InstallmentOptions` | `Sas_H_Product` · `Sas_H_PaymentMethod` · `Sas_H_InstallmentOption` | host | Ürün, ödeme yöntemi (`Commission`), taksit — satış/abonelik ekranlarının lookup kaynağı. |
| **Public Sales Orders** | `App.Orders.SalesOrders` | `Sas_H_Order` + `Sas_H_OrderItem` | host | **Onay akışı + alt kalem + toplam + diyalog** birlikte kullanılan tam örnek (§12.6). |
| **Public Blog Category / Posts** | `App.BlogManagement.Category` · `.Posts` | `Sas_H_BlogCategory` · `Sas_H_BlogPost` | host | Çok dilli içerik (`ContentTr`/`ContentEn`), slug, yayın durumu, sayaç alanları. |
| **Public Demos** | `App.Demos` | `Sas_H_Demo` | host | Siteden gelen demo talepleri — public form → tablo akışının örneği. |
| **Dev Requests** | `App.DevRequests` | `Sas_H_DevRequest` | host | **Kanban/Todo düzeninin** referansı: `Status`, `Priority`, `SortOrder`, `Tags`, `Assignees`, `SubTasks`, `Timesheets`. |
| **Setting Definitions** | `App.SettingDefinitions` | `Sas_H_SettingDefinition` | host | Yeni uygulama ayarı: `Code`, `MainGroupKey`/`SubGroupKey`, `DataType`, `SelectOptions`, `DefaultValue`, `Providers`, `RequiredPermissionName`, `IsEncrypted`, `IsVisibleToClients`. Ayarlanabilir olması gereken değeri koda gömme. |
| **Languages Language / Language Text** | `App.Languages.Language` · `.LanguageText` | `Sas_H_Language` · `Sas_H_LanguageKey` · `Sas_H_LanguageText` | host | Dil anahtarları. Üretilen her ekranın EN+TR metinleri buraya (ve `LanguagesData.json`'a) yazılır. |
| **Data Source** | `App.DataSource` | `Sas_H_DataSource` | host | `Code`, `DataSourceType`, `ConnectionString`. **İki tür kayıt bir arada:** elle tanımlanan host/harici bağlantılar ve `Code = tenant adı` olan otomatik tenant bağlantıları (Tenants ekranındaki bağlantı diyaloğu yönetir, elle dokunma). `IsTenant` ekran önce tenant kaydını, yoksa `DataSourceCode`'u kullanır — çözüm kuralı `lowcode` §9.3.3. Bağlantı dizesi koda/JSON'a yazılmaz. |
| **Notifications Types / Rules / Notifications** | `App.Notifications.NotificationTypes` · `.NotificationRules` · `.Notification` | `Sas_H_NotificationType` · `Sas_H_NotificationRule` · `Sas_H_Notification` | host | Olay bazlı bildirim (7 kanal); kural ekranındaki `CreateNotification` diyaloğu ile elle bildirim üretilir. Ayrıntı: §9.11. |
| **Background Workers Recurring Jobs / Jobs** | `App.BackgroundWorkers.RecurringJobs` · `.Jobs` | `Sas_H_BackgroundWorker` · `Sas_H_BackgroundWorker_JobFlow` | host | Cron'lu işler ve çalıştırma geçmişi (`ExecutionDate`, `Duration`, `Status`, `FailureReason`, `ExceptionDetails`). Ayrıntı: §9.10 ve bu dosyanın §11'i. |
| **Menus Routes / Menu Group / Menu / Manager** | `App.Menus.Routes` · `.MenuGroup` · `.Menu` · `.Manager` (`/admin/menuManager`) | `Sas_H_Route` · `Sas_H_MenuGroup` · `Sas_H_Menu` | host | Menü ve route veritabanından gelir; üretilen ekranın menü kaydı buradan açılır. `Menu` ekranı ağaç düzeninin referansıdır, `Routes` yalnızca özel React sayfası eklenirken kullanılır. |
| **Developer Kit SQL Query Manager** | `App.SqlQueryManager` · `/admin/sqlQueryManager` | — | — | View/procedure/function yazma ve çalıştırma; karar sırasının 2. adımı buradan başlar. |
| **Developer Kit Custom Endpoints** | `App.DeveloperKit.CustomEndpoints` | `Sas_H_CustomEndpoint` | tenant | `Name`, `Url`, `Method`, `DataSourceCode`, `Sql`, `ParametersJson`, `PermissionsJson` — parametreli SQL'i yetkili bir HTTP ucuna çevirir. |
| **Developer Kit Dynamic Services** | `App.DeveloperKit.DynamicServices` · `/admin/developerkit/dynamic-services` | `Sas_H_DynamicService` | host | Monaco editöründe yazılan, derlenip yayınlanan C# servisi; SQL'in yetmediği iş kuralı için 3. adım. |
| **Developer Kit Components** | `App.DeveloperKit.Components` · `/admin/developerkit/components` | `Sas_H_CustomComponent` | host | Custom component listesi ve **Visual Designer** girişi (§10). |
| **Developer Kit ListForm** | `App.Listforms.Listform` | `Sas_H_ListForm` · `Sas_H_ListFormField` · `Sas_H_ListFormWorkflow` · `Sas_H_ListFormCustomization` · `Sas_H_ListFormImport` | host | Ekran tanımlarının kendisi. Bu dosyada anlatılan bütün JSON kolonlarının canlı hâli; düzenleyicisi `/admin/listform/edit/{kod}`. |
| **Developer Kit Wizard Manager** | menü kodu `App.Listforms.WizardManager` · yetki `App.Listforms.Wizard` · `/admin/listform/wizardManager` | — | host | Wizard seed dosyalarının listesi, düzenlemesi, silinmesi, export/import'u. Sihirbazın kendisi ayrı bir rotadadır: `/admin/listform/wizard`. |
| **Forum Management** | `App.ForumManagement` · `/admin/forumManagement` | `Sas_T_ForumCategory` · `Sas_T_ForumTopic` · `Sas_T_ForumPost` | tenant | Forum kategori/konu yönetimi; yayın tarafı Administration'daki `/admin/forum`. |
> Menü kodu ile yetki adı **her zaman aynı değildir**: Wizard Manager'da kod
> `App.Listforms.WizardManager`, yetki `App.Listforms.Wizard`'dır; Administration'daki Forum
> ekranında kod `App.Forum`, yetki `App.ForumManagement.Publish`'tir. Yeni ürettiğin ekranlarda
> ikisini ayırma — wizard zaten aynı kökü kullanır (`lowcode` §2).
### 12.3 Administration menüsü
Kök menü `App.Administration`. Bu menünün tabloları `Adm_T_*` — yani **kiracı başına** ayrışır.
| Ekran | Kod / route | Tablo | Komponent üretirken ne işe yarar |
| --- | --- | --- | --- |
| **Definitions Sector** | `App.Definitions.Sector` | `Adm_T_Sector` | Sektör lookup'ı. |
| **Definitions Department** | `App.Definitions.Department` | `Adm_T_Department` | `ParentId` ile **ağaç (TreeList) düzeninin** referansı; personel/onay ekranlarının departman lookup'ı. |
| **Definitions Job Position** | `App.Definitions.JobPosition` | `Adm_T_JobPosition` | Ünvan ağacı (`ParentId` + `DepartmentId`) — departmana bağlı cascade örneği. |
| **Definitions Org Chart** | `App.Definitions.OrgChart` · `/admin/organization` | `Adm_T_Department` | Departman/ünvan verisinin organizasyon şeması görünümü. |
| **Licence** | `App.Licence` · `/admin/form/App.Licence` | `AbpTenants` + `V_Sas_H_OrderItem_ByTenantId` | **`ListFormType = Form`** (listesiz, tek kayıtlık ekran) + alt kalem listesi. "Tek kayıtlık kart ekran" isteğinin karşılığı budur. |
| **Dev Request** | `App.DevRequest` | `Sas_H_DevRequest` | Kiracı tarafındaki talep ekranı (Saas'taki listenin kullanıcı yüzü). |
| **Agenda** | `App.Agenda` | `Adm_T_Agenda` | **Takvim (Scheduler) düzeninin** referansı: `StartDate`, `EndDate`, `AllDay`, `RecurrenceRule`, `RecurrenceException`. Tekrarlayan randevu isteği kod gerektirmez. |
| **Settings** | `App.Setting` · `/admin/settings` | — | `SettingDefinition` kayıtlarından üretilen ayar ekranı; değerler burada girilir. |
| **Intranet Announcement (+Like/Comment)** | `App.Intranet.Announcement` | `Adm_T_Announcement` · `Adm_T_AnnouncementLike` · `Adm_T_AnnouncementComment` | Duyuru + beğeni + yorum: **ana kayıt / alt etkileşim** kalıbının hazır örneği. |
| **Intranet Survey (+Question/Option/Response/Answer)** | `App.Intranet.Survey` | `Adm_T_Survey` · `Adm_T_SurveyQuestion` · `Adm_T_SurveyQuestionOption` · `Adm_T_SurveyResponse` · `Adm_T_SurveyAnswer` | Anket motoru; soruseçenekyanıt zinciri **iki seviyeli alt form** ihtiyacının referansıdır. |
| **Intranet Social Post (+Comment/Like)** | `App.Intranet.SocialPost` | `Adm_T_SocialPost` · `Adm_T_SocialComment` · `Adm_T_SocialLike` (+ `SocialPollOption`, `SocialMedia`, `SocialLocation`) | Kurum içi akış; `IsLiked`, `IsOwnPost` gibi hesaplanmış kolonların view içinde üretilmesine örnek. |
| **Intranet Event Type / Category / Event (+Like/Comment)** | `App.Intranet.Events.*` | `Adm_T_EventType` · `Adm_T_EventCategory` · `Adm_T_Event` · `Adm_T_EventPhoto` · `Adm_T_EventLike` · `Adm_T_EventComment` | Etkinlik yönetimi; foto ve katılımcı sayacı olan kayıt kalıbı. |
| **Restrictions Work Hour** | `App.Restrictions.WorkHour` | `Adm_T_WorkHour` | Gün bazlı çalışma saati (`Monday`…`Sunday`, `StartTime`, `EndTime`); kullanıcıya `AbpUsers.WorkHour` ile bağlanır. "Sadece mesai saatinde girilebilsin" burada çözülür. |
| **Restrictions IP Restrictions** | `App.Restrictions.IpRestrictions` | `Adm_T_IpRestriction` | `ResourceType` + `ResourceId` + `IP` — kullanıcı/rol bazlı IP kısıtı. |
| **Identity Permission Groups / Permissions** | `Abp.Identity.PermissionGroups` · `Abp.Identity.Permissions` | `AbpPermissionGroups` · `AbpPermissions` | Yetki ağacı (tree düzeni). Yeni ekranın yetkileri burada görünür; `MenuGroup` kolonu yetkiyi modüle bağlar. |
| **Identity Claim Type** | `App.IdentityManagement.ClaimType` | `AbpClaimTypes` | Kullanıcıya ek alan (claim) tanımı: `ValueType`, `Regex`, `Required`, `IsStatic`. |
| **Identity Roles** | `AbpIdentity.Roles` | `AbpRoles` | Rol yönetimi + `RolesPermission` diyaloğu; yeni ekranın yetkisi role buradan verilir. |
| **Identity Users** | `AbpIdentity.Users` | `AbpUsers` | Kullanıcı yönetimi + `UsersPermission` diyaloğu, **KPI widget'ları** ve `list-form-dynamic-api/user-*` ile devredilen yazma. Kullanıcı `WorkHour`, `DepartmentId`, `JobPositionId` alanlarını taşır. |
| **Identity Organization Units** | `Abp.Identity.OrganizationUnits` · `/admin/ous` | ABP OU tabloları | Birim ağacı. Ekranı `IsOrganizationUnit = true` yaparsan veri bu ağaca göre süzülür; bildirim alıcısı da OU olabilir. |
| **Identity Audit Logs** | `App.IdentityManagement.AuditLogs` | `AbpAuditLogs` | İstek denetim kaydı + `AuditLogDetail` diyaloğu. "Kim ne zaman ne yaptı" isteği yeni tablo gerektirmez. |
| **Identity Sessions** | `App.IdentityManagement.Sessions` | `AbpSessions` | Açık oturumlar; `UiEvalService.ApiKickUser` ile oturum düşürme (§9.13). |
| **Reports Categories / Templates** | `App.Reports.Categories` · `App.Reports.ReportTemplates` | `Adm_T_ReportCategory` · `Adm_T_ReportTemplate` | Kendi düzeni olan çıktılar (fatura, teklif); ekrana `CommandColumnJson` butonuyla bağlanır (§9.12). |
| **Videoroom** | `App.Videoroom` · `/admin/videoroom/dashboard` | `Adm_T_Videoroom` · `Adm_T_VideoroomParticipant` · `Adm_T_VideoroomAttandance` · `Adm_T_VideoroomChat` | Görüntülü oda, katılım ve sohbet kaydı. |
| **Files** | `App.Files` · `/admin/files` | — | Dosya yöneticisi. Ekranın dosya alanı için ayrı depolama kurma; dosya/görsel editörleri bu altyapıyı kullanır. |
| **Forum** | menü kodu `App.Forum` · yetki `App.ForumManagement.Publish` · `/admin/forum` | `Sas_T_Forum*` | Forumun kullanıcı tarafı. |
Menüde görünmeyen ama route'u olan ekranlar: `/admin/dashboard`, `/admin/ai`,
`/admin/activityLog`, `/admin/changeLog`, `/admin/profile/{general,password,notification-settings}`,
`/admin/users/detail/:userId` (yetki `AbpIdentity.Users.Update`), `/admin/videoroom/list` ve
`/admin/videoroom/room/:id`, `/admin/reports/*`, `/admin/listform/{wizard,wizardManager}`,
`/admin/listform/edit/:listFormCode` ve dinamik ekran rotaları.
**Dinamik ekran rotaları** — üretilen her ListForm ekranı bunları kullanır, ayrıca route kaydı
ılmaz:
| Route | Bileşen | Ne açar |
| --- | --- | --- |
| `/admin/list/:listFormCode` | `views/list/List` | Liste (grid/card/pivot/tree/gantt/scheduler/todo — `LayoutJson`'a göre) |
| `/admin/form/:listFormCode` | `views/form/FormNew` | Yeni kayıt formu |
| `/admin/form/:listFormCode/:id` | `views/form/FormView` | Tek kayıt görüntüleme (`AllowDetail` bunu açar) |
| `/admin/form/:listFormCode/:id/edit` | `views/form/FormEdit` | Tek kayıt düzenleme |
| `/admin/chart/:listFormCode` | `views/list/Chart` | Yalnız grafik ekranı |
`/admin/pivot/...` diye bir route **yoktur**; pivot, liste ekranındaki bir görünümdür.
### 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.
Bir route kaydının alanları: `key`, `path`, `componentType`, `componentPath` (`@/views/...`),
`routeType`, `authority[]`.
| `routeType` | Anlam |
| --- | --- |
| `public` | Oturum gerekmez — genel siteye açık sayfalar |
| `authenticated` | Kimlik akışı sayfaları (giriş, kayıt, parola, doğrulama) |
| `protected` | Oturum zorunlu; `authority` doluysa ayrıca yetki kontrolü yapılır |
`authority: []` **yetki kontrolü yok** demektir; ekranın kendi yetkisi varsa kontrol
bileşenin/ListForm'un içindedir. Custom component route'ları da böyle üretilir — bu yüzden
görünürlük `checkPermission` ile bileşen içinde kurulur (`lowcode` §7.5).
| Route | Bileşen | Yetki |
| --- | --- | --- |
| `/admin/menuManager` | `views/menu/MenuManager` | `App.Menus.Manager` |
| `/admin/listform/wizard` | `listForm/wizard/Wizard` | `App.Listforms.Wizard` |
| `/admin/listform/wizardManager` | `listForm/wizard/WizardFileManager` | `App.Listforms.Wizard` |
| `/admin/listform/edit/:listFormCode` | `listForm/edit/FormEdit` | `[]` — yetki ListForm tarafında |
| `/admin/sqlQueryManager` | `developerKit/SqlQueryManager` | `App.SqlQueryManager` |
| `/admin/developerkit/dynamic-services{,/new,/edit/:id}` | `DynamicServiceManager` · `DynamicServiceEditor` | `App.DeveloperKit.DynamicServices` |
| `/admin/developerkit/components{,/edit/:id}` | `ComponentManagerPage` · `ComponentCodeLayout` | `App.DeveloperKit.Components` |
| `/admin/reports/:report/{view,design}/:id?/:listFormCode?` | `DevexpressReportViewer` · `DevexpressReportDesigner` | — |
| `/admin/public/{home,about,services,contact}/designer` | ilgili public sayfa (tasarım modu) | `App.Home` · `App.About` · `App.Services` · `App.Contact` |
| `/admin/settings` | `settings/Settings` | `App.Setting` |
| `/admin/files` | `admin/files/FileManager` | `App.Files` |
| `/admin/ous` · `/admin/organization` | `organization-unit/OrganizationUnits` · `hr/OrgChart` | `Abp.Identity.OrganizationUnits` · `App.Definitions.Department` |
| `/admin/forum` · `/admin/forumManagement` | `forum/Forum` · `forum/Management` | `App.ForumManagement.Publish` · `App.ForumManagement` |
| `/admin/videoroom/{dashboard,list,room/:id}` | `admin/videoroom/{Dashboard,RoomList,RoomDetail}` | `App.Videoroom{,.List,.Detail}` |
| `/admin/ai` | `ai/Assistant` | `App.Definitions.AiBot.Asistant` |
| `/admin/dashboard` · `/admin/activityLog` · `/admin/changeLog` · `/admin/profile/*` | `Dashboard` · `admin/activityLog/ActivityLog` · `version/ChangeLog` · `admin/profile/Profile` | `[]` |
| `/admin/users/detail/:userId` | `admin/user-management/Details` | `AbpIdentity.Users.Update` |
**Oturum gerektirmeyen sayfalar** (`routeType: public`) — genel site. İçerikleri kod değil,
Saas Public altındaki tasarımcı ekranlarından ve tablolardan gelir; bir "tanıtım sayfası"
isteğinde yeni React sayfası yazma, bunları kullan:
| Route | Bileşen | Veri |
| --- | --- | --- |
| `/home` · `/about` · `/services` · `/contact` | `views/public/{Home,About,Services,Contact}` | `Sas_H_{Home,About,Service,Contact}` · tasarımcı: `/admin/public/{ad}/designer` |
| `/products` · `/checkout` · `/payment` · `/success` | `views/public/{Products,Checkout,Payment,Success}` | `Sas_H_Product` · `Sas_H_PaymentMethod` · `Sas_H_InstallmentOption` · `Sas_H_Order` |
| `/blog` · `/blog/:id` | `views/public/{Blog,BlogDetail}` | `Sas_H_BlogPost` · `Sas_H_BlogCategory` |
| `/demo` | `views/public/Demo` | `Sas_H_Demo` |
| `/access-denied` | `views/AccessDenied` | — |
**Kimlik akışı** (`routeType: authenticated`): `/login`, `/register`, `/forgot-password`,
`/reset-password`, `/confirm`, `/confirm/:userId/:token`, `/extend-login`
`views/auth/*`. Bunlara dokunma; parola ve doğrulama akışları ABP tarafındadır.
### 12.5 Talep → hangi menü
§0'daki katman taraması bu tabloyla eşleşir; "kod yazmamız gerekir" demeden önce buraya bak.
| Talepte geçen | Menü / ekran | Ne yapılır |
| --- | --- | --- |
| "numara otomatik gelsin" | Saas Definitions Sequence | Kayıt aç, alan varsayılanına `CustomValueType: 5` |
| "her gece / saat başı çalışsın" | Saas Background Workers | `WorkerType: 2` + `BeforeSp`; prosedür `sql/object/` altına |
| "bilgilendirme gitsin" | Saas Notifications (+ MailQueue §11) | Tür + kural; e-posta ise MailQueue |
| "onaya düşsün" | `WorkflowJson` + `ListFormWorkflow` (örnek: Sales Orders) | Onay düğümleri; `Inform` düğümü e-posta gönderir |
| "çıktısı alınsın / fatura basılsın" | Administration Reports | Hazır `DynamicGrid` ya da `ReportTemplate` |
| "dosya eklensin" | Administration Files | Dosya/görsel editörü; ayrı depolama kurma |
| "başka veritabanından gelsin" | Saas Data Source | Yeni DataSource + ekranın `DataSourceCode` alanı |
| "ayarlanabilir olsun" | Saas Setting Definitions | Tanım aç, değeri `/admin/settings`'ten yönet |
| "İngilizcesi de olsun" | Saas Languages | Dil anahtarı + `LanguagesData.json` |
| "aramada çıksın" | Saas Definitions Global Search | `System`/`Group`/`Term`/`Weight`/`Url` kaydı |
| "sadece şu rol görsün" | Administration Identity Roles / Permissions | Yetki kodu + ekranın `PermissionJson`'ı |
| "şube bazlı olsun" | Saas Branches | `IsBranch = true` |
| "birim ağacına göre süzülsün" | Administration Identity Organization Units | `IsOrganizationUnit = true` |
| "mesai dışında girilemesin" / "sadece ofis IP'si" | Administration Restrictions | Work Hour · IP Restriction kaydı |
| "kim değiştirmiş görelim" | Administration Identity Audit Logs | Hazır ekran; kayıt notu için `ShowNote` |
| "menüye eklensin" | Saas Menus Manager | Menü kaydı + yetki + route eşlemesi |
| "ülke/il/ilçe, para birimi, birim, departman, ünvan" | Saas / Administration Definitions | Var olan tabloya lookup bağla, yenisini üretme |
| "yapay zekâ cevaplasın" | Saas Definitions AiBot | Bot tanımı; `/admin/ai` bu tanımı kullanır |
### 12.6 Canlı referans uygulamalar
İstenen davranışın bu uygulamada çalışan örneği. Tanımlar
`api/src/Sozsoft.Platform.DbMigrator/Migrations/ListFormSeeder_{Saas,Administration}.cs`
içinde ilgili `#region` altındadır.
| İhtiyaç | Bak |
| --- | --- |
| Ağaç (TreeList) | `Menu`, `Permission`, `Department`, `JobPosition` |
| Kanban / Todo | `DevRequests` (`TodoOptionJson` + `SortOrder`, `Priority`, `Tags`) |
| Takvim (Scheduler) | `Agenda` (`SchedulerOptionJson` + `RecurrenceRule`) |
| Tek kayıtlık form ekranı | `Licence` (`ListFormType = Form` + alt kalem listesi) |
| Onay akışı | `Sales Orders``WorkflowJson` (`ApprovalUserFieldName`, `ApprovalStatusFieldName`, `ApprovalDateFieldName`, `ApprovalDescriptionFieldName`) + `ListFormWorkflow` düğümleri (Start → Approval → End/End) |
| Alt form (master-detail) | `Tenant → Branches`, `Sales Orders → Sales Order Item`, `Survey → Question → Option` |
| KPI widget | `User``WidgetsJson`; sorgu `Title`, `Value`, `Color`, `SubTitle`, `Icon` kolonlarını döndürür |
| Toolbar'dan diyalog açma | `Tenant` (`TenantsConnectionString`), `Role` (`RolesPermission`), `User` (`UsersPermission`), `Audit Logs` (`AuditLogDetail`), `Notification Rule` (`CreateNotification`), `Branches` (`BranchSeed`), `Sales Orders` (`CreateTenantFromOrderDialog`) |
| Yazmayı servise devretme | `Tenant`, `Role`, `User``*ServiceAddress = "list-form-dynamic-api/{tenant\|role\|user}-{insert\|update}"` |
| Toplam satırı | `Sales Order Item`, `Licence Item` (`TotalSummaryJson`) |
| View üzerinden okuma | `Background Worker Jobs`, `Licence Item` (`SelectCommandType = View`) |
| Cascade lookup | `City``District` (ülke/il/ilçe zinciri) |
| Alan varsayılanı ve soft delete | `Tenant` (`FormFieldsDefaultValueJson`, `DeleteFieldsDefaultValueJson`) |
### 12.7 Uyarılar
- **Bu ekranların seeder'ı idempotenttir:** `ListFormCode` zaten varsa kayıt **güncellenmez**.
Hazır bir ekranın davranışını değiştirmek gerekiyorsa seeder'ı düzenlemek yetmez; değişikliği
`sql/execute/{Ad}.sql` altında var olan kaydı güncelleyen bir prosedürle taşı.
- **Host tablosuna kiracı verisi yazma.** `Sas_H_*` tabloları bütün kiracılar için ortaktır;
kiracıya özel veri `*_T_*` tablosuna gider. Ekranın `IsTenant`/`IsBranch` bayrakları ile
tablonun kapsam harfi tutarlı olmalıdır.
- **Yetki adı menüden gelir.** Ekranın `PermissionJson`'ındaki adlarla menünün
`RequiredPermissionName` değeri aynı sözleşmeyi göstermelidir; farklıysa kullanıcı menüyü görür,
ekranı göremez.
- **Platformun hazır tablolarına doğrudan yazan ekran üretme.** `AbpUsers`, `AbpRoles`,
`AbpTenants` yazma işi `list-form-dynamic-api` uçlarındadır; ham SQL ile yazmak parola
hash'ini, yetki önbelleğini ve kiracı kurulumunu atlar.
---
## 13. Bu dosyanın kapsamadıkları
| Konu | Nerede |
| --- | --- |
| Karar sırası, üretim protokolü, seed sözleşmesi | `lowcode.instructions.md` §0§2 |
| Wizard seed dosyasının alanları | `lowcode.instructions.md` §4 |
| `EditorScript` tarifleri ve runtime API | `lowcode.instructions.md` §5 |
| `EditorOptions` sözlüğü ve preset'ler | `lowcode.instructions.md` §6 |
| Visual Designer doküman şeması ve event script'leri | `lowcode.instructions.md` §7 |
| SQL nesneleri, CRUD/Custom Endpoint, Dynamic Service | `lowcode.instructions.md` §8§9 |
| Sequence, zamanlanmış iş, bildirim, rapor ekranları | `lowcode.instructions.md` §9.9§9.14 |
| `api/` kod standardı | `dotnet.instructions.md` |
DevExtreme'in burada listelenmeyen bir seçeneğini kullanman gerekiyorsa, **nereye yazdığın
belirleyicidir**:
| Nereye | Bilinmeyen anahtara ne olur |
| --- | --- |
| Ekran seviyesindeki `*Json` kolonları (§2§8) | **Düşer.** `GridOptionsDto` ham metni `[JsonIgnore]` ile gizler, istemciye yalnızca tipli DTO gider. Kalıcı olarak gerekiyorsa önce ilgili DTO'ya alan eklenir, sonra bu dosya güncellenir |
| Alan seviyesindeki `ListFormField.EditorOptions` (§9.8) | **Geçer.** Ham metin olarak istemciye iner ve editöre olduğu gibi verilir; sözlükte olmayan anahtar Options Builder'ın "Sözlük dışı ayarlar" bölümünden de yazılabilir (`lowcode` §6.1) |
| `CustomJsSourcesJson` / `CustomStyleSourcesJson` (§5.5) | Geçer — ama son çaredir, denetlenmez |
Yani "DevExtreme'de var, platformda yok" durumunda önce §9.8'e (editör seçeneği mi?) bak; ekran
seviyesindeki bir seçenekse DTO'ya eklenmeden çalışmayacağını bilerek planla.