sozsoft-platform/claude.md

614 lines
51 KiB
Markdown
Raw Normal View History

2026-03-25 05:52:55 +00:00
# Sozsoft Platform - Claude Instructions
This file provides Claude-specific operating rules for this repository.
Primary source of truth for platform behavior is:
- `.github/instructions/ai.instructions.md`
If there is any conflict, follow `.github/instructions/ai.instructions.md`.
## Communication Rules (apply to every response)
1. **Never introduce or summarize the platform.** Assume the user knows what this
application is, how it is built, and which technologies it uses. Do not open a response
with "Sozsoft Platform is a multi-tenant low-code engine…" or any equivalent framing.
2. **Answer the request, nothing more.** No unsolicited architecture overviews, no
restating the decision order, no re-explaining ListForm/DeveloperKit concepts unless
the user actually asked about them.
3. **No preamble, no epilogue.** Skip "Great question", "I reviewed the codebase",
summaries of what you are about to do, and closing recaps of what you just did.
4. **Match the question's size.** A yes/no question gets a sentence. A config question
gets the config. Only a full feature request gets a full proposal.
5. **Respond in the language the user writes in** (Turkish → Turkish).
6. Mention a rule from this file only when it changes the answer — never as boilerplate.
2026-03-25 05:52:55 +00:00
## Purpose
- Maximize delivery through runtime configuration.
- Minimize custom code.
- Preserve platform consistency, security, and tenant isolation.
Primary principle: Configuration first, code last.
## Mandatory Decision Order
For every request, evaluate in this order — internally. State the chosen step only when the
user is asking how to build something, and state it in one line, not as a walkthrough of the
options you rejected.
2026-03-25 05:52:55 +00:00
1. Dynamic configuration with existing ListForm ecosystem
2. SQL Query Manager + Custom Endpoint
3. Dynamic Service
4. Code change (last resort, justification required)
## Non-Negotiable Rules
1. Do not propose new custom React component/page development for standard feature requests.
2. Build new screens using platform configuration mechanisms.
3. Every implementation proposal must include tenant and permission design.
2026-03-25 05:52:55 +00:00
4. Never bypass platform authorization patterns.
5. Never hardcode secrets, tenant IDs, or connection strings.
2026-09-22 20:59:36 +00:00
6. Never step outside the framework without explicit approval (standing default 11).
2026-03-25 05:52:55 +00:00
Exception:
- Custom React/backend code is allowed only when the user explicitly requests implementation
and configuration is insufficient.
- In such cases, explain why configuration-first options are not enough — in a sentence or two.
2026-03-25 05:52:55 +00:00
## Architecture Guardrails
- Backend: Respect ABP module boundaries and explicit, auditable permissions.
- Frontend: Use existing dynamic view infrastructure and metadata-driven behavior.
- Data: Use parameterized SQL patterns and enforce tenant-safe access.
## Dynamic Platform Expectations
- Menus and routes are database-driven.
- Dynamic List/Form/Component infrastructure is the default solution path.
- Keep route, menu, permission, and datasource mappings coherent.
## Security and Compliance
- Enforce RBAC and permission-driven visibility in all layers.
- Never output real credentials, tokens, keys, or secrets.
- Use placeholders in examples.
- Maintain tenant isolation in every query and action.
## Response Contract
The list below applies **only** to a full implementation proposal for a new screen, module,
or integration. It is not a template for questions, debugging, code review, refactors,
explanations, or small changes.
Even for a full proposal: include only the items that carry real content for that request,
and drop the rest. An empty or obvious heading is noise.
2026-03-25 05:52:55 +00:00
1. Goal
2. Decision flow result (which step used)
3. Artifacts to configure
4. SQL/query/endpoint design (if needed)
5. Menu + route + component mapping
6. Permission and role mapping
7. Tenant isolation notes
8. Validation and test checklist
9. Rollback strategy
---
## Standing Context (read this before proposing anything)
These sections encode expectations the user will **not** repeat in every prompt.
`README.md` is the technical map of the platform; this file is how to act on it.
### Where the truth lives
| Konu | Kaynak |
| --- | --- |
| Platform davranışı, karar sırası, çıktı sözleşmesi | `.github/instructions/ai.instructions.md` |
| **Artefakt üretimi**: seed şemaları, enum değerleri, çalışan örnekler | `.github/instructions/lowcode.instructions.md` |
2026-09-29 11:46:39 +00:00
| **Yetenek envanteri**: JSON kolonlarının alan alan sözleşmesi, grafik/pivot/tasarımcı/mail modülü, Saas + Administration + İK menüsündeki hazır ekranlar | `.github/instructions/lowcode-reference.instructions.md` |
| `api/` kod standardı (sürüm, nullable, ölü kod, modern C#, ABP katmanları) | `.github/instructions/dotnet.instructions.md` |
| Modül/liste ekleme prosedürü, seeder dosya sorumlulukları | `.github/instructions/list.instructions.md` |
| Ne nerede yaşıyor, hangi ekran ne yapıyor | `README.md` |
2026-10-07 08:17:46 +00:00
| Bir modülün nasıl çalıştığı, analizi ve kararları | `configs/seeds/docs/modules/{Menü}.md` (dizin: `README.md` §10.5) |
| Yetki kodları | `PlatformConsts.AppCodes` (backend) + `constants/permission.constant.ts` (UI) |
| Seed yolları | `SeedPathResolver` |
2026-10-06 11:24:30 +00:00
| SQL Server → PostgreSQL çeviri kuralları | `.github/instructions/lowcode.instructions.md` §8.3.1 |
Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` → bu dosya → `README.md`.
### Standing defaults — do not ask again
1. **Yeni tablo** → tenant + tam audit kolonları varsayılan gelir (`Id`, `TenantId`,
`CreationTime`, `CreatorId`, `LastModificationTime`, `LastModifierId`, `IsDeleted`,
`DeletionTime`, `DeleterId`). Kullanıcı açıkça "tenant yok / audit yok" demedikçe çıkarma.
Yeni **tanım** tablosu (tanım olup olmadığına talebin içeriğine göre analizde karar verilir;
sabit ad listesi yoktur) buna ek olarak `IsActive bit NOT NULL DEFAULT 1` ile gelir; liste + form alanı, varsayılan
2026-10-02 07:09:23 +00:00
`true`, Aktif/Pasif widget'ı. Tanım olmasa da MCP ile (ya da wizard ile) üretilen her ekranda
`IsActive` kolonu aynı varsayılanla gelir: tabloda `NOT NULL DEFAULT 1` (`create_table`'da
`isNullable: false`, `defaultValue: "1"`), formda yeni kayıt `true` ile açılır
(`FormFieldsDefaultValueJson`). Ayrıntı: `lowcode.instructions.md` §8.1.
Görsel tutan her kolon (fotoğraf, logo, avatar kopyası) `nvarchar(MAX)` + editör `dxImageUpload`;
değer base64 saklanır, sınırlı boy ve `dxImageViewer` kullanılmaz (deploy ikisini de reddeder).
2. **Yeni ekran** → Wizard yolu. `Definitions` altına otomatik yerleştirme yok; modüle ait yeni
2026-09-29 14:55:13 +00:00
bir kök menü oluştur, `Order = max(Order) + 1`. Yetki ağacı menü ağacını izler: ekranın okuma
2026-09-30 14:57:25 +00:00
yetkisi menüdeki dalın ara yetkisinin altına yazılır; menüsüz alt formun yetkisi ise listenin
yetkisine bağlanır (`ParentName` = listenin yetki kodu) (`lowcode.instructions.md` §0.12 Menü yeri).
3. **Yeni ekran/menü** → yetki sözleşmesi olmadan önerilmez. Menü ve route aynı ekran
sözleşmesini göstermeli.
4. **Kullanıcıya görünen her metin** → dil anahtarı üzerinden, EN + TR birlikte. Koda gömülü
metin önerme.
5. **Runtime'da üretilen her artefakt** (wizard, custom component, crud endpoint) → ilgili seed
dosyası da yazılır/güncellenir. Veritabanı sıfırlandığında geri gelmeyen bir şey üretme.
2026-08-28 07:47:17 +00:00
6. **Yeni ekran/komponent talebi — yazılı ya da görsel** → dosya yazmadan önce **keşif turu**:
toplu sorularla (tur başına en fazla 4, seçenekli, önerilen varsayılanlı) ekran türü, veri
kaynağı, modül, kapsam ve yolun soru setini al; tarifi kur ve **onaylat**, sonra
`configs/seeds/` altına üret. Şüphede Wizard. Kullanıcı "sorma / sen seç" derse
varsayılanlarla üret ve sonunda listele. Depodan okunabilen şeyi sorma; tabloya yazma hedefi,
onaycı ve hesap formülü asla varsayılmaz. Ekran görüntüsü piksel sözleşmesi değildir;
görsel Tur 2'nin çoğunu cevaplar, yalnızca görselden okunamayanlar sorulur.
Bu kural yalnızca **yeni üretim** içindir; düzeltme/alan ekleme/debug doğrudan yapılır.
Ayrıntı: `lowcode.instructions.md` §0.6–§0.7.
2026-09-22 20:59:36 +00:00
7. **Ziyaretçiye açık yeni yol** (public `RoutePath` taşıyan custom component, `Pub` menüsü,
yeni public sayfa) → SEO alanları da doldurulur. Ayrı bir SEO tablosu yoktur: meta, yolu
tanımlayan kaydın `Seo*` kolonlarındadır — `data/App.Menus.Routes.json` ya da
`data/App.DeveloperKit.CustomComponents/{Id}.json`. Metin `::Anahtar` ile dil anahtarı taşır.
Kullanıcı SEO bilgisi girmez; üreten yazar. Genel varsayılanlar kayıtta değil
`App.SiteManagement.Seo.*` ayarlarındadır. Ayrıntı: `lowcode.instructions.md` §0.9.
8. **Ekran içi hesap/koşul ihtiyacı** → önce `EditorScript` (Script Builder tarifleri), sonra
`EditorOptions`; kod yazmak son çare.
2026-09-22 20:59:36 +00:00
9. **SQL** → her zaman parametreli. String birleştirme ile sorgu kurma.
10. **Silme** → `DeleteCommand = DefaultDeleteCommand("{Tablo}")`; ham SQL string'i yazma.
11. **Çerçeve sınırı** → uygulama kendini kendi mekanizmalarıyla geliştirir (seed artefaktları;
2026-08-28 07:47:17 +00:00
var olan `ui` bileşenine eksik olay/prop/küçük yetenek ekleme — komponentin %70'i hazır
araçlarla kuruluyorsa kalanı bu eklemelerle tamamlanır, yeni bileşen yazılmaz; geriye dönük
uyumlu tarif/seçenek/token ekleme).
Bunun dışına çıkan her şey — yeni React bileşeni/sayfası, çekirdek motor, yeni entity/
migration, platform tablosu şeması, yeni paket, `Routes`, dış entegrasyon — **önce sorulur,
yalnızca onayla yapılır**; onay talebe özeldir. Çerçeve içinde yapılabilen kısım sorudan önce
bitirilir. "Yapılamaz" cevabı yoktur. Listeler: `lowcode.instructions.md` §0.8.
2026-09-24 07:24:48 +00:00
12. **Liste ekranı görünümleri** → prompt/görsel/tarifle üretilen her liste ekranı `Grid` + `Card` +
`Pivot` + `Chart` açık, `DefaultLayout: "grid"` ile gelir; "liste/grid" demek diğerlerini
kapatmak değildir. Bir görünüm yalnızca istek onu açıkça dışarıda bıraktığında `false` yazılır.
Tree/Gantt/Scheduler/Todo yalnızca istenince açılır. Ayrıntı: `lowcode.instructions.md` §9.8.
13. **Liste ekranı widget'ları** → Wizard ya da MCP `deploy_wizard` ile üretilen her List ekranı
sorulmadan **en az 3 kartlık** `Widgets` ile gelir; kartlar tablonun durum / boolean bayrak /
tarih / tutar kolonlarından seçilir, başlıklar dil anahtarıdır (`App.Widget.*` önce). Kiracı
tablosunda her kart `"TenantId" = '@TENANTID'` taşır; `IsDeleted` koşulu yazılmaz. Form/Chart,
2026-09-30 20:52:33 +00:00
alt form ve basit tanım listeleri istisnadır. **Alt form oluşturulurken widget oluşturulmaz**:
başka bir ekranın `SubForms` sekmesi olarak üretilen her ekran — menüsüz ya da kendi menüsü olan —
`Widgets: []` ile deploy edilir. Deploy menüsüz (`CreateMenu: false`) wizard'ın `Widgets`'ını
ayrıca düşürür; ekran alt form sekmesinde açıldığında şerit de çizilmez
(`useListFormWidgets(…, isSubForm)`) — kart sorgusu ana kayda göre süzülmez. Ayrıntı:
`lowcode.instructions.md` §4.6.1.
Alt form ekranının menü/yetki/düzenleme kuralları (menüsüz alt formun yetkisi ana ekranın altında,
`Form` sekmesi tek kayıt + `AllowAdding`/`AllowUpdating` açık): `lowcode.instructions.md` §4.6.
2026-10-04 15:04:16 +00:00
14. **Modül dokümanı** → MCP ya da wizard ile oluşturulan her modül çalışma şeklini
2026-10-07 08:17:46 +00:00
`configs/seeds/docs/modules/{Menü}.md` dosyasında taşır: dosya kök menü başına tektir ve adı kök
menünün kodudur (`App.Hr.md`, `App.Prc.md`, `App.Administration.md`),
menünün altındaki her dal dosyada bir `module-doc:section` bölümüdür. Bölüm keşif cevapları ve
onaylanan tarifi (analiz), ekranları, veri modelini, hesapları/durum geçişlerini, yetki dağılımını,
entegrasyonları, sık sorulanları taşır. Dosyayı, dalın bölümünü ve "Ek — Ekran envanteri"ni deploy
kendisi açar/yeniler; anlatım alt bölümlerini (`module-doc:todo`) üreten doldurur — MCP'de
`save_module_doc` (ekran/dal koduyla yalnızca o bölüm), Claude Code'da dosyaya doğrudan. MCP talebi
bölümü tamamlanmadan `Testing`'e alınamaz. Wizard dışı modülün bölümü elle yazılır. README'ye
yalnızca §10.5 dizin satırı/bölüm adı ve ilgili bölümde tek cümlelik bağlantı yazılır.
2026-10-04 15:04:16 +00:00
"X nasıl çalışıyor?" sorusunda önce bu dosya okunur. Ayrıntı: `lowcode.instructions.md` §0.13.
15. **Ekran açıklaması** → wizard/MCP ile üretilen her liste ekranının (alt formlar dahil)
`DescTr`/`DescEn` metni ayrıntılıdır; başlıktaki ⓘ simgesinde gösterilir: ne işe yaradığı,
menüde nerede / hangi ekranın sekmesi olduğu, ana alanlar, otomatik hesap ve geçişler, ilişkili
ekranlar (`RichText` biçimi). MCP `deploy_wizard` 3 satır / 150 karakterin altını reddeder.
Ayrıntı: `lowcode.instructions.md` §4.4.2.
2026-10-06 11:24:30 +00:00
16. **İki veritabanı sağlayıcısı** → uygulama SQL Server ile olduğu gibi PostgreSQL ile de çalışır
(`SettingsConsts.DefaultDatabaseProvider`). Veritabanına dokunan her değişiklik ikisi için birlikte
düşünülür ve yazılır; kullanıcı bunu her istekte hatırlatmaz:
- `configs/seeds/sql/{object,execute,host/…}/X.sql` yazılan/değişen her dosyanın
`configs/seeds/postgres/…/X.sql` eşi aynı işte yazılır/güncellenir (aynı ad, aynı parametre sırası,
şema PG'de `public`). Biri olmadan diğeri commit edilmez; "PG sonra" yoktur.
- EF modeli SQL Server sözdizimiyle yazılır (kolon tipi, index filtresi, check, varsayılan); PG
karşılığı `PostgreSqlModelSyntax` üzerinden `PlatformDbContext.ConfigureProviderSpecificModel`'de
üretilir. Çeviriye girmeyen yeni bir sözdizimi eklenirse çeviri de eklenir.
- C#'ta üretilen SQL (Dapper, `QueryManager`, seeder komutları, ekran `*Command`/`LookupQuery`
metinleri) ya iki sağlayıcıda da çalışan tırnaklı/ANSI biçimde yazılır ya da `DataSourceType`'a göre
dallanır.
- SQL değişikliği doğrulanırken PG eşi de bir PostgreSQL veritabanında çalıştırılır (iki kez —
idempotent). Ayrıntı ve dönüşüm tablosu: `lowcode.instructions.md` §8.3.1.
17. **Her prompt sonunda optimizasyon + ölü kod temizliği** → kullanıcı "optimize et, ölü kodları
kaldır" yazmaz; her iş bitmeden, kullanıcı istemese de o işte dokunulan kod üzerinde yapılır:
kullanılmayan `using`/üye/parametre/tip/dil anahtarı silinir (tip silmeden önce repo geneli
tarama, "Definition of done"), aynı mantığın ikinci kopyası ortak metoda indirilir, gereksiz
tekrar sorgu/dosya okuması kaldırılır, kod/değer **statik yazılmaz** — tablo adı
`TableNameResolver`'dan, değer tablo/seed/ayar verisinden dinamik bulunur. Son mesajda ne
temizlendiği tek satırla söylenir.
18. **Yeni kaydın form varsayılanı** → Wizard ve MCP ile üretilen her listede form varsayılanı
kolonun veritabanındaki sabit `DEFAULT` değeridir; deploy onu tablodan (katalog ya da seed
scripti) okuyup `FormFieldsDefaultValueJson`'a yazar, değer koda gömülmez. Bu yüzden tablo
şu `DEFAULT`'larla kurulur: `IsActive` → `1` (true), ölçü birimi (`*UomId`) → `'Adet'`, para birimi
(`*CurrencyId`/`*Currency`) → `'TRY'` (lookup'ın anahtarı neyse); talepte başka sabit varsayılan
varsa (Süre = 60) o da kolonun `DEFAULT`'udur. Alana özel değer wizard öğesinin `DefaultValue`'su ile
verilir. Ayrıntı: `lowcode.instructions.md` §4.3.5.1.
### Cross-cutting: touching one thing means touching these too
2026-10-04 15:04:16 +00:00
- **Modül dokümanı** → `ModuleDocManager.RefreshAllAsync` wizard'ı yazan her yoldan çağrılır (deploy,
silme, `WizardSeedSynchronizer`, import kapanışı); wizard dosyasını yazan yeni bir yol eklenirse
2026-10-07 08:17:46 +00:00
çağrı da eklenir, yoksa envanter bayatlar. Wizard → doküman/bölüm eşlemesi tek yerdedir
(`ModuleDocCatalog`: dosya = kök menü, bölüm = beyan → alt formun ana ekranı → menü dalı; kök ve
dal `data/App.Menus.Menu.json`'dan okunur, sabit liste yoktur); envanter biçimi
2026-10-04 15:04:16 +00:00
`ModuleDocRenderer`'dadır. Export kapanışı dokümanı taşır (`WizardExportCollector`), import
`docs/modules/*.md` yolunu kabul eder.
- **`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.
2026-10-06 12:36:01 +00:00
- **`phoneFormat.ts` ↔ `DynamicReportPhoneFormatter.cs`** — telefon token'larının (`phoneGlobal`, `phoneTR`,
`phoneIntl`, `phoneCountry`) görüntü kuralı iki yerde yazılır: liste/kart istemcide, dinamik rapor sunucuda.
Biri değişirse diğeri de değişir; yoksa liste ile rapor aynı numarayı farklı yazar.
- **Liste popup'ı (Grid/Tree) ↔ form sayfası (`FormDevExpress`)** — editör yetenekleri ortak yardımcılardadır
(`list/shared/editingForm.ts`, `editingFormScripts.ts`, `cascade.ts`); TagBox/GridBox/ImageUpload/ImageViewer'ın
tek uygulaması `form/editors/*`, liste hücresi yalnızca `list/editors/cellEditors.tsx` adaptörüdür. Bir tarafa
yetenek eklenirken ortak yardımcıya eklenir; tek tarafa yazılan yetenek eşliği bozar. Tablo:
`lowcode.instructions.md` §4.3.4.
- **`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 (`CommandColumns` →
`CommandColumnJson` bu yolla taşınır; wizard ekranında adımı yoktur, UI modeli düzenlemede korur).
Dosyada kalan wizard alanları üç başlık altında toplanır — `Menu`, `Language`, `Groups` — ve
`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.
2026-10-05 12:58:59 +00:00
- **Wizard ile üretilen ekran** → seed dosyası (`configs/seeds/wizard/{WizardName}.json`)
wizard cevaplarının yanında ekranın `GridOptionsEditDto` (`ListForm`) ve alanların
`ColumnFormatEditDto` (`Fields`) sözleşmesini taşır. ListForm detayından yapılan her kayıt
(`ListFormsAppService`, `ListFormFieldsAppService`, `ListFormJsonRowAppService`) bu bölümleri
ve `Wizard` bölümündeki karşılıklarını geri yazar (`WizardSeedSynchronizer`). Bu üçlüden birine
yeni bir kayıt yolu eklenirse senkronizasyon çağrısı da eklenir; yoksa dosya bayatlar.
- **Wizard girdisinden ekran üretimi** → tek kaynak `ListFormWizardDto.BuildListForm/BuildFields`,
entity'ye yazma `GridOptionsEditDto.ApplyTo` / `ColumnFormatEditDto.ApplyTo`. Deploy, seeder ve
senkronizasyon aynı metotları çağırır; ikinci bir üretim kopyası yazma.
- **Katman sınırı (DDD)** → `DbMigrator` Application'a referans vermez. Seeder ile AppService'in
paylaştığı dönüşüm `Application.Contracts`'ta DTO metodudur; entity'ye yazma Domain.Shared'deki
`IListFormArtifact` / `IListFormFieldArtifact` sözleşmeleri üzerinden yapılır.
Ayrıntı: `dotnet.instructions.md` §5.
- **Yeni bir yetki** → `PlatformConsts.AppCodes` + `data/Abp.Identity.Permissions.json` + (UI'da kullanılacaksa)
`permission.constant.ts` + `data/App.Languages.LanguageText.json`. Yetki ekranındaki sıra `AbpPermissions.Order`
(grup için `AbpPermissionGroups.Order`) sütunundan gelir ve seed satırındaki `Order` alanıyla
yazılır; sıra kardeşler arasındadır — her üst yetkinin altında 1'den başlar, yeni satırı menüdeki
yerine denk gelen numarayla ekle.
2026-09-17 09:01:14 +00:00
- **`/mcp` ucuna yeni bir araç** → üç yer birlikte değişir: `McpToolNames` (ad kayıt defteri),
ilgili `Mcp*Tools` sınıfı (`Sozsoft.Mcp.HttpApi`) ve arkasındaki AppService sözleşmesi
(`Sozsoft.Mcp.Application.Contracts`). Arac adı `McpToolNames.All` içinde yoksa araç listesi
süzgecinden geçmez ve hiç görünmez; MCP Servers ekranındaki `AllowedTools` seçenekleri de
2026-09-18 13:47:23 +00:00
`SelectableTools`'dan üretildiği için kendiliğinden güncellenir. Sunucu kaydında tek anahtar
`AllowedTools`'tur: boşsa tüm araçlar, doluysa yalnızca seçilenler açıktır; araç tipine göre ayrı
bir bayrak yoktur, sınırı kullanıcı yetkisi çizer. **İki MCP yetkisi vardır:** `.Invoke` uca
erişim ve okumadır (MCP servislerinin sınıf düzeyinde aranır); `.Write` MCP üzerinden yapılan her değişikliktir ve
değişiklik yapan her araç `RequiredPermissions`'ta `.Write`'a bağlanır — okuma/yazma ayrımı için
yeni yetki açılmaz. **Kiracı veri okur ve yazar, geliştirme yapamaz**: kiracı bağlamında açık
araçlar `McpToolNames.TenantTools` ile sınırlıdır (şema, `query_list`, `run_select`,
`insert_row`/`update_row`/`delete_row`) ve `AllowedTools` bu kümeyi yalnızca daraltır. Satır
yazma ekranın C/U/D sözleşmesinden geçtiği için kiracıya açıktır; ekran yetkisinden geçmeden
yazabilen araç (procedure, Custom Endpoint) ve geliştirme araçları (`DevelopTools`) `TenantTools`'a
eklenmez. Geliştirme işlemi yine Wizard / Custom Components AppService'inden geçer.
**`/mcp` istek düzeyindeki unit of work'ün dışındadır** (`AbpAspNetCoreUnitOfWorkOptions.IgnoredUrls`):
cevap SSE ile aktığı için istek UoW'si sonuç istemciye gittikten sonra commit edilir ve bağlantı
kapanınca geri alınır — araç başarılı görünür, EF kayıtları kaybolur. Her MCP servis çağrısı
kendi UoW'sini sonuç dönmeden tamamlar; bu istisna kaldırılmaz.
2026-09-17 09:01:14 +00:00
Kapı iki yerdedir: `AddListToolsFilter` listeyi süzer, `McpAppService.EnsureToolAllowedAsync`
çağrıyı reddeder — süzme tek başına yetki sınırı değildir, ikisi birlikte yazılır. `Invoke`
uçta değil her MCP servisinin sınıf düzeyindeki `[Authorize]`'dadır; yeni bir MCP AppService'i de
bu attribute'la açılır.
**Hata istemciye yalnızca `McpException` olarak ulaşır**; `McpToolErrorTranslator` (çağrı
filtresi) yetki reddini "şu yetkiniz yok" mesajına, `UserFriendlyException`'ı mesajına çevirir.
Kullanıcının göreceği her hata bu iki türden biriyle atılır. Yeni aracın arkasındaki servis
bir yetkiyi `[Authorize]` attribute'uyla istiyorsa (ret mesajı yetki adını taşımaz) o yetki
`McpToolNames.ServicePermissions`'a eklenir; ekran yetkisi gereken araç yetkiyi
`IMcpListFormAccessFilter.GetPermissionNameAsync` + `CheckAsync` ile adıyla önceden ister.
Araç → yetki tablosu `README.md` §13.9'dadır; araç ya da yetki değişirse tablo da değişir.
Hazır prompt'lar (`McpPromptNames` + `McpDevelopPrompts`) yalnızca metindir; adımları tekrar
etmez, `get_dev_guide` bölümüne yönlendirir. Bir kural bağlayıcıysa prompt'a değil araca yazılır
(örnek: `Ready to Start` şartı `start_dev_request`'tedir).
- **Wizard deploy veritabanına yazmaz** → wizard ekranı, MCP `deploy_wizard` ve düzenleme aynı
yoldan (`ListFormWizardAppService.Create`) geçer ve **yalnızca seed dosyası yazar**: `wizard/{Ad}.json`
+ menü/modül/izin grubu/yetki/dil satırları (`data/App.Menus.{Menu,Module}.json`,
`data/Abp.Identity.Permission{Groups,s}.json`, `data/App.Languages.LanguageText.json`;
`WizardSeedRowStore`, anahtarlar `WizardSeedRowKeys`). Kurulum yalnızca DB Migrate'tedir:
`WizardDataSeeder` ekrana özgü kayıtları (veri kaynağı, ListForm, alan, iş akışı) kurar,
`ListFormSeedDataApplier` satırları ekler. Deploy/import dosyaya `Pending` yazar; Wizard Manager
onu "Migrate bekliyor" gösterir (`WizardFileInfoDto.IsPending`), migrate önceki sürümün kayıtlarını
(`Pending.Replaced`) kaldırıp ekranı yeniden kurar ve `Pending`'i siler. Yetkiler **hiçbir role
otomatik atanmaz** (admin dahil); rol ekranından verilir. Deploy'a veritabanı yazan ya da silen bir
adım ekleme. Ayrıntı: `lowcode.instructions.md` §4.0.
- **MCP ile demo veri** → geliştirme isteği örnek satır taşıyorsa (prompt'taki tablo/liste, ekran
görüntüsü) ekran `deploy_wizard`'a `SeedData: true` ile gider (`SeedFilePath = data/{ListFormCode}.json`
2026-09-25 07:52:06 +00:00
+ `SeedSync*` açık, `ListFormWizardDto.BuildListForm`) ve satırlar aynı çağrıda `seedRows` ile
2026-10-05 12:58:59 +00:00
`configs/seeds/data/{ListFormCode}.json` dosyasına yazılır (`McpDevelopAppService`; alan adları
2026-09-25 07:52:06 +00:00
ekrana göre doğrulanır, `Guid` anahtarı sunucu üretir). Migrate ekranı kurar, ardından satırları
ekler; MCP migrate'i beklemez. Talep döngüsü `Testing`'de biter, `Staging`'e kullanıcı alır. Dosya elle yazılmaz, görselden okunamayan değer uydurulmaz.
`SeedData` wizard ekranında sorulmaz ama düzenlemede korunur (`RefreshFrom` + UI modeli).
Ayrıntı: `lowcode.instructions.md` §0.10.1.
- **Talepteki görsel** → `App.DevRequests` açıklamasına yapıştırılan görsel base64 `data:` URI olarak
kalır, hiçbir yere yüklenmez. `start_dev_request` / `get_dev_request` onu metinden ayıklar
(`McpDevRequestImages`) ve MCP resim içeriği (`ImageContentBlock`) olarak döndürür; metinde
2026-10-07 08:17:46 +00:00
`[image-N]` kalır. Sonucun tamamı istemcinin araç sonucu sınırına (Claude Desktop 1 MB) sığar:
kalan pay görsellere bölünür, payını aşan görsel `IMcpImageShrinker` (Host'ta SkiaSharp) ile küçültülüp
JPEG'e çevrilir, yine sığmayan gönderilmez ve metinde bildirilir; kaynak açıklama değişmez.
Açıklama bu yüzden `update_row` ile yeniden yazılmaz. `SubTasks` de
`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,
2026-10-07 18:46:45 +00:00
sonraki her üretim/veri yazma işlemi (`create_table`, `save_sql_object`, `generate_crud_endpoints`,
`deploy_wizard`, `delete_wizard`,
`save_component`, `delete_component`, `save_report_category`, `save_report_template`,
`delete_report_template`, 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.
2026-09-29 14:18:47 +00:00
Satır aracın UoW'si commit edildikten sonra ayrı UoW'de yazılır; aynı UoW'de yazmak Dapper
transaction'ının `Sas_H_DevRequest` kilidini EF'in ayrı bağlantısından bekletip zaman aşımına düşürür.
- **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`
2026-10-07 12:45:18 +00:00
ile yalnızca `Backlog`/`Analysis` talebini analiz edip `Analysis`'e alır (ekran/tablo üretmez,
modül dokümanına yazmaz — dosya ve dal bölümü üretimde, deploy ile açılır; onaylanan analiz bölümün
"2. Analiz ve kararlar" alt bölümüne üretimde `save_module_doc` ile yazılır);
`Ready to Start`'a kullanıcı taşır, üretim notu `append_dev_request_note` ile `Analysis`'e eklenir.
Analiz standardı tek yerdedir: `lowcode.instructions.md` §0.12; prompt'lar oraya yönlendirir.
2026-09-17 09:01:14 +00:00
- **MCP şema araçları** → tablo/sütun bilgisi canlı katalogdan değil `Sas_H_DbTableColumn`
sözlüğünden okunur (`IMcpSchemaDictionary`). Sözlüğün alan adları
`dbo.Sas_H_ListFormFieldsDictionaryJson` prosedürünün ürettiği JSON ile birebir aynıdır;
2026-09-30 22:54:21 +00:00
prosedür değişirse `McpDictionaryListForm`/`McpDictionaryField` de değişir. Sözlük tablo kataloğunu
değil ekranların alanlarını döker: bir tablonun ekranda alan olarak tanımlanmamış kolonunu MCP göremez.
Modelin okuması gereken kolon (ör. `AbpUsers`'ın kişisel bilgileri) ilgili ekranda gizli alan olarak durur.
2026-09-17 09:01:14 +00:00
- **MCP OAuth** → bilinen sağlayıcılar (Claude, ChatGPT) seed edilmiş `Platform_Mcp` istemcisini,
2026-10-07 08:17:46 +00:00
yerel `mcp-remote` proxy'si açık onaylı `Platform_Mcp_Local` istemcisini,
2026-09-17 09:01:14 +00:00
diğer MCP istemcileri `/connect/register` ile üretilen `mcp_` önekli açık onaylı istemcileri
kullanır (`McpOAuthClientManager`; seed `McpOAuthClientDataSeedContributor`). Bilinen sağlayıcı
eklemek = DbMigrator'daki `Platform_Mcp:RedirectUris` listesine callback eklemek. MCP
istemcisi kararı tek yerdedir (`McpConsts.IsMcpClient`): `resource` parametresi yok sayılır ve
token kullanıcı oturumuna bağlanmaz; token ucuna yeni bir oturum yolu eklenirse bu istisna
korunur, yoksa connector web oturumunu düşürür.
2026-10-07 18:46:45 +00:00
- **MCP yalnızca seed dosyası yazar** → Wizard gibi: geliştirme araçları (`create_table`,
`save_sql_object`, `generate_crud_endpoints`, `deploy_wizard`) yalnızca `configs/seeds/` altına dosya
yazar, veritabanına DB Migrate yansıtır. Yeni bir geliştirme aracı veritabanına yazan AppService'i
çağırmaz, seed dosyasını üreten ortak metodu kullanır (ör. `CrudEndpointSeedFileDto.Generate/Write`;
diyaloğun servisi de aynı metottan geçer). Hata kodu yalnızca migrate'i bozacak girdi içindir;
düzeltilebilen girdi (bilinmeyen seçenek, boş/tekrar eden index) sessizce normalize edilir.
Kolon adları tahmin edilmez: şema araçları geliştiriciye migrate bekleyen wizard ekranlarını ve
seed-only tabloları da döner (`McpSchemaAppService.GetSeedOnlySourcesAsync`). `deploy_wizard`
girdisindeki `ListForm`/`Fields` bölümleri ekrana katman olarak uygulanır (`WizardSeedFileDto.FromDeployJson`
+ `WizardScreenOverlay`); `ListFormWizardDto`'ya editörde karşılığı olan alan eklenirse katman onu
kendiliğinden taşır.
2026-09-17 09:01:14 +00:00
- **MCP yetki vermez** → yeni bir MCP aracı kullanıcının uygulamadaki yetkisini aşamaz: liste verisi
ekranın sorgusundan (`IListFormSelectAppService`/`IListFormDataAppService`) geçer; liste
yetkisini aşan bir yetenek (ham SQL gibi) `McpToolNames.RequiredPermissions`'a uygulamadaki
karşılık gelen yetkiyle eklenir. `create_table` bu yüzden `.Write`'a ek olarak `App.SqlQueryManager`
2026-09-18 13:47:23 +00:00
ister; tablo scriptini tasarımcının `generateCreateTableSql` çıktısıyla aynı biçimde üretir
2026-10-07 12:45:18 +00:00
(`McpTableCreator`) ve **veritabanında çalıştırmaz** — MCP veritabanı kurmaz, tabloyu da ekran gibi
kullanıcının çalıştırdığı DB Migrate kurar; wizard deploy'u kurulmamış tablonun kolonlarını seed
scriptinden okur (`PostgreSqlTableScript.ReadSeedColumns`) — tasarımcının şablon kolonları ya da script biçimi değişirse o da değişir. Tasarımcı
2026-10-06 11:24:30 +00:00
(`SaveTableScriptAsync`) ve `create_table` T-SQL dosyanın PostgreSQL eşini `PostgreSqlTableScript` ile
üretip `postgres/object/` altına yazar; script biçimine yeni bir deyim eklenirse çevirisi de eklenir,
yoksa PG eşi yazılmaz (log uyarısı). Düşürülen nesnenin dosyası iki klasörden de silinir.
2026-10-05 14:11:06 +00:00
- **Çalışan (persona) ekranları ve profil** → çalışanın/yöneticinin kendi listeleri İK menüsüne
konmaz: menüsüz `App.Hr.My*`/`Team*` wizard + Intranet panosu widget'ı. Profil sayfasının İzinlerim /
Puantajım / Performansım sekmeleri persona ekranlarını salt okunur gösteren çekirdek bileşenlerdir
(düzenle/sil yok, tek aksiyon izin talebi oluşturma); yeni persona
ekranını profile eklemek kod + rota değişikliğidir (onay). Çalışan Bilgileri sekmesi ve Genel sekmesi
kullanıcının kendi alanlarını `my-profile` ek alanlarından okur (`PlatformProfileAppService.ProfileExtraProperties`);
sağlık, ücret ve işten çıkış alanları bu listeye girmez. Ayrıntı: `lowcode.instructions.md` §0.12.1.
- **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
2026-10-05 12:58:59 +00:00
gelir: kendi veritabanı olan kiracı seed dosyasından alır, host veritabanını paylaşana
`NotificationTenantDefaultsSeedContributor` aynı dosyalardan yeni kimliklerle kopyalar; iki yol
aynı kiracıda çalışmaz. Kiracı verisine dokunan zamanlanmış işin
`Scope` alanı `Tenant` ya da `Host ve Kiracılar` olmalıdır — `Host` kapsamında çalışan bir iş
kiracı satırlarını göremez (`WorkerScopeEnum`, `PlatformBackgroundWorker`).
- **Bildirim bayrakları** → sıra değişmez: `IsSent` (iletildi) olmadan `IsRead` yazılmaz, `IsRead`
ile `ReadTime` birlikte yazılır. `UiActivity` kayıt oluşurken iletilmiş sayılır, `UiToast`/`Desktop`
tarayıcıda gösterildiğinde (`NotificationChannels.BrowserChannels`; `sent-many` ucu yalnızca bu
kümeyi işaretler), kalan kanalları `NotificationWorker` işaretler — gönderim okuma değildir.
Kullanıcı tercihi (`IsCustomized` + `RecipientType = User`) kural değildir, yalnızca sahibini
kapatır; alıcıyı kurallar belirler. Yeni bildirim üretildiği anda `/notificationhub` ile
duyurulur (`INotificationRealtimeNotifier`; sözleşme bildirim modülünün Domain'inde, SignalR
gerçeklemesi barındıran uygulamada — modül katmanı ASP.NET Core'a bağlanmaz) — duyuru en iyi çabadır, istemcideki yedek yoklama kaldırılmaz.
Ayrıntı: `README.md` §13.3–§13.5.
2026-09-22 20:59:36 +00:00
- **SEO** → **ayrı bir SEO tablosu yoktur**; meta, yolu tanımlayan kaydın üzerinde yaşar. Üç
parça birlikte çalışır: genel varsayılanlar `App.SiteManagement.Seo.*` ayarları, yol bazlı
alanlar `Route.Seo*` ve `CustomComponent.Seo*` (ikisinin de `SeedSync*` bayrakları açık),
istemci tarafı `SeoHead`. Üçü de uygulama konfigürasyonunun `seo` alanından beslenir
(`PlatformApplicationConfigurationContributor` → `SeoAppService.GetConfigAsync`); `sitemap.xml`
ve `robots.txt` aynı servisten `SeoController` ile yayınlanır. Aynı yolu iki kaynak da
tanımlıyorsa bileşen kazanır — çalışma zamanında da bileşen fiziksel rotayı gölgeler.
**Ziyaretçiye açık yeni bir yol üreten her iş SEO alanlarını da doldurur** (standing default 7).
Sitemap'e giren kaynaklar (`Pub` menüleri, aktif custom component rotaları, yayınlanmış blog
yazıları) `SeoAppService` içindedir; yeni bir public kaynak türü eklenirse toplayıcıya da
eklenir, yoksa sayfa sitemap'te görünmez. Yeni bir meta alanı = iki entity + `SeoRouteDto` +
`SeoFields` (seeder) + `SeoHead` birlikte.
2026-10-05 12:58:59 +00:00
- **Yeni bir dil anahtarı** → `configs/seeds/data/App.Languages.LanguageText.json` (EN + TR iki satır;
`Id` = `Sas_H_LanguageText:{ResourceName}:{Key}:{CultureName}` adından URL isim alanlı v5 GUID); eklemeden önce anahtarın zaten var olup
olmadığını kontrol et.
- **Custom component sınıfları** → bileşen kodu veritabanında yaşar, Tailwind derlemede yalnızca
seed dosyasını görür. Seed dosyası `ui/` dışında olduğu için aynı sınıflar `ui/safelist.txt`
sonuna da yazılır (`twSafelistGenerator`, derlemede otomatik); yoksa uygulama sunucuda stilsiz
kalır. İkinci bir safelist dosyası açma.
- **Custom component kaydı/silinmesi** → `data/App.DeveloperKit.CustomComponents/{Id}.json`
(Custom Components ekranının seed verisi); ekran klasör modundadır, her bileşen kendi satır
dosyasındadır. Hem listeden hem Visual Designer'dan (`CustomComponentAppService`) yapılan kayıt
aynı klasöre yansır; kullandığı endpoint'ler `crud/{Entity}.json`.
- **Wizard dosyası** → tek başına taşınmaz; export zip'i **özyinelemeli bağımlılık kapanışını**
taşır (`WizardExportCollector`): alt formların wizard dosyaları, ekranın `SeedFilePath` veri
aynası, lookup sorgularının işaret ettiği nesnelerin scriptleri, `crud/` ve
`{sql|postgres}/{object|execute}/` dosyaları. `Custom` yolunda `data/` girdisi yalnızca ilgili
bileşen ve bağımlılık zincirine süzülür; import'ta hedef dosyanın üstüne yazılmaz, satırlar
anahtar üzerinden birleştirilir. Kapanışa yeni bir bağımlılık türü eklenirse
`WizardImportValidator`'daki karşılığı da eklenir — biri toplar, diğeri eksikliğini yakalar.
- **Talep bağı (`DevRequest`)** → MCP `deploy_wizard` wizard dosyasına etkin talebi
(`IMcpDevRequestTimesheetRecorder.GetActiveRequestIdAsync`) `DevRequest { Id, Title }` olarak
yazar; bağ modelin girdisinden gelmez (`ListFormWizardDto.DevRequestId` `[JsonIgnore]`). Elle
yapılan kayıt önceki bağı korur, talepsiz wizard'da bölüm hiç yazılmaz. Wizard Manager talebi
gösterir, kaydına bağlar ve talebin bütün wizard'larını tek kapanışta export eder
(`export-dev-request`; `WizardExportCollector.CollectAsync` birden çok dosya alır). Wizard
dosyasını yeniden yazan yeni bir yol eklenirse `DevRequest` korunur — dosyayı DTO olarak okuyup
yazan yollar bunu kendiliğinden yapar.
- **Şema değişikliği** → ayrım **kayıp riskine** göredir. Eksik kolon **eklenir** (kayıpsız;
`ALTER TABLE ADD`), var olan kolon **hiçbir zaman değiştirilmez**, hiçbir kolon düşürülmez,
hiçbir tablo `DROP` edilmez. Ölçü farkında (uzunluk/kesinlik/nullability) import durdurulur ve
fark somut olarak bildirilir; varsayılanı olmayan `NOT NULL` bir kolonun dolu tabloya eklenmesi
de durdurulur — hangi değerin yazılacağı iş kararıdır. Karşılaştırma tek yerdedir
(`SqlTableSchemaComparer`), analiz ve kapanış aynı sonucu kullanır.
Karşılaştırmada tip **adı** kullanılmaz — sağlayıcı katalogları farklı kanonik ad raporlar ve
metin karşılaştırması sahte fark üretir. Genel kural: **sağlayıcıya göre değişen bir değeri
metin olarak karşılaştırma, katalogdan dinamik oku.**
- **Veritabanına dokunan her import ucu** → `EnsureImportNotBlocked` ile başlar. Analizdeki
engelleme kararı sunucuda `blocked` dosyasında durur; yeni bir uç eklenirse kontrolü de eklenir,
yoksa karar istemci tarafından atlanabilir hâle gelir.
- **Wizard import'u** → analiz dosyalar yazılmadan **önce** doğrular (`WizardImportValidator`);
`Error` seviyesinde bir bulgu varsa oturuma `blocked` işareti düşer ve `ApplyImport` reddeder.
Kapanış (`CompleteImport`) bağımlılık sırasıyla çalışır: `sql/object` → `sql/execute` → `crud`
→ `data` → `wizard`. Tablo eksikse önce scripti çalışır; sıra değiştirilmez. Ekran import'ta
**kurulmaz**: wizard dosyasına `Pending` yazılır ve ekran deploy'daki gibi DB Migrate'te kurulur;
dosyadaki `ListForm`/`Fields` sözleşmesi olduğu gibi kullanılır, wizard cevaplarından yeniden
türetilmez — türetmek tasarımcı değişikliklerini silerdi. Wizard'ın menü/yetki/dil satırlarını
taşıyan platform dosyaları `data` adımında uygulanmaz (`WizardSeedRowStore.ListFormCodes`).
Engelleyici bulgu iki sınıftır: **arşiv kaynaklı** (`RequiresReexport` — bozuk/eksik dosya,
karşılığı olmayan referans) hedef ortamda giderilemez, export tekrarlanır; **ortam kaynaklı**
(eksik tablo, şema farkı) ekrandan giderilir. Yeni bir `Error` eklerken hangisi olduğu işaretlenir.
Engelleme **oturum genelidir, dosya bazlı değildir** —
import ya bütün olarak çalışır ya da hiç. Bunun bedeli, her engelin ekran içinde çözülebilir
olmasıdır: tabloya dair bir bulgu üretirken `TableName` (+ tablo hedefte yoksa `TableMissing`)
doldurulur, istemci tablo tasarımcısını buna göre açar.
2026-09-04 09:05:26 +00:00
- **`ListForm.SeedFilePath` dolu bir ekran** → `SeedSyncInsert/SeedSyncUpdate/SeedSyncDelete`
2026-10-05 12:58:59 +00:00
bayraklarından işaretli olan işlemler seed klasöründeki hedefe yansır
(`ListFormSeedDataSynchronizer`); yalnızca host bağlamındaki kayıt yansır, kiracının kaydı
veritabanında kalır. Hedef iki biçimdedir ve ayrım uzantıdadır: `.json` ile biten
değer **tek dosyadır** (`data/{ListFormCode}.json`, bütün satırlar orada), uzantısız değer
**klasördür** (`data/{ListFormCode}/{anahtar}.json`, her satır kendi dosyasında) ve klasör yoksa
ilk kayıtta oluşturulur. Klasör modu satırı büyük ya da sık yazılan ekranlar içindir
(varsayılan tek dosya). **Biçimin tek kaynağı ekranın tanımıdır**; diskte ne bulunduğu kararı
değiştirmez ve tanım kod içinde ekran adıyla sabitlenmez. Hedefi okuyan/yazan her yol
(senkronizasyon, export/import, temizleme, wizard satır deposu, MCP demo satırları, bildirim
varsayılanları) `ListFormSeedTarget` üzerinden gider; paylaşılan ekranların tanımı
`ListFormWizardAppService.ReadSeedFilePathsAsync` ile okunup bileşenlere verilir. Applier `data/`
altını özyinelemeli tarar ve **bir klasörün tamamını tek unit of work'te** uygular — ekran
tanımı, alan listesi ve veri kaynağı satır dosyası başına değil ekran başına bir kez çözülür;
dosyadaki `ListFormCode` boşsa ekran kodu klasör adından gelir. Ekran bir hedef tanımlıyorsa
yalnızca o hedef uygulanır; tanımın dışında kalan dosya (biçimi değişmiş ekranın eski dosyası)
uyarıyla atlanır. Biçimi değiştirmek tanımı (ListForm detayı ya da seeder) değiştirmektir;
yeniden wizard deploy'u tanımlı hedefi korur.
Migrate/seed sırasında ve wizard import'unun kapanışında
(`CompleteImport`) `ListFormSeedDataApplier` dosyayı geri uygular. Migrate/seed'de kayıt yoksa
eklenir, varsa dokunulmaz; import'ta `overwriteExisting` açıktır: var olan kayıt dosyadaki
değerlerle güncellenir ve soft delete izleri (`IsDeleted`/`DeletionTime`/`DeleterId`) temizlenir. Satırı veritabanından okuyan senkronizasyon açık UoW varsa commit sonrasında kendi UoW'sinde çalışır (EF ile yazan çağıran, ör. `MenuAppService`, aksi hâlde eski değeri dosyaya yazardı); yalnızca dosyaya dokunan `RemoveRowsByFieldAsync` hemen çalışır. Yeni bir kayıt yolu (yeni endpoint, toplu işlem, tipli AppService) eklenirse
senkronizasyon çağrısı da eklenir; yoksa dosya bayatlar.
2026-10-05 12:58:59 +00:00
- **Seed kapsamı** → `configs/seeds/` tek klasördür; `host/` ya da `tenants/{tenantId}/` yoktur.
Host ve kendi veritabanı olan her tenant aynı dosyalarla kurulur, host veritabanını paylaşan
tenant'ta dosyalar yeniden uygulanmaz (`SeedFileScope`; migrate kararı `DataSeedContext`'e yazar).
Dosyayı okuyan yeni bir seeder `SeedFileScope.IsEnabled` ile başlar. Dosyalar yalnızca host
bağlamında yazılır; dosyaya yazan yeni bir yol tenant bağlamında yazmaz. Bekleyen wizard kurulumu
(`Pending`) dosyaları uygulayan son veritabanında kapanır (`SeedFileScope.CompletesPending`).
Tek istisna `{sql|postgres}/host/{object,execute}`: yalnızca host'ta çalışır; tenant veritabanında
karşılığı olmayan nesneye (HangFire tabloları) dayanan script buraya konur, tablo önekine bakılmaz.
Kendi veritabanı olan tenant'ta EF ile yalnızca `IMultiTenant` varlıklar o veritabanına gider;
ListForm, menü ve yetki tanımını ABP her zaman host'ta okur. Kiracı tablosunun satırları kiracı
adıyla kayıtlı `DataSource` üzerinden gider. Kiracı yalnızca kimliğiyle değiştirildiğinde ad boş
kalır; bu durumda adı `DataSourceManager` kiracı kaydından okur. Yeni tenant yöneticisi ilk
seed'de kiracı tarafı bütün yetkileri alır (`PlatformIdentityDataSeeder`). Bunun nedeni,
DbMigrator'da dinamik yetki deposunun kapalı olmasıdır: ABP'nin yetki seed'i seed dosyasından
gelen yetkileri göremez.
- **Seed dosyası yazmak** → veri dosyası `ListFormSeedDataFileDto.Serialize`, wizard dosyası
`WizardSeedFileDto.ToSeedJson` ile yazılır; düz `JsonSerializer.Serialize` + `File.WriteAllText`
kullanılmaz. System.Text.Json emojiyi her zaman vekil çift kaçışına çevirir; dosya baştan
yazıldığında bütün emojiler sahte fark üretir. İkisi de `SeedJsonText.RestoreSurrogatePairs`'ten
2026-09-25 07:52:06 +00:00
geçer. Veri dosyasının `GeneratedAt` değeri oluşturma anıdır: `Serialize` yalnızca boşsa doldurur,
hiçbir yazma yolu onu güncellemez — ekleyip geri kaldıran işlem (wizard deploy + silme) dosyayı
birebir önceki hâline döndürür. `crud/` dosyalarının damgası ayrıdır ve karar verir (aşağıda).
- **`crud/{Entity}.json`** → uygulama kuralı `CrudEndpointSeedApplier`'dadır ve damga
karşılaştırmalıdır: eksik endpoint eklenir, mevcut kayıt yalnızca dosyanın `GeneratedAt` değeri
kaydın `LastModificationTime`/`CreationTime` değerinden yeniyse güncellenir/silinir. Migrate
kullanıcının runtime revizyonunu ezmez. Yeni bir seeder yazarken bu kuralı taklit et: **migrate
varsayılanı eklemektir, ezmek değil.**
2026-09-29 11:46:39 +00:00
- **Modül = menü = tablo öneki = yetki kökü** → kök menüler `Sas` (`App.Saas`), `Adm`
(`App.Administration`), `Hr` (`App.Hr`, İK) ve `Pub` modüllerindedir. Bir ekranı modüller arası
taşımak birlikte yapılır: `TableNameResolver` (`MenuPrefix`) + `AppCodes` (Seed/Platform) +
`ListFormSeeder_{Saas,Administration,Hr}.cs` + `data/{ListFormCode}.json` adı + menü/yetki/dil
satırları + route `Authority`. Yetki `Modules` değeri: Saas/Administration `Sas|Adm`, İK `Sas|Hr`
(`Sas` host, `Adm`/`Hr` kiracı görünürlüğü). İK departman/pozisyon `BranchId` zorunludur; seed
satırı host şubesine (`PlatformConsts.Branches.BranchIdDefaultValue`) bağlanır.
2026-10-05 12:58:59 +00:00
- **Menü ağacı ve yetkiler** → `configs/seeds/data/App.Menus.{Routes,Module,Menu}.json` ve
`Abp.Identity.Permission{Groups,s}.json`; platformun kendi menü/yetki kayıtları da diğer liste
verisiyle aynı mekanizmadan (`ListFormSeedDataApplier`) geçer, ayrı bir seeder yoktur. `Order`
alanı bağımlılık sırasını kurar: route → modül → menü, yetki grubu → yetki, ülke grubu → ülke →
2026-09-18 06:28:25 +00:00
şehir → ilçe (`App.Definitions.{CountryGroup,Country,City,District}.json`), bildirim tipi → kuralı
(`App.Notifications.Notification{Types,Rules}.json`). Para birimi, hitap, AI bot
(`App.Definitions.{Currency,ContactTitle,AiBot}.json`), ayar tanımları (`App.SettingDefinitions.json`)
ve zamanlanmış işler (`App.BackgroundWorkers.RecurringJobs.json`), dil → metin
(`App.Languages.{Language,LanguageText}.json`; `LanguagesData.json` + `LanguageDataSeeder` kaldırıldı) da buradadır; `HostData.json`
2026-09-18 06:28:25 +00:00
kaldırıldı, `HostDataSeeder` yalnızca bağlantı cümlesi appsettings'ten gelen varsayılan veri kaynağını kurar. Dosyalar ekranın
anahtarını (`KeyFieldName`) kullanır; `Guid` anahtarlı satırın `Id`'si iş anahtarından türetilmiş
2026-09-22 20:59:36 +00:00
sabit bir GUID'dir, satır eklerken aynı kuralla üret. `App.Menus.Routes.json` dosyasına
yalnızca var olan satırın `Seo*` alanları için dokunulur (standing default 7); rota eklemek,
silmek ya da yolunu değiştirmek çerçeve dışıdır.
- **Public site** → menü `Menu` tablosunda `ModuleId = "Pub"` altında (`PlatformConsts.PublicSite`);
`App.Public.Header` hem üst menüyü hem alt bilgideki hızlı bağlantıları besler (ikisi de
`PublicNav` düğümü) ve ziyaretçiye uygulama konfigürasyonunun `publicMenus` alanıyla taşınır
(menü ucu `[Authorize]`). Sayfa ise Custom Component'tir: `/admin/` ile
başlamayan `RoutePath` otomatik public route olur ve aynı yolu paylaşan fiziksel route'u gölgeler;
`RoutePath` boş bırakılabilir (rotasız bileşen). Yeni public sayfa =
`data/App.DeveloperKit.CustomComponents/{Id}.json` satırı + `Pub` menü kaydı; ikisi birlikte yazılır.
Üst ve alt bilgi rotasız bileşenlerdir (`PublicHeader`, `PublicFooter`), layout ikisini de
`renderComponent` ile çizer; rotasız bileşende `RoutePath` **NULL** yazılır (tekil indeks yalnızca
dolu değerleri kapsar). Üst bilginin davranışı `components/publicSite` katalog düğümlerinde,
yerleşimi tasarımcıdadır.
**Public bileşenlerin hepsi tasarımcı belgesidir** (`Props.visualDesigner`, `sourceMode: visual`);
kod belgeden üretilir (`generateDesignerCode`), elle yazılmış koda dönülmez. Runtime kapsamında
`react-icons`/`react-router` yoktur — ikon `PlatformIcon` düğümü, gezinme `a` düğümü. Kanvasın
doğrudan çizdiği katalog düğümleri tek sözlüktedir (`componentEditor/runtimeNodes.ts`); yeni bir
düğüm eklerken bileşen + bu sözlük + `catalog.ts` tanımı + dil anahtarı birlikte yazılır. Elle
yazılmış bir bileşen tasarımcıda kod modunda açılır, kanvasa çevrilmez. Ayrıntı: `README.md` §10.4.
2026-09-01 13:44:05 +00:00
- **Çok değerli alan (`dxTagBox` / çoklu `dxGridBox`)** → tek metin kolonunda `|` ile saklanır.
Ekran varsayılan `list-form-data/*` ucundan kaydediyorsa birleştirmeyi `QueryHelper` yapar;
tipli DTO alan bir uca (`list-form-dynamic-api/...`, Custom Endpoint, Dynamic Service)
bağlıysa DTO alanına `[JsonConverter(typeof(MultiValueStringJsonConverter))]` eklenir —
yoksa istek `400` ile düşer. Ayrıntı: `lowcode.instructions.md` §4.3.2.1.
### Definition of done
- Ölü kod bırakma: kullanılmayan `using`, private üye, alan, DTO, hook, servis, tip. Bir tip
silinmeden önce **repo geneli** (api + ui + configs) referans taraması yapılır; DI ile çözülen
tipler düz metin aramasında referanssız görünür.
- Yorum satırına alınmış kod bloğu bırakılmaz.
2026-10-04 15:04:16 +00:00
- Modül/ekran/bileşen ekleyen ya da davranışını değiştiren iş modül dokümanını
2026-10-07 08:17:46 +00:00
(`configs/seeds/docs/modules/{Menü}.md`) yazar veya günceller; liste ekranının açıklaması
2026-10-04 15:04:16 +00:00
ayrıntılıdır (standing default 14–15).
- `api/` değişikliğinden sonra: `dotnet build -p:EnforceCodeStyleInBuild=true` — 0 hata, yeni
`IDE00xx` yok.
- `ui/` değişikliğinden sonra: `npm run typecheck` ve `npm run lint`.
- Yorumlar **neden**i anlatır, ne yaptığını değil. Kod zaten ne yaptığını söylüyor.
2026-09-04 09:05:26 +00:00
- **Dokümantasyon kodla birlikte güncellenir.** Platformun davranışını değiştiren her değişiklik
(yeni/kaldırılan seeder, seed klasörü ya da dosya biçimi, ListForm sözleşmesine alan ekleme,
yeni yetki/dil anahtarı, katman sınırı, yeni mekanizma) aynı commit içinde ilgili `.md`
dosyasına yansıtılır: `README.md` (ne nerede yaşıyor, klasör düzeni, tablolar),
`.github/instructions/lowcode*.instructions.md` (artefakt/yetenek sözleşmesi),
`dotnet.instructions.md` (kod standardı, katman kuralı), `CLAUDE.md` (çalışma kuralı).
Değişiklik hangi md'de karşılığı olduğu bilinmiyorsa önce grep ile eski anlatım aranır ve
düzeltilir; bayat kalan bir satır bırakma. Doküman güncellemesi "sonraya" bırakılmaz.
### Tone
- Türkçe soruya Türkçe cevap.
- Platformu tanıtma, mimariyi özetleme, ne yapacağını anlatıp sonra bir de ne yaptığını özetleme.
- Cevabın boyutu sorunun boyutu kadar olsun.