sozsoft-platform/claude.md
2026-09-08 18:00:23 +03:00

19 KiB
Raw Blame History

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.

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.

  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.
  4. Never bypass platform authorization patterns.
  5. Never hardcode secrets, tenant IDs, or connection strings.
  6. Never step outside the framework without explicit approval (standing default 10).

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.

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.

  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
Yetenek envanteri: JSON kolonlarının alan alan sözleşmesi, grafik/pivot/tasarımcı/mail modülü, Saas + Administration 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
Yetki kodları PlatformConsts.AppCodes (backend) + constants/permission.constant.ts (UI)
Seed yolları SeedPathResolver

Bir çelişki varsa sıra: ai.instructions.mddotnet.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ııkça "tenant yok / audit yok" demedikçe çıkarma.
  2. Yeni ekran → Wizard yolu. Definitions altına otomatik yerleştirme yok; modüle ait yeni bir kök menü oluştur, Order = max(Order) + 1.
  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.
  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.
  7. Ekran içi hesap/koşul ihtiyacı → önce EditorScript (Script Builder tarifleri), sonra EditorOptions; kod yazmak son çare.
  8. SQL → her zaman parametreli. String birleştirme ile sorgu kurma.
  9. SilmeDeleteCommand = DefaultDeleteCommand("{Tablo}"); ham SQL string'i yazma.
  10. Çerçeve sınırı → uygulama kendini kendi mekanizmalarıyla geliştirir (seed artefaktları; 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.

Cross-cutting: touching one thing means touching these too

  • 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.
  • Wizard seed dosyasında tekrar yokWizard bölümü yalnızca ekrandan üretilemeyen bilgileri taşır. ListForm/Fields içinde karşılığı olan her alan (veri kaynağı, select, anahtar alan, kırılım/düzen/düzenleme bayrakları, görünüm option blokları, alt form, widget, iş akışı, alan tanımları) dosyaya yazılmadan çıkarılır (WizardSeedFileDto.ToSeedJson) ve okurken geri doldurulur (FromSeedJson). Wizard'a yeni bir alan eklerken karşılığı ListForm'da varsa listeye ekle. Dosyada kalan wizard alanları üç başlık altında toplanır — Menu, Language, Groups — ve ListFormCodeWizardCode, MenuParentModuleIdModuleId adıyla yazılır; varsayılanı olan alanlar (CreateMenu: true, boş DataSourceConnectionString) 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.
  • Wizard ile üretilen ekran → seed dosyası (configs/seeds/{kapsam}/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 yetkiPlatformConsts.AppCodes + PermissionsData.json + (UI'da kullanılacaksa) permission.constant.ts + LanguagesData.json.
  • Yeni bir dil anahtarıLanguagesData.json; 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ı/silinmesidata/App.DeveloperKit.CustomComponents.json (Custom Components ekranının seed verisi); bileşenin kendi dosyası yoktur, her bileşen bu dosyada bir satırdır. Hem listeden hem Visual Designer'dan (CustomComponentAppService) yapılan kayıt aynı dosyaya 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.
  • Ş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 ucuEnsureImportNotBlocked 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/objectsql/executecruddatawizard. Tablo eksikse önce scripti çalışır; sıra değiştirilmez. Ekran kurulumu wizard ekranıyla aynı yoldan geçer (DeployWizardAsync); 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. Var olan ekrana dokunulmaz, her ekran kendi UoW'unda kurulur. 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.
  • ListForm.SeedFilePath dolu bir ekranSeedSyncInsert/SeedSyncUpdate/SeedSyncDelete bayraklarından işaretli olan işlemler kapsam klasöründeki data/{ListFormCode}.json dosyasına yansır (ListFormSeedDataSynchronizer); 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ıktır: var olan kayıt dosyadaki değerlerle güncellenir ve soft delete izleri (IsDeleted/DeletionTime/DeleterId) temizlenir. Yeni bir kayıt yolu (yeni endpoint, toplu işlem, tipli AppService) eklenirse senkronizasyon çağrısı da eklenir; yoksa dosya bayatlar.
  • 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.
  • MenusData.jsonRoutes bölümüne dokunma; yalnızca Modules ve Menus.
  • 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.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.
  • Ç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.
  • 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 nedeni anlatır, ne yaptığını değil. Kod zaten ne yaptığını söylüyor.
  • 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.