1481 lines
95 KiB
Markdown
1481 lines
95 KiB
Markdown
# 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** | Menüsü ve sayfaları veritabanından yönetilen ziyaretçi sitesi: sayfalar Custom Component, menü `Pub` modülü (bkz. §10.4). Ürün/ödeme ve demo akışları fiziksel sayfalardır. |
|
||
| **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/`, `wizard/`, `data/`, `sql/`, `postgres/` klasörleri bulunur:
|
||
|
||
```
|
||
configs/seeds/
|
||
host/
|
||
crud/ wizard/ data/
|
||
sql/ { object/ execute/ }
|
||
postgres/ { object/ execute/ }
|
||
tenants/
|
||
{tenantId}/
|
||
crud/ 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ı `ICrudEndpointSeedApplier` üzerinden uygular. Politika **damga karşılaştırmalıdır**: eksik endpoint her zaman eklenir, mevcut bir kayıt yalnızca dosyanın `GeneratedAt` damgası kaydın `LastModificationTime`/`CreationTime` değerinden **yeniyse** güncellenir ya da silinir; aksi halde kayıt korunur ve log'a drift uyarısı düşer. Böylece CRUD Endpoint Manager'dan yapılan bir revizyon depodan gelen eski bir dosya yüzünden migrate sırasında geri alınmaz. Damgası olmayan (eski biçimde yazılmış) dosya hiçbir zaman yeni sayılmaz. |
|
||
| `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. Aynı uygulayıcı wizard import'unun kapanışında da (`CompleteImport`) yalnızca o import'ta yazılan dosyalar için, `overwriteExisting` açık olarak çalışır — orada var olan satır dosyadaki değerlerle güncellenir. |
|
||
|
||
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. Liste, wizard'ın ilk deploy damgasına
|
||
(`Wizard.SeededAt`) göre **tersine** sıralıdır — en son üretilen ekran en üstte durur; damgası
|
||
okunamayan dosyalar sona düşer. Butonlar `App.Listforms.Wizard.*` yetkileriyle gizlenir; asıl
|
||
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.
|
||
|
||
Toplama **özyinelemelidir** (`WizardExportCollector`): alt formların wizard dosyaları kuyruğa
|
||
eklenir ve onların bağımlılıkları da aynı kurallarla toplanır. Böylece zip tek başına çalışır.
|
||
|
||
| Yol | İçerik |
|
||
| --- | --- |
|
||
| `wizard/{dosya}.json` | Wizard tanımının kendisi **ve** `SubFormsDto[].Code` ile bağlı alt form ekranlarının wizard dosyaları (özyinelemeli) |
|
||
| `data/App.DeveloperKit.CustomComponents.json` | Custom yolunda bağlı component ve bağımlılıkları — dosyanın yalnızca bu satırlara süzülmüş kopyası |
|
||
| `data/{ListFormCode}.json` | Ekranın `SeedFilePath` değeri doluysa kendi veri aynası |
|
||
| `crud/{entity}.json` | Component'lerin/nesnenin kullandığı CRUD endpoint tanımları |
|
||
| `{sql\|postgres}/{object\|execute}/{nesne}.sql` | `SelectCommand`'a karşılık gelen SQL nesnesi, lookup sorgularının (`LookupDto.LookupQuery`) `FROM`/`JOIN` ile işaret ettiği nesneler ve Custom yolunda CRUD endpoint'lerinin dayandığı tablolar |
|
||
|
||
Script dosyaları sabit bir sağlayıcı/klasör kombinasyonundan **tahmin edilmez**: kapsam kökündeki
|
||
script klasörleri (`sql/object`, `postgres/execute` …) diskten taranır ve nesne adıyla eşleşen her
|
||
dosya arşive girer. Yeni bir sağlayıcı ya da script klasörü eklendiğinde toplayıcı değişmez.
|
||
|
||
Script bulunamaması **uyarı üretmez**: her tablo seed ile yönetilmez — ABP'nin kendi tabloları
|
||
(`AbpUsers`, `AbpRoles` …) EF migration'larıyla kurulur ve seed script'leri yoktur. "Bu tablo
|
||
hedefte var mı" sorusunun tek doğru cevabı hedef veritabanındadır; kararı import analizi verir,
|
||
export varsayımda bulunmaz.
|
||
|
||
Çözülemeyen bir **kayıtlı referans** (seed dosyasında adı geçen ama karşılığı bulunmayan alt form,
|
||
`SeedFilePath` veri aynası, `DataSources[].SeedFile` CRUD dosyası, custom component satırı)
|
||
indirmeyi engellemez ama sessiz de kalmaz: `ExportAnalysis` ucu indirmeden önce arşivin tam
|
||
içeriğini ve eksikleri döndürür, Wizard File Manager eksik varsa önce bu listeyi gösterir.
|
||
|
||
**İçe aktarma dört adımlı bir sihirbazdır** (`WizardImportDialog`, `Steps` bileşeni):
|
||
|
||
| Adım | İçerik | Geçiş koşulu |
|
||
| --- | --- | --- |
|
||
| **Dosyalar** | Zip girdileri ve durumları; çakışanlar Monaco `DiffEditor` ile çözülür | Çözülmemiş çakışma kalmamalı |
|
||
| **Kontroller** | Analiz bulguları ve zip'te atlanan girdiler. Engelleyiciler iki başlıkta ayrılır — **arşiv eksik ya da bozuk** (burada giderilemez, kaynak ortamda export tekrarlanmalı; düzeltme düğmesi yoktur) ve **ortamda giderilebilir**. Tabloya dokunan bulgularda mevcut `SqlTableDesignerDialog` açılır — şema farkında **Tabloyu düzenle** (düzenleme modu), eksik tabloda **Tabloyu oluştur** (oluşturma modu, ad ön dolu); deploy sonrası analiz kendiliğinden yenilenir (önceki oturum bırakılır) | Engelleyici (`Error`) bulgu kalmamalı |
|
||
| **Yapılacaklar** | Onaylandığında ne olacağının tam listesi: yazılacak dosyalar, çalışacak SQL script'leri, eklenecek kolonlar (cümleleriyle), uygulanacak CRUD ve veri dosyaları, kurulacak ekranlar. Sıra sunucudaki kapanış sırasıyla aynıdır | Onay |
|
||
| **Uygulama** | Dosya dosya yazım, kapanış adımlarının sonucu | — |
|
||
|
||
Geriye dönüş her zaman serbesttir; ileri atlama bağımlılık koşullarına bağlıdır. Adım başlıklarına
|
||
tıklanarak da gezinilebilir.
|
||
|
||
İçe aktarma **toplu (batch) bir işlemdir**: engelleme oturum genelindedir, dosya bazlı değildir.
|
||
Bir tek engelleyici bulgu tüm zip'i durdurur ve o dosyanın işaretini kaldırarak aşılamaz — yarım
|
||
kurulum üretmemenin tek güvenli yolu budur. Karşılığında, tabloya dair her engel diyalogdan
|
||
çıkmadan giderilebilir (tablo tasarımcısı → deploy → analiz yenilenir). Tabloyla ilgisi olmayan
|
||
engeller (eksik alt form, eksik custom component bağımlılığı, bozuk JSON) zip'in kendisinin eksik
|
||
olduğunu gösterir; bunlar kaynakta düzeltilip yeniden export edilmelidir.
|
||
|
||
Adımların altında yatan üç sunucu işlemi şunlardır:
|
||
|
||
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.
|
||
`data/*.json` girdilerinde karşılaştırma **satır bazlıdır**: hedef dosyadan yalnızca gelen
|
||
satırların anahtarları süzülür, dosya düzeyindeki `GeneratedAt`/`Order` karşılaştırmaya girmez.
|
||
Böylece aktarılan kaydın dışındaki satırlar fark olarak görünmez; gelen satırların hiçbiri
|
||
hedefte yoksa dosya var olsa bile durum `New` (ekleme), varsa ve içerik aynıysa `Identical`
|
||
(hiç aktarılmaz), farklıysa `Conflict` (güncelleme) olur.
|
||
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.
|
||
3. **Kapanış** (`CompleteImport`) — oturum kapatılmadan önce zip'in getirdiği dosyalar
|
||
**bağımlılık sırasıyla** veritabanına uygulanır. Sıra bilinçli ve sabittir:
|
||
**(a)** `{sql|postgres}/{object,execute}/*.sql` scriptleri çalıştırılır (`object` önce) — tablo
|
||
yoksa burada oluşur, aksi halde sonraki iki adım eksik tablo yüzünden baştan düşerdi;
|
||
**(b)** hedefte eksik olan kolonlar eklenir (aşağıya bakın);
|
||
**(c)** `crud/*.json` dosyaları `ICrudEndpointSeedApplier` ile uygulanır;
|
||
**(d)** `data/*.json` dosyaları
|
||
`IListFormSeedDataApplier.ApplyFilesAsync(..., overwriteExisting: true)` ile veritabanına
|
||
uygulanır: tabloda olmayan satır eklenir, var olan satır dosyadaki değerlerle **güncellenir**
|
||
(migrate/seed akışından farkı budur — orada dosya bayat olabileceği için canlı kayda
|
||
dokunulmaz). Kayıt daha önce **soft delete** edilmişse silinme izleri de temizlenir
|
||
(`IsDeleted`, `DeletionTime`, `DeleterId`); aksi halde satır tabloda durur ama ekranın
|
||
varsayılan süzgeci (`"IsDeleted" = 'false'`) onu gizlemeye devam ederdi. Hangi kolonların
|
||
sıfırlanacağı ekranın `DeleteCommand`'ından okunur, hard delete yapan ekranda hiçbir şey
|
||
eklenmez. Hedefle **zaten aynı** olan (`Identical`) veri dosyaları da uygulanır: yazacak bir şey
|
||
yoktur ama satırlar veritabanında eksik ya da silinmiş olabilir. Kullanıcının "mevcudu koru"
|
||
dediği (farklı olup yazılmayan) dosyaya dokunulmaz. Anahtarı olmayan satır güncellenemez,
|
||
atlanır; eklenen/güncellenen/atlanan satır
|
||
sayısı dialogda raporlanır. Bu adım `RollbackImport`
|
||
kapsamında **değildir** — geri alma bu adımdan önce yapılır.
|
||
|
||
5. **Ekran tanımları** (`wizard/*.json`) — son adım: ekranın tablosu, CRUD ucu ve lookup verileri o
|
||
noktada hazırdır. Kurulum wizard ekranının kullandığı yolun aynısından geçer
|
||
(`DeployWizardAsync`), dosya ekranın üretilmiş `ListForm`/`Fields` sözleşmesini taşıdığı için
|
||
bunlar wizard cevaplarından **yeniden türetilmez** — tasarımcı üzerindeki her değişiklik olduğu
|
||
gibi kurulur. **Hedefte zaten var olan ekrana dokunulmaz.** Her ekran kendi işleminde kurulur:
|
||
bir dosyadaki hata yalnızca o ekranın kayıtlarını geri alır. İmport bittiğinde ekran çalışır
|
||
durumdadır, migrate beklemez; istemci ABP config'ini yeniler, böylece menü anında görünür.
|
||
|
||
**Analiz doğrulama da yapar** (`WizardImportValidator`). Zip'in hedef ortamda yarım bir kurulum
|
||
bırakıp bırakmayacağı dosyalar yazılmadan **önce** denetlenir; bulgular `Error`/`Warning` olarak
|
||
raporlanır ve en az bir `Error` varken import başlatılamaz — sunucu oturuma `blocked` işaret
|
||
dosyası bırakır, dolayısıyla `ApplyImport` ucu doğrudan çağrılsa bile reddeder.
|
||
|
||
| Kural | Ağırlık |
|
||
| --- | --- |
|
||
| Bozuk JSON (`wizard`, `crud`, `data`) | Error |
|
||
| Wizard bölümü ya da adı olmayan wizard dosyası; `ListForm` bölümü eksik List wizard'ı | Error |
|
||
| Ekranın tablosu (`SelectCommand`, `Table`/`View`) hedefte **yok** ve zip onu oluşturan `.sql` dosyasını **taşımıyor** | Error |
|
||
| `crud/{Entity}.json`'un tablosu hedefte yok ve zip'te oluşturan script yok | Error |
|
||
| `data/{code}.json`'un ekranı ne zip'te ne hedefte var | Error |
|
||
| Custom component'in `Dependencies` ya da `DataSources[].SeedFile` bağımlılığı ne zip'te ne hedefte var | Error |
|
||
| Custom wizard'da bileşen adı / rota yolu boş | Error |
|
||
| Alt form (`SubFormsDto[].Code`) ne zip'te ne hedefte var | Error |
|
||
| Nesne varlığı sorgulanamadı (bağlantı/izin) ve script de yok | Warning |
|
||
| Zip yalnızca karşı sağlayıcının (`sql` ↔ `postgres`) scriptlerini taşıyor | Warning |
|
||
| Ekranın `SeedFilePath` veri dosyası ne zip'te ne hedefte var; boş CRUD/veri dosyası | Warning |
|
||
| Script'in kurduğu tablo hedefte **var** ama bir kolonu eksik | Warning — kapanışta eklenir |
|
||
| Eksik kolon `NOT NULL`, varsayılanı yok ve tabloda kayıt var | Error (otomatik eklenemez) |
|
||
| Var olan kolonun uzunluk / kesinlik / ondalık / nullability değeri script'ten farklı | Error |
|
||
| Hedefte script'te olmayan fazladan kolon var | Warning (dokunulmaz) |
|
||
|
||
Eksik tablo ölçütü "veritabanında var" değil, "veritabanında var **ya da** zip onu oluşturan
|
||
scripti taşıyor"dur — kapanış scriptleri veri satırlarından önce çalıştırdığı için zip'te scripti
|
||
olan tablo eksik sayılmaz.
|
||
|
||
#### Şema karşılaştırması — tablo var ama yapısı farklıysa
|
||
|
||
Üretilen tablo script'leri `IF OBJECT_ID(...) IS NULL BEGIN CREATE TABLE ... END` kalıbıyla sarılıdır:
|
||
hedefte tablo varsa `CREATE` bloğu **tamamen atlanır**. Dolayısıyla eski şemalı bir tabloya yeni bir
|
||
kolon kendiliğinden gelmez; ekran o kolonu bir alan olarak tanımladığı için açılışta "geçersiz kolon"
|
||
hatası verir. Bu sessiz uyuşmazlığı analiz adımı yakalar (`SqlCreateTableParser` +
|
||
`WizardImportValidator`): zip'in getirdiği `CREATE TABLE` bildirimi, hedef tablonun
|
||
`INFORMATION_SCHEMA.COLUMNS` üzerinden okunan canlı şemasıyla karşılaştırılır.
|
||
|
||
Ayrım **kayıp riskine** göre yapılır:
|
||
|
||
- **Eksik kolon eklenir.** Kolon eklemek kayıpsız bir işlemdir; analiz "şu kolon eklenecek" diye
|
||
uyarır, çalıştırılacak cümleyi gösterir ve kapanışta (SQL script'lerinden sonra, CRUD ve veriden
|
||
önce) uygular. Tek istisna: `NOT NULL` olup varsayılan değeri olmayan bir kolon dolu bir tabloya
|
||
eklenemez — kolona hangi değerin yazılacağı bir iş kararıdır, bu durumda import durdurulur ve
|
||
cümle kullanıcıya bırakılır. Tablonun boş olup olmadığı çalışma anında sorgulanır; boş tabloya
|
||
böyle bir kolon güvenle eklenir.
|
||
- **Var olan kolon değiştirilmez.** Uzunluk/kesinlik/ondalık/nullability farkında import durur.
|
||
Daraltma veri keser, tip dönüşümü başarısız olabilir; doğru işlem veriye bakmayı gerektirir.
|
||
Fark somut olarak bildirilir ("uzunluk hedefte 200, script'te 300"), düzeltmeyi kullanıcı yapar.
|
||
- **Hiçbir kolon düşürülmez, hiçbir tablo `DROP` edilmez.** Hedefteki fazla kolon yalnızca
|
||
bilgilendirme olarak listelenir.
|
||
|
||
Karşılaştırma **tip adına bakmaz**. Sağlayıcı kataloğu kendi kanonik adını raporlar (PostgreSQL'de
|
||
`VARCHAR` → `character varying`, `TIMESTAMP` → `timestamp without time zone`); script'teki yazılışla
|
||
metin olarak karşılaştırmak her `VARCHAR` kolonunda sahte fark üretirdi. Yalnızca her iki
|
||
sağlayıcıda da aynı anlamı taşıyan ölçüler karşılaştırılır: uzunluk, kesinlik/ondalık, nullability.
|
||
Script bir tablo kurmuyorsa (procedure, view) ya da `CREATE TABLE` çözülemiyorsa karşılaştırma
|
||
sessizce atlanır — tahmin yürütülmez.
|
||
|
||
`data/*.json` dosyaları kapsamdaki bütün satırları taşıdığı için üzerine yazılmaz: satırlar anahtar
|
||
alan üzerinden birleştirilir (gelen satır varsa günceller, yoksa eklenir, hedefteki diğer satırlar
|
||
korunur). Diff ekranında düzenlenen içerik de aynı sözleşmeyi taşıdığı için elle birleştirme bu
|
||
davranışı bozmaz.
|
||
|
||
Güvenlik sınırları: yalnızca `wizard`, `crud`, `data`, `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/list/App.DeveloperKit.DynamicServices` | Liste bir ListForm ekranıdır (KPI şeridi, Swagger butonu, kart/ızgara görünümü); kod yazma listeden açılan `DynamicServiceEditor` diyalogundadır: Monaco editörü, 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/list/App.DeveloperKit.CustomComponents` | React bileşenini veritabanında saklama; `@babel/standalone` ile tarayıcıda derleyip route'a bağlama. Liste bir ListForm ekranıdır (KPI şeridi, ızgara/kart görünümü, grid'in kendi ekleme/düzenleme formu); satırdaki **Design** butonu `/admin/developerkit/components/design/{id}` tasarımcısını, **Open URL** butonu bileşenin `RoutePath`'ini açar. Kayıtlar `configs/seeds/host/data/App.DeveloperKit.CustomComponents.json` dosyasına senkronlanır. Yetkiler `App.DeveloperKit.CustomComponents{,.Create,.Update,.Delete,.Export,.Import}`. |
|
||
| **Visual Designer** | `/admin/developerkit/components/design/:id` | Custom Component listesindeki **Design** butonundan açılır; 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.** Bileşenlerin seed kaynağı Custom Components ekranının veri dosyasıdır:
|
||
`configs/seeds/{host|tenants/{tenantId}}/data/App.DeveloperKit.CustomComponents.json`. Bileşene
|
||
yazan **iki yol** da bu dosyaya işlenir (`ListFormSeedDataSynchronizer`): listeden yapılan
|
||
ekleme/güncelleme/silme ve Visual Designer'ın kaydı (`CustomComponentAppService`). Veritabanı
|
||
sıfırlandığında `ListFormSeedDataApplier` satırları geri yazar; `Code`, `Props` ve `DataSources`
|
||
kolonları bu yüzden ekranda gizli alan olarak tanımlı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. Wizard export'u bu referansları izleyerek bağlı `crud/*.json` dosyalarını zip'e ekler.
|
||
|
||
**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.<ad>.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.
|
||
|
||
**Kanvas doğruluğu.** Tasarım zamanında görülen, canlıda görülendir; bunu iki mekanizma sağlar.
|
||
(1) *Yerleşim sınıflarının taşınması*: kanvas her düğümü seçim/sürükleme için bir sarmalayıcıya
|
||
alır ve üst öğe grid/flex olduğunda asıl öğe o sarmalayıcı olur. `splitLayoutClasses` düğümün
|
||
yerleşim sınıflarını sarmalayıcıya geçirir — `col-span`/`row-span`/`order`/`self`/`flex-1`/`basis`,
|
||
sabit ve kesirli `w-*`, kenar boşlukları taşınır; konum sınıfları (`absolute`, `inset-*`, `z-*`,
|
||
`w-full`) her ikisinde de kalır. Görünürlük sınıfları da sarmalayıcıya kopyalanır (`hidden lg:flex`
|
||
→ sarmalayıcıda `hidden lg:block`): aksi hâlde mobilde gizlenmesi gereken masaüstü şeridi yine bir
|
||
grid hücresi işgal eder ve komşularını yanlış hücreye iter. `fixed` kanvasta akışa çevrilir, yoksa
|
||
düğüm tasarım yüzeyinden taşardı. (2) *Cihaz çerçevesi*: araç çubuğundan masaüstü/tablet/mobil seçildiğinde kanvas kendi
|
||
belgesinde çizilir (`CanvasFrame`), böylece `md:`/`lg:` kuralları tarayıcı penceresine değil seçilen
|
||
genişliğe göre çözülür. Cihaz modunda tasarım yüzeyi kenar boşluğunu bırakır: kanvas o cihazın ekranıdır. `Responsive`
|
||
seçimi aynı sayfada, çerçevesiz ve boşluklu çizer. (3) *Gezinme kapalıdır*: kanvastaki bir bağlantıya
|
||
tıklamak seçim yapar, sayfayı değiştirmez — tıklama yakalama evresinde durdurulur, `react-router`'ın
|
||
`Link`'i de `defaultPrevented` görünce gezinmez.
|
||
|
||
**Diğer notlar.** `PlatformIcon` tasarımcı dokümanındaki ikon adını çözer; `selectComponents.ts`
|
||
`Select.componentAs` için saklanan adı (`ReactSelect`, `CreatableSelect`, `AsyncSelect`) gerçek
|
||
bileşene çevirir — kanvas ve üretilen bileşenin aynı adı aynı şekilde yorumlamasını sağlayan tek
|
||
nokta budur. Yeni bileşen `configs/seeds/host/data/App.DeveloperKit.CustomComponents.json`
|
||
içindeki bir satır olarak 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.
|
||
- Aynı yolu bir fiziksel route ile bir Custom Component paylaşıyorsa **Custom Component kazanır**;
|
||
karşılığı olan dosyası bulunmayan rota kaydı hiç yüklenmez. Public site menüsü bu modelin
|
||
dışındadır: `Pub` modülü altında tutulur ve uygulama konfigürasyonuyla taşınır (bkz. §10.4).
|
||
|
||
**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.CustomComponents` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import` |
|
||
| `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ı) |
|
||
|
||
> **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` | Forum kullanımı; yönetim `App.ForumManagement` altındaki ListForm ekranlarıyla yapılır. |
|
||
| 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` · `/contact` (Custom Component) · `/products` · `/checkout` · `/payment` ·
|
||
`/success` · `/blog` · `/blog/:id` · `/demo` (fiziksel sayfalar).
|
||
|
||
Ziyaretçiye açık kısım iki parçadan oluşur ve ikisi de veritabanında yaşar:
|
||
|
||
**Menü.** Public menüler `Menu` tablosunda `ModuleId = "Pub"` modülü altında tutulur ve Menü
|
||
Yönetimi ekranından girilir (sözleşme: `PlatformConsts.PublicSite`). `App.Public.Header` kökü hem
|
||
üst navigasyonu hem de alt bilgideki hızlı bağlantıları besler — ikisi de `PublicNav` düğümüdür,
|
||
menü bir kez eklenir iki yerde birden görünür; alt kaydı olan bir menü üstte açılır liste olur.
|
||
Alt bilgide `cta` kayıtları (Giriş) yer almaz: oradaki düğüm `source="navigation"` ile çizilir. `Url` sayfa yolu, `Icon`
|
||
react-icons adı, `Order` sıra, `IsDisabled` yayın anahtarı, `DisplayName` dil anahtarıdır;
|
||
`CssClass` içinde `cta` geçen kayıt düz bağlantı yerine vurgulu buton olarak çizilir. Menü ucu
|
||
`[Authorize]` olduğu için menüler uygulama konfigürasyonunun `publicMenus` alanıyla taşınır
|
||
(`PlatformApplicationConfigurationContributor`), istemcide `usePublicMenu` okur. `Pub` modülü
|
||
yönetim navigasyonuna girmez (`abpConfig.model.ts` menüyü kurarken bu modülü eler; Menü Yönetimi
|
||
ekranı elemez, menüler oradan düzenlenir). Seed: `MenusData.json` → `Modules` + `Menus`.
|
||
|
||
**Sayfa.** Her public sayfa bir Custom Component'tir: `RoutePath` `/admin/` ile başlamadığı sürece
|
||
bileşen otomatik olarak public route olur ve `PublicLayout` altında yayınlanır. Tasarım yalnızca
|
||
DeveloperKit > Custom Components (Visual Designer) üzerinden değişir. Aynı yolu bir fiziksel route
|
||
ile paylaşan custom component kazanır; karşılığı olan dosyası bulunmayan rota kaydı ise hiç
|
||
yüklenmez (`hasPhysicalComponent`) — seeder yalnızca eklediği için eski kayıtlar veritabanında
|
||
kalsa bile ekran patlamaz. Seed: `configs/seeds/host/data/App.DeveloperKit.CustomComponents.json`;
|
||
bileşenin ayrı dosyası yoktur, her bileşen bu dosyada bir satırdır.
|
||
|
||
Runtime kapsamı sınırlıdır: bileşen kodundaki `import` satırları derlemede temizlenir,
|
||
kullanılabilenler `React`, `ui` kit, `PlatformViewHost`, `apiService`, `axios`, `DOMPurify`,
|
||
`translate`, `checkPermission`, `getCulture` ve **katalog düğümleri**
|
||
(`components/componentEditor/runtimeNodes.ts`). **`react-icons` ve `react-router` yoktur** — ikon
|
||
`<PlatformIcon name="FaUsers" size={40} className="..." />` ile ada göre çizilir (menü ikonlarıyla
|
||
aynı sözlük), gezinme `<a href>` ile yazılır. Kullanıcıya görünen metinler dil anahtarı üzerinden
|
||
gelir.
|
||
|
||
**Tailwind sınıf yüzeyi.** Bileşenin kodu veritabanında yaşar; derleme sırasında taranan tek
|
||
kaynak seed dosyasıdır (`configs/seeds/*/data/App.DeveloperKit.CustomComponents.json`). Bu dosya
|
||
depo kökünde, `ui/` dışındadır — derleme bağlamı yalnızca `ui/` klasörü olduğunda (docker, ayrı
|
||
checkout) glob boş döner ve seed'e özgü sınıflar (`md:col-span-4`, `bg-gray-950/80`, `opacity-20`)
|
||
CSS'e hiç girmez: uygulama yerelde doğru, sunucuda stilsiz görünür. Bu yüzden aynı sınıflar var
|
||
olan `ui/safelist.txt` dosyasına da yazılır. Dosyayı zaten `twSafelistGenerator` eklentisi üretiyor
|
||
(renk/ölçü listesi); eklenti artık seed dosyalarındaki `className` değerlerini de toplayıp
|
||
`# --- custom component classes ---` işaretinin altına ekliyor. `safelist.txt` `ui/` içinde ve
|
||
depoda olduğu için her ortamda taranır. Seed kökü görünmüyorsa işaretin altındaki liste olduğu gibi
|
||
korunur — eksik bir bağlam listeyi silip sorunu büyütmez. Ayrı bir betik ya da ikinci bir safelist
|
||
dosyası yoktur; liste her `npm run build` / `npm start` ile tazelenir.
|
||
|
||
**Katalog düğümleri.** Kanvasın doğrudan çizdiği, derlenen bileşen listesinde yer almayan
|
||
bileşenler tek bir sözlükte durur (`RUNTIME_NODE_COMPONENTS`): kanvas onu `VisualCanvas` içinde,
|
||
üretilen kod ise runtime kapsamı üzerinden kullanır — iki taraf aynı kaynaktan beslendiği için
|
||
tasarım ve çalışma zamanı ayrışamaz. Sözlükte `PlatformIcon` ve public site parçaları
|
||
(`components/publicSite`) bulunur. Yeni bir düğüm eklerken: bileşen `components/publicSite` (ya da
|
||
uygun klasör) → `runtimeNodes.ts` sözlüğü → `catalog.ts` tanımı (`kind: 'custom'`) → `LanguagesData.json`
|
||
açıklama anahtarı.
|
||
|
||
Elle yazılmış bir bileşen Visual Designer'da **kod modunda** açılır: tasarımcı yalnızca kendi
|
||
ürettiği kodu düğüm ağacına çevirir (`isDesignerGeneratedCode`), aksi hâlde tanımadığı JSX'i
|
||
düşürüp kaydederken kodu yok ederdi.
|
||
|
||
Public bileşenlerin tamamı — `/home`, `/about`, `/contact` sayfaları ile üst ve alt bilgi
|
||
(`PublicHeader`, `PublicFooter`; rotaları yok) — **tasarımcı belgesi** olarak tutulur: `Props` alanındaki
|
||
`visualDesigner` düğüm ağacı kaynaktır (`sourceMode: "visual"`), `Code` ondan üretilir
|
||
(`generateDesignerCode`) ve runtime da bileşeni bu belgeden derler. Yani hepsi kanvasta görünür,
|
||
sürükle-bırak ve özellik paneliyle düzenlenir. Belgeler `div`/`h1`-`h5`/`p`/`span`/`img`/`a`
|
||
HTML düğümleri ve `PlatformIcon` ikon düğümüyle kurulmuştur; `::` ile başlayan metinler üretilen
|
||
kodda `translate()` çağrısına döner. `RoutePath` boş bırakılabilir; rotası olmayan bir bileşen
|
||
yalnızca başka bir ekranın içinde çizilir (alt bilgi gibi).
|
||
|
||
Üst ve alt bilgi de birer Custom Component'tir (`PublicHeader`, `PublicFooter`; rota yok):
|
||
`PublicLayout` ikisini de `renderComponent` ile çizer ve geriye yalnızca rota değişiminde başa
|
||
sarma ile demo penceresi kalır. Bileşen kayıtlı değilse o parça çizilmez.
|
||
|
||
Üst bilginin davranışı (menü listesi, aktif bağlantı, kaydırmada değişen görünüm, mobil panel,
|
||
tema/dil/demo kontrolleri) `components/publicSite` altındaki katalog düğümlerinde yaşar; yerleşim
|
||
ve sınıflar tasarımcıdadır: `PublicHeaderBar` (kaydırıldığında `scrolledClassName`'e geçen kabuk),
|
||
`PublicNav` (`source`: `navigation`/`actions`/`all`, `variant`: `horizontal`/`vertical`),
|
||
`PublicMobileMenu` (hamburger + içeriği tasarlanan panel), `PublicLogo`, `PublicThemeToggle`,
|
||
`PublicLanguageSelector`, `PublicDemoButton`.
|
||
|
||
Rotası olmayan bileşende `RoutePath` **NULL** yazılır; `Sas_H_CustomComponent`'in `RoutePath`
|
||
tekil indeksi yalnızca dolu değerleri kapsar (`[IsDeleted] = 0 AND [RoutePath] IS NOT NULL`), aksi
|
||
hâlde ikinci rotasız bileşen birincisiyle çakışırdı.
|
||
|
||
`/home`, `/about`, `/contact` bu yolla çalışır (`PublicHomePage`, `PublicAboutPage`,
|
||
`PublicContactPage`); üst ve alt bilgi rotasızdır (`PublicHeader`, `PublicFooter`).
|
||
|
||
Veriden beslenen public sayfalar (`/products`, `/checkout`, `/payment`, `/success`, `/blog`,
|
||
`/blog/:id`, `/demo`) fiziksel kalır; içerik sayfaları Custom Component'tir. Blog listesi ve detayı
|
||
`PublicAppService`'in `post-list` / `post-by-slug` uçlarından beslenir, yönetimi
|
||
`App.BlogManagement.*` ekranlarındadır.
|
||
|
||
Eski statik içerik sayfaları ve sayfa içi tasarım modu (`?design=1`) kaldırılmıştır:
|
||
`views/public/Home|About|Contact|Services`, `views/public/designer/`, bunlara özel istemci
|
||
servisleri; sunucuda `Home`/`About`/`Contact`/`Service` entity'leri, `PublicAppService` sayfa
|
||
Get/Save uçları ve DTO'ları, `TenantData.json` + `TenantDataSeeder`,
|
||
`App.{Home,About,Services,Contact}` yetkileri ve `.Design` alt yetkileri, `/admin/public/*/designer`
|
||
rota ve menüleri.
|
||
|
||
---
|
||
|
||
## 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=<KULLANICI>
|
||
&password=<PAROLA>
|
||
&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 <Ad>
|
||
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.<Modul> -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`, `CrudDataSeeder.cs` — aşağıdaki
|
||
runtime seed dosyalarını okuyup uygulayan seeder'lar
|
||
- `ListFormSeedDataApplier`, `CrudEndpointSeedApplier` (`Domain/Data/`) — uygulama kuralının tek
|
||
yeri; hem migrate/seed akışı hem wizard import'unun kapanışı aynı servisleri çağırır
|
||
|
||
**2. Runtime'da üretilen seed'ler** — `configs/seeds/`. Wizard, Custom Components ekranı/Visual
|
||
Designer, CRUD Endpoint Manager ve `SeedFilePath` tanımlı ListForm ekranları ç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
|
||
│ ├── crud/ # {EntityName}.json → CrudEndpointSeedApplier
|
||
│ ├── data/ # {ListFormCode}.json → ListFormSeedDataApplier
|
||
│ ├── 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`).
|