@appaflytech/zeyrek-ai-mcp 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +46 -0
- package/README.md +260 -0
- package/dist/config.js +128 -0
- package/dist/index.js +88 -0
- package/dist/knowledge/componentCatalog.js +438 -0
- package/dist/knowledge/componentEvents.js +164 -0
- package/dist/knowledge/coverage.js +60 -0
- package/dist/knowledge/normalize.js +1309 -0
- package/dist/knowledge/outlines.js +167 -0
- package/dist/knowledge/policy.js +44 -0
- package/dist/knowledge/reservedTables.js +75 -0
- package/dist/knowledge/rules.js +1725 -0
- package/dist/observability/trace.js +337 -0
- package/dist/platform/errors.js +132 -0
- package/dist/platform/http.js +169 -0
- package/dist/platform/responses.js +94 -0
- package/dist/platform/token.js +79 -0
- package/dist/resources/examples/entity-pair-m2m.json +105 -0
- package/dist/resources/examples/flow-list-to-form.json +65 -0
- package/dist/resources/examples/flow-load-table.json +178 -0
- package/dist/resources/examples/microservice-table-list.json +49 -0
- package/dist/resources/examples/middleware-authenticate.json +194 -0
- package/dist/resources/examples/page-detail-profile.json +95 -0
- package/dist/resources/examples/page-dynamic-form.json +221 -0
- package/dist/resources/examples/page-form-upsert.json +279 -0
- package/dist/resources/examples/page-html-embed.json +106 -0
- package/dist/resources/examples/page-sign-in.json +194 -0
- package/dist/resources/examples/workflow-basic.json +94 -0
- package/dist/resources/guides/component.md +108 -0
- package/dist/resources/guides/entity.md +348 -0
- package/dist/resources/guides/expressions.md +139 -0
- package/dist/resources/guides/getting-started.md +109 -0
- package/dist/resources/guides/html.md +106 -0
- package/dist/resources/guides/microservice.md +313 -0
- package/dist/resources/guides/middleware.md +271 -0
- package/dist/resources/guides/modify-existing.md +35 -0
- package/dist/resources/guides/page.md +1574 -0
- package/dist/resources/guides/view.md +89 -0
- package/dist/resources/guides/workflow.md +359 -0
- package/dist/resources/knowledge.js +44 -0
- package/dist/resources/schemas/CreateDatasourceCommand.json +54 -0
- package/dist/resources/schemas/CreateDiscoveredEntitiesCommand.json +133 -0
- package/dist/resources/schemas/CreateEntityCommand.json +387 -0
- package/dist/resources/schemas/CreateMicroserviceCommand.json +528 -0
- package/dist/resources/schemas/CreateQueryCommand.json +43 -0
- package/dist/resources/schemas/CreateViewCommand.json +158 -0
- package/dist/resources/schemas/CreateWorkflowCommand.json +1719 -0
- package/dist/resources/schemas/Filter.json +124 -0
- package/dist/resources/schemas/GetRowsQuery.json +122 -0
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +565 -0
- package/dist/resources/schemas/PreviewQueryCommand.json +74 -0
- package/dist/resources/schemas/PreviewWorkflowCommand.json +981 -0
- package/dist/resources/schemas/StepDto.json +900 -0
- package/dist/resources/schemas/UpdateDatasourceCommand.json +58 -0
- package/dist/resources/schemas/UpdateEntityCommand.json +679 -0
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +512 -0
- package/dist/resources/schemas/UpdateQueryCommand.json +86 -0
- package/dist/resources/schemas/UpdateViewCommand.json +153 -0
- package/dist/resources/schemas/UpdateWorkflowCommand.json +1719 -0
- package/dist/resources/schemas.js +40 -0
- package/dist/server.js +63 -0
- package/dist/tools/access.js +27 -0
- package/dist/tools/applications.js +59 -0
- package/dist/tools/automations.js +103 -0
- package/dist/tools/common.js +18 -0
- package/dist/tools/components.js +280 -0
- package/dist/tools/datasources.js +82 -0
- package/dist/tools/dependencies.js +17 -0
- package/dist/tools/deployments.js +17 -0
- package/dist/tools/dtos.js +54 -0
- package/dist/tools/entities.js +166 -0
- package/dist/tools/files.js +138 -0
- package/dist/tools/flows.js +226 -0
- package/dist/tools/folders.js +51 -0
- package/dist/tools/layouts.js +105 -0
- package/dist/tools/microservices.js +198 -0
- package/dist/tools/organizations.js +65 -0
- package/dist/tools/pages.js +597 -0
- package/dist/tools/platformInfo.js +44 -0
- package/dist/tools/projects.js +152 -0
- package/dist/tools/queries.js +48 -0
- package/dist/tools/rows.js +115 -0
- package/dist/tools/screens.js +97 -0
- package/dist/tools/templates.js +65 -0
- package/dist/tools/variables.js +94 -0
- package/dist/tools/views.js +58 -0
- package/dist/tools/workflows.js +196 -0
- package/package.json +49 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_meta": {
|
|
3
|
+
"synthetic": true,
|
|
4
|
+
"note": "hr projesinde doğrulanmış şekil. Kurallar: step/branch id'leri GERÇEK GUID ve global benzersiz (RowAlreadyExists); DtoId verilen yerde Behavior zorunlu; table rule'da datasourceId + fieldId zorunlu; filtre value JavaScript ifadesi; preview girdisi previewPayload anahtarıyla."
|
|
5
|
+
},
|
|
6
|
+
"definition": {
|
|
7
|
+
"name": "Product Lookup",
|
|
8
|
+
"slug": "product-lookup",
|
|
9
|
+
"type": "workflow",
|
|
10
|
+
"parameterDtoId": "<girdi DTO id: { productName: string }>",
|
|
11
|
+
"returnDtoId": "<çıktı DTO id: { name, price }>",
|
|
12
|
+
"parameterBehavior": "object",
|
|
13
|
+
"returnBehavior": "object",
|
|
14
|
+
"steps": [
|
|
15
|
+
{
|
|
16
|
+
"id": "<GUID-1 üret: crypto.randomUUID()>",
|
|
17
|
+
"name": "Start",
|
|
18
|
+
"type": "start",
|
|
19
|
+
"branches": [
|
|
20
|
+
{
|
|
21
|
+
"id": "<GUID-2>",
|
|
22
|
+
"name": "start",
|
|
23
|
+
"type": "success",
|
|
24
|
+
"nextStepId": "<GUID-3>"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "<GUID-3>",
|
|
30
|
+
"name": "Load Product",
|
|
31
|
+
"type": "table",
|
|
32
|
+
"rule": {
|
|
33
|
+
"stepType": "table",
|
|
34
|
+
"entityId": "<products entity id>",
|
|
35
|
+
"operation": "get",
|
|
36
|
+
"isSingle": true,
|
|
37
|
+
"selectFields": [
|
|
38
|
+
{
|
|
39
|
+
"alias": "<entity slug>",
|
|
40
|
+
"fieldSlug": "name",
|
|
41
|
+
"path": "",
|
|
42
|
+
"fieldId": "<name alanı id>"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"alias": "<entity slug>",
|
|
46
|
+
"fieldSlug": "price",
|
|
47
|
+
"path": "",
|
|
48
|
+
"fieldId": "<price alanı id>"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"filters": [
|
|
52
|
+
{
|
|
53
|
+
"fieldSlug": "name",
|
|
54
|
+
"operator": "eq",
|
|
55
|
+
"value": "input.productName",
|
|
56
|
+
"fieldId": "<name alanı id>"
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"joins": [],
|
|
60
|
+
"datasourceId": "<datasource id>"
|
|
61
|
+
},
|
|
62
|
+
"branches": [
|
|
63
|
+
{
|
|
64
|
+
"id": "<GUID-4>",
|
|
65
|
+
"name": "success",
|
|
66
|
+
"type": "success",
|
|
67
|
+
"nextStepId": "<GUID-6>"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "<GUID-5>",
|
|
71
|
+
"name": "fail",
|
|
72
|
+
"type": "fail",
|
|
73
|
+
"nextStepId": null
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"id": "<GUID-6>",
|
|
79
|
+
"name": "Response",
|
|
80
|
+
"type": "response",
|
|
81
|
+
"rule": {
|
|
82
|
+
"stepType": "response",
|
|
83
|
+
"bodyExpression": "{ name: load_product.data.name, price: load_product.data.price }",
|
|
84
|
+
"httpStatusCode": 200,
|
|
85
|
+
"headerExpression": "{ }"
|
|
86
|
+
},
|
|
87
|
+
"branches": []
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
"automationVariant": {
|
|
92
|
+
"note": "Automation: returnDtoId/parameterDtoId YASAK (validator reddeder), returnBehavior 'object' verilebilir; state=unready NORMALDİR ve tetiklemeyi etkilemez. Tetikleme kapısı automation nesnesindeki entityId + operation + isQueue (false=anlık, true=kuyruk; null=asla tetiklenmez!). steps hem üst seviyede hem automation içinde (PLT-007); response yasak, hata yolu revert."
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Komponent Rehberi (katalog, ortak katman, olay modeli)
|
|
2
|
+
|
|
3
|
+
Sayfaya konan her şeyin ortak kuralları. Kuruluş sırası ve şema gövdesi için
|
|
4
|
+
`platform_guide('page')`; HTML kaçış kapısının derin sözleşmesi için `platform_guide('html')`.
|
|
5
|
+
|
|
6
|
+
## Keşif: iki tool, üç bilgi katmanı
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
component_list → hangi tipler var (slug, kategori, droppable) — kompakt
|
|
10
|
+
component_get → tek tipin TAM sözleşmesi, üç katman birleşik:
|
|
11
|
+
props/defaults/sizes (platform sözlüğü — tip/enum/default)
|
|
12
|
+
events[].payload/reads (olay yükü sözleşmeleri)
|
|
13
|
+
knowledge (davranış bilgisi: ne işe yarar, nasıl davranır)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- `knowledge` alanı yoksa davranış sözlüğe işlenmemiştir — **tahmin etme**.
|
|
17
|
+
- Yanıtta `guide` dönerse (`html` gibi) o tip için derin rehber vardır; ilk kullanımdan önce oku.
|
|
18
|
+
- Şemaya **uydurma prop yazma**: platform 200 döner ama prop sessizce kaybolur. Tek istisna
|
|
19
|
+
`isHidden` — katalogda görünmese de her komponentte çalışır (ortak render katmanı çizer).
|
|
20
|
+
|
|
21
|
+
## Ortak katman gerçekleri (RenderComponent — her komponent için geçerli)
|
|
22
|
+
|
|
23
|
+
- **`isHidden`** her komponenti gizler; setter ile yazmak katalogda listelenmeyen tiplerde de
|
|
24
|
+
çalışır. Gizli komponent `mount` olayını görünür olana dek TETİKLEMEZ.
|
|
25
|
+
- **`mount`** olayını komponentin kendisi değil ortak katman yayar: komponent ilk kez
|
|
26
|
+
görünür olduğunda bir kez. Sayfa açılış akışı `page_container.mount`'a bağlanır.
|
|
27
|
+
- **`name` = `elementId`** kuralı: runtime her komponent için `const <name> = Components[...]`
|
|
28
|
+
üretir; bozuk ad sayfadaki BÜTÜN ifadeleri öldürür (`platform_guide('page')` Kural 1c-2).
|
|
29
|
+
- **Boyut:** `blocks[].size` katalogdaki `maxSize`'ı aşamaz; yükseklikte
|
|
30
|
+
`appearance.heightType: 'auto'` tercih edilir. Katalog varsayılanı bazı tiplerde kendi
|
|
31
|
+
sınırını aşar — körü körüne kopyalama, gateway kırpar ve bildirir.
|
|
32
|
+
|
|
33
|
+
## Olay modeli
|
|
34
|
+
|
|
35
|
+
- Olay adları `component_get.events`'ten okunur, **`on` öneki almaz** (tek istisna
|
|
36
|
+
`texteditor`: onMount/onChange). Uydurma ada bağ sessizce ölü kalır — gateway PAGE-008 ile
|
|
37
|
+
reddeder.
|
|
38
|
+
- Yük `events[].payload`'dadır ama akışa **`event.data` ile GELMEZ**: motor yükü komponentin
|
|
39
|
+
KENDİ prop'una yazar (`FlowMachine.onEmit` → `setNode`) ve akışı emit'in `params`'ıyla başlatır.
|
|
40
|
+
Yani `payload` anahtarları prop adlarıdır ve `self.<anahtar>` ile okunur (ya da
|
|
41
|
+
`value.type:'property'`); `reads` alanı yükte olmayan prop'ları söyler. `event.data` yalnız
|
|
42
|
+
`html` komponentinin `fireEvent` aksiyonlarında dolar.
|
|
43
|
+
- Akış bağlama: `flow_create` → `page_schema_patch set_event`. İstisna: `html` komponentinin
|
|
44
|
+
aksiyonları kendi `flow` prop'uyla bağlanır (`platform_guide('html')`).
|
|
45
|
+
|
|
46
|
+
## Stil
|
|
47
|
+
|
|
48
|
+
Her komponentin `style` prop'u vardır ve iç parçalara iner (`textinput.style`: `&__label` ·
|
|
49
|
+
`&__input` · `&__error`; `form.style`: `&__title` · `&__header` · `&__body`). `html`
|
|
50
|
+
komponentinde `style` serbest bir emotion CSS bloğudur. Tasarımı varsayılanda bırakmak
|
|
51
|
+
zorunda değilsin.
|
|
52
|
+
|
|
53
|
+
## Widget: kayıt → sayfaya koyma → akışlar
|
|
54
|
+
|
|
55
|
+
Widget, kendi komponent ağacını taşıyan yeniden kullanılabilir pakettir (`kind:'widget'`,
|
|
56
|
+
`widgetType: container | modal | drawer`).
|
|
57
|
+
|
|
58
|
+
1. **Kayıt:** `component_create` — `kind:'widget'`, `widgetType`, `schema` (widget'ın kendi
|
|
59
|
+
ağacı; `name = elementId` kuralı burada da geçerli — layout gibi widget adları da kullanan
|
|
60
|
+
sayfaya sızar).
|
|
61
|
+
2. **Sayfaya koyma:** `add_component` düğümünde `kind:'widget'` ve **`type` = widget KAYDININ
|
|
62
|
+
ID'si** — slug DEĞİL (runtime widget'ı `widget.id === node.type` ile çözer; slug yazarsan
|
|
63
|
+
kayıt 200 döner, render sessizce boş kalır — gateway **PAGE-012/LAY-005** ile reddeder).
|
|
64
|
+
`widgetType` alanını da düğüme yaz.
|
|
65
|
+
3. **Akışlar:** widget'ın kendi flow'ları `flow_*` tool'larında `host:'component'`,
|
|
66
|
+
`hostId: <widget kaydının id'si>` ile yönetilir. Kayıtta adımlar widget şemasındaki somut
|
|
67
|
+
`elementId`'leri kullanır; Studio düzenleyicisinin gösterdiği `__widget__` yer tutucusu
|
|
68
|
+
yalnız editör katmanıdır (kayıt anında gerçek id'ye çevrilir) — API'den yazarken yer
|
|
69
|
+
tutucu KULLANMA.
|
|
70
|
+
|
|
71
|
+
## `states` ve `appearance` sözlükleri
|
|
72
|
+
|
|
73
|
+
Her şema düğümünde iki sözlük vardır; ikisi de ortak render katmanında çözülür:
|
|
74
|
+
|
|
75
|
+
| `states` | Anlamı |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `isDroppable` | İçine komponent alır (container/form/repeater true) |
|
|
78
|
+
| `isScrollable` | İçeriği kendi alanında kaydırır (sabit yükseklikte `overflow-y: auto`) |
|
|
79
|
+
| `isWrapper` | Sayfanın/layout'un/widget'ın ANA kabı — salt düzen elemanı: `height:100%` + **`min-height:80vh`**, kap başlığı ÇİZİLMEZ. **Yalnız sayfa boyu kaplaması gereken tek kap için kullan:** iç içe kutuya verirsen 720px'lik pencerede o kutu 36px içerikle bile 576px çizilir (ölçüldü, `platform_guide('page')` Kural 1f). Çerçeve/başlık gizlemek için wrapper değil `style` / `hideBorders` kullan; `states` için micro-op olmadığından düzeltmek düğümü yeniden kurmayı gerektirir |
|
|
80
|
+
| `isSticky` | Kaydırmada yerinde kalır (header/sidebar; z-index'i otomatik) |
|
|
81
|
+
|
|
82
|
+
> **Çocukların DİZİLİMİ `states`'te değil kabın PROP'undadır:** `container` — ve dolayısıyla
|
|
83
|
+
> `page_container` — `layout: 'flex' | 'grid'` + altı ayar (`direction`, `horizontalAlign`,
|
|
84
|
+
> `verticalAlign`, `size`, `gap`, `wrap`) taşır. Katalog varsayılanı `flex`'tir ama varsayılan
|
|
85
|
+
> düğüm kurulurken yazılır: `layout` prop'u hiç yoksa renderer IZGARA çizer, o yüzden şemayı sen
|
|
86
|
+
> kuruyorsan açıkça yaz. Ortalama/yaslama/aralık işini `style` ile değil bu grupla kur:
|
|
87
|
+
> `platform_guide('page')` Kural 1f-2.
|
|
88
|
+
|
|
89
|
+
| `appearance` | Değerler | Anlamı |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `heightType` | `auto` · `fixed` | `auto`: içerik kadar (önerilen — Kural 1d); `fixed`: `blocks.h × 10px` |
|
|
92
|
+
| `marginType` / `marginValue` | `normal` · `none` · `custom` + px | Dış boşluk: normal=5px, custom=`marginValue` |
|
|
93
|
+
| `paddingType` / `paddingValue` | `normal` · `none` · `custom` + px | Droppable kapların iç boşluğu: normal=10px |
|
|
94
|
+
| `alignType` | `left` · `center` · `right` | İçerik hizalama (destekleyen komponentlerde) |
|
|
95
|
+
| `widthType` | `cover` · `contain` | Görsel/medya sığdırma davranışı |
|
|
96
|
+
| `aspectRatio` | sayı | En-boy oranı kilidi (medya komponentleri) |
|
|
97
|
+
|
|
98
|
+
`isHidden` bu sözlüklerde değil PROP'tur ve her komponentte çalışır; flow'lar `margin` /
|
|
99
|
+
`padding` / `height` prop adlarıyla da appearance'ı setter üzerinden değiştirebilir
|
|
100
|
+
(RenderComponent bu üç prop'u appearance'a çevirir).
|
|
101
|
+
|
|
102
|
+
## Komponent seçimi
|
|
103
|
+
|
|
104
|
+
"Hangi işe hangi komponent" tablosu ve `table` / `datatable` karşılaştırması:
|
|
105
|
+
`platform_guide('page')` Kural 1e ve 7e. Kaçınılacak tek şey yarım kurulumdur (süzme
|
|
106
|
+
arayüzü açık, arkası statik uç). Hazır komponentlerin hiçbiri işi karşılamıyorsa `html`
|
|
107
|
+
kaçış kapısıdır — yeteneklerini `platform_guide('html')` anlatır; "platform bunu yapamaz"
|
|
108
|
+
demeden önce onu oku.
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# Entity Rehberi
|
|
2
|
+
|
|
3
|
+
Buradaki kurallar gerçek projelerde (qm, hr, sms, klinik) **deneyerek doğrulandı**.
|
|
4
|
+
|
|
5
|
+
## Slug seçimi — isim uzayı platformla paylaşımlıdır
|
|
6
|
+
|
|
7
|
+
Her environment şeması ~75 platform tablosu taşır ve entity slug'ları bu tablolarla aynı isim
|
|
8
|
+
uzayındadır. Çakışan slug `Migration failed … relation "X" already exists` verir ve **entity
|
|
9
|
+
kaydı hiç oluşmaz**. Rezerve adlardan bilinenler: `branches`, `applications`, `caches`,
|
|
10
|
+
`components`, `datasources`, `entities`, `fields`, `files`, `flows`, `folders`, `layouts`,
|
|
11
|
+
`microservices`, `pages`, `permissions`, `projects`, `queries`, `queued_events`, `roles`,
|
|
12
|
+
`steps`, `users`, `variables`, `views`, `workflows`. Alan adı bunlardan biriyse eş anlamlısını
|
|
13
|
+
seç (ör. şube/branş için `branches` değil `specialties`).
|
|
14
|
+
|
|
15
|
+
> **Ama `users`/`roles`/`files`/`folders` bir istisna:** bunlar "dolu olduğu için kaçınılacak"
|
|
16
|
+
> adlar değil, **platformun sana verdiği hazır entity'ler**. Kopyasını yapmadan önce aşağıdaki
|
|
17
|
+
> bölümü oku.
|
|
18
|
+
|
|
19
|
+
## Hazır entity'ler — kimlik tablosu ZATEN VAR
|
|
20
|
+
|
|
21
|
+
Her projeye seed sırasında 9 entity açılır ve **id'leri her kurulumda aynı sabitlerdir**
|
|
22
|
+
(`Defaults` sınıfı) — aramana gerek yok, doğrudan `entity_get` ile çekebilirsin:
|
|
23
|
+
|
|
24
|
+
| slug | id | Ne için |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `users` | `01917ede-330e-7254-8544-eef0db3693af` | **Kimlik.** `id` (uuid PK) · `email` (display, UNIQUE) · `password` · `first_name` · `last_name` |
|
|
27
|
+
| `roles` | `01917ede-88a2-72ea-8397-2619e5d5dca0` | `page_create`/`microservice` `roleIds`'inin okuduğu roller (`role_list`) |
|
|
28
|
+
| `user_roles` | `01917ede-be1e-7d62-9a7c-d0ce4e4daaaf` | kullanıcı ↔ rol |
|
|
29
|
+
| `permissions` · `role_permissions` | `01917ede-a457-…` · `01917ede-d450-…` | yetki matrisi |
|
|
30
|
+
| `files` · `folders` | `0191dbf2-39c4-…` · `0191df94-f635-…` | Drive; `FILE` alanları buraya bağlanır (`entity_list`'te GİZLİ) |
|
|
31
|
+
| `audit_trails` · `audit_trail_values` | `01961f53-25c3-…` · `01961f53-3552-…` | denetim izi |
|
|
32
|
+
|
|
33
|
+
**`users` gerçek bir entity'dir**, sahte bir sistem tablosu değil: `entity_get` alanlarını verir,
|
|
34
|
+
`RELATION` alanı hedef alabilir, table step / microservice okur, `row_create` yazar, kendi default
|
|
35
|
+
DTO'su vardır. Auth middleware tarifi zaten bunu okur — `ngapps://examples/middleware-authenticate`
|
|
36
|
+
`entityId` olarak `users`'ı kullanır.
|
|
37
|
+
|
|
38
|
+
### Neden gözden kaçıyor
|
|
39
|
+
|
|
40
|
+
`entity_list`'i **`applicationId` ile** çağırdığında hazır entity'ler listede **görünmez**: seed
|
|
41
|
+
onlara `EntityApplication` kaydı açmaz, filtre de `EntityApplications.Any(...)` ile süzer. Kimlik
|
|
42
|
+
tablosunu görmek için `entity_list`'i `applicationId` VERMEDEN çağır (ya da yukarıdaki id'yi
|
|
43
|
+
doğrudan kullan).
|
|
44
|
+
|
|
45
|
+
### Kullanırken bilinmesi gerekenler
|
|
46
|
+
|
|
47
|
+
- **Silinemez** (`CantDeleteDefaultEntityException`) ve default alanları (`email`, `password`…)
|
|
48
|
+
silinemez. Buna karşılık **`entity_patch` ile alan EKLENEBİLİR** — telefon, departman, avatar,
|
|
49
|
+
`musteri_tipi` gibi profil alanları `users`'a eklenebilir.
|
|
50
|
+
- **Eklediğin alan `nullable: true` olmalı.** Platform bu tabloya EF üzerinden de yazıyor
|
|
51
|
+
(`organization_sync_users`) ve EF senin kolonunu bilmiyor; NOT NULL + varsayılansız bir kolon o
|
|
52
|
+
yolu kırar.
|
|
53
|
+
- **`password` alanı `Hasher.Hash`'lidir.** Satır yazarken hash'i ifadeyle ürettir
|
|
54
|
+
(`crypto.SHA256.encode(...)` — gerçek algoritma için `platform_guide('expressions')`); düz metin
|
|
55
|
+
yazarsan giriş hiçbir zaman eşleşmez.
|
|
56
|
+
- **`isAuditTrailActive`'i AÇMA.** `users` tablosunun audit kolonları EF tarafında `Ignore`
|
|
57
|
+
edilmiş; `sys_*` eklemek EF'in bilmediği kolonlar yaratır.
|
|
58
|
+
- **`organization_sync_users` Studio operatörlerini bu tabloya süper yönetici rolüyle kopyalar**
|
|
59
|
+
(yalnız production dışı environment'lara). Yani tablo hem platform operatörünü hem uygulama
|
|
60
|
+
kullanıcısını taşır ve roller `page.roleIds` yetkilendirmesiyle ortaktır.
|
|
61
|
+
- **İlişki aynı datasource içinde kurulur.** `users` built-in datasource'tadır; entity'lerin dış
|
|
62
|
+
bir DB'deyse `users`'a ilişki kuramazsın.
|
|
63
|
+
|
|
64
|
+
### Karar: `users`'ı genişlet mi, ayrı entity mi?
|
|
65
|
+
|
|
66
|
+
**Karar senin** — ikisi de geçerli. Ayrım şu: `users` **kimliktir** (giriş, `user.id` kapsaması,
|
|
67
|
+
roller), domain kaydı değil.
|
|
68
|
+
|
|
69
|
+
- **Kimlik alanları** (e-posta, parola, ad, telefon, avatar, dil tercihi) → `users`'a ekle.
|
|
70
|
+
- **Domain verisi** (siparişler, kredi limiti, öğrencinin sınıfı, temsilcinin iş yükü) → ayrı
|
|
71
|
+
entity + `users`'a `one-to-many`. Bir kişi aynı anda iki rolde olabilir (hem temsilci hem
|
|
72
|
+
talep sahibi), `users` da silinemeyen/şeması kısmen kilitli bir tablodur.
|
|
73
|
+
|
|
74
|
+
**Kaçınılacak tek şey:** kendi entity'ne `email` + `password` koyup **ikinci bir kimlik sistemi**
|
|
75
|
+
kurmak. O noktada iki ayrı kullanıcı tablosu, iki ayrı hash düzeni ve `middlewareIds`/`roleIds`
|
|
76
|
+
ile hiç konuşmayan bir yetkilendirme olur. Gateway bu şekli ENT-009 ile hatırlatır (warn — bilerek
|
|
77
|
+
yapıyorsan devam et).
|
|
78
|
+
|
|
79
|
+
## Alan tipleri (dbType + commonType İKİSİ birden verilir)
|
|
80
|
+
|
|
81
|
+
| dbType (BÜYÜK HARF zorunlu) | commonType |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `UUID` | `guid` |
|
|
84
|
+
| `VARCHAR`, `TEXT` | `text` |
|
|
85
|
+
| `BOOL` | `bool` |
|
|
86
|
+
| `INT2`, `INT4`, `INT8` | `number` |
|
|
87
|
+
| `DATE` | `date` |
|
|
88
|
+
| `TIME` | `time` |
|
|
89
|
+
| `TIMESTAMP`, `TIMESTAMPTZ` | `datetime` |
|
|
90
|
+
| `JSONB` | `custom` |
|
|
91
|
+
| `FILE` | `file` |
|
|
92
|
+
| `RELATION` | `relation` |
|
|
93
|
+
| `Incremental` (tam bu yazım) | `incremental` |
|
|
94
|
+
|
|
95
|
+
- Kontrol **büyük/küçük harfe duyarlı** — küçük harf tümüyle reddedilir. `Incremental` bu
|
|
96
|
+
tablodaki tek karma yazımdır (`PostgreSqlConnector` onu ayrı bir tip grubu olarak yayınlar;
|
|
97
|
+
fiziksel tip `TEXT`'tir, bu yüzden kayıttan sonra `entity_get` `dbType: "TEXT"` +
|
|
98
|
+
`commonType: "incremental"` gösterir — bu normaldir, alanı geri çevirme).
|
|
99
|
+
- **Ondalık tip YOK:** `NUMERIC`, `FLOAT4/8`, `MONEY`, `DECIMAL` reddedilir (datasource'un
|
|
100
|
+
`dataTypes` listesi yanıltır, ona güvenme). Birim konvansiyonu kullan ve birimi
|
|
101
|
+
`description`'a yaz: para → `INT8` kuruş (`*_minor`), süre → `INT4` dakika, yüzde →
|
|
102
|
+
`INT4` ×100, puan → `INT4` ×10.
|
|
103
|
+
- `commonType`'sız `UUID`/`BOOL` "isn't a supported database type" hatasıyla reddedilir.
|
|
104
|
+
|
|
105
|
+
## Alan tipine karar verme (önce buna bak, sonra yaz)
|
|
106
|
+
|
|
107
|
+
Yanlış tip seçmek sessiz teknik borçtur: satırlar yazılır, servisler 200 döner, ama Studio
|
|
108
|
+
formu doğru bileşeni gösteremez ve veri serbest metne dönüşür. Sırayla sor:
|
|
109
|
+
|
|
110
|
+
1. **Sabit bir değer kümesi mi?** (durum, öncelik, dönem, unvan, sınav tipi) → **enum**:
|
|
111
|
+
`valueOptions` dolu + `isEnum: true`. Serbest `VARCHAR` bırakma.
|
|
112
|
+
- **Aynı anda birden fazla değer seçilebilecekse → multi-enum**: `VARCHAR` +
|
|
113
|
+
`relationType: 'many-to-many'` + `valueOptions`; `relationId` ve `isEnum` **verilmez** —
|
|
114
|
+
platform `<slug>_values` enum-values entity'sini ve junction'ı kendisi üretir
|
|
115
|
+
(`relationMetadata.enumValuesEntityId` yanıtta dolu döner).
|
|
116
|
+
2. **Dosya mı?** → `dbType: 'FILE'` + `commonType: 'file'`; tekil dosya `relationType: 'one-to-many'`,
|
|
117
|
+
çoklu dosya `relationType: 'many-to-many'`. `relationId` **verme** — platform yerleşik Files
|
|
118
|
+
entity'sini kendisi bağlar (`one-to-one` verilirse `one-to-many`'ye çevrilir).
|
|
119
|
+
3. **Başka bir kayda referans mı?** → `RELATION` (yukarıdaki ilişkiler bölümü).
|
|
120
|
+
4. **Sıralı, insan okuyabilir bir kod mu?** (talep no `TLP-0001`, teklif no, fatura no) →
|
|
121
|
+
**`Incremental`** — aşağıdaki bölüm. Primary key ile karıştırma: PK teknik kimliktir,
|
|
122
|
+
incremental kullanıcıya gösterilen iş numarasıdır; ikisi aynı tabloda birlikte bulunur.
|
|
123
|
+
5. **Serbest metin / sayı / tarih mi?** → tablodaki temel tipler.
|
|
124
|
+
|
|
125
|
+
> **m2m/FILE/multi-enum alanı iki aşamada kurulur — gateway bunu artık kendisi yapar.**
|
|
126
|
+
> Create yolu junction entity kaydını açar ama **fiziksel tabloyu kurmaz**
|
|
127
|
+
> (`EntityService.CreateAsync` migration'ı yalnız ana entity için koşar); sonuç 500
|
|
128
|
+
> `42P01 relation "…" does not exist` ve alan silinemez de. `entity_create` bu alanları
|
|
129
|
+
> gövdeden ayırır, entity'yi onlarsız kurar, sonra bir güncelleme turunda ekler (update
|
|
130
|
+
> migration'ı junction tabloyu kurar) ve yanıtta `gatewayNormalized` ile bildirir — gövdeye
|
|
131
|
+
> yazmaya devam edebilirsin. Ham HTTP ile çalışıyorsan sırayı elle uygula.
|
|
132
|
+
|
|
133
|
+
**Enum yazmıyorsan gerekçen olsun.** `courses.semester` ("2025-2026 Güz") bileşik bir etiket
|
|
134
|
+
olduğu için serbest metindir; `course_assignments.semester` (Güz/Bahar/Yaz) enum'dur.
|
|
135
|
+
|
|
136
|
+
```jsonc
|
|
137
|
+
{ "name": "Durum", "slug": "status", "dbType": "VARCHAR", "commonType": "text",
|
|
138
|
+
"relationType": "none", "nullable": false,
|
|
139
|
+
"isEnum": true,
|
|
140
|
+
"valueOptions": [
|
|
141
|
+
{ "value": "Aktif", "icon": "#47ad10" },
|
|
142
|
+
{ "value": "Bırakıldı", "icon": "#888888" },
|
|
143
|
+
{ "value": "Tamamlandı", "icon": "#0052CC" }
|
|
144
|
+
] }
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- `valueOptions[].icon` bir **hex renktir**, ikon adı değil.
|
|
148
|
+
- `isEnum` Studio tarafında `valueOptions.length > 0` ile türetilir; yine de ikisini birlikte ver.
|
|
149
|
+
- **Enum PostgreSQL'de CHECK constraint üretir.** Var olan bir metin alanını enum'a çevirirken
|
|
150
|
+
tablodaki değerler `valueOptions` içinde yoksa migration `check constraint ... is violated` ile
|
|
151
|
+
düşer. Sıra: **önce satırları kanonik değerlere taşı, sonra alanı enum yap.**
|
|
152
|
+
|
|
153
|
+
## Artan kod alanı (`Incremental`)
|
|
154
|
+
|
|
155
|
+
Sıralı, önekli, insan okuyabilir kod üretir (`TLP-0001`). Alan tanımı:
|
|
156
|
+
|
|
157
|
+
```jsonc
|
|
158
|
+
{ "name": "Talep No", "slug": "ticket_no",
|
|
159
|
+
"dbType": "Incremental", "commonType": "incremental",
|
|
160
|
+
"relationType": "none", "nullable": false, "unique": true,
|
|
161
|
+
"properties": { "isCaseSensitive": false } }
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Kod satır yazılırken üretilir ve üretimi ALANA YAZDIĞIN DEĞERİN TİPİ belirler**
|
|
165
|
+
(`EntityService.ApplyIncrementalValuesAsync`) — `row_create`, `row_update` ve workflow table
|
|
166
|
+
create step'inde aynı kural geçerlidir:
|
|
167
|
+
|
|
168
|
+
```jsonc
|
|
169
|
+
// NESNE verirsen: platform kodu üretir ve değeri onunla DEĞİŞTİRİR
|
|
170
|
+
"ticket_no": { "Prefix": "TLP", "Separator": "-", "Counter": 1, "DigitCount": 4 } // → "TLP-0001"
|
|
171
|
+
|
|
172
|
+
// STRING verirsen: olduğu gibi yazılır, üretim ATLANIR (veri taşımada işine yarar)
|
|
173
|
+
"ticket_no": "TLP-0002"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Girdi sınırları (`IncrementalCodeInput.TryParse`; ihlal edilirse nesne geçersiz sayılır ve kod
|
|
177
|
+
üretilmez): `Prefix` ≤ 3 karakter · `Separator` ≤ 1 karakter · `Counter` ≥ 1 ·
|
|
178
|
+
`DigitCount` 1–12.
|
|
179
|
+
|
|
180
|
+
- **Sayaç kendini onarır:** üretim var olan en yüksek koddan devam eder
|
|
181
|
+
(`EntityIncrementSequenceService.ResolveStartingCounterAsync`), yani elle `TLP-0005` yazdıktan
|
|
182
|
+
sonra nesne biçimiyle yazılan ilk satır `TLP-0006` olur. `Counter: 1` vermek "1'den başla"
|
|
183
|
+
demek değil, "taban 1" demektir.
|
|
184
|
+
- `properties.isCaseSensitive` büyük/küçük harf duyarlılığını belirler (`Field.IsCaseSensitiveIncremental`).
|
|
185
|
+
- Sayfa tarafındaki karşılığı `incrementalinput` komponentidir.
|
|
186
|
+
- `datasource_list.dataTypes` çıktısında bu tipi ayrı bir grup olarak görürsün; listede
|
|
187
|
+
görmezsen yine de geçerlidir (rehberdeki "dataTypes'a güvenme" uyarısı burada da geçerli).
|
|
188
|
+
|
|
189
|
+
## Primary key
|
|
190
|
+
|
|
191
|
+
```jsonc
|
|
192
|
+
// GUID anahtar
|
|
193
|
+
{ "name": "ID", "slug": "id", "dbType": "UUID", "commonType": "guid",
|
|
194
|
+
"primaryKey": true, "nullable": false, "unique": true, "identity": true,
|
|
195
|
+
"defaultValueType": "none", "defaultValue": "",
|
|
196
|
+
"properties": { "generationType": 0 }, "relationType": "none" }
|
|
197
|
+
|
|
198
|
+
// INT anahtar (auto-increment) — dbType ve commonType dışında birebir aynı
|
|
199
|
+
{ "name": "ID", "slug": "id", "dbType": "INT4", "commonType": "number",
|
|
200
|
+
"primaryKey": true, "nullable": false, "unique": true, "identity": true,
|
|
201
|
+
"defaultValueType": "none", "defaultValue": "",
|
|
202
|
+
"properties": { "generationType": 0 }, "relationType": "none" }
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
- **GUID zorunlu değildir.** `UUID/guid` ve `INT2|INT4|INT8 / number` ikisi de geçerli birinci
|
|
206
|
+
sınıf seçeneklerdir; platform kuralı GUID dayatmaz (bu, backend repo'sunun `Guid.CreateVersion7()`
|
|
207
|
+
kuralıyla karıştırılmamalı — o C# tarafının kuralı, platform verisinin değil). Yüksek hacimli /
|
|
208
|
+
sıralı okunması doğal tablolarda (yoklama, log, hareket) `INT4` tercih edilebilir; dağıtık
|
|
209
|
+
üretim, dışa açık id, birleştirilecek veri varsa `UUID`.
|
|
210
|
+
- **`identity: true` + `properties.generationType: 0` olmadan anahtar otomatik üretilmez** ve her
|
|
211
|
+
satırda id elle gönderilmek zorunda kalır. `generationType` datasource seçenekleri:
|
|
212
|
+
`0 = Always`, `1 = ByDefault`.
|
|
213
|
+
- `properties.generationType` **yalnız primary key'de** anlamlıdır; identity olmayan alanlarda
|
|
214
|
+
Studio bu anahtarı zaten siler.
|
|
215
|
+
- Doğrulama: satır yazdıktan sonra `row_list` ile geri oku — id üretilmişse (`1, 2, 3…` ya da
|
|
216
|
+
UUIDv7) anahtar doğru kurulmuştur.
|
|
217
|
+
|
|
218
|
+
Gateway bu iki kuralı ENT-006 (PK identity/tip uyumu) ve ENT-007 (enum şekli) olarak denetler.
|
|
219
|
+
|
|
220
|
+
## Application bağı — ne yapar, ne yapmaz
|
|
221
|
+
|
|
222
|
+
`applicationIds` **create'te platformca bağlanır** (`CreateEntityCommand` → `EntityService.CreateAsync`
|
|
223
|
+
→ `Entity` ctor). Gateway'in ayrıca patch atmasına gerek yok.
|
|
224
|
+
|
|
225
|
+
Bağın gerçek etkisi ikidir:
|
|
226
|
+
|
|
227
|
+
- `EntityRepository.cs:167` — `entity_list`'in `applicationId` filtresi, yani **Studio'nun
|
|
228
|
+
application bazlı entity listesi**. Bağsız entity o listede görünmez.
|
|
229
|
+
- `MicroserviceRepository.cs:556` — bağımlılık/etki analizi sorgusu.
|
|
230
|
+
|
|
231
|
+
**Satır uçları bu bağa İHTİYAÇ DUYMAZ.** Bağsız bir entity'de `row_create` / `row_list` sorunsuz
|
|
232
|
+
çalışır (16 satırlık bağsız tabloda doğrulandı). Eski "bağsız entity'de satır uçları 500
|
|
233
|
+
'Sequence contains no matching element' döner" bilgisi **yanlıştı**, kod tarafında karşılığı yok.
|
|
234
|
+
|
|
235
|
+
**Bağ auto page ÜRETMEZ.** Auto page üreten
|
|
236
|
+
`UpdatePageWhenEntityUpdatedEventHandler`, `EntityApplications`'a değil `PageSettings`'e bakar
|
|
237
|
+
(`PageSettings` boşsa hiç çalışmaz) ve `PageSettings` yalnız `UpdateEntityCommand.AutoPages`
|
|
238
|
+
ile dolar. 10 entity'nin tamamı bağlıyken `entity_page_settings = 0`, `pages = 1` ölçüldü.
|
|
239
|
+
|
|
240
|
+
Karar: **Studio'dan yönetilecek entity'lerde `applicationIds` ver; yalnız API'den kullanılacaksa
|
|
241
|
+
boş bırakmak geçerli bir tercihtir** (ENT-002 warn'ı bunu hatırlatır, zorunlu kılmaz).
|
|
242
|
+
|
|
243
|
+
> `entity_patch` uyarısı: `EntityDto` çıktıda `applications` (nesne listesi) döner ama
|
|
244
|
+
> `UpdateEntityCommand` girdide `applicationIds` (Guid listesi) okur. Gateway bu çeviriyi
|
|
245
|
+
> kendisi yapar; ham PUT atarken **siz yapmazsanız her güncelleme bağı sessizce siler.**
|
|
246
|
+
|
|
247
|
+
## İlişkiler (doğru şekil — 57 alanla doğrulandı)
|
|
248
|
+
|
|
249
|
+
```jsonc
|
|
250
|
+
{ "name": "Department", "slug": "department_id",
|
|
251
|
+
"dbType": "RELATION", "commonType": "relation",
|
|
252
|
+
"relationType": "one-to-many",
|
|
253
|
+
"relationId": "<hedef entity id>",
|
|
254
|
+
"nullable": true }
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
- `relation` alt nesnesini (`primaryKeyId`, `displayFieldId`, ...) **platform kendisi doldurur**
|
|
258
|
+
— elle verme.
|
|
259
|
+
- `relationType`: `one-to-one | one-to-many | many-to-many`.
|
|
260
|
+
- **m2m yalnız FARKLI iki entity arasında kurulabilir.** Kendine referanslı m2m (ör. ders ↔
|
|
261
|
+
ön koşul ders) platformda `500 "Operation is not valid due to the current state of the object"`
|
|
262
|
+
ile reddedilir. Kendine referans gerekiyorsa ara entity + iki one-to-many kullan.
|
|
263
|
+
- m2m değerleri satırlara **id dizisi** olarak yazılır (`{"qualified_courses": ["<id>", "<id>"]}`),
|
|
264
|
+
okurken `[{ id, <displayAlanı> }]` döner.
|
|
265
|
+
- **m2m mi, ara entity mi:** bağın kendisi ekstra alan taşımıyorsa (ürün↔etiket) → m2m alanı
|
|
266
|
+
(Studio çoklu seçim UI'ı bedava). Bağın kendi alanları varsa (tarih, puan, durum) → ayrı
|
|
267
|
+
entity + iki yana one-to-many.
|
|
268
|
+
- İki entity'yi önce ilişkisiz oluşturup ilişki alanını sonra `entity_patch` ile eklemek en
|
|
269
|
+
güvenli sıra (id'ler ancak oluşunca belli olur).
|
|
270
|
+
- `display: true` entity başına tek alanda olabilir; ilişkilerde görüntülenen değer bu alandır.
|
|
271
|
+
|
|
272
|
+
## TEXT kolonunda JSON: yazarken string, okurken NESNE döner
|
|
273
|
+
|
|
274
|
+
Şema ile ifade edilemeyen değişken yapıları (anket cevabı, ayar bloğu, anlık görüntü) `TEXT`
|
|
275
|
+
kolonda JSON metni olarak tutmak meşru bir desendir — ama **gidiş ve dönüş şekli aynı değildir**;
|
|
276
|
+
bilmezsen "kayıt bozulmuş" sanırsın.
|
|
277
|
+
|
|
278
|
+
- **Yazarken string ver.** Microservice/flow parametresinde `JSON.stringify(...)` gönder; alan
|
|
279
|
+
`commonType: text` olduğu için dizi/nesne göndermek doğru değildir.
|
|
280
|
+
- **Okurken platform onu senin için AYRIŞTIRIR.** `DictionaryExtensions.ToNested()`
|
|
281
|
+
(`NgApps.Infrastructure/Extensions/DictionaryExtensions.cs:49-64`) her string değere bakar;
|
|
282
|
+
kırpılmış hâli `{`…`}` ya da `[`…`]` ile başlayıp bitiyorsa `ToObject<object>()` ile parse eder,
|
|
283
|
+
patlarsa string olarak bırakır. Yani `row_list` / uç yanıtı sana **hazır nesne/dizi** verir —
|
|
284
|
+
ikinci kez `JSON.parse` etme.
|
|
285
|
+
- **Yan etki:** JSON'a benzeyen ama JSON olmayan metinler (`[taslak]`, `{sablon}`) de bu kontrole
|
|
286
|
+
girer; parse başarısız olunca string kalır, veri bozulmaz.
|
|
287
|
+
|
|
288
|
+
> **Studio tablosunda `[object Object],[object Object]` görmek NORMALDİR ve veri sağlamdır.**
|
|
289
|
+
> Grid hücresi değeri `row[cell.key]?.toString()` ile basıyor
|
|
290
|
+
> (`apps/studio/src/components/data-grid/DataGrid.svelte:125`); parse edilmiş bir dizide bu
|
|
291
|
+
> ifade `[object Object],…` üretir. Ölçüm (anket projesi, 2026-08-19): grid'de `[object Object]`
|
|
292
|
+
> görünen satırın `row_list` çıktısı `question_id / question_text / type / value_text /
|
|
293
|
+
> option_ids` alanlarıyla eksiksizdi. Gerçek içeriği görmek için grid'e değil `row_list`'e bak.
|
|
294
|
+
> Kolonu tabloda okunur göstermek gerekiyorsa özet bir alan daha tut (ör. `answer_summary` TEXT)
|
|
295
|
+
> ya da sayfada `repeater`/`html` ile render et.
|
|
296
|
+
|
|
297
|
+
## Satır işlemleri
|
|
298
|
+
|
|
299
|
+
- `row_create/row_update` anahtarları **field slug'larıdır** (name değil): `{"code": "IK"}`.
|
|
300
|
+
- Yazdıktan sonra `row_list` ile geri oku; ilişki alanları `{ id, name }` nesnesi olarak döner.
|
|
301
|
+
- **`isAuditTrailActive: true` ile KURULAN entity'ye satır yazılamaz.** `sys_*` kolonları create
|
|
302
|
+
yolunda oluşmaz, yalnız ilk **etkin** `entity_update`'inde eklenir; o ana kadar **her**
|
|
303
|
+
`row_create` şu hatayla 500 verir:
|
|
304
|
+
|
|
305
|
+
```
|
|
306
|
+
Sequence contains no matching element [InvalidOperationException]
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Gateway'in bu vakadaki "entity bir application'a bağlı değil (PLT-004)" ipucu **yanlış yöne
|
|
310
|
+
gönderir** — entity bağlıyken de aynı hata çıkar, `row_list` çalışır, yalnız yazma kilitlidir.
|
|
311
|
+
`true → true` aynı-değer patch'i **saymaz** (etkisiz update). İki güvenli yol: entity'yi
|
|
312
|
+
`isAuditTrailActive: false` ile kur, ya da create'ten sonra `false → true` turunu at.
|
|
313
|
+
|
|
314
|
+
> `Sequence contains no matching **element**` (audit kolonu eksik) ile
|
|
315
|
+
> `Sequence contains no **elements**` (satır yok — genelde preview rollback'i) **farklı**
|
|
316
|
+
> sorunlardır; karıştırmak teşhisi saptırır.
|
|
317
|
+
|
|
318
|
+
- **Audit izi ne zaman gerçekten yazılır?** `CreateAuditTrailCommandHandler` şu üç durumda
|
|
319
|
+
**hiç kayıt açmaz**: `IsAuditTrailActive == false`, `AuditTrailType == null`, ya da
|
|
320
|
+
`AuditTrailType == simple`. Yani iz tutulması için `isAuditTrailActive: true` **ve**
|
|
321
|
+
`auditTrailType: "basic" | "detailed"` birlikte gerekir. Enum yalnız üç değer tanır —
|
|
322
|
+
`simple` · `basic` · `detailed` (`AuditTrailType.cs`); `advanced` diye bir değer **yoktur**,
|
|
323
|
+
gönderirsen bağlama hatası alırsın.
|
|
324
|
+
- **Audit izi IP adresi tutar.** `audit_trails.IpAddress`, isteğin
|
|
325
|
+
`HttpContext.Connection.RemoteIpAddress` değerinden doldurulur (`UserContext.cs`) ve satır
|
|
326
|
+
olaylarıyla (`Row.Created/Updated/Deleted` → `UserIpAddress`) audit consumer'a taşınır; kullanıcı
|
|
327
|
+
id'si ve e-postası da aynı yolla gider.
|
|
328
|
+
|
|
329
|
+
> **Anonim veri toplayan tablolarda `isAuditTrailActive: false` bırak** — anket cevabı, geri
|
|
330
|
+
> bildirim, başvuru gibi "kimliksiz" vaadi olan her tabloda. `false` iken hiçbir gizli kolon ya
|
|
331
|
+
> da yan kayıt oluşmaz; `true` + `basic/detailed` iken "anonim" dediğin satırın yanında IP
|
|
332
|
+
> durur. Bu, ürünün gizlilik vaadini sessizce bozan tek ayardır.
|
|
333
|
+
|
|
334
|
+
- **`defaultValueType: "static"` sessizce `"none"`e düşer** — DB varsayılanı kurulmaz. Bu yüzden
|
|
335
|
+
her `BOOL`/sayısal alanı **her** `row_create`'te ve her workflow write adımında **açıkça** yaz;
|
|
336
|
+
"varsayılanı platform koyar" varsayımı `null` satır üretir.
|
|
337
|
+
- **`row_list`'in `filters` parametresi çalışmıyor** — denenen her biçim
|
|
338
|
+
`Failed to invoke 'CompileNestedCondition'` ile 500 verir. Daraltmayı `selectedFields` +
|
|
339
|
+
`order` + `pageLength` ile yap, ya da doğrulamayı entity satırından değil **ucun kendisinden**
|
|
340
|
+
(`microservice_execute`) yap.
|
|
341
|
+
- **`users`'ta `row_create` verdiğin `id`'yi yok sayar** (PK `identity` + `generationType: 0`);
|
|
342
|
+
Studio operatörünü proje tablosuna aynı id ile taşıyamazsın, eşleme e-posta üzerinden kurulur.
|
|
343
|
+
- Silmeden önce `entity_dependencies` / `dependency_graph`.
|
|
344
|
+
|
|
345
|
+
## Büyük entity'lerde
|
|
346
|
+
|
|
347
|
+
`entity_get view:'outline'` alan listesi; `view:'part', part:'fields[slug=email]'` tek alan;
|
|
348
|
+
değişiklik `entity_patch`.
|