# Sozsoft Platform **Çalışma zamanında yapılandırılabilen, çok kiracılı (multi-tenant) low-code uygulama motoru.** Sozsoft Platform, klasik bir "kod yaz–derle–yayınla" uygulaması değildir. Ekranlar, menüler, route'lar, yetkiler, veri kaynakları, iş akışları ve hatta API endpoint'leri **veritabanındaki konfigürasyon kayıtlarından** üretilir. Yeni bir modül veya ekran eklemek çoğu durumda tek satır React/C# kodu yazmadan, yalnızca konfigürasyon ile mümkündür. > **Temel ilke:** Configuration first, code last. > Bu ilkenin operasyonel karşılığı ve yapay zeka ajanları için bağlayıcı kurallar > [`.github/instructions/ai.instructions.md`](.github/instructions/ai.instructions.md) dosyasındadır. --- ## İçindekiler 1. [Platform Ne Yapar?](#1-platform-ne-yapar) 2. [Mimari Genel Bakış](#2-mimari-genel-bakış) 3. [Teknoloji Yığını](#3-teknoloji-yığını) 4. [Depo Yapısı](#4-depo-yapısı) 5. [Hızlı Başlangıç](#5-hızlı-başlangıç) 6. [Yapılandırma (Configuration)](#6-yapılandırma-configuration) 7. [Low-Code Motoru: ListForm Ekosistemi](#7-low-code-motoru-listform-ekosistemi) 8. [Developer Kit](#8-developer-kit) 9. [Dinamik Menü, Route ve Yetki Modeli](#9-dinamik-menü-route-ve-yetki-modeli) 10. [Modül Kataloğu](#10-modül-kataloğu) 11. [Kimlik, Oturum ve Güvenlik](#11-kimlik-oturum-ve-güvenlik) 12. [Çok Kiracılılık (Multi-Tenancy)](#12-çok-kiracılılık-multi-tenancy) 13. [Bildirim ve Entegrasyonlar](#13-bildirim-ve-entegrasyonlar) 14. [Arka Plan İşleri](#14-arka-plan-işleri) 15. [Raporlama](#15-raporlama) 16. [Dosya Yönetimi ve CDN](#16-dosya-yönetimi-ve-cdn) 17. [Gerçek Zamanlı Özellikler](#17-gerçek-zamanlı-özellikler) 18. [Frontend Mimarisi](#18-frontend-mimarisi) 19. [API ve Swagger](#19-api-ve-swagger) 20. [Dağıtım (Deployment)](#20-dağıtım-deployment) 21. [Geliştirme Standartları ve Sık Kullanılan Komutlar](#21-geliştirme-standartları-ve-sık-kullanılan-komutlar) 22. [Sorun Giderme](#22-sorun-giderme) 23. [Bilinen Sınırlar ve Notlar](#23-bilinen-sınırlar-ve-notlar) --- ## 1. Platform Ne Yapar? | Yetenek | Açıklama | | --- | --- | | **Dinamik liste/form ekranları** | `ListForm` + `ListFormField` kayıtlarıyla tanımlanan; grid, pivot, ağaç, grafik, gantt, scheduler, kart ve todo görünümlerini destekleyen ekranlar. | | **Dinamik menü ve route** | Menüler ve route'lar veritabanından okunur; frontend bunları çalışma zamanında React Router'a bağlar. | | **Yetki tabanlı görünürlük** | Menü, ekran, sütun ve buton seviyesinde ABP permission kontrolü. | | **SQL Query Manager** | Tarayıcı içinden SQL nesne gezgini, sorgu editörü, sonuç grid'i ve tablo tasarımcısı. | | **Custom / CRUD Endpoint** | Kod yazmadan, SQL veya tablo tanımından REST endpoint üretimi. | | **Dynamic Service** | Roslyn ile çalışma zamanında derlenen ve controller olarak kaydedilen C# ApplicationService'ler. | | **Custom Component** | Babel ile tarayıcıda derlenen, veritabanında saklanan React bileşenleri ve bunların route'ları. | | **İş akışı / onay** | ListForm üzerinde görsel workflow tasarımcısı, koşullu dallanma ve çok kişili onay adımları. | | **Çok kiracılılık** | Tenant başına ayrı bağlantı dizesi (ayrı veritabanı) desteği, şube (branch) ve organizasyon birimi kırılımı. | | **Bildirim ve entegrasyon** | SMS, e-posta, WhatsApp, Rocket.Chat, masaüstü ve UI kanallarına kural tabanlı bildirim. | | **Raporlama** | DevExpress Report Designer/Viewer + ListForm'dan otomatik üretilen dinamik raporlar. | | **Arka plan işleri** | Hangfire + ABP Background Worker; zamanlanmış SQL, mail kuyruğu, yedekleme, oturum temizliği. | | **Gerçek zamanlı** | SignalR tabanlı messenger ve video oda (WebRTC/TURN) altyapısı. | | **Intranet & Forum** | Duyuru, anket, sosyal duvar, etkinlik; kategori/konu/gönderi tabanlı forum. | | **Public web sitesi** | Ana sayfa, hakkımızda, hizmetler, ürün, ödeme, blog, demo ve iletişim içerikleri (tasarımcı ekranlarıyla düzenlenebilir). | | **PWA** | Service worker ile offline kabuk, kontrollü sürüm güncellemesi ve changelog bildirimi. | --- ## 2. Mimari Genel Bakış ``` ┌──────────────────────────────────────────────────────────────────────┐ │ UI — React 19 + Vite + TypeScript + DevExtreme + Tailwind (PWA) │ │ ├─ DynamicRouter (route kayıtlarından React Router üretimi) │ │ ├─ ListForm runtime (Grid / Pivot / Tree / Chart / Gantt / ...) │ │ ├─ Form runtime (DevExtreme Form, metadata ile alan üretimi)│ │ ├─ Developer Kit UI (SQL, endpoint, component, dynamic service) │ │ └─ easy-peasy store + React Query + SignalR │ └───────────────┬──────────────────────────────────────────────────────┘ │ HTTPS / OAuth2 (OpenIddict) / SignalR ┌───────────────▼──────────────────────────────────────────────────────┐ │ API — ASP.NET Core (.NET 10) + ABP Framework 10 │ │ ├─ HttpApi.Host : Swagger, OpenIddict, Hangfire, SignalR Hub, │ │ │ DevExpress Reporting, Setup/Migration akışı │ │ ├─ Application : ListForms, DeveloperKit, Identity, Tenants, │ │ │ Menu, Routes, DataSource, FileManagement, ... │ │ ├─ Domain : Entity'ler, dinamik veri erişimi, seed'ler │ │ └─ EF Core : Migration'lar, dinamik DbContext, tenant DB │ │ │ │ Modüller: Languages · Settings · Notifications · MailQueue · │ │ Sender · SqlQueryManager │ └───────────────┬──────────────────────────────────────────────────────┘ │ ┌───────────────▼──────────────────────────────────────────────────────┐ │ Veri ve Altyapı │ │ SQL Server / PostgreSQL · Redis (cache + SignalR backplane) · │ │ Hangfire (job storage) · Dosya sistemi tabanlı BLOB/CDN · │ │ coturn (TURN) · nginx · Elasticsearch (opsiyonel) │ └──────────────────────────────────────────────────────────────────────┘ ``` **Akışın özeti:** Kullanıcı giriş yapar → ABP `application-configuration` yanıtına `PlatformApplicationConfigurationContributor` menü, route ve yetkileri ekler → `DynamicRouter` route kayıtlarını React bileşenlerine bağlar → `/admin/list/{ListFormCode}` gibi bir ekran açıldığında `ListFormsAppService` metadata'yı, `ListFormDataAppService` ise veriyi döner → DevExtreme bileşenleri bu metadata'ya göre kendini kurar. --- ## 3. Teknoloji Yığını ### Backend | Bileşen | Sürüm / Notlar | | --- | --- | | .NET | `net10.0` (SDK 10.0.300, `global.json` ile sabit) | | ABP Framework | 10.0.0 (Identity, TenantManagement, PermissionManagement, AuditLogging, OpenIddict, BlobStoring, BackgroundWorkers) | | Veritabanı | SQL Server 2022 veya PostgreSQL 17 (`PlatformConsts.DefaultDatabaseProvider`) | | ORM | Entity Framework Core | | Kimlik | OpenIddict (password + refresh token, `/connect/token`) | | Cache | Redis (opsiyonel; `Redis:IsEnabled`) | | Job | Hangfire (`default`, `platform` kuyrukları) + ABP Background Workers | | Raporlama | DevExpress Reporting (Web Document Viewer + Report Designer) | | Log | Serilog | | Dinamik derleme | Roslyn (`DynamicServiceCompiler`) | | Şablon | Scriban (mail şablonları), MailKit/MimeKit | | Gerçek zamanlı | SignalR (Redis backplane destekli) | ### Frontend | Bileşen | Sürüm / Notlar | | --- | --- | | React | 19.2 | | Build | Vite 8 + TypeScript 5.9 | | UI kütüphaneleri | DevExtreme 26.1 (React), Tailwind CSS 3.4, kendi `components/ui` tasarım sistemi | | Routing | react-router-dom 7 (dinamik route üretimi) | | State | easy-peasy (global store) + @tanstack/react-query | | Form | Formik + Yup, DevExtreme Form | | Kod editörü | Monaco Editor | | Runtime derleme | @babel/standalone (Custom Component) | | Takvim/Gantt | FullCalendar, DevExtreme Scheduler/Gantt | | Gerçek zamanlı | @microsoft/signalr | | PWA | vite-plugin-pwa (Workbox) | | Node | 24.13 / npm 11 (`volta` ile sabitlenmiş) | --- ## 4. Depo Yapısı ``` sozsoft-platform/ ├── api/ # .NET çözümü (Sozsoft.Platform.sln) │ ├── src/ │ │ ├── Sozsoft.Platform.Domain.Shared/ # Sabitler, enum'lar, permission kodları (AppCodes) │ │ ├── Sozsoft.Platform.Domain/ # Entity'ler, dinamik veri erişimi, repository'ler │ │ ├── Sozsoft.Platform.Application.Contracts/ # DTO'lar, servis arayüzleri, permission tanımları │ │ ├── Sozsoft.Platform.Application/ # Uygulama servisleri (iş mantığı) │ │ ├── Sozsoft.Platform.EntityFrameworkCore/ # DbContext, migration'lar, dinamik veri katmanı │ │ ├── Sozsoft.Platform.HttpApi/ # Controller'lar (conventional) │ │ ├── Sozsoft.Platform.HttpApi.Client/ # HTTP istemci proxy'leri │ │ ├── Sozsoft.Platform.HttpApi.Host/ # Host: Swagger, auth, Hangfire, SignalR, raporlama │ │ └── Sozsoft.Platform.DbMigrator/ # Migration + seed uygulaması │ ├── modules/ # Bağımsız ABP modülleri │ │ ├── Sozsoft.Languages/ # Dil, dil anahtarı, çeviri metinleri │ │ ├── Sozsoft.Settings/ # Ayar tanımları ve ayar UI'ı │ │ ├── Sozsoft.Notifications/ # Bildirim tipleri, kuralları, kullanıcı bildirimleri │ │ ├── Sozsoft.MailQueue/ # Şablonlu mail kuyruğu ve ekleri │ │ ├── Sozsoft.Sender/ # Mail (SES), SMS, WhatsApp, Rocket.Chat göndericileri │ │ └── Sozsoft.SqlQueryManager/ # SQL nesne yönetimi ve sorgu çalıştırma │ └── test/ # Test projeleri ├── ui/ # React uygulaması │ └── src/ │ ├── routes/ # dynamicRouter, dynamicRouteLoader, route.constant │ ├── views/ # list, form, admin, developerKit, public, intranet, forum, report, auth, setup │ ├── components/ # ui (tasarım sistemi), template (layout), importManager, visualDesigner, componentEditor │ ├── services/ # API istemcileri (her modül için ayrı servis dosyası) │ ├── store/ # easy-peasy modelleri (auth, theme, locale, abpConfig, admin) │ ├── contexts/ # ComponentContext (runtime bileşenler), Dialog, Scroll │ └── utils/ # editorScriptRuntime, workflow, hooks, hoc, biçimlendirme yardımcıları ├── configs/ │ ├── docker/ # Yerel geliştirme için veri katmanı compose dosyaları ve scriptler │ ├── deployment/ # Dev/Prod compose dosyaları, nginx/redis/turn konfigürasyonu, deploy scriptleri │ ├── seeds/ # Runtime'da düzenlenebilen seed'ler; CDN ile aynı kapsam düzeni │ │ # host/{crud,custom,wizard,sql,postgres} │ │ # tenants/{tenantId}/{crud,custom,wizard,sql,postgres} │ │ # {sql|postgres}/{object,execute} │ └── ai/ # AI entegrasyonu (n8n akış tanımları) ├── .github/instructions/ # ai.instructions.md (bağlayıcı platform kuralları) │ # lowcode.instructions.md (artefakt üretim referansı: şemalar, örnekler) │ # dotnet.instructions.md (api/ için bağlayıcı .NET/ABP kod standardı) │ # list.instructions.md (modül/liste ekleme prosedürü) ├── CLAUDE.md # Claude Code için operasyon kuralları └── README.md ``` --- ## 5. Hızlı Başlangıç ### 5.1. Önkoşullar - .NET SDK **10.0.300+** - Node.js **24.x** ve npm **11.x** (Volta önerilir) - Docker Desktop (veritabanı ve Redis için) - DevExpress lisansı (`api/DevExpress_License.txt`) ve DevExtreme npm erişimi ### 5.2. Veri katmanını ayağa kaldırma ```powershell # SQL Server + Redis .\configs\docker\start_sql.bat # veya PostgreSQL + Redis .\configs\docker\start_postgres.bat ``` Compose dosyaları `configs/docker/docker-compose-data.yml` içindedir; `sql` ve `postgres` profilleri ile hangi veritabanının kalkacağı seçilir. Redis her iki profilde de çalışır. ### 5.3. Backend ```powershell cd api dotnet restore dotnet run --project src/Sozsoft.Platform.HttpApi.Host ``` Uygulama `https://localhost:44344` adresinde açılır. Swagger UI kök adreste yayınlanır. **Veritabanı ilk kurulum:** Veritabanı yoksa host, tam ABP yığını yerine minimal bir "setup" uygulaması ile açılır (`DbStartup/SetupAppRunner`). Bu durumda: - `GET /api/setup/application-status` — veritabanının hazır olup olmadığını döner (anonim). - UI tarafında `/setup` route'u (`views/setup/DatabaseSetup.tsx`) migration'ı tetikleyen ekranı gösterir. - Migration için `Setup:MigrationPassword` yapılandırması veya `App.Setup.Migrate` yetkisi gerekir. Alternatif olarak migration + seed'i doğrudan çalıştırabilirsiniz: ```powershell dotnet run --project api/src/Sozsoft.Platform.DbMigrator ``` DbMigrator; şema migration'larını uygular ve ardından menü, route, permission, dil, host ayarları, ülke/şehir/ilçe verileri ile seed edilmiş ListForm ekranlarını yükler (kodla versiyonlanan sabit seed'ler `api/src/Sozsoft.Platform.DbMigrator/Migrations/`, runtime'da düzenlenebilen seed'ler `configs/seeds/` altındadır — bkz. `App:SeedsPath`). `configs/seeds` altında en üst seviye kapsamdır (CDN klasörleriyle aynı mantık): host veritabanı için `host/`, her tenant için `tenants/{tenantId}/`. Kapsamın altında içerik türüne göre `crud/`, `custom/`, `wizard/`, `data/`, `sql/`, `postgres/` klasörleri bulunur: ``` configs/seeds/ host/ crud/ custom/ wizard/ data/ sql/ { object/ execute/ } postgres/ { object/ execute/ } tenants/ {tenantId}/ crud/ custom/ wizard/ data/ sql/ { object/ execute/ } postgres/ { object/ execute/ } ``` Aktif veritabanı sağlayıcısına göre `sql/` (SQL Server) ya da `postgres/` okunur. Her `.sql` dosyası amacını belirten bir klasörün altındadır; klasör köklerinde dosya bulunmaz: | Klasör | Ne zaman çalışır | | --- | --- | | `{sql\|postgres}/object` | Seed sırasında nesneyi oluşturur/günceller. SqlTableDesigner ve SqlQueryManager, deploy ettiği script'i çalıştığı kapsamın bu klasörüne yazar (host bağlamı → `host/`, tenant seçiliyken → `tenants/{tenantId}/`). | | `{sql\|postgres}/execute` | Nesneyi oluşturur; ayrıca tüm migration ve seed'ler bittikten sonra `AfterAllMigrationsSqlExecutor` dosya adından türettiği procedure'ü çalıştırır (dosya adı = procedure adı, `schema.Procedure.sql` de olur). | | `wizard` | ListForm Wizard'ın ürettiği `.json` konfigürasyonları; `WizardDataSeeder` kendi kapsamındaki dosyaları okur. | | `crud` | CrudEndpoint konfigürasyonları; `CrudDataSeeder` kendi kapsamındaki dosyaları okur. | | `custom` | Custom Component konfigürasyonları (`{Name}.json`); Component Manager kaydetme/silme sırasında dosyayı senkronlar, `CustomComponentDataSeeder` kendi kapsamındaki dosyaları okuyup veritabanına uygular. | | `data` | Ekranlardan girilen listelerin veri aynası (`{ListFormCode}.json`). `ListForm.SeedFilePath` dolu olan ekranda `SeedSyncInsert/Update/Delete` bayraklarından işaretli olan işlemler dosyaya yansır (`ListFormSeedDataSynchronizer`); migrate/seed sırasında bütün contributor'lar bittikten sonra `ListFormSeedDataApplier` dosyayı geri uygular: anahtarı veritabanında **olmayan** satırları ekler, var olanlara dokunmaz. | Klasör kökünde kalmış eski `.sql` dosyaları geriye dönük uyumluluk için hâlâ işlenir, fakat `SqlDataSeeder` bunları uyarı ile loglar — ilgili klasöre taşınmaları beklenir. ### 5.4. Frontend ```powershell cd ui npm install npm start # vite dev server (http://localhost:3000) ``` Visual Designer ve Custom Component altyapısının kullandığı bileşen kataloğu `src/components/visualDesigner/generated/componentProps.json` dosyasında tutulur ve repoya dahildir. `src/components/ui` altındaki bileşen prop'ları değiştiğinde bu dosya elle güncellenmelidir. ### 5.5. İlk giriş Seed edilen host yöneticisi ile `/login` üzerinden giriş yapılır (kullanıcı bilgileri `PlatformIdentityDataSeeder` ve `HostData.json` ile belirlenir; ortam bazlı değerler `HostData.Dev.json` / `HostData.Production.json` dosyalarındadır). Giriş sonrası `/admin/dashboard` açılır. --- ## 6. Yapılandırma (Configuration) ### 6.1. Backend (`appsettings.json`) | Anahtar | Açıklama | | --- | --- | | `App:SelfUrl` | API'nin kendi adresi (OpenIddict authority ile uyumlu olmalı). | | `App:ClientUrl` | React uygulamasının kök adresi (mail linkleri bu adresi kullanır). | | `App:CorsOrigins` | Virgülle ayrılmış izinli origin listesi; wildcard subdomain destekli. | | `App:RedirectAllowedUrls` | OAuth yönlendirme için izinli adresler. | | `App:CdnUrl` / `App:CdnPath` | Dosya servisinin adresi ve BLOB kök dizini. | | `App:AttachmentsPath` | Mail kuyruğu eklerinin yazıldığı dizin. | | `App:BackupPath` | Veritabanı yedek dizini (BackupWorker kullanır). | | `App:Version` | Uygulama sürümü (UI sürüm kontrolü ile eşleşir). | | `ConnectionStrings:SqlServer` / `PostgreSql` | Host veritabanı bağlantıları. | | `Redis:IsEnabled` / `Redis:Configuration` | Dağıtık cache ve SignalR backplane. | | `AuthServer:Authority` / `SwaggerClientId` | OpenIddict authority ve Swagger istemcisi. | | `OpenIddict:TokenLifetimes:*` | Access/refresh token ömrü (dakika). | | `Setup:MigrationPassword` | Setup ekranından migration tetiklemek için parola. | | `StringEncryption:DefaultPassPhrase` | ABP string şifreleme anahtarı. | | `Serilog:MinimumLevel` | Log seviyeleri. | > **Güvenlik:** Depodaki `appsettings.json` dosyaları geliştirme değerleri içerir. > Üretimde bağlantı dizeleri, `MigrationPassword`, `DefaultPassPhrase` ve entegrasyon > anahtarları **ortam değişkeni veya secret yöneticisi** ile verilmelidir; repoya yazılmamalıdır. ### 6.2. Frontend (`ui/.env`, `.env.dev`, `.env.production`) | Değişken | Açıklama | | --- | --- | | `VITE_API_URL` | API kök adresi. | | `VITE_CDN_URL` | Dosya/CDN kök adresi. | | `VITE_REACT_APP_VERSION` | `package.json` sürümünden beslenir. | | `VITE_AI_URL` | AI asistanının n8n webhook kökü. | | `VITE_USE_POLLING` | Dosya izlemede polling (WSL/Docker senaryoları). | | `VITE_PWA_DEV` | Geliştirmede service worker'ı açar (varsayılan kapalı). | ### 6.3. Uygulama içi ayarlar Çalışma zamanı ayarları veritabanında tutulur ve **Ayarlar** ekranından (`/admin/settings`) yönetilir. `Sozsoft.Settings` modülü ayar tanımlarını, `SettingUiAppService` ise bu tanımların UI gösterimini yönetir. Şifre politikası, oturum kuralları, gönderici kimlik bilgileri (SMS, mail, WhatsApp, Rocket) ve AI bot yapılandırması bu yolla değiştirilir — kod dağıtımı gerekmez. --- ## 7. Low-Code Motoru: ListForm Ekosistemi Platformun kalbi budur. Bir iş ekranı; bir `ListForm` kaydı, ona bağlı `ListFormField` kayıtları ve bir menü/route/permission üçlüsünden oluşur. ### 7.1. Kavramlar | Varlık | Rolü | | --- | --- | | `DataSource` | Hedef veritabanı bağlantısı (MSSQL / PostgreSQL). Ekranlar `DataSourceCode` ile bağlanır. | | `ListForm` | Ekranın tüm davranışı: veri kaynağı, sütun/filtre/sayfalama/düzenleme ayarları, yetkiler, alt formlar, iş akışı, grafik ayarları. | | `ListFormField` | Tek bir sütun/alanın davranışı: başlık, tip, genişlik, editör, lookup, doğrulama, biçim, yetki. | | `ListFormCustomization` | Kullanıcı bazlı kişiselleştirme: kayıtlı filtre, grid state, sunucu tarafı join/where. | | `ListFormWorkflow` | Onay ve koşul düğümlerinden oluşan iş akışı grafiği. | | `ListFormImport` / `ImportLog` | Excel/CSV içe aktarma tanımı ve satır bazlı sonuç günlüğü. | ### 7.2. `ListForm` anatomisi Ekran davranışı büyük ölçüde JSON kolonlarında saklanır. Öne çıkanlar: | Alan | İşlevi | | --- | --- | | `SelectCommandType` + `SelectCommand` | Veri kaynağı türü: `Table`, `View`, `TableValuedFunction`, `Query`, `StoredProcedure`. | | `KeyFieldName` / `KeyFieldDbSourceType` | Birincil anahtar alanı ve tipi. | | `PermissionJson` | Ekranın create/read/update/delete/export/import/note yetki eşlemesi. | | `EditingOptionJson` / `EditingFormJson` | Düzenleme modu (row/cell/batch/form/popup) ve düzenleme formu düzeni. | | `FilterRowJson`, `HeaderFilterJson`, `FilterPanelJson`, `SearchPanelJson`, `GroupPanelJson` | Filtreleme, arama ve gruplama davranışı. | | `ColumnOptionJson`, `PagerOptionJson`, `SelectionJson`, `StateStoringJson` | Sütun, sayfalama, seçim ve durum saklama ayarları. | | `Insert/Update/DeleteCommand` (+ `Before` / `After`) | CRUD komutları ve öncesi/sonrası çalışacak SQL kancaları. | | `Insert/Update/DeleteServiceAddress` | Varsayılan olarak `list-form-data/*`; özel endpoint'e yönlendirilebilir. | | `SeedFilePath` | Doluysa seed sırasında listenin verisi kapsam klasöründeki bu JSON dosyasından geri yüklenir (`data/{ListFormCode}.json`). | | `SeedSyncInsert` / `SeedSyncUpdate` / `SeedSyncDelete` | Ekranda yapılan hangi işlemin seed dosyasına yansıyacağı; kapalıysa o işlem dosyaya dokunmaz. | | `SubFormsJson` | Ana-detay ilişkisi (ParentFieldName → ChildFieldName eşlemesi). | | `WidgetsJson` | Ekranın üstünde gösterilecek KPI kartları. | | `WorkflowJson` | İş akışı bağlaması. | | `ExtraFilterJson` | Ekrana özel ek filtre araç çubuğu. | | `PivotOptionJson`, `TreeOptionJson`, `GanttOptionJson`, `SchedulerOptionJson`, `TodoOptionJson` | Alternatif görünümlerin ayarları. | | Grafik alanları (`SeriesJson`, `LegendJson`, `ArgumentAxisJson`, `ValueAxisJson`, `TooltipJson`, `ZoomAndPanJson`, …) | DevExtreme Chart yapılandırması. | | `CustomJsSourcesJson` / `CustomStyleSourcesJson` | Ekran yüklendiğinde çalışacak JS/CSS. | | `IsTenant`, `IsBranch`, `IsOrganizationUnit` | Otomatik tenant/şube/organizasyon birimi filtrelemesi. | | `UserId`, `RoleId`, `CultureName` | Aynı ekranın kullanıcı, rol veya dil bazlı varyantları. | ### 7.3. Görünüm tipleri Aynı `ListForm` tanımı, aynı veri hattı üzerinden birden fazla görünümle sunulabilir: `Grid` · `Pivot` · `Tree` · `Chart` · `Gantt` · `Scheduler` · `CardView` · `TodoBoard (Kanban)` · `Widget Group` Kullanıcı görünümler arasında geçiş yapabilir; grid durumu (sütun sırası, genişlik, filtre, gruplama) kullanıcı bazlı saklanır ve sıfırlanabilir. **TodoBoard artık bir Kanban panosudur:** kolonlar `TodoOptionJson` içindeki `statusExpr` değerlerinden üretilir, kartlar kolonlar arasında sürüklenerek durum değiştirir ve panodan yeni kolon (durum) eklenebilir. Kart içeriği `titleExpr`, `descriptionExpr`, `dueDateExpr`, `tagExpr` ve atanan kullanıcı alanlarından kurulur. ### 7.4. Alan (field) davranışı - **Editör tipleri:** `dxTextBox`, `dxTextArea`, `dxNumberBox`, `dxDateBox`, `dxDateRangeBox`, `dxCalendar`, `dxCheckBox`, `dxSwitch`, `dxRadioGroup`, `dxSelectBox`, `dxTagBox`, `dxLookup`, `dxDropDownBox`, `dxGridBox`, `dxAutocomplete`, `dxColorBox`, `dxHtmlEditor`, `dxSlider`, `dxRangeSlider` — ayrıca görsel yükleme/görüntüleme editörleri. - **Lookup kaynakları:** `StaticData`, `Query`, `WebService`; ebeveyn–çocuk (cascade) desteklidir. - **Doğrulama:** `ValidationRuleJson` ile required/range/pattern/custom kuralları. - **Editör script:** `EditorScript` alanı ile alan değişiminde çalışan JS (örn. tarih farkından gün hesaplama, miktar × birim fiyat toplamı). Çalıştırma `utils/editorScriptRuntime.ts` üzerinden yapılır. - **Editör seçenekleri:** `EditorOptions` alanı DevExtreme editörüne geçirilen JSON'dur (format, maske, placeholder, yükseklik, buton görünürlüğü, platform editörlerinin tipli ayarları). Elle JSON yazmak zorunlu değildir; bkz. 7.4.1. - **Koşullu biçimlendirme:** `ColumnStylingJson`, `ColumnCssClass`/`ColumnCssValue`. - **Alan bazlı yetki:** `PermissionJson` ile sütun düzeyinde okuma/yazma/dışa aktarma kontrolü. #### 7.4.1. Script Builder ve Editor Options Builder `EditorScript` ve `EditorOptions` alanları hem görsel olarak hem de seeder kodundan üretilir; **iki tarafın çıktısı birebir aynı olmak zorundadır.** **Editor Script Builder** (`json-row-operations/editor-script/`) - Kural sözlüğü `scriptRecipes.ts` içindedir; her tarif (recipe) tek satırlık runtime çağrısı üretir. Gruplar: hesap (`calc`), veri (`data`), görünüm (`view`), bildirim, API. - Üretilen script'in ilk satırındaki `// @builder {...}` başlığı kuralları saklar. Dialog script'i regex ile çözmeye çalışmaz, bu başlıktan geri okur; başlık bozulursa/elle düzenlenirse script "manuel" sayılır ve kural editörü kapanır. - Kural tetikleyicileri: `change` (varsayılan), `open` (form açılışında — varsayılan değer üretmek için, script başına `// @runOnOpen` direktifi eklenir), `both`. - Koşullar `and`/`or` ile birleşir: `equals`, `notEquals`, `contains`, `empty`, `notEmpty`, `greaterThan`, `lessThan`, `isTrue`, `isFalse`, `always`. - Dialog'un kendisi ortaktır (`components/scriptBuilder/ScriptBuilderDialog.tsx` + IntelliSense); ListForm lehçesi `formScriptDialect.ts`, Visual Designer lehçesi `designerScriptDialect.ts` ile aynı sözleşmeye bağlanır. **Seeder tarafı (C#)** — `Sozsoft.Platform.Domain.Shared/Editors/` `scriptRecipes.ts` ve editorOptions sözlüğünün C# portudur. Seeder ile basılan script/JSON, dialogda açılıp görsel olarak düzenlenebilir kalır. Bir tarif TypeScript tarafında değişirse buradaki karşılığı da güncellenmelidir. | Tip | Kullanım | | --- | --- | | `EditorScript` | `Multiply`, `Subtract`, `Percent`, `Sum`, `Formula`, `Today`, `Days`, `Hours`, `Copy`, `SetValue`, `Clear`, `ReadOnly`, `Notify`, `Ask`, `OpenUrl`, `ApiToField`, `Custom` → `EditorScript.Build(rules)` | | `EditorScriptRule` | `.When(...)` / `.WhenAny(...)` koşulları, `.OnChange()` / `.OnOpen()` / `.OnOpenAndChange()` tetikleyicisi; `string`'e örtük dönüşür | | `EditorScriptCondition` | `Is`, `IsNot`, `Contains`, `IsEmpty`, `IsNotEmpty`, `GreaterThan`, `LessThan`, `IsTrue`, `IsFalse`, `Always` | | `EditorOptions` | Hazır başlangıçlar: `Disabled()`, `ReadOnly()`, `ShowClearButton()`, `Multiline(h)`, `Number(precision)`, `Percent()`, `Date()`, `DateTime()`, `Time(interval)`, `Phone()`, `Slider()`, `ImageUpload()`, `Html(h)` | | `EditorOptionsBuilder` | Akıcı ekleme: `.Placeholder()`, `.MaxLength()`, `.Height()`, `.Width()`, `.Format()`, `.Mask()`, `.Flag()`, `.Text()`, `.Number()`, `.Json()`; `string`'e örtük dönüşür | ```csharp EditorOptions = EditorOptions.Number(4).ShowClearButton(), EditorOptions = EditorOptions.Multiline(60).Placeholder("Açıklama"), EditorScript = EditorScript.Build( EditorScript.Multiply("Quantity", "UnitPrice", "Total"), EditorScript.Percent("Total", "VatRate", "VatAmount", mode: EditorScriptPercentMode.Add) .When(EditorScriptCondition.IsNotEmpty("VatRate"))), ``` **Editor Options Builder** (`json-row-operations/editor-options/`) - UI tamamen `optionSpecs.ts` veri sözlüğünden üretilir; yeni bir ayar eklemek için oraya tek satır yazmak yeterlidir. Her ayar `path` (örn. `format.precision`), tip (`boolean` üç durumlu / `number` / `text` / `select` / `size` / `stringList` / `json`), grup ve hangi editörlerde anlamlı olduğu bilgisini taşır. - `platform: true` işaretli ayarlar backend'in tipli DTO'ya (`GridBoxOptionsDto`, `TagBoxOptionsDto`, `ImageUploadOptionsDto`) deserialize ettiği alanlardır; yanlış tipte yazılırsa sessizce yok sayılır. - `presets.ts` hazır kalıplar sunar (HTML editör tam araç çubuğu, telefon maskesi, tarih/saat…); kalıp mevcut JSON ile **birleştirilir**, diğer ayarları silmez. ### 7.5. İş akışı ve onay `FormTabWorkflow` ve `views/admin/listForm/workflow/WorkflowDesigner.tsx` üzerinden görsel tasarlanır. Düğüm türleri koşul karşılaştırması (`CompareColumn`/`CompareOperator`/`CompareValue`) ve onay adımlarıdır; her adım için `NextOnTrue`, `NextOnFalse`, `NextOnApprove`, `NextOnReject` geçişleri tanımlanır. Onaycı birden fazla kişi olabilir. Formlar içinde iş akışına bağlı özel butonlar gösterilebilir. ### 7.6. Yeni ekran ekleme akışı (Wizard) `/admin/listform/wizard` altındaki sihirbaz, aşağıdaki artefaktları tek akışta üretir: 1. **ListForm** kaydı (kod, ad, başlık, veri kaynağı, select komutu, anahtar alan) 2. **ListFormField** kümesi (sütunlar, editörler, lookup'lar, doğrulamalar) 3. **Route** kaydı (`key`, `path`, `componentPath`, `routeType`, `authority`) 4. **Menu** kaydı (`ParentCode`, `Code`, `DisplayName`, `Url`, `Icon`, `RequiredPermissionName`, `Order`) 5. **Permission** kayıtları (`.Default`, `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note`) 6. **Dil anahtarları** (menü, başlık, açıklama; EN + TR) 7. Gerekiyorsa **ayar/entegrasyon** bağımlılıkları 8. **Seed dosyası** — `configs/seeds/{host|tenants/{tenantId}}/wizard/{Ad}.json` (wizard cevapları + üretilen `ListForm`/`Fields` sözleşmesi) 9. **Doğrulama ve geri alma** notları **Adım bileşenleri.** Adımlar numaralı dosya adları yerine işlevleriyle adlandırılır ve `React.lazy` ile yüklenir; aynı anda yalnızca görünen adım indirilir, sihirbazın açılış maliyeti adım sayısından bağımsızdır. | Adım | Dosya | İçerik | | --- | --- | --- | | Menü ve kimlik | `WizardStepMenu.tsx` | Wizard adı, ListForm kodu, menü ağacı/üst menü, ikon, sıra, izin grubu, dil metinleri | | Veri ayarları | `WizardStepDataSettings.tsx` | Veri kaynağı, select komutu tipi, anahtar alan, CRUD endpoint diyaloğu | | Alanlar | `WizardStepFields.tsx` | Sütun grupları, editör tipleri, lookup, doğrulama | | Alt formlar | `WizardStepSubForms.tsx` | Ana–detay ilişki eşlemesi | | Widget'lar | `WizardStepWidgets.tsx` | KPI kartları | | İş akışı | `WizardStepWorkflow.tsx` | Onay/koşul grafiği | | Düzen adımları | `WizardStepTodoLayout` · `WizardStepTreeLayout` · `WizardStepGanttLayout` · `WizardStepSchedulerLayout` | Yalnızca ilgili görünüm açıksa görünür | | Bileşen | `WizardStepComponent.tsx` · `WizardStepCustomComponent.tsx` | Custom yolunda bağlanacak bileşen | | Yayınlama | `WizardStepDeploy.tsx` | Özet, doğrulama ve seed dosyasının üretimi | Menü ağacı yardımcıları (`menuTree.ts`) adım bileşenlerinden ayrı bir modüldedir; böylece Wizard ve `SqlTableDesignerDialog` bu fonksiyonları kullanırken adım bileşenlerini pakete çekmez. **Seed dosyası ekranın kendisini taşır.** Dosya `Wizard` bölümünün yanında ekranın `GridOptionsEditDto` sözleşmesini (`ListForm`) ve alanların `ColumnFormatEditDto` sözleşmesini (`Fields`) tutar; `WizardDataSeeder` ekranı bu iki bölümden kurar. Böylece Wizard ile ListForm detayı aynı veri yapısını konuşur ve tasarımcıdaki değişiklikler wizard'a geri yazılabilir. `Wizard` bölümü yalnızca ekrandan üretilemeyen bilgileri (menü, yetki, dil metinleri, bileşen yolu, alan başlıklarının dil karşılıkları) taşır; `ListForm`/`Fields` içinde karşılığı olan alanlar dosyaya yazılmaz, okuma sırasında geri doldurulur. Kalanlar dosyada `Menu`, `Language` ve `Groups` başlıkları altında toplanır (`WizardSeedFileDto.ToSeedJson` / `FromSeedJson`). Dosya adı `{Ad}.json`'dır (zaman damgası yok); uygulama sırası `Wizard.SeededAt` damgasından gelir. **İki yol: `ComponentKind`.** `ListFormWizardDto.ComponentKind` sihirbazın yol ayrımıdır ve seed dosyasında ilk alandır. Varsayılan `List` olduğu için bu alanı taşımayan eski seed dosyaları eskisi gibi çalışır. | `ComponentKind` | Üretilen | Menü URL'i | Yetkiler | | --- | --- | --- | --- | | `List` | ListForm + ListFormField + Route + Menu + Permission + dil anahtarları | `/admin/list/{ListFormCode}` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | `Custom` | Menü + Permission + dil anahtarları; ekran seçilen Custom Component'tir | Component'in `RoutePath` değeri | Yalnızca `.Create`, `.Update`, `.Delete` (Export/Import/Note ListForm'a özgüdür) | **Menüsüz wizard (`CreateMenu = false`).** Menü (ve gerekiyorsa üst menü) kaydı hiç üretilmez; ListForm, permission ve dil anahtarları her iki durumda da üretilir. Menüsüz wizard'lar başka bir ekranda SubGrid/parça olarak kullanılmak üzere tanımlanır. Alan varsayılanı `true` olduğundan bu alanı taşımayan eski seed dosyaları etkilenmez. **İzin grubu seçimi.** Menü adımında izin grubu bir seçim listesinden gelir (`GetWizardPermissionGroups`). Görünen adlar, grup adıyla aynı olan dil anahtarının metinlerinden okunur; seçim yapıldığında `PermissionGroupEn/Tr` forma doldurulur. Yeni bir grup tanımlanırsa grup adıyla aynı dil anahtarına bu metinler yazılır; mevcut grup seçilip alanlar boş bırakılırsa sunucu veritabanındaki değeri geri yazar. Böylece seed dosyası her durumda iki dilli görünen adı taşır. Dinamik liste ekranlarının route deseni `/admin/list/{ListFormCode}` biçimindedir; form görünümleri `/admin/form/{listFormCode}/:id`, grafik `/admin/chart/{listFormCode}`, pivot `/admin/pivot/{listFormCode}` yollarını kullanır. Var olan bir ekranı düzenlemek için `/admin/listform/edit/{listFormCode}` — tüm JSON yapılandırması sekmeli bir editörde yönetilir (Veritabanı, Sütunlar, Filtreler, Düzenleme, Yetkiler, Alt Form, Pivot, Tree, Gantt, Scheduler, Todo, Widget, Workflow, Durum, Grafik sekmeleri). **Wizard File Manager** (`/admin/listform/wizard` liste ekranı) üretilmiş seed dosyalarını yönetir: liste/kart görünümü arasında geçiş (tercih diğer listelerle aynı yerde, `admin.lists.states` altında saklanır), arama, düzenleme (dosyanın yerine geçen yeni bir çalıştırma), silme, veritabanı migrate tetikleme, dışa aktarma ve içe aktarma. Butonlar `App.Listforms.Wizard.*` yetkileriyle gizlenir; asıl kontrol `ListFormWizardAppService` üzerindedir. ### 7.7. İçe/dışa aktarma **Veri (ekran içi)** - **Dışa aktarma:** xlsx, csv, pdf (grid durumuna ve görünür sütunlara saygı duyar). - **İçe aktarma:** `components/importManager` altındaki dosya yükleme → önizleme → ilerleme → sonuç akışı; sonuçlar `ListFormImportLog` üzerinde satır bazında raporlanır. Şablon dosyası ekran tanımından üretilir. **Ekran tanımı (wizard seed paketi)** Bir ekranın tanımı, bağımlılıklarıyla birlikte tek bir zip olarak taşınır. Zip içindeki yollar seed kapsam klasörü (`host` / `tenants/{tenantId}`) kökü baz alınarak yazılır; arşiv başka bir ortamda aynı klasör düzenine doğrudan açılabilir. | Yol | İçerik | | --- | --- | | `wizard/{dosya}.json` | Wizard tanımının kendisi | | `custom/{component}.json` | Custom yolunda bağlı component ve bağımlılıkları | | `crud/{entity}.json` | Component'lerin/nesnenin kullandığı CRUD endpoint tanımları | | `{sql\|postgres}/{object\|execute}/{nesne}.sql` | List yolunda `SelectCommand`'a karşılık gelen SQL nesnesi | **İçe aktarma iki adımlıdır** (`WizardImportDialog`): 1. **Analiz** (`AnalyzeImport`) — zip, seed kökü altındaki `.imports/{importId}/staged` klasörüne açılır (nokta ile başladığı için seeder taramalarına girmez) ve her dosya hedefteki karşılığıyla karşılaştırılır: `New` (hedefte yok), `Identical` (aynı, sorulmaz), `Conflict` (farklı). Çakışan dosyalar Monaco `DiffEditor` ile karşılaştırılıp birleştirilir. 2. **Uygulama** (`ApplyImport`) — dosyalar tek tek yazılır, ilerleme satır satır gösterilir. Yazılan her dosyanın önceki hâli `.imports/{importId}/backup` altına alındığı için hata durumunda `RollbackImport` ile toplu işlem geri alınabilir; `CompleteImport` oturumu kapatır. Güvenlik sınırları: yalnızca `wizard`, `crud`, `custom`, `sql`, `postgres` kök klasörleri (SQL sağlayıcı klasörlerinin altında yalnızca `object` ve `execute`) kabul edilir; dosya başına 5 MB, arşiv başına 50 MB, en çok 500 girdi. Kabul edilmeyen girdiler analiz sonucunda uyarı olarak listelenir. Yetkiler: `App.Listforms.Wizard.Export` / `App.Listforms.Wizard.Import`. --- ## 8. Developer Kit Teknik kullanıcılar için `/admin/developerkit` altında toplanan araçlar: | Araç | Route | Ne işe yarar | | --- | --- | --- | | **SQL Query Manager** | `/admin/sqlQueryManager` | Nesne gezgini, Monaco tabanlı SQL editörü, sonuç grid'i, **tablo tasarımcısı**, **view tasarımcısı** ve **CRUD endpoint yönetimi**. | | **Custom Endpoint** | `/admin/list/App.DeveloperKit.CustomEndpoints` | SQL veya servis tanımından REST endpoint üretimi; GET/POST/PUT/DELETE için ayrı yetki kapıları (`App.DeveloperKit.CustomEndpoints.*`) ve kullanıcı/rol/global erişim kuralları. | | **CRUD Endpoint** | SQL Query Manager içinde | Tablo tanımından tam CRUD endpoint kümesi üretimi. Ayrı ekranı yoktur; bkz. aşağıdaki not. | | **Dynamic Service** | `/admin/developerkit/dynamic-services` | C# kodunu tarayıcıda yazıp Roslyn ile derleme (`TestCompile`), yayınlama (`Publish`) ve çalışan uygulamaya controller olarak kaydetme. Yetkiler: Create/Edit/Delete/Manage/TestCompile/Publish/ViewCode. | | **Custom Component** | `/admin/developerkit/components` | React bileşenini veritabanında saklama; `@babel/standalone` ile tarayıcıda derleyip route'a bağlama. Liste/kart görünümü, arama; yetkiler `App.DeveloperKit.Components{,.Create,.Update,.Delete}`. | | **Visual Designer** | Component editörü içinde | Sürükle-bırak kanvas ile bileşen üretimi ve kod üretimi (`visualDesigner/codeGenerator.ts`). | | **ListForm** | `/admin/list/App.Listforms.Listform` | Var olan ekranların ham tanım listesi; buradan `/admin/listform/edit/{kod}` sekmeli editörüne geçilir. | | **Wizard Manager** | `/admin/listform/wizardManager` | Üretilmiş wizard seed dosyalarının listesi/kartı, düzenleme, silme, DB migrate, export/import. Yetki `App.Listforms.Wizard{,.Create,.Update,.Delete,.Export,.Import}`. | > Bu ekranların artefakt şemaları, enum değerleri ve çalışan örnekleri > [`.github/instructions/lowcode.instructions.md`](.github/instructions/lowcode.instructions.md) > dosyasındadır. ### 8.1. SQL View Designer `SqlViewDesignerDialog` (+ `sqlViewDesigner/`), SSMS Query Designer düzeninde görsel view oluşturma aracıdır. Üç panel: - **Diagram** (`DiagramPane.tsx`) — `ViewSource` kutuları (x/y konumlu, daraltılabilir, yalnızca seçili kolonları gösterebilir) ve aralarındaki JOIN okları. Kaynak bir tablo/view olabileceği gibi `CROSS/OUTER APPLY` ya da türetilmiş bir alt sorgu da olabilir; alt sorgunun gövdesi olduğu gibi saklanır. JOIN türleri: `INNER`, `LEFT`, `RIGHT`, `FULL`, `CROSS`; koşul operatörleri `=`, `<>`, `>`, `>=`, `<`, `<=`. - **Criteria grid** (`CriteriaGrid.tsx`) — Column / Alias / Output / Group By / Sort / Filter / Or… satırları. Bir satır ya `sourceId + columnName` referansıdır ya da serbest bir SQL ifadesidir. Group By sütunu `GroupBy`, `Where` (satır çıktıya girmez, yalnızca filtre taşır) ve `SUM`/`COUNT`/`COUNT_DISTINCT`/`AVG`/`MIN`/`MAX` değerlerini alır. Filtre hücreleri SSMS'teki gibi serbest yüklemdir (`> 100`, `LIKE '%abc%'`, `IS NULL`). - **T-SQL önizleme** — model → SQL üretimi (`generateViewSql`). Tasarımcı tek yönlü çalışır: **model → T-SQL**. Mevcut bir view açılırken `parseViewSql` ile geri okunmaya çalışılır; üretilen kanonik şekle uymayan bir tanım gelirse dialog **ham SQL moduna** düşer ve kullanıcı Query Editor'dan devam eder (`onOpenInEditor`). PostgreSQL bağlantılarında `isPostgreSql` bayrağı ile söz dizimi buna göre üretilir. > **CRUD Endpoint, SQL Query Manager ile birleştirildi.** Ayrı `/admin/developerkit/endpoints` > ekranı ve menüsü kaldırıldı. Endpoint üretme, aktif/pasif etme, test etme ve silme işlemleri > artık iki yerden yapılır: SQL Query Manager nesne gezgininde tablo satırının **CRUD Endpoints** > aksiyonu (ve seçili tablolar için toolbar'daki toplu üretim butonu), ayrıca ListForm > sihirbazının **Adım 2 – Veri Kaynağı** ekranındaki aynı diyalog. Ayrıca **tablo > tasarımcısında deploy öncesi bir adım** vardır: endpoint üretilip üretilmeyeceği ve > hangi operasyonların (GetList/GetById/Create/Update/Delete) aktif başlayacağı seçilir > ("tümünü seç" destekli); seçilmeyenler pasif olarak kaydedilir, sonradan diyalogdan > açılabilir. Hepsi `CrudEndpointDialog` bileşenini kullanır. Yetki `App.SqlQueryManager` altındaki > `App.SqlQueryManager.CrudEndpoints`'tir; izin verilmemişse butonlar görünmez ve > `crud-endpoint-generate` uçlarının tamamı (base CRUD metotları dahil) reddedilir. > Üretilen endpoint'ler `configs/seeds/{host|tenants/{tenantId}}/crud/{EntityName}.json` olarak > seed dosyasına yazılır; `CrudDataSeeder` aynı dosyaları okuyup endpoint'leri geri yükler. > **Tablo tasarımı varsayılanı:** Yeni tablo oluştururken tenant ve tam denetim (audit) kolonları > varsayılan olarak eklenir: `Id`, `TenantId`, `CreationTime`, `CreatorId`, `LastModificationTime`, > `LastModifierId`, `IsDeleted`, `DeletionTime`, `DeleterId`. Kullanıcı açıkça istemedikçe bu > kolonlar çıkarılmaz. ### 8.2. Custom Component ve Visual Designer **Saklanan tanım.** Bir custom component `Name`, `RoutePath`, `Code` (JSX), `Props`, `Dependencies` ve `DataSources` alanlarından oluşur. Görsel tasarımcı dokümanı iki yerde tutulur: `Props.visualDesigner` içinde (nodes, canvas, lifecycle, dataSources) ve üretilen kodun ilk satırındaki `/*__SOZSOFT_VISUAL_DESIGNER__…__*/` yorumunda. Böylece yalnızca kod elinizdeyse bile tasarımcı dokümanı geri okunabilir. `sourceMode` alanı `visual` ya da `code` olur; kod moduna geçilen bir bileşen kanvasa geri dönmez. **Seed senkronizasyonu.** Component Manager üzerinden kaydedilen/silinen her bileşen `configs/seeds/{host|tenants/{tenantId}}/custom/{Name}.json` olarak yazılır; `CustomComponentDataSeeder` veritabanı silinip yeniden oluşturulduğunda aynı dosyaları okuyup geri yükler. Dosya düzeni bilinçli olarak `TenantData.json` içindeki `CustomComponents` bloğuyla aynıdır. `DataSources` sütunu tasarımcı dokümanından türetilir (`CustomComponentDataSourceResolver`): Data sekmesindeki her endpoint `method + path` ile CRUD endpoint kataloğunda aranır, eşleşenler `EntityName` + `crud/{EntityName}.json` referansını taşır, elle yazılmış olanlar listede kalır ama bu alanları boş gelir. Aynı çözüm hem kaydetmede (katalog veritabanından) hem seed'de (katalog `crud/*.json` dosyalarından) kullanıldığı için sütun iki yolda da aynı üretilir. **Toolbox.** Kanvasa bırakılabilecekler beş aileye ayrılır: | Aile | İçerik | | --- | --- | | `layout` | `PageContainer`, `FlexRow` (kolon sayısı, ilk kolon genişliği, hizalama, gap, wrap), `Spacer` | | `data` | `Form` — ASP.NET'in Form + FormView karşılığı; dört CRUD endpoint'ini sahiplenen kapsayıcı | | `platform` | `ListView`, `DataGridView`, `TreeView`, `GanttView`, `TodoBoard`, `CardView`, `SchedulerView`, `PivotView`, `ChartView` — hepsi `listFormCode` ile bir ListForm ekranını gömer | | `html` / `ui` | Ham HTML etiketleri ve `components/ui` tasarım sistemi bileşenleri (sözleşmeleri metadata'dan okunur) | | `custom` | Başka custom component'ler (bağımlılık olarak kaydedilir) | **Form bileşeni.** `selectEndpoint` / `insertEndpoint` / `updateEndpoint` / `deleteEndpoint`, `keyFieldName`, `collectionPath`, `keySource` + `keyParamName`, `previewKeyValue`, `autoLoad`, `showToolbar`, `columnCount`, `gap` özellikleriyle yapılandırılır. İçine bırakılan her bileşen Select sonucunun bir kolonuna bağlanır ve Save/Delete üzerinden geri yazar. **Veri bağlama.** `DesignerBinding` bir kaynağa (`sourceId`) ve yola (`path`) bağlanır; `labelPath` / `valuePath` seçim bileşenleri içindir. `columns` ile ekranda görünmeyen ek sütunlar da taşınır ve script'ten `refs..getColumn('sutun')` ile okunup başka bir bileşenin değerine ya da Form kaydına yazılır. Filtreler CrudEndpoint `GetList` sözleşmesine göre üretilir: `eq` çıplak query parametresi (`?RoleId=…`), diğerleri son ek taşır (`?Name.contains=…`). Operatörler: `eq`, `ne`, `contains`, `startswith`, `endswith`, `gt`, `gte`, `lt`, `lte`, `in`, `isnull`, `notnull`. **Yetki modeli.** İki katmanlıdır: - **Node görünürlüğü** — `designerPermission` prop'u dolu olan bir düğüm, yetki verilmemişse render edilmez. - **Form komutları** — her komut (`selectPermission`, `insertPermission`, `updatePermission`, `deletePermission`) ya serbesttir (boş) ya da bir yetkiye bağlıdır. `Otomatik` modda temel, Wizard'ın bu bileşen için ürettiği okuma yetkisidir (menü kaydının korunduğu yetkinin aynısı) ve komutlara `''` / `.Create` / `.Update` / `.Delete` son ekleri eklenir. `Özel` modda yetki adı elle yazılır. **Script.** Tasarımcı, ListForm Editor Script ile aynı ortak dialog'u kullanır (`designerScriptDialect.ts` + `designerScriptRecipes.ts`); tarif grupları bileşen erişimi, API çağrıları, form ve olay/sayfa başlıkları altında toplanır. **Diğer notlar.** `PlatformIcon` tasarımcı dokümanındaki ikon adını çözer; `selectComponents.ts` `Select.componentAs` için saklanan adı (`ReactSelect`, `CreatableSelect`, `AsyncSelect`) gerçek bileşene çevirir — kanvas ve üretilen bileşenin aynı adı aynı şekilde yorumlamasını sağlayan tek nokta budur. Yeni bileşen `configs/seeds/host/custom/NewComponent.json` şablonundan başlar. **Dinamik servis yaşam döngüsü:** `DynamicServiceCompiler` kodu derler → `DynamicAssemblyRegistrationService` assembly'yi tenant bağlamıyla kaydeder → `ActionDescriptorChangeProvider` MVC'ye route tablosunun değiştiğini bildirir → `DynamicControllerActivator` bağımlılıkları enjekte eder. Uygulama yeniden başlatılmaz. --- ## 9. Dinamik Menü, Route ve Yetki Modeli ``` Permission (ABP) ──┐ ├──► Menu.RequiredPermissionName ──► menüde görünürlük Route.Authority ──┘ └► PermissionGuard ile erişim ``` - **Route** (`Entities/Tenant/Administration/Route.cs`): `Key`, `Path`, `ComponentType`, `ComponentPath`, `RouteType` (`public` / `protected`), `Authority[]`. - **Menu** (`Menu.cs`): `Code`, `ParentCode`, `DisplayName`, `Url`, `Icon`, `Order`, `RequiredPermissionName`, `Target`, `IsDisabled`, ayrıca `UserId` / `RoleId` / `CultureName` ile kullanıcı, rol ve dil bazlı menü varyantları. - **Menü yöneticisi** (`/admin/menuManager`): sürükle-bırak ağaç ile menü düzenleme. - Frontend'de `dynamicRoutesContext` route'ları çeker, `dynamicRouteLoader` bunları fiziksel view'lara veya runtime derlenmiş Custom Component'lere eşler, `DynamicRouter` React Router ağacını kurar; her korumalı route `ProtectedRoute` + `PermissionGuard` ile sarılır. **Yetki kodları** `PlatformConsts.AppCodes` içinde merkezî olarak tanımlıdır ve `PermissionsData.json` ile seed edilir. Ana gruplar: `App.Saas`, `App.Branches`, `App.Intranet.*`, `App.Definitions.*`, `App.Restrictions.*`, `App.Languages.*`, `App.Listforms.*`, `App.Notifications.*`, `App.BackgroundWorkers.*`, `App.Menus.*`, `App.DeveloperKit.*`, `App.SqlQueryManager.*`, `App.Orders.*`, `App.BlogManagement.*`, `App.IdentityManagement.*`, `App.Reports.*`, `App.Administration`, `App.Setting`, `App.Setup.Migrate`. Aksiyon yetkisi olan alt gruplar (UI tarafındaki karşılıkları `constants/permission.constant.ts` içindedir; oradaki kontroller yalnızca butonları gizler, asıl kontrol AppService'lerdedir): | Grup | Alt yetkiler | | --- | --- | | `App.Listforms.Wizard` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import` | | `App.DeveloperKit.Components` | `.Create`, `.Update`, `.Delete` | | `App.DeveloperKit.CustomEndpoints` | `.Get`, `.Post`, `.Put`, `.Remove` (dispatcher üzerinden çağrı kapısı; endpoint bazlı User/Role/Global kuralları bunun üstünde denetlenir) | | `App.DeveloperKit.DynamicServices` | `.Create`, `.Edit`, `.Delete`, `.Manage`, `.TestCompile`, `.Publish`, `.ViewCode` | | `App.SqlQueryManager` | `.CrudEndpoints` | | `App.Setup.Migrate` | Migration + seed tetikleme (host tarafı) | | `App.{Home,About,Services,Contact}.Design` | Public site sayfa tasarım modu (`?design=1`) | > **Kural:** Yetki sözleşmesi olmayan menü/route önerilmez ve eklenmez. --- ## 10. Modül Kataloğu ### 10.1. Backend modülleri (`api/modules`) | Modül | Kapsam | | --- | --- | | **Sozsoft.Languages** | Dil tanımları, dil anahtarları, çeviri metinleri; tenant bazlı lokalizasyon (`TenantLocalizationMiddleware`). | | **Sozsoft.Settings** | Ayar tanımları, sağlayıcılar, şifreleme bayrakları ve ayar ekranı metadata'sı. | | **Sozsoft.Notifications** | Bildirim tipleri, kuralları ve kullanıcı bildirimleri; kanal bazlı yönlendirme. | | **Sozsoft.MailQueue** | Şablon (Scriban) tabanlı gövde üretimi, ek dosya yaşam döngüsü, kuyruk çalıştırma ve günlükleme. | | **Sozsoft.Sender** | Amazon SES (mail), Posta Güvercini (SMS), WhatsApp Cloud API, Rocket.Chat göndericileri. | | **Sozsoft.SqlQueryManager** | SQL nesne yönetimi, sorgu çalıştırma, tablo/kolon metadata'sı. | ### 10.2. Uygulama servisleri (`api/src/Sozsoft.Platform.Application`) `AiBots` · `AuditLogs` · `BackgroundWorker` · `Blog` · `Branch` · `Dashboard` · `DataSource` · `DeveloperKit` · `FileManagement` · `Forum` · `GlobalSearch` · `Hr` · `Identity` · `Intranet` · `ListForms` (+ `Administration`) · `Menu` · `Messenger` · `Note` · `OrgChart` · `OrganizationUnits` · `Public` · `Routes` · `Tenants` · `Videoroom` ### 10.3. Yönetim ekranları (UI) | Alan | Route | Açıklama | | --- | --- | --- | | Dashboard | `/admin/dashboard` | Widget tabanlı özet ekran. | | Kullanıcı / Rol | `/admin/list/...`, `/admin/users/detail/:userId` | Kullanıcı, rol ve permission atamaları. | | Organizasyon birimleri | `/admin/ous` | OU ağacı ve üyelik yönetimi. | | Tenant yönetimi | ListForm ekranları | Tenant kayıtları, bağlantı dizeleri, siparişten otomatik tenant açma. | | Ayarlar | `/admin/settings` | Sistem ve entegrasyon ayarları. | | Menü yöneticisi | `/admin/menuManager` | Menü ağacı düzenleme. | | Dosya yöneticisi | `/admin/files` | Klasör/dosya işlemleri. | | Aktivite ve denetim kaydı | `/admin/activityLog`, `/admin/changeLog` | Kullanıcı hareketleri ve ABP audit log detayı. | | Bildirimler | `/admin/profile/notification-settings`, bildirim ekranları | Kanal tercihleri ve bildirim oluşturma. | | Forum | `/admin/forum`, `/admin/forumManagement` | Forum kullanımı ve yönetimi. | | Intranet | Intranet dashboard ve widget'ları | Duyuru, anket, sosyal duvar, etkinlik. Hangi widget'ın hangi kolonda, hangi sırada ve hangi yetkiyle yayınlandığı `Adm_T_IntranetWidget` kaydından gelir; kayıtlar `configs/seeds/{kapsam}/data/App.DeveloperKit.IntranetWidgets.json` ile senkron tutulur. | | Video oda | `/admin/videoroom/*` | Oda listesi, detay, planlama, katılımcı ve ekran paylaşımı. | | Raporlar | `/admin/reports/:report/view|design/...` | DevExpress rapor görüntüleyici ve tasarımcı. | | AI asistanı | `/admin/ai` | n8n webhook üzerinden sohbet arayüzü. | | Profil | `/admin/profile/*` | Genel bilgiler, şifre, bildirim ayarları. | ### 10.4. Public site `/home` · `/about` · `/services` · `/products` · `/checkout` · `/payment` · `/success` · `/blog` · `/blog/:id` · `/demo` · `/contact` — içerikler veritabanından yönetilir; `/about/designer` ve `/services/designer` sayfa tasarımcılarıdır. --- ## 11. Kimlik, Oturum ve Güvenlik ### 11.1. Kimlik doğrulama - **OpenIddict** password + refresh token akışı. Token uç noktası: `POST /connect/token` (`grant_type=password`, `client_id=Platform_PublicApi`, `scope=offline_access Platform`). - Token ömürleri `OpenIddict:TokenLifetimes` ile yapılandırılır (varsayılan 60 dk access, 90 dk refresh). - Swagger için ayrı istemci: `AuthServer:SwaggerClientId`. - İki aşamalı doğrulama (2FA) ve hesap doğrulama (e-posta/telefon) desteklenir. - Kayıt ve iletişim formlarında Cloudflare Turnstile tabanlı captcha (`CaptchaMiddleware`). ### 11.2. Oturum yönetimi - `PlatformSessionValidationMiddleware` her istekte oturumun hâlâ geçerli olduğunu doğrular. - `PlatformSessionRevocationHandler` token iptalinde oturumu sonlandırır. - `PlatformSessionCleanupWorker` süresi dolmuş oturumları temizler. - Eş zamanlı kullanıcı limiti aşıldığında giriş reddedilir. ### 11.3. Giriş engelleri `UserCannotSignInErrors` altında tanımlı, kullanıcıya lokalize mesajla dönen durumlar: | Kod | Anlamı | | --- | --- | | `LoginNotAllowed_NotVerified` | Hesap doğrulanmamış. | | `LoginNotAllowed_NotAllowedIp` | IP kısıtlaması (`IpRestriction`). | | `LoginNotAllowed_WorkHour` | Çalışma saati kısıtlaması (`WorkHour`). | | `LoginNotAllowed_LoginEndDateDue` | Kullanıcının giriş yetki süresi dolmuş. | | `ShouldChangePasswordOnNextLogin` / `ShouldChangePasswordPeriodic` | Zorunlu şifre değişimi. | | `LoginNotAllowed_TenantIsPassive` / `TenantNotFound` | Tenant pasif veya bulunamadı. | | `LoginNotAllowed_BranchLimit` | Şube lisans limiti aşıldı. | | `LoginNotAllowed_ConcurrentUserLimit` | Eş zamanlı kullanıcı limiti aşıldı. | ### 11.4. Güvenlik kuralları - Tüm katmanlarda RBAC ve yetki tabanlı görünürlük zorunludur. - Dinamik SQL'de **yalnızca parametreli** desenler kullanılır; kullanıcı girdisi string birleştirme ile sorguya eklenmez. - Her sorgu ve eylemde tenant izolasyonu korunur (`IsTenant`, `IsBranch`, `IsOrganizationUnit` bayrakları ve ABP tenant filtreleri). - Gerçek kimlik bilgileri, token ve anahtarlar örneklerde/dokümanda yer almaz; yer tutucu kullanılır. - Denetim: kritik işlemler ABP Audit Log'a yazılır; yüksek frekanslı `list-form-customization` çağrıları denetim dışı bırakılmıştır. --- ## 12. Çok Kiracılılık (Multi-Tenancy) - `PlatformConsts.IsMultiTenant = true`. - Tenant çözümleme host adı (subdomain) ve ABP tenant resolver'ları ile yapılır (`utils/subdomain.ts`). - **Tenant başına ayrı veritabanı:** `TenantConnectionString` kayıtları ile her tenant kendi veritabanına yönlendirilebilir; migration'lar `DatabaseMigrationEventHandlerBase` üzerinden tenant oluşturulduğunda otomatik uygulanır. - **Şube (Branch):** Tenant altındaki fiziksel/örgütsel kırılım; kullanıcı–şube eşlemesi `BranchUsers` ile tutulur, lisans limiti girişte kontrol edilir. - **Organizasyon birimi:** ABP `OrganizationUnit` ağacı; ListForm'lar OU bazlı filtrelenebilir. - Tenant bazlı lokalizasyon: `TenantLocalizationInitializer` + `TenantLocalizationMiddleware`. --- ## 13. Bildirim ve Entegrasyonlar ### 13.1. Kanallar `Sms` · `Mail` · `Rocket` · `Desktop` · `UiActivity` · `UiToast` · `WhatsApp` (`Telegram` altyapıda tanımlı, UI'da kapalı) ### 13.2. Yönlendirme modeli Bildirim **tip + kanal** eşleşmesiyle yönlendirilir. Alıcı hedefleme seçenekleri: `All`, `User`, `Role`, `OrganizationUnit`, `Custom`. Kullanıcılar kendi bildirim tercihlerini `/admin/profile/notification-settings` üzerinden kanal bazında yönetir. ### 13.3. Göndericiler (`Sozsoft.Sender`) | Kanal | Sağlayıcı | | --- | --- | | E-posta | ABP Emailing + Amazon SES (`AmazonSesEmailSender`), arka plan iş kuyruğu ile | | SMS | Posta Güvercini HTTP API | | WhatsApp | WhatsApp Cloud API (şablon tabanlı) | | Rocket.Chat | Rocket.Chat HTTP API | Tüm sağlayıcı kimlik bilgileri ayar ekranından yönetilir (`App.Settings.*` anahtarları); koda gömülmez. ### 13.4. Mail kuyruğu `Sozsoft.MailQueue`; şablondan gövde üretir, PDF/XLS/TXT çıktıları ve ek dosyaları yönetir, kuyruğu arka plan işçisiyle çalıştırır ve sonuçları günlükler. ### 13.5. AI entegrasyonu `AiBot` kayıtları tenant bazlıdır; n8n webhook üzerinden LangChain ajanı + bellek penceresi ve Gemini sohbet modeli bağlanır (`configs/ai/Chat.json`). UI tarafında `/admin/ai` ve header'daki asistan bileşeni bu uç noktayı kullanır. --- ## 14. Arka Plan İşleri İki motor birlikte kullanılır: **Hangfire** (kalıcı iş deposu, `default` ve `platform` kuyrukları) ve **ABP Background Workers** (yinelenen işler). Yönetim `/admin` altındaki Background Worker ekranlarından yapılır; yetkiler `App.BackgroundWorkers.RecurringJobs` ve `.Jobs`. | Worker tipi | İşlevi | | --- | --- | | `MailQueueWorker` | Mail kuyruğunu işler. | | `SqlWorker` | Zamanlanmış SQL çalıştırır. | | `NotificationWorker` | Bildirim kurallarını değerlendirir ve gönderir. | | `SessionCleanupWorker` | Süresi dolmuş oturumları temizler. | | `BackupWorker` | Veritabanı yedeği alır ve eski yedekleri temizler. | Hangfire panosu geliştirmede serbest, üretimde `AbpHangfireAuthorizationFilter` ile korumalıdır (`/hangfire`). --- ## 15. Raporlama - **DevExpress Reporting**: Web Document Viewer (`/admin/reports/:report/view/...`) ve Report Designer (`/admin/reports/:report/design/...`). - **Rapor deposu**: `ReportTemplate` ve `ReportCategory` varlıkları; `CustomReportStorageWebExtension` ile veritabanı üzerinden okuma/yazma. - **Dinamik raporlar** (`HttpApi.Host/PredefinedReports`): ListForm tanımından otomatik üretilen grid, form ve ağaç raporları — grid durumunu (sütun sırası, gruplama, filtre) rapora yansıtır. - Linux konteynerlerde font sorunlarını önlemek için `DevExpressFontConfiguration` devrededir. --- ## 16. Dosya Yönetimi ve CDN - ABP BlobStoring, dosya sistemi sağlayıcısıyla `App:CdnPath` altına yazar; dosyalar `App:CdnUrl` üzerinden servis edilir. - `FileManagementAppService`: listeleme, yükleme, indirme, kopyalama, taşıma, yeniden adlandırma, silme. - UI: `/admin/files` (`views/admin/files/FileManager.tsx`) — breadcrumb, çoklu yükleme, önizleme. - Avatar, aktivite görselleri, içe aktarma dosyaları ve veritabanı yedekleri ayrı konteynerlerde tutulur. --- ## 17. Gerçek Zamanlı Özellikler - **Messenger**: SignalR hub'ı `/messengerhub`. Konuşma ve mesaj varlıkları veritabanında; Redis etkinse backplane olarak kullanılır. Query string ile gelen `access_token`, hub bağlantısı için `Authorization` başlığına çevrilir. - **Video oda**: Oda oluşturma/başlatma/bitirme, katılımcı yönetimi, sohbet, doküman ve ekran paylaşımı panelleri; TURN sunucusu `configs/deployment/configs/turnserver.conf` ile yapılandırılır. - **Global arama**: `GlobalSearchAppService` üzerinden çapraz modül arama. --- ## 18. Frontend Mimarisi ### 18.1. Route ve bileşen çözümü ``` Route kayıtları (DB) ├─ componentPath ──► fiziksel view (React.lazy) └─ CustomComponent ──► @babel/standalone ile runtime derleme ──► ComponentContext │ DynamicRouter ──► ProtectedRoute ──► PermissionGuard ──► PageContainer ``` `ROUTES_ENUM` (`src/routes/route.constant.ts`) statik yol sözleşmelerini tutar; iş modülleri için (`supplychain`, `maintenance`, `warehouse`, `projects`, `hr`, `crm`, `mrp`, `accounting`) ayrılmış yol desenleri de buradadır. Bu alanların ekranları, fiziksel React sayfaları yerine ListForm konfigürasyonu ile üretilir. ### 18.2. Durum yönetimi - **easy-peasy** global store: `auth`, `theme`, `locale`, `abpConfig`, `admin`, `client`, `base`. Oturum ve tercih verileri `localStorage` yerine store üzerinden yönetilir (`stateSync.ts`). - **React Query**: sunucu verisi önbellekleme. - **Context'ler**: `ComponentContext` (runtime bileşen kaydı), `DialogContext`, `ScrollContext`. ### 18.3. Tema ve lokalizasyon - Tailwind tabanlı tasarım sistemi (`components/ui`) + DevExtreme temaları; açık/koyu mod ve tema yapılandırıcı (`ThemeConfigurator`). - **Varsayılan mod koyudur.** `proxy/theme/theme.config.ts`: `mode` ve `navMode` `dark`, DevExtreme stili `dx.material.blue.dark.compact`. Kullanıcı tercihi store üzerinden saklanır; bu yalnızca ilk açılış varsayılanıdır. - Dil metinleri veritabanından gelir (`Sozsoft.Languages`); dil seçici header'dadır. Tenant bazlı çeviri geçersiz kılma desteklenir. - Layout seçenekleri: dikey menü, yatay menü, yığılmış yan menü, mobil navigasyon. ### 18.4. PWA ve sürüm yönetimi - Kurulum iki kademelidir: **kabuk** (index.html + entry JS/CSS + eager vendor chunk'ları) workbox precache manifest'inden gelir ve zorunludur; **bileşenler** (tüm lazy chunk'lar, build'de üretilen `dist/warmup.json`) güncelleme penceresinde aynı ilerleme çubuğunda arka planda indirilir. İkinci kademe best-effort'tur (inemeyen dosya kurulumu düşürmez, süre bütçesi aşılırsa kalanlar runtime cache'e kalır); böylece deploy sonrası ilk gezinmede chunk beklenmez ama yavaş bağlantıda kurulum timeout'a düşmez. DevExtreme temaları (~33 MB), font ve görseller runtime cache'tedir. - `registerType: 'prompt'` — yeni sürüm indirilir, indirme bitince otomatik devreye alınır (`views/version/swRegistration.ts`, `sw.ts`, `AppUpdateDialog.tsx`). - Isıtma yalnızca kuruluma bağlı değildir: uygulama açılışta `ENSURE_WARMUP` mesajı yollar, service worker eksik kalan bileşenleri kaldığı yerden tamamlar. - **Sürüm bilgisi backend'dedir.** `Sas_H_ChangeLog` tablosu tek kaynaktır; istemci sürüm numarasını ve son sürümün notlarını `application-configuration` yanıtındaki `extraProperties.changeLogs` alanından okur (`PlatformApplicationConfigurationContributor`), tam listeyi ise `/api/app/change-log` endpoint'inden alır. Ayrı bir `version.json` isteği yoktur. Changelog `/admin/changeLog` ekranında gösterilir; sürüm numarası son görülenden farklıysa kullanıcı giriş sonrası oraya yönlendirilir (tetikleyici bundle değil, sürümdür — yalnızca yeni bir git tag'i eklenmiş olsa da çalışır). - **Sürüm notu akışı — DbMigrator gerektirmez:** `configs/change-logs/generate-change-logs.sh` deploy sırasında (`deploy/app.sh`) git tag'lerinden `configs/change-logs/change-logs.json` üretir, dosya API konteynerine `/etc/api/change-logs` altına salt okunur mount edilir ve `ChangeLogStartupService` uygulama açılışında tabloyu bu dosyayla eşitler. Dosya imaja **gömülmez**: api build context'i içindeyken her yeni tag Dockerfile'daki `COPY . .` katmanını geçersiz kılıp imajı gereksiz yere yeniden derletiyordu; artık kod değişmediyse imaj cache'ten gelir. Yeni sürüm için tag atıp deploy etmek yeterlidir. Notlar **annotated** tag mesajından okunur (`git tag -a 1.2.0 -m "..."`), her satır bir madde. - **Tablo git tag listesinin aynasıdır:** yeni tag eklenir, mesajı düzeltilen tag güncellenir, git'ten silinen tag tablodan da (hard delete ile) kaldırılır. Bu yüzden `Sas_H_ChangeLog` elle düzenlenmemelidir — ilk deploy'da geri alınır. Dosya okunamaz veya boşsa senkronizasyon hiçbir şey yapmaz, tablo boşaltılmaz. - Deploy algılaması service worker'ın kendi `registration.update()` kontrolüne dayanır: herhangi bir chunk değiştiğinde entry hash'i, dolayısıyla index.html ve `sw.js` içindeki precache manifest'i de değişir. --- ## 19. API ve Swagger - Swagger UI, API kökünde yayınlanır; OAuth2 ile "Authorize" düğmesi üzerinden token alınabilir. - Endpoint'ler ABP **conventional controller** mekanizmasıyla uygulama servislerinden üretilir: | Namespace | Kök yol | | --- | --- | | `Sozsoft.Platform.ListForms.Administration` | `/api/admin/...` | | Diğer `Sozsoft.Platform.*` servisleri | `/api/app/...` | | Modül servisleri (Languages, Settings, MailQueue, Notifications, SqlQueryManager) | Modül kendi kök yolunu kullanır | - DevExpress raporlama controller'ları (`CustomReportDesigner`, `CustomWebDocumentViewer`, `QueryBuilder`) Swagger dokümanından hariç tutulur. - Yanıtlar Brotli/Gzip ile sıkıştırılır; `X-Correlation-Id` başlığı istemciye açılır. - Hata kodları: `PlatformConsts.AppErrorCodes` (`Error:0001` yetkisiz, `App.NoResults` kayıt yok, `Error:0003` parametre geçersiz, `Error:0005` iç hata). **Token örneği** (yer tutucularla): ```http POST /connect/token HTTP/1.1 Content-Type: application/x-www-form-urlencoded grant_type=password &username= &password= &client_id=Platform_PublicApi &scope=offline_access%20Platform ``` --- ## 20. Dağıtım (Deployment) `configs/deployment` altında üç ortam için compose dosyaları ve numaralandırılmış scriptler bulunur. | Dosya | Amaç | | --- | --- | | `docker-compose-data.yml` | Redis, SQL Server / PostgreSQL, yedek volume'ları | | `docker-compose-app.yml` / `.dev.yml` / `.production.yml` | API, UI, migrator, nginx | | `docker-compose-devops.yml` | Forgejo + runner (CI/CD) | | `Dockerfile`, `api/*.Dockerfile`, `ui/Sozsoft.Platform.Ui.Dockerfile` | İmaj tanımları | | `configs/nginx.conf`, `redis.conf`, `turnserver.conf`, `elasticsearch.yml` | Servis yapılandırmaları | Script sırası (`configs/deployment/scripts`): ``` 1-devops.sh → DevOps makinesi (Forgejo, runner) 2-data-postgres.sh / 3-data-sql.sh → Veri katmanı 4-production-build.sh → İmaj build 5-production-deploy.sh → Yayın 6-production-migrator-true.sh → Migration çalıştırma 7-setup_ssl.sh → Sertifika 8-dev-build.sh / 9-dev-deploy.sh / 10-dev-migrator-true.sh → Dev ortamı ``` Migrator servisi `SEED` ortam değişkeni ile çalışır ve compose dosyasında `SEED=${SEED:-true}` olarak tanımlıdır: değişken verilmezse seed **çalışır**. Seed dosyaları imaja gömülmez; depodaki `configs/seeds` klasöründen mount edilir (`App:SeedsPath`), böylece bir seed değiştiğinde imaj build etmek gerekmez. Ayrıntılı kurulum notları: [`configs/deployment/README.md`](configs/deployment/README.md), [`Readme_Production.md`](configs/deployment/Readme_Production.md), [`Readme_Devops.md`](configs/deployment/Readme_Devops.md). > Bu dokümanlarda geçmişte örnek amaçlı bırakılmış kimlik bilgileri bulunabilir; üretimde > tümü döndürülmeli ve secret yöneticisine taşınmalıdır. --- ## 21. Geliştirme Standartları ve Sık Kullanılan Komutlar ### 21.1. Çözüm kuralları 1. Her istek şu sırayla değerlendirilir: **(1)** ListForm konfigürasyonu → **(2)** SQL Query Manager + Custom Endpoint → **(3)** Dynamic Service → **(4)** kod değişikliği (son çare, gerekçe zorunlu). 2. Standart iş ihtiyaçları için yeni özel React sayfası/bileşeni geliştirilmez. 3. Her öneri tenant ve yetki tasarımını içerir. 4. Platform yetkilendirme desenleri atlanmaz. 5. Secret, tenant id veya bağlantı dizesi koda gömülmez. ### 21.2. Frontend ```powershell cd ui npm start # geliştirme sunucusu npm run build # üretim derlemesi (metadata + version + vite build) npm run lint # ESLint npm run format # prettier --write + eslint --fix ``` ### 21.3. Backend ```powershell cd api dotnet build dotnet run --project src/Sozsoft.Platform.HttpApi.Host dotnet format --include .\modules\Sozsoft.Notifications\ --folder # Kod standardı kapısı (ölü kod / stil analizörleri) dotnet build Sozsoft.Platform.sln --no-incremental ` -p:EnforceCodeStyleInBuild=true -p:GenerateDocumentationFile=true dotnet format Sozsoft.Platform.sln --diagnostics IDE0005,IDE0161 --severity warn # Migration (EntityFrameworkCore projesi içinde) dotnet ef migrations add dotnet ef database update dotnet ef migrations remove ``` .NET/ABP kod standardı (hedef sürümler, nullable politikası, ölü kod kuralları, modern C# kullanımı, ABP katman sınırları) bağlayıcı olarak [`.github/instructions/dotnet.instructions.md`](.github/instructions/dotnet.instructions.md) dosyasındadır. Standart derlemede zorlanır: `api/Directory.Build.props` analizörleri açar, `api/.editorconfig` kural şiddetlerini tanımlar; bu iki dosya standardın tek kaynağıdır. Yeni ABP modülü eklemek için: `abp new Sozsoft. -t module --no-ui -m none --database-provider ef` ### 21.4. Seed dosyaları İki ayrı seed yüzeyi vardır ve karıştırılmamalıdır. **1. Depo içi (kod ile taşınan) seed'ler** — `api/src/Sozsoft.Platform.DbMigrator/Migrations/`. Platformun kendi ekranları, menüleri, yetkileri ve dil metinleri buradadır; değişiklikleri derlenip yayınlanır. Yeni bir modülün nasıl kurulacağını öğrenmek için başvurulacak dosyalar: - `ListFormSeeder_Saas.cs`, `ListFormSeeder_Administration.cs` — ListForm + alan tanımları - `MenusData.json` — `Routes`, `Modules`, `Menus` - `PermissionsData.json` — yetki grupları ve tanımları - `HostData.json` — ayar/entegrasyon değerleri - `LanguagesData.json` — dil anahtarları (EN/TR) - `WizardDataSeeder.cs`, `CustomComponentDataSeeder.cs`, `CrudDataSeeder.cs` — aşağıdaki runtime seed dosyalarını okuyup uygulayan seeder'lar **2. Runtime'da üretilen seed'ler** — `configs/seeds/`. Wizard, Component Manager ve CRUD Endpoint Manager çalışma zamanında burayı yazar; veritabanı silinip yeniden oluşturulduğunda aynı dosyalar geri yüklenir. Kapsam klasörü CDN düzeniyle aynıdır ve `SeedPathResolver` üzerinden çözülür: ``` configs/seeds/ ├── host/ # host kapsamı │ ├── wizard/ # {Ad}.json → WizardDataSeeder │ ├── custom/ # {ComponentName}.json → CustomComponentDataSeeder │ ├── crud/ # {EntityName}.json → CrudDataSeeder │ ├── sql/{object,execute}/ # .sql (SQL Server) │ └── postgres/{object,execute}/ ├── tenants/{tenantId}/… # aynı düzen, tenant kapsamı └── .imports/{importId}/ # wizard import staging + backup (seeder taramalarına girmez) ``` > Bu dosyalar elle de düzenlenebilir; ilgili ekrandan tekrar kaydedildiğinde yeniden üretilirler. > Wizard dosyası `EditFileName` ile güncellenirse sunucu önce eski dosyayı ve ürettiği kayıtları > siler, sonra yenisini üretir. Wizard'ın ürettiği ekran **ListForm detayından** düzenlendiğinde > de aynı dosya güncellenir (`WizardSeedSynchronizer`): `ListForm`/`Fields` bölümleri ve > `Wizard` bölümündeki karşılıkları veritabanındaki güncel haliyle değiştirilir. --- ## 22. Sorun Giderme | Belirti | Olası neden ve çözüm | | --- | --- | | `/api/abp/application-configuration` 503 dönüyor | Veritabanına erişilemiyor. Bağlantı dizesini ve veri konteynerini kontrol edin; `/api/setup/application-status` ile durumu görün. | | UI `/setup` ekranına düşüyor | Şema oluşmamış veya bekleyen migration var. Setup ekranından migration'ı tetikleyin ya da DbMigrator'ı çalıştırın. | | Giriş "UserCannotSignIn..." hatası veriyor | [11.3](#113-giriş-engelleri) tablosuna bakın: IP, çalışma saati, doğrulama, şube/eş zamanlı kullanıcı limiti. | | Yeni sürüm tarayıcıda görünmüyor | Service worker `prompt` modundadır; güncelleme bildirimini onaylayın veya sekmeyi tamamen kapatıp açın. | | DevExtreme teması yüklenmiyor | `public/css` altındaki tema dosyaları runtime cache'tedir (StaleWhileRevalidate); hard refresh yeterlidir. | | Hangfire başlangıçta hata veriyor | Bağlantı dizesi boşsa Hangfire kaydı atlanır ama ABP modülleri yüklenir. Bağlantı dizesini doğrulayın. | | Dinamik servis yayınlanmıyor | Önce `TestCompile` çalıştırın; derleme hatası mesajı UI'da döner. `Publish` için ilgili yetki gerekir. | | Raporlarda font/karakter bozukluğu (Linux) | `DevExpressFontConfiguration.InstallLinuxFonts` loglarını kontrol edin; konteynerde font paketi eksik olabilir. | --- ## 23. Bilinen Sınırlar ve Notlar - `route.constant.ts` içindeki `supplychain`, `maintenance`, `warehouse`, `projects`, `crm`, `mrp`, `accounting` ve `hr` yol sabitleri **yol sözleşmesidir**; bu alanların ekranları fiziksel React sayfaları olarak değil, ListForm konfigürasyonu ile üretilir. `hr` altında yalnızca organizasyon şeması (`OrgChart.tsx`) fiziksel bir view'dır. - `Telegram` bildirim kanalı altyapıda tanımlıdır ancak UI'da kapalıdır. - Depodaki `appsettings*.json` ve deployment dokümanları geliştirme değerleri/örnek kimlik bilgileri içerir; üretim öncesi tümü değiştirilmelidir. - SQL View Designer tek yönlüdür (model → T-SQL). Elle yazılmış ya da tasarımcının kanonik şekline uymayan bir view tanımı geri okunamaz; dialog ham SQL moduna düşer. - `api/test/Sozsoft.Platform.EntityFrameworkCore.Tests` şu an SQLite şema oluşturmada (`nvarchar(max)` → `SQLite Error 1`) kırıktır; bu kırıklık kod standardından önce de vardı ve ayrı bir iş olarak ele alınmalıdır. - Rol–yetki eşleşmeleri veritabanında müşteri ortamına göre değişir; buradaki yetki kodları tanımın kendisidir, atama değil. --- ## Lisans ve Sahiplik Bu depo Sozsoft'a aittir. DevExpress/DevExtreme bileşenleri ticari lisans gerektirir (`api/DevExpress_License.txt`).