@appaflytech/zeyrek-ai-mcp 0.0.4 → 0.0.6
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 +8 -3
- package/.env.production.example +2 -0
- package/README.md +229 -193
- package/dist/config.js +20 -2
- package/dist/knowledge/backendConstraints.js +897 -0
- package/dist/knowledge/componentCatalog.js +196 -42
- package/dist/knowledge/coverage.js +43 -0
- package/dist/knowledge/flowGuards.js +30 -0
- package/dist/knowledge/guideSections.js +49 -0
- package/dist/knowledge/hydrate.js +97 -0
- package/dist/knowledge/languageCodes.js +36 -0
- package/dist/knowledge/languages.js +105 -0
- package/dist/knowledge/layoutSummary.js +10 -0
- package/dist/knowledge/localization.js +51 -0
- package/dist/knowledge/normalize.js +449 -16
- package/dist/knowledge/outlines.js +136 -12
- package/dist/knowledge/propTypes.js +80 -0
- package/dist/knowledge/rules.js +618 -43
- package/dist/knowledge/schemaGuard.js +199 -0
- package/dist/knowledge/styleResolve.js +63 -4
- package/dist/observability/trace.js +27 -3
- package/dist/platform/errors.js +46 -4
- package/dist/platform/http.js +33 -4
- package/dist/platform/patch.js +27 -0
- package/dist/platform/refs.js +104 -0
- package/dist/platform/responses.js +9 -2
- package/dist/platform/screenshot.js +527 -16
- package/dist/platform/secrets.js +40 -0
- package/dist/platform/tokenVault.js +89 -0
- package/dist/platform/writeDiff.js +281 -0
- package/dist/resources/examples/layout-app-shell.json +1 -1
- package/dist/resources/examples/microservice-table-list.json +2 -4
- package/dist/resources/examples/page-dynamic-form.json +2 -2
- package/dist/resources/examples/page-flex-sections.json +99 -0
- package/dist/resources/examples/page-sign-in.json +3 -2
- package/dist/resources/guides/component.md +69 -8
- package/dist/resources/guides/entity.md +404 -16
- package/dist/resources/guides/expressions.md +44 -2
- package/dist/resources/guides/external-component.md +9 -0
- package/dist/resources/guides/getting-started.md +77 -7
- package/dist/resources/guides/layout.md +53 -10
- package/dist/resources/guides/microservice.md +226 -13
- package/dist/resources/guides/middleware.md +89 -1
- package/dist/resources/guides/page.md +383 -46
- package/dist/resources/guides/translation.md +126 -8
- package/dist/resources/guides/view.md +16 -1
- package/dist/resources/guides/workflow.md +198 -27
- package/dist/resources/knowledge.js +5 -0
- package/dist/resources/rules.js +27 -0
- package/dist/resources/schema-fingerprint.json +8 -0
- package/dist/resources/schemas/CreateBulkRowCommand.json +33 -0
- package/dist/resources/schemas/CreateDatasourceCommand.json +15 -6
- package/dist/resources/schemas/CreateDiscoveredEntitiesCommand.json +19 -8
- package/dist/resources/schemas/CreateEntityCommand.json +52 -12
- package/dist/resources/schemas/CreateMicroserviceCommand.json +26 -2
- package/dist/resources/schemas/CreateQueryCommand.json +56 -3
- package/dist/resources/schemas/CreateRowCommand.json +38 -0
- package/dist/resources/schemas/CreateViewCommand.json +13 -10
- package/dist/resources/schemas/CreateWorkflowCommand.json +95 -14
- package/dist/resources/schemas/GetRowsQuery.json +3 -0
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +16 -0
- package/dist/resources/schemas/PreviewQueryCommand.json +5 -2
- package/dist/resources/schemas/PreviewWorkflowCommand.json +34 -9
- package/dist/resources/schemas/StepDto.json +23 -3
- package/dist/resources/schemas/UpdateBulkRowCommand.json +33 -0
- package/dist/resources/schemas/UpdateDatasourceCommand.json +15 -6
- package/dist/resources/schemas/UpdateEntityCommand.json +49 -10
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +28 -3
- package/dist/resources/schemas/UpdateQueryCommand.json +13 -3
- package/dist/resources/schemas/UpdateRowCommand.json +40 -0
- package/dist/resources/schemas/UpdateViewCommand.json +15 -10
- package/dist/resources/schemas/UpdateWorkflowCommand.json +95 -14
- package/dist/server.js +4 -0
- package/dist/tools/access.js +3 -3
- package/dist/tools/applications.js +1 -1
- package/dist/tools/automations.js +63 -30
- package/dist/tools/common.js +39 -0
- package/dist/tools/components.js +16 -7
- package/dist/tools/datasources.js +83 -21
- package/dist/tools/deployments.js +34 -2
- package/dist/tools/dtos.js +25 -12
- package/dist/tools/entities.js +113 -28
- package/dist/tools/externalComponents.js +9 -3
- package/dist/tools/files.js +20 -6
- package/dist/tools/flows.js +110 -11
- package/dist/tools/folders.js +7 -2
- package/dist/tools/globalFunctions.js +63 -0
- package/dist/tools/layouts.js +103 -29
- package/dist/tools/microservices.js +229 -38
- package/dist/tools/organizations.js +5 -6
- package/dist/tools/pages.js +365 -100
- package/dist/tools/platformInfo.js +152 -11
- package/dist/tools/projects.js +183 -33
- package/dist/tools/queries.js +32 -10
- package/dist/tools/rows.js +159 -45
- package/dist/tools/screenWrite.js +59 -0
- package/dist/tools/screens.js +28 -0
- package/dist/tools/translations.js +24 -8
- package/dist/tools/views.js +20 -10
- package/dist/tools/workflows.js +33 -16
- package/package.json +6 -3
|
@@ -14,9 +14,41 @@ kendi arayüz dili (`i18n.md`, yalnız frontend'i ilgilendirir) ile **karıştı
|
|
|
14
14
|
`key`'e bakar).
|
|
15
15
|
- Proje **dilleri** ve **varsayılan dil** application değil **proje** düzeyinde ayardır
|
|
16
16
|
(`project_get`/`project_update` `languages`/`defaultLanguage`) ve tam **ISO 639-1** kod
|
|
17
|
-
kümesinden seçilir (`ProjectConstants.SupportedLanguages`, ~184 kod).
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
kümesinden seçilir (`ProjectConstants.SupportedLanguages`, ~184 kod).
|
|
18
|
+
|
|
19
|
+
## ÖNCE DİLLERİ KUR — yoksa çeviri yazmak hiçbir işe yaramaz
|
|
20
|
+
|
|
21
|
+
> **Gateway'den açılan projede bu iş halledilmiştir (PRJ-003).** Platformun create ucu dil alanı
|
|
22
|
+
> taşımadığı için `project_create` projeyi dilsiz doğuruyordu; gateway artık create'ten hemen sonra
|
|
23
|
+
> dilleri kuruyor — verdiğinizi, vermezseniz tek dillik `['en']` + `'en'` tohumunu — ve bunu
|
|
24
|
+
> `gatewayNormalized` ile bildiriyor. Başka dil istiyorsanız `project_create`'e `languages`
|
|
25
|
+
> yazın. Aşağısı **eski projeler** ve gateway dışından açılmış projeler için geçerlidir.
|
|
26
|
+
|
|
27
|
+
**Platform tarafında yeni proje dilsiz doğar:** `CreateOrganizationProjectCommand`
|
|
28
|
+
`Languages`/`DefaultLanguage` alanı taşımaz, ikisi de `null` başlar. Bu durumda:
|
|
29
|
+
|
|
30
|
+
1. `translation_update` yazmayı **kabul eder ve 200 döner** — satırlar veritabanına düşer.
|
|
31
|
+
2. Runtime sayfa paketi `languages: null` taşır, aktif dil hiç seçilemez ve fallback zinciri
|
|
32
|
+
anahtarın kendisine düşer: ekranda `dashboard.card.candidate_statistics` yazar.
|
|
33
|
+
3. **Hiçbir katman uyarmaz.** Backend dil kodunu yalnız 184 kodluk ISO sözlüğüne göre doğrular
|
|
34
|
+
(TR-001), projenin `languages` listesine göre **doğrulamaz** — iki aggregate arasında bağ yoktur.
|
|
35
|
+
|
|
36
|
+
Ölçüldü: 2026-09-09 1. koşu `S-15` — 15 anahtar × 2 dil (200) + 15 prop bağı (200), ekranda her
|
|
37
|
+
etiket ham anahtar. Koşunun en pahalı sessiz düşmesi; yalnız gerçek karede görülüyor.
|
|
38
|
+
|
|
39
|
+
```jsonc
|
|
40
|
+
// SIRA: önce bu
|
|
41
|
+
{ "id": "<project id>", "languages": ["en", "tr"], "defaultLanguage": "en" } // project_update
|
|
42
|
+
// sonra çeviriler
|
|
43
|
+
{ "applicationId": "<app id>", "keys": [ /* … */ ] } // translation_update
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Gateway bu bağı kurar: `translation_update` yazmadan önce projeyi okur ve liste boşsa, kod listede
|
|
47
|
+
yoksa ya da `defaultLanguage` kurulu değilse **TR-002 caution** düşürür (yazmayı durdurmaz).
|
|
48
|
+
`project_get` ve `project_overview` yanıtlarındaki `localization` bloğu durumu doğrudan söyler —
|
|
49
|
+
`runtimeResolvesTranslations: false` ise çeviri yazmanın ekranda karşılığı olmayacak demektir.
|
|
50
|
+
Platform dil alanlarını `null` olduklarında serileştirmede düşürdüğü için ham yanıtta `languages`
|
|
51
|
+
diye bir alan **hiç görünmez**; blok tam olarak bunu görünür kılmak için var.
|
|
20
52
|
|
|
21
53
|
## Araçlar
|
|
22
54
|
|
|
@@ -49,12 +81,36 @@ backend'de zaten tanımlı, Studio'nun "Translate" aksiyonunun ürettiği şekil
|
|
|
49
81
|
"value": { "type": "translation", "ref": "home.welcome", "data": "Hoş geldiniz" } }
|
|
50
82
|
```
|
|
51
83
|
|
|
84
|
+
> **`replace_prop` ile kurulamaz, `set_prop_type` ile kurulur.** Micro-op applier her `value`'yu
|
|
85
|
+
> `Static` (ifade verilmişse `Code`) Prop'a çevirir (`PageSchemaMicroOpApplier.cs:77`);
|
|
86
|
+
> `translation` sarmalı gönderildiğinde sarmal `Data`'nın içine düşer ve prop sessizce bozulur.
|
|
87
|
+
> Gateway `replace_prop`'un bu kullanımını **reddeder**. Kurulu bir prop'u çeviriye bağlamanın
|
|
88
|
+
> yolu `set_prop_type`'tır:
|
|
89
|
+
>
|
|
90
|
+
> ```jsonc
|
|
91
|
+
> { "op": "set_prop_type", "target": "welcome_text", "prop": "text",
|
|
92
|
+
> "propType": "translation", "ref": "home.welcome" }
|
|
93
|
+
> ```
|
|
94
|
+
>
|
|
95
|
+
> Gateway şemayı okur, prop'un TİPİNİ yerinde değiştirir ve sayfayı tam gövdeyle geri yazar —
|
|
96
|
+
> düğümün olay/setter bağları korunur. Eski yol (`remove_component` + `add_component`) düğümü
|
|
97
|
+
> yeniden kurduğu için ona yazan setter iteratee'lerini sessizce öldürüyordu; artık gerekmiyor.
|
|
98
|
+
> Taşıyıcı alan tipe göre değişir: `static` → `data`, `code` ve `translation` → `ref`. Eksik
|
|
99
|
+
> taşıyıcı istek platforma gitmeden reddedilir ve `page_schema_validate` aynı kararı verir.
|
|
100
|
+
>
|
|
101
|
+
> Ölçüldü 2026-09-08 (yerel `dil-dogrulama/dil-app`): kurulu bir `statcard`'ın `title` prop'u tek
|
|
102
|
+
> `set_prop_type` op'uyla `f11.tam` anahtarına bağlandı; gerçek ekranda `tr` → "iki dilde dolu",
|
|
103
|
+
> `en` → "filled in both", `de` → "in beiden gefuellt" ve dil değişimi sayfa yenilenmeden geçti.
|
|
104
|
+
|
|
52
105
|
- **Anahtar `ref`'tedir, `data` DEĞİL.** Runtime her `getNodeProps` turunda `data`'yı
|
|
53
106
|
`resolveTranslation(...)` sonucuyla EZER (`code` prop'larıyla aynı davranış — `page.md` Kural 1c
|
|
54
107
|
bunun `code` karşılığını anlatır). `ref`'i okumadan/yazmadan `data`'ya güvenme; `data` yalnız
|
|
55
108
|
Studio'nun sakladığı önceki statik değerdir (fallback/geri dönüş amaçlı, çözümlemeyi ETKİLEMEZ).
|
|
56
109
|
- **Fallback zinciri:** aktif dil → projenin varsayılan dili → anahtarın kendisi. Boş string de
|
|
57
110
|
"eksik" sayılır ve zincirde bir alt basamağa düşer — bir anahtar hiçbir zaman boş render olmaz.
|
|
111
|
+
Zincirin sonu anahtarın kendisi olduğu için **proje dilsizken ekran boş değil, ham anahtar dolu
|
|
112
|
+
görünür** — hata gibi durmadığı için gözden kaçar. Kaynak: `resolveRuntimeLanguage` +
|
|
113
|
+
`resolveTranslation` (`zeyrek-frontend/packages/ng-apps-screen-builder/src/translation.functions.ts`).
|
|
58
114
|
- Hangi prop'lar çeviriye bağlanabilir platformca kısıtlanmaz (Studio'da yalnız `text`/`long-text`
|
|
59
115
|
tipli prop'larda "Translate" aksiyonu gösterilir, ama şema düzeyinde her static prop aynı Prop
|
|
60
116
|
şeklini kabul eder).
|
|
@@ -67,14 +123,76 @@ Son kullanıcı dili `language-selector` komponentiyle değiştirir (`platform_g
|
|
|
67
123
|
prop'lar sayfa yenilenmeden yeniden çözülür — ayrı bir akış kurmana gerek yok, komponenti sayfaya
|
|
68
124
|
eklemen yeterli. Projede dil tanımlı değilse (`languages` boşsa) liste boş çizilir.
|
|
69
125
|
|
|
126
|
+
## İstek dili: nereden gelir, hangi ifadede ne denir
|
|
127
|
+
|
|
128
|
+
Her istekte dil şu sırayla çözülür: **`X-Data-Language` başlığı → `Accept-Language` → projenin
|
|
129
|
+
varsayılan dili**. Bölgeli kodlar dil kısmına indirilir (`tr-TR` → `tr`). Aynı değer hem satır
|
|
130
|
+
okumasında (companion tablosu), hem sayfa çevirilerinde, hem ifadelerde kullanılır.
|
|
131
|
+
|
|
132
|
+
| Dünya | Aktif dil | Anahtar çözme | Nerede |
|
|
133
|
+
|---|---|---|---|
|
|
134
|
+
| UI flow (tarayıcı) | `machine` state'i | `t(key)` | `platform_guide('expressions')` §2 |
|
|
135
|
+
| Backend (workflow/microservice ifadesi) | `context.language` | `Loc(key)` | `platform_guide('workflow')` |
|
|
136
|
+
| Ham SQL | — | `{{language}}` ayrılmış parametresi | `platform_guide('microservice')` |
|
|
137
|
+
|
|
138
|
+
`t()` ve `Loc()` **aynı fallback zincirini** izler: aktif dil → projenin varsayılan dili →
|
|
139
|
+
anahtarın kendisi; boş string de "eksik" sayılır. İsimlerin farklı olmasının tek sebebi iki ayrı
|
|
140
|
+
motor olmasıdır (tarayıcı JS'i ve Jint).
|
|
141
|
+
|
|
142
|
+
> **Backend motorunun kültürü de istek dilinden gelir.** `tr` isteğinde `tr-TR`, diğer her dilde
|
|
143
|
+
> `en-US`. Eskiden `tr-TR`'ye sabitti; sabit biçim istiyorsan kültüre güvenme.
|
|
144
|
+
|
|
145
|
+
## Sayfa sekmesi başlığı: `browserTitleKey`
|
|
146
|
+
|
|
147
|
+
`page_update` / `page_create` `browserTitle` (düz metin) yanında `browserTitleKey` alır. Anahtar
|
|
148
|
+
verilmişse sekme başlığı çeviri sözlüğünden çözülür; anahtar boşsa `browserTitle` olduğu gibi
|
|
149
|
+
kullanılır. İkisi de boşsa sayfa adı yazılır.
|
|
150
|
+
|
|
151
|
+
> **Sekme başlığı SAYFA YÜKLENİRKEN çözülür, canlı dil değişimini İZLEMEZ.** Ölçüldü 2026-09-08
|
|
152
|
+
> (yerel runtime): `language-selector` ile dil değiştirildiğinde sayfa içeriği ve layout başlığı
|
|
153
|
+
> anında yeni dile geçiyor, sekme başlığı ise açılıştaki dilde kalıyor; aynı dille sayfa yeniden
|
|
154
|
+
> yüklendiğinde başlık doğru geliyor. Sebep `Runtime.svelte`'te dilin bir `const` olarak bir kez
|
|
155
|
+
> çözülmesi. Sekme başlığının dilini doğrulayacaksan **yeniden yükleyerek** doğrula.
|
|
156
|
+
|
|
157
|
+
## Doğrulama mesajları: `t:` öneki
|
|
158
|
+
|
|
159
|
+
Komponent şemasındaki `validations[].message` bir **düz metindir** ve translation prop'u ALMAZ.
|
|
160
|
+
Çeviriye bağlamak için mesajın kendisine `t:` öneki konur:
|
|
161
|
+
|
|
162
|
+
```jsonc
|
|
163
|
+
{ "op": "set_validations", "target": "email_input",
|
|
164
|
+
"validations": [{ "type": "required", "message": "t:form.emailRequired", "isActive": true }] }
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Runtime `t:` ile başlayan bir mesajı anahtar sayar ve normal zincirden çözer; önek yoksa metin
|
|
168
|
+
olduğu gibi gösterilir. Çözüm çalışma anında olduğu için şema varsayılanlarını değiştirmek
|
|
169
|
+
gerekmez — `schema.ts`'e dokunulmaz, katalog yeniden yüklenmez.
|
|
170
|
+
|
|
70
171
|
## Bilinen sınırlar
|
|
71
172
|
|
|
72
173
|
- **Flow adımlarında Translation kaynağı YOK.** `value.type` sözlüğünde (`platform_guide('page')`
|
|
73
174
|
Kural 1c sonundaki tablo) `translation` yoktur — bir flow adımının **değerini** doğrudan bir
|
|
74
175
|
çeviri anahtarına bağlayamazsın, yalnız sayfa şemasındaki statik prop'lar bağlanabilir. İfadeden
|
|
75
|
-
okumak gerekiyorsa `t('anahtar')`
|
|
76
|
-
|
|
77
|
-
`
|
|
78
|
-
|
|
79
|
-
`
|
|
176
|
+
okumak gerekiyorsa **UI flow kodunda** `t('anahtar')` kullanılır: bu tarayıcı tarafındaki
|
|
177
|
+
`runCode` önsözünde tanımlı bir yardımcıdır, backend ifade yüzeyinde (Jint) karşılığı YOKTUR —
|
|
178
|
+
backend tarafının karşılığı `Loc()`'tur (`platform_guide('workflow')`). İkisinin de fallback
|
|
179
|
+
zinciri aynı: aktif dil → varsayılan dil → anahtarın kendisi
|
|
180
|
+
(`platform_guide('expressions')` §2).
|
|
181
|
+
- ~~Runtime sayfa yanıtı önbellekten eski çeviri döndürebilir.~~ **Çözüldü — 2026-09-08:**
|
|
182
|
+
`translation_update` artık uygulamanın bütün sayfalarının önbellek satırlarını düşürüyor
|
|
183
|
+
(`RefreshPageCacheWhenTranslationChangedCommand`), okuma yolu cache-aside olduğu için bir
|
|
184
|
+
sonraki `page_runtime_get` taze değeri kurar. Yazmadan hemen sonra okuyabilirsin.
|
|
80
185
|
- Mobil runtime (`apps/mobile`) bu özelliği henüz beslemiyor — yalnız web.
|
|
186
|
+
|
|
187
|
+
## Backend doğrulama sınırları (TR-001)
|
|
188
|
+
|
|
189
|
+
`translation_update` gövdesi platforma gitmeden denetlenir (block): `keys[].key` boş olamaz ve
|
|
190
|
+
tekil; `values`'taki dil kodları ISO 639-1 iki harfli küçük kod (`tr`, `en`, `de`… — `tr-TR`
|
|
191
|
+
reddedilir; 184 kodluk liste `ngapps://rules/backend-constraints` içinde); `deletedKeys` boş anahtar
|
|
192
|
+
taşıyamaz. Proje dilleri de aynı listeyle doğrulanır (`project_update`, PRJ-002).
|
|
193
|
+
|
|
194
|
+
**Bu listenin doğrulamadığı şey:** kodun PROJENİN `languages` listesinde olup olmadığı.
|
|
195
|
+
`UpdateTranslationsCommandValidator`, `UpsertTranslationKeyCommandValidator` ve
|
|
196
|
+
`Translation.ValidateState()` üçü de yalnız `ProjectConstants.SupportedLanguages`'a bakar; hiçbiri
|
|
197
|
+
`Project.Languages`'ı okumaz. Bağı **yalnız gateway** kurar (TR-002, `warn`) — Studio UI'dan ya da
|
|
198
|
+
doğrudan API'den yazan bir istemci için boşluk açık kalır.
|
|
@@ -4,6 +4,11 @@ View, **serbest metin araması** içindir: seçtiğin alanlar bir analizörden g
|
|
|
4
4
|
projeksiyon tablosuna indekslenir. **Raporlama/agregasyon aracı değildir** — özet/sayım için
|
|
5
5
|
`query_create` (raw SQL) + query kaynaklı microservice kullan.
|
|
6
6
|
|
|
7
|
+
> **İki bağımsız koşu da bu yanlış beklentiyle başladı** (09-02 M-3; 2026-09-04'ün iki koşusunda
|
|
8
|
+
> da tekrarladı): "view" adı SQL VIEW'ünü çağrıştırıyor, oysa buradaki view bir **arama
|
|
9
|
+
> indeksidir**. Karar tek satır: *sayı/özet mi istiyorsun* → `query_create`; *metin arıyor
|
|
10
|
+
> musun* → `view_create`. Tool açıklamaları da bunu söyler.
|
|
11
|
+
|
|
7
12
|
Gövde şemaları: `ngapps://schemas/CreateViewCommand` · `ngapps://schemas/UpdateViewCommand`.
|
|
8
13
|
|
|
9
14
|
## Kuruluş sırası
|
|
@@ -35,6 +40,10 @@ Gövde şemaları: `ngapps://schemas/CreateViewCommand` · `ngapps://schemas/Upd
|
|
|
35
40
|
- `analyzer` verilmezse platform `ViewAnalyzer.Default()` kullanır — Türkçe içerikte
|
|
36
41
|
`language: 'turkish'` + `tokenFilters: ['lowercase','asciifolding']` açıkça verilmelidir, yoksa
|
|
37
42
|
"Talep" ile "talep" ya da "yazilim" ile "yazılım" eşleşmez.
|
|
43
|
+
- `asciifolding` PostgreSQL `unaccent()` ile **hem indeks hem sorgu** tarafında uygulanır: filtre
|
|
44
|
+
açıkken "Ayse" araması "Ayşe" satırını döndürür. Filtreyi var olan bir view'a **sonradan**
|
|
45
|
+
eklersen eski projeksiyon satırları aksansız metni taşımaz — `view_rebuild` çağırmadan eşleşme
|
|
46
|
+
olmaz.
|
|
38
47
|
- `fields[].weight` sıralama ağırlığıdır (`double`): başlık 2, gövde 1 gibi.
|
|
39
48
|
- `fields[].viewEntityAlias`, `entities[].alias` ile birebir eşleşmeli. Eşleşmezse alan **sessizce
|
|
40
49
|
ilk tabloya** bağlanır (`ViewSourceMapper.Map` → `tablesByAlias.GetValueOrDefault(...) ?? tables.FirstOrDefault()`).
|
|
@@ -83,7 +92,13 @@ parametresi ister (+ `limit`/`offset`). Ayrıntı: `platform_guide('microservice
|
|
|
83
92
|
## Bakım
|
|
84
93
|
|
|
85
94
|
- `view_rebuild` projeksiyonu sıfırdan kurar; toplu satır yüklemesinden ya da alan listesi
|
|
86
|
-
değişikliğinden sonra çağır.
|
|
95
|
+
değişikliğinden sonra çağır. `analyzer.tokenFilters` değişikliği de (özellikle `asciifolding`)
|
|
96
|
+
rebuild ister — analyzer yalnız yeni yazılan satırlara uygulanır.
|
|
87
97
|
- View'in `slug`'ı projeksiyon tablosunun/indekslerinin adıdır — slug değiştirmek onları yeniden
|
|
88
98
|
adlandırır; elle oluşturulmuş bir tabloyla çakışmasın diye entity slug'larıyla aynı isim uzayında
|
|
89
99
|
düşün (`platform_guide('entity')` §"Slug seçimi").
|
|
100
|
+
|
|
101
|
+
## Backend doğrulama sınırı (VIEW-001)
|
|
102
|
+
|
|
103
|
+
`name` zorunlu; `providerType` yalnız `postgres` (tek değer). Gateway bunu istek gitmeden `block`
|
|
104
|
+
olarak uygular; tam katalog `ngapps://rules/backend-constraints`.
|
|
@@ -23,7 +23,7 @@ taşır; gateway açıklamasız gövdeyi platforma göndermez.
|
|
|
23
23
|
okunuyor ve hiçbir şey eklemiyor. `"kullanıcının asal pozisyonunu seçer; birden çok aktif atama
|
|
24
24
|
varsa is_primary olanı tercih eder, o da yoksa ilkini alır"` — yazılmadıkça hiçbir yerde
|
|
25
25
|
bulunmayan bilgi budur.
|
|
26
|
-
- **`start`
|
|
26
|
+
- **`start` muaftır** (kural açıklama istemez): yapısal işaretçi, açıklanacak
|
|
27
27
|
davranışları yok.
|
|
28
28
|
- **Gateway'in enjekte ettiği `gatewayOnError` adımı kendi açıklamasını taşır** — o adımı sen
|
|
29
29
|
yazmadığın için kural seni onun yüzünden durdurmaz.
|
|
@@ -74,6 +74,9 @@ outline görünümünde geri okunur — sonraki oturumda tuzağı tam gövdeyi a
|
|
|
74
74
|
4. **Kaydetmeden önce `workflow_preview`.** Test girdisi **`previewPayload`** anahtarıyla
|
|
75
75
|
verilir (`parameters`/`input` çalışmaz, ifadeler `undefined` üretir); değişkenler
|
|
76
76
|
`previewVariables`.
|
|
77
|
+
`type:'workflow'` için `previewPayload` göndereceksen önce `parameterDtoId` ve
|
|
78
|
+
`parameterBehavior` tanımlamalısın; DTO'suz workflow'ta alan gerekçeli doğrulama hatasıyla
|
|
79
|
+
reddedilir. Automation ve middleware preview değişkenleri kendi bağlam kurallarını izler.
|
|
77
80
|
- **`previewPayload` bir STRING olmalı ve tek kanonik biçimi `"({ … })"`'dir.** Alan
|
|
78
81
|
JavaScript **kaynak metni** bekliyor (`PreviewWorkflowCommand` gövdeyi `jsEngine.Eval` ile
|
|
79
82
|
çalıştırır) ve **ifadenin sonucu bir NESNE olmak zorundadır**:
|
|
@@ -101,12 +104,40 @@ outline görünümünde geri okunur — sonraki oturumda tuzağı tam gövdeyi a
|
|
|
101
104
|
`Sequence contains no elements` alırsın ve hata seni entity'yi suçlamaya iter.
|
|
102
105
|
Kalıcı satır istiyorsan akışı bağlı ucundan `microservice_execute` ile çağır.
|
|
103
106
|
|
|
107
|
+
## İstek dili: `context.language` ve `Loc()`
|
|
108
|
+
|
|
109
|
+
Aktif dil `context.language`, anahtar çözmek için `Loc(key)`. Motor kültürü de aynı dilden gelir
|
|
110
|
+
(`tr` → `tr-TR`, diğerleri `en-US`). **`context.language` yalnız gerçek istekte doludur** —
|
|
111
|
+
önizleme tetikleyici kaynağını kurmaz; dile bağlı dalı `microservice_execute` +
|
|
112
|
+
`headers: { 'X-Data-Language': 'tr' }` ile doğrula. Ayrıntı: `platform_guide('translation')`.
|
|
113
|
+
|
|
104
114
|
## Step'ler nasıl bağlanır
|
|
105
115
|
|
|
106
116
|
Her step'in `branches[]` dizisi vardır; `nextStepId` sonraki step'in id'sini gösterir.
|
|
107
117
|
Bağlanmamış step çalışmaz. `start` tek branch taşır; normal step'ler `success` + `fail`;
|
|
108
|
-
`condition` koşul branch'leri + `else`; terminal step'ler (`response`, `convert`, `revert
|
|
109
|
-
`end`
|
|
118
|
+
`condition` koşul branch'leri + `else`; terminal step'ler (`response`, `convert`, `revert`)
|
|
119
|
+
**branch taşımaz**. Ayrı bir `end` step tipi yoktur; son dalın `nextStepId` değerini
|
|
120
|
+
`null` bırakarak akışı bitirin.
|
|
121
|
+
|
|
122
|
+
## Preview yazmaz — rollback eder (ölçüm: İK koşusu W-1, 2026-09-01)
|
|
123
|
+
|
|
124
|
+
`workflow_preview` ve `microservice_preview` tek transaction'da koşar ve sonunda **rollback**
|
|
125
|
+
edilir (`PreviewWorkflowCommand`: `BeginTransactionAsync` → … → `RollbackTransactionAsync`).
|
|
126
|
+
Table create/update/upsert step'leri kalıcı satır **yazmaz**; preview'ı istediğin kadar tekrar
|
|
127
|
+
edebilirsin. Tek istisna: code step içinden yapılan **dış HTTP çağrıları** geri alınamaz — dış
|
|
128
|
+
sisteme yazan bir akışı preview'da koşarken bunu bil.
|
|
129
|
+
|
|
130
|
+
**Preview step/branch id'lerini de TÜKETMEZ** (ölçüldü 2026-09-05, `f09-repro`): aynı GUID
|
|
131
|
+
bloğuyla iki kez preview 200 döner, sonra aynı gövde `workflow_create`'e verilince id'ler olduğu
|
|
132
|
+
gibi kaydedilir — önizlemeye ayrı blok ayırmayın. Preview sonrası `RowAlreadyExists` alıyorsanız
|
|
133
|
+
sebebi Kural 3'tür: o id'ler kaydedilmiş başka bir akışta duruyordur.
|
|
134
|
+
|
|
135
|
+
`query_preview` de rollback edilir ve bu daha sinsidir: yazan bir sorgu `affectedRowCount`'ta
|
|
136
|
+
gerçek sayıyı döner, tablo boş kalır (ölçüm: 09-04 Y-19) ve **yanıtta rollback'i söyleyen bir alan
|
|
137
|
+
yoktur** (ölçüm: 2026-09-07). Yazmayı doğrulamak istiyorsan sorguyu kaydet, microservice/workflow
|
|
138
|
+
üzerinden çalıştır ve sonucu `row_list` ile say.
|
|
139
|
+
|
|
140
|
+
Tool açıklamaları bu bölüme işaret eder; iki kaynak çelişirse **bu rehber** doğrudur.
|
|
110
141
|
|
|
111
142
|
## Hata yolu
|
|
112
143
|
|
|
@@ -135,13 +166,16 @@ yapıyı dışarı sızdırır.
|
|
|
135
166
|
|
|
136
167
|
- **Global-error dalı TEK olmalı ve START adımında durmalı.** Başka adıma koyulan dal hiç
|
|
137
168
|
çalışmaz, platform 400 döner. Gateway bunu `WF-022` ile istek gitmeden reddeder.
|
|
138
|
-
-
|
|
139
|
-
|
|
169
|
+
- **`returnDtoId` süzmesi yalnız 2xx yanıtlarda uygulanır (2026-09-05).** Bir `response` adımının
|
|
170
|
+
`httpStatusCode`'u 2xx dışındaysa (401, 404, 422, 500…) gövde sözleşmeden GEÇMEZ ve
|
|
171
|
+
`bodyExpression` ne ürettiyse o döner. Yani bir koşul dalından `({ success: false, message: '…' })`
|
|
172
|
+
ile 401 dönmek için DTO'ya `message` alanı eklemek gerekmez — muafiyet artık global-error
|
|
173
|
+
dalıyla sınırlı değil. Öncesinde bu gövde sessizce boş `{}` oluyordu.
|
|
140
174
|
- **Loop içi hatalar global-error dalına GİTMEZ.** Loop çocuk bağlamı bu yönlendirmeyi kapatır;
|
|
141
175
|
loop adımının kendi `fail` dalını bağla.
|
|
142
176
|
- **`automation` tipinde `response` adımı yasaktır**, bu yüzden gateway bu tipe enjeksiyon
|
|
143
|
-
yapmaz. Hata yolunu kendin yaz: global-error dalını `revert` (
|
|
144
|
-
|
|
177
|
+
yapmaz. Hata yolunu kendin yaz: global-error dalını `revert` (kapsamı `isQueue`'ya
|
|
178
|
+
bağlı — §izin matrisi) ya da `email`/`table` adımına bağla. Bağlı hata yolu yoksa `WF-021` uyarır.
|
|
145
179
|
- **Hata yolu hiç yoksa** akış patladığında platform 500 + ham exception mesajı döner. Çalışır,
|
|
146
180
|
ama çıktı denetimsizdir ve lokalize değildir.
|
|
147
181
|
|
|
@@ -206,6 +240,27 @@ gidilir, hiçbiri tutmazsa `else` dalı yürür:
|
|
|
206
240
|
| convert | ✓ | – | – |
|
|
207
241
|
| revert (Fail and Rollback) | – | ✓ | – |
|
|
208
242
|
|
|
243
|
+
> **`revert`'in iki alanı JavaScript ifadesidir, düz metin değil.** `rule.revertType` ve
|
|
244
|
+
> `rule.revertMessage` çalışma anında `Evaluate` edilir; Studio bu alanları kod editörüyle sunar ve
|
|
245
|
+
> varsayılanlarını tırnaklı verir (`"Failed"`, `"Transaction is reverted."`). Tırnaksız metin
|
|
246
|
+
> gönderirsen ifade çözülmez ve adım
|
|
247
|
+
> `Step '<ad>' failed. Please check the workflow. [EvaluateWorkflowStepFailedException]` ile düşer;
|
|
248
|
+
> mesaj hangi alanın sorunlu olduğunu söylemez. Doğru yazım: `revertType: "'all'"`,
|
|
249
|
+
> `revertMessage: "'Is kurali hatasi.'"` (2026-09-02 ölçümü).
|
|
250
|
+
>
|
|
251
|
+
> **Önizlemede `revert` artık 400 değil, dolu bir adım ağacı döndürür (2026-09-05).** Kuru koşuda
|
|
252
|
+
> revert bir hata değil, kapının çalıştığının kanıtıdır: `automation_preview` 200 döner,
|
|
253
|
+
> `executionSuccess: false` olur ve `revert` adımı ağaçta `hasError: true` + `errorType` =
|
|
254
|
+
> `revertType` + `errorMessage` = `revertMessage` ile görünür.
|
|
255
|
+
>
|
|
256
|
+
> **`revert` exception fırlatır ve bulunduğu transaction'ı İKİ yolda da geri alır; ayrım o
|
|
257
|
+
> transaction'ın kapsamıdır (2026-09-07).** `isQueue:false` (async): kapsam yalnız akışın
|
|
258
|
+
> yazdıklarıdır — tetikleyen satır COMMIT olmuş, çağıran 200 almıştır; olay `failed` +
|
|
259
|
+
> `revertMessage` damgalanır ve bu yolda `failed` damgası kapının ÇALIŞTIĞININ izidir, kusur
|
|
260
|
+
> değil. `isQueue:true` (senkron): kapsam satır işlemini de içerir — satır geri alınır, çağırana
|
|
261
|
+
> 400 `{ code: revertType, message: revertMessage }` gider (**AUT-002**); seçim §Bilinen sınırlar'da.
|
|
262
|
+
> `rule.isExpression` bayrağı bu iki alan için **okunmaz**.
|
|
263
|
+
|
|
209
264
|
|
|
210
265
|
## Loop step — dizinin her öğesi için bir adım koştur
|
|
211
266
|
|
|
@@ -316,10 +371,26 @@ Tek uçta "başlık + N alt kayıt" yazmanın yolu budur (anket + sorular + seç
|
|
|
316
371
|
**`platform_guide('expressions')`** — uydurma fonksiyon adı runtime 500'üdür.
|
|
317
372
|
- Yazma step'lerinde (create/update): **yazılacak** alanlar `fields`, **okunacak** alanlar
|
|
318
373
|
`selectFields` — aynı alan ikisinde birden olamaz (`An item with the same key...`).
|
|
319
|
-
- **Yazma step'inin çıktısı yalnız primary key'dir
|
|
320
|
-
|
|
374
|
+
- **Yazma step'inin çıktısı yalnız primary key'dir**; sonraki step'lerin ya da response'un
|
|
375
|
+
başka alana ihtiyacı varsa bunları **`returnFields`** ile iste
|
|
321
376
|
(`{ alias, fieldId, fieldSlug }` öğeleriyle) — `selectFields` write operasyonunda sessizce
|
|
322
377
|
yok sayılır.
|
|
378
|
+
- **Çıktının ŞEKLİ `isSingle`'a bağlıdır** (ölçüm: 09-04 koşusu Y-15). `isSingle: true` ise
|
|
379
|
+
`<step>.data` nesnedir ve `<step>.data.id` çalışır; **`isSingle: false` ise `data` bir
|
|
380
|
+
DİZİDİR** — `<step>.data.id` `undefined` olur, akış `RowValidationFailed` ile düşer ve hata
|
|
381
|
+
hangi adımı işaret ettiğini söylemez. YAZMA adımı da aynı kurala uyar: `isSingle: false` olan
|
|
382
|
+
bir `create`/`update` adımının çıktısı dizidir, ve o id'yi bir FK alanına geçiren sonraki adım
|
|
383
|
+
`23502 null value in column "<fk>"` ile düşer — hata FK'nın adını söyler, sebebin ŞEKİL
|
|
384
|
+
uyuşmazlığı olduğunu değil (09-05 koşusu `S-5`; kuru koşu yakaladı, kaydedilseydi yarım
|
|
385
|
+
kullanıcı yazılmış olurdu). **Üç vakayı da karşılayan tek savunmalı yazım:**
|
|
386
|
+
|
|
387
|
+
```js
|
|
388
|
+
// dizi (isSingle:false) · nesne (isSingle:true) · düz değer (yalnız pk dönen yazma)
|
|
389
|
+
(Array.isArray(x.data) ? (x.data[0] && x.data[0].id) : (x.data && x.data.id !== undefined ? x.data.id : x.data))
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
Şekli bilmiyorsan bu yazımı kullan; `workflow_preview` çıktısında `steps[].output`'a bakarak
|
|
393
|
+
hangi vakada olduğunu da görebilirsin.
|
|
323
394
|
|
|
324
395
|
> **Gateway table step'lerinde `path`/`sort`/`limit` eksiklerini otomatik dolduruyor**
|
|
325
396
|
> (yanıtta `gatewayNormalized`). Dolu değerlere dokunmaz; yanlış path yine WF/MS block'una takılır.
|
|
@@ -390,31 +461,45 @@ zorunludur (`CreateWorkflowCommandValidator`: `When(ReturnDtoId.HasValue) → Re
|
|
|
390
461
|
|
|
391
462
|
## Automation gerçekleri (hr + qm projelerinde doğrulandı)
|
|
392
463
|
|
|
393
|
-
- **`returnDtoId`/`parameterDtoId` automation'da
|
|
394
|
-
be empty"
|
|
464
|
+
- **`returnDtoId`/`parameterDtoId` ve `returnBehavior`/`parameterBehavior` automation'da
|
|
465
|
+
YASAKTIR** (validator: "'Return Dto Id' must be empty" / "'Return Behavior' must be empty");
|
|
466
|
+
`automation_create` kabul ediyor gibi görünse de `automation_update` reddeder (ölçüm: 09-04
|
|
467
|
+
Y-13). Dördünü de automation gövdesinde hiç yazma.
|
|
395
468
|
- **`state: 'unready'` automation için NORMALDİR ve tetiklemeyi etkilemez** — qm'deki çalışan
|
|
396
469
|
automation'lar da unready'dir; "Studio'dan aktifleştirme" diye bir işlem yoktur.
|
|
397
|
-
- **Tetikleme kapısı üç alandır**, üçü de `automation` nesnesinde: `entityId`
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
`
|
|
470
|
+
- **Tetikleme kapısı üç alandır**, üçü de `automation` nesnesinde: `entityId`, `operation`
|
|
471
|
+
(`create`/`update`/`delete`) ve **`isQueue`** — adı yanıltıcıdır (`Entity.cs:735-736`):
|
|
472
|
+
**`true` = isteğin İÇİNDE senkron** koşar (`queueOrder` zorunlu, sıra ondan gelir),
|
|
473
|
+
**`false` = RabbitMQ'ya giden async** ateşle-unut yoldur — satır yazıldıktan hemen sonra
|
|
474
|
+
okursanız automation'ın yazdığını göremezsiniz. `null` bırakılırsa tetikleme sorgusu HİÇ
|
|
475
|
+
eşleşmez — automation sessizce ölü kalır. `condition` opsiyonel JavaScript ifadesidir;
|
|
476
|
+
`isActive` diye bir alan YOKTUR (yok sayılır).
|
|
401
477
|
- `steps` hem üst seviyede hem `automation` içinde verilir (PLT-007); `response` step'i
|
|
402
478
|
kullanılamaz, hata yolu için `revert` vardır.
|
|
403
479
|
- **Tetikleyen satıra `input` ile DEĞİL `row` ile erişilir**; update'te `previousRow`, işlemi
|
|
404
480
|
yapan kullanıcı `user` altındadır (`row.title`, `previousRow.user`, `user.id`). Step
|
|
405
|
-
`fields[]` öğelerinde `source: '
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
481
|
+
`fields[]` öğelerinde `source: 'expression'` + `value: '<ifade>'` kullanılır — table step ile
|
|
482
|
+
aynı yazım. Eski kayıtlarda `source: 'body'` görürsün; davranış AYNIDIR — `TableStep` default
|
|
483
|
+
modda her alanın `value`'sunu `source`'a **bakmadan** JS ile değerlendirir
|
|
484
|
+
(`TableStep.cs:392-412`), yani `expression` automation'da da çalışır.
|
|
409
485
|
- Hem `row_create` ucundan hem `operation: 'create'` yapan bir microservice'ten tetiklenir —
|
|
410
486
|
ikisi de aynı hook'a düşer.
|
|
411
|
-
- **
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
487
|
+
- **Tetikleyen satıra geri yazan automation'ın kapısı `automation.condition` OLMALIDIR, akışın
|
|
488
|
+
içindeki bir `condition` ADIMI değil.** Sıra bunu belirler: `automation.condition` eşleşmezse
|
|
489
|
+
mesaj kuyruğa hiç girmez ve sayaç artmaz; akışın ilk adımına konan kapı iş sonucunu doğru tutar
|
|
490
|
+
ama koşumu saydırmaya devam eder. (Ölçüm: `08-kural-envanteri.md`, `B-20`.)
|
|
491
|
+
- **Satır olayının DIŞINDAN değer geçirmek: `rowContext` (2026-09-05).** `row_create`/`row_update`
|
|
492
|
+
(tekil ve toplu) isteğe bağlı bir `rowContext` sözlüğü alır; tetiklenen automation onu
|
|
493
|
+
ifadelerinde **`rowContext.<anahtar>`** ile okur. Tarihsel (geçmiş tarihli) veri üretmenin yolu
|
|
494
|
+
budur: automation damgayı `UtcNow()` yerine `rowContext.occurredAt`'ten alabilir —
|
|
495
|
+
`(typeof rowContext !== 'undefined' && rowContext && rowContext.occurredAt) ? rowContext.occurredAt : UtcNow().toISOString()`.
|
|
496
|
+
- **AUT-003:** `rowContext` yoksa automation sessizce `UtcNow()`a düşer — tarihsel automation'ın
|
|
497
|
+
entity'sine yazan her yol onu verir, duman testi dahil.
|
|
498
|
+
- **`automation_trigger` bir DOĞRULAMA aracıdır, veri üretme aracı DEĞİL:** gerçekten çalıştırır,
|
|
499
|
+
`rowContext` **almaz**, damgası hep `UtcNow()`'dur — tarihsel tohumun üstünde tek çağrı huni
|
|
500
|
+
ortalamasını 5 sa → 226 sa yaptı ve hiçbir uyarı çıkmadı (`B-52`). Tarihsel veri: küçükse
|
|
501
|
+
`rowContext`'li `row_create`, kümeyse
|
|
502
|
+
`platform_guide('entity')` §"Toplu ve türetilmiş satır".
|
|
418
503
|
|
|
419
504
|
```jsonc
|
|
420
505
|
{
|
|
@@ -431,6 +516,18 @@ zorunludur (`CreateWorkflowCommandValidator`: `When(ReturnDtoId.HasValue) → Re
|
|
|
431
516
|
}
|
|
432
517
|
```
|
|
433
518
|
|
|
519
|
+
## Bilinen sınırlar ve kabul edilen kanıt
|
|
520
|
+
|
|
521
|
+
Bunlar **platform sınırıdır**, gövdeyi değiştirerek aşılmaz — ama sınır doğrulamayı iptal etmez,
|
|
522
|
+
yolunu değiştirir: kapalı yolu deneyip raporuna "kanıtlayamadım" yazma, kanıt sütunundaki çıktıyı
|
|
523
|
+
üret.
|
|
524
|
+
|
|
525
|
+
| Kapalı yol | Kabul edilen kanıt |
|
|
526
|
+
|---|---|
|
|
527
|
+
| **`AUT-004`** — enum/zorunluluk/benzersizlik denetleyen `revert` dalı `row_create` yolundan HİÇ tetiklenemez: entity doğrulaması automation'dan ÖNCE koşar | `automation_preview`: revert adımı `hasError` + `errorType` ile döner (§izin matrisi) — **tam** kanıt, ikinci koşum aranmaz. Canlı red de şartsa kuralı enum OLMAYAN bir alana kur |
|
|
528
|
+
| **`AUT-002`** — `isQueue:false` automation ÇAĞIRANI reddedemez (§izin matrisi) | Reddin izi `automation_histories`: `failed` + `revertMessage`; çağırana 400 gerekiyorsa kural `isQueue:true` + `queueOrder` yoluna kurulur |
|
|
529
|
+
| **`automation_preview` CANLI davranışı göstermez** — tek transaction, rollback | ŞEKLİN kanıtı preview; CANLI davranışın kanıtı tetikleyen satır + `row_list` + `automation_histories` (`AUT-006`) |
|
|
530
|
+
|
|
434
531
|
## Sık hatalar (politika lint'inin yakaladıkları)
|
|
435
532
|
|
|
436
533
|
- Bağlanmamış step grafı (WF-001, block) · workflow'da returnDtoId eksik (WF-002, block)
|
|
@@ -442,6 +539,15 @@ zorunludur (`CreateWorkflowCommandValidator`: `When(ReturnDtoId.HasValue) → Re
|
|
|
442
539
|
- Adımda ya da akışta `description` yok (WF-024, block — Studio'da adım okunamaz kalır)
|
|
443
540
|
- İlişki alanının içini okuyan ifade (WF-020, warn — join yoksa alan düz FK'dır)
|
|
444
541
|
- `set-user` adımı olmadan `user` okuyan middleware (MW-003, warn)
|
|
542
|
+
- Backend zorunlulukları (WF-026, block — istek gitmeden): `name`/`slug`; `returnDtoId` varsa
|
|
543
|
+
`returnBehavior`, `parameterDtoId` varsa `parameterBehavior` (`primitive` | `object` | `array`),
|
|
544
|
+
update/preview'da DTO yokken behavior `null`; `type: 'workflow'` + `parameterDtoId` yokken
|
|
545
|
+
`previewPayload` verilemez; `variable` adımına `user` adı verilemez (set-user'a ayrılmış);
|
|
546
|
+
tekil filtrede `fieldId`; automation `parameterDtoId` almaz, `isQueue: true` ⇒ `queueOrder`
|
|
547
|
+
(0 geçerli). Tam katalog: `ngapps://rules/backend-constraints`.
|
|
548
|
+
- DTO gövdesi (DTO-001, block): `type` sözlükten (`string`, `number`, `guid`, `datetime`, `object`,
|
|
549
|
+
`array`… — `text` YOK, G-23), `children[].slug` zorunlu ve kardeşler arasında tekil, `referenceId`
|
|
550
|
+
yalnız `object`/`array` çocukta.
|
|
445
551
|
|
|
446
552
|
## Hedefli değişiklik: `workflow_patch` yollarında İNDEKS KULLANMA
|
|
447
553
|
|
|
@@ -458,7 +564,9 @@ Gateway seçiciyi gövde platforma **gitmeden** indekse çevirir, çözülemezse
|
|
|
458
564
|
ve yanıtta `patchTargets` ile her op'un hangi adıma (ad + tip + id) indiğini söyler. Aynı seçici
|
|
459
565
|
`microservice_patch`'te de çalışır (`/sourceParameters/joins[alias=customers]/path`).
|
|
460
566
|
|
|
461
|
-
|
|
567
|
+
Patch tam gövde yazmaz; gateway farkı `{ baseVersion, ops }` olarak gönderir. Araya başka bir
|
|
568
|
+
yazma girdiyse **409** döner ve hiçbir op uygulanmaz — `workflow_get` ile yeniden oku. `version`
|
|
569
|
+
**string**tir, sayıya çevirme.
|
|
462
570
|
|
|
463
571
|
## Table adımının filtresi: `alias` YOKSA filtre SESSİZCE DÜŞER
|
|
464
572
|
|
|
@@ -482,3 +590,66 @@ kusur `operation: 'update'` filtresinde **yanlış satırı günceller**.
|
|
|
482
590
|
|
|
483
591
|
`source` da **`expression`** olmalı: verilmezse `body`'ye düşer ve `value` bir ifade değil
|
|
484
592
|
**gövde alanı adı** sayılır — yine filtre kaybolur.
|
|
593
|
+
|
|
594
|
+
## Query adımı: kayıtlı query'nin parametreleri (ölçüm 2026-09-03)
|
|
595
|
+
|
|
596
|
+
**Parametreyi query'yi kaydederken bildir.** `query_create` ve `query_update` gövdesindeki
|
|
597
|
+
`parameters: [{ name, type, value }]` alanı, query'ye bağlı bir parametre DTO'su kurar; `query_get`
|
|
598
|
+
bunu `parameterScheme` olarak geri verir. Bildirmediğin bir parametre sözleşmede yoktur — kaydetme
|
|
599
|
+
başarılı olur, sorgu runtime'da bağlanmaz.
|
|
600
|
+
|
|
601
|
+
```jsonc
|
|
602
|
+
// query_create gövdesi: "WHERE extract(year from start_date) = @year"
|
|
603
|
+
{ "rawQuery": "SELECT count(*) AS total FROM leave_requests WHERE extract(year from start_date) = @year",
|
|
604
|
+
"slug": "izin-raporu", "name": "Izin Raporu", "datasourceId": "<datasource id>",
|
|
605
|
+
"outputType": "object",
|
|
606
|
+
"parameters": [ { "name": "year", "type": "number", "value": 2026 } ] }
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
`value` burada **önizleme değeridir**: kayıt sırasında sorgu bu değerlerle bir kez çalıştırılır, hem
|
|
610
|
+
SQL doğrulanır hem de yanıt şeması (`returnScheme`) üretilir. Sorgu hatalıysa kayıt 422 ile reddedilir.
|
|
611
|
+
|
|
612
|
+
Kaydedilen sözleşme üç tüketim yolunda da aynı şekilde bağlanır:
|
|
613
|
+
|
|
614
|
+
| Tüketim yolu | Değer nereden gelir |
|
|
615
|
+
|---|---|
|
|
616
|
+
| `queryStepSourceType: 'library'` (workflow query adımı) | Adımın ifadeleri: `rule.expression` (nesne literali) ya da `rule.queryParameters[]` — ikisi de **JavaScript ifadesidir**; istek girdisini (`input.year`), önceki adım çıktısını **ve bağlı middleware'in `user.*` değişkenini** okur |
|
|
617
|
+
| Query kaynaklı microservice (`source: 'query'`) | Yalnız çağrının kendisi: **body → query-string → header** (`MicroserviceExecuteParameter.FindValue`); ifade YOKTUR, `user.*` bu yola girmez |
|
|
618
|
+
| `query_preview` | `parameters` alanı — davranış yukarıdaki ikisiyle aynıdır |
|
|
619
|
+
|
|
620
|
+
> **Boş string parametre `NULL`'a çevrilir.** `Query.NormalizePreviewParameters` değeri normalize
|
|
621
|
+
> ederken boş ya da yalnız boşluktan oluşan değeri `null` yapar. `WHERE status = {{durum}}` yazıp
|
|
622
|
+
> `durum: ''` gönderirsen sorgu `= NULL` olur ve **hiçbir satırla eşleşmez**: 0 satır döner, hata
|
|
623
|
+
> ya da uyarı yoktur. 2026-09-04 ölçümü: aynı sorgu `''` ile 0, `IS NULL` dalı yazıldığında 346
|
|
624
|
+
> satır. "Filtre yok" demek istiyorsan sentinel kullan (`'all'` gibi) ya da sorguyu
|
|
625
|
+
> `({{durum}} IS NULL OR status = {{durum}})` biçiminde yaz. Query kaynaklı uçta da aynı
|
|
626
|
+
> (üç koşuda ölçüldü: 09-02, 09-04·1, 09-04·4).
|
|
627
|
+
|
|
628
|
+
> **`query_preview` yazan sorguyu koşturur, geri alır ve bunu söylemez** (yukarıda Kural 3).
|
|
629
|
+
> Kalıcı yazmanın reçetesi: `platform_guide('entity')` §"Toplu ve türetilmiş satır".
|
|
630
|
+
|
|
631
|
+
```jsonc
|
|
632
|
+
// library query adımı: query'de "WHERE extract(year from start_date) = @year" yazıyorsa
|
|
633
|
+
{ "id": "<GUID-Q>", "name": "izin_raporu", "type": "query",
|
|
634
|
+
"rule": { "stepType": "query", "queryStepSourceType": "library", "isExpression": false,
|
|
635
|
+
"queryId": "<kayıtlı query id>",
|
|
636
|
+
"expression": "{ year: input.year }", // bugün BAĞLAYAN yazım
|
|
637
|
+
"queryParameters": [ { "name": "year", "value": "input.year", "type": "number" } ] },
|
|
638
|
+
"branches": [ /* success + fail */ ] }
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
> **Bağlamayı `rule.expression`'a yaz.** Kayıtlı sorgunun parametreleri bildirilmişse çalışan
|
|
642
|
+
> motor `rule.queryParameters` dizisine BAKMIYOR: parametreler `null` bağlanıyor ve çağrı
|
|
643
|
+
> **`200` + sıfır satır** dönüyor, hiçbir katman uyarmıyor (ölçüldü 2026-09-07; düzeltme depoda
|
|
644
|
+
> var, canlı dağıtım geride — `B-63`). Gateway bu adımı `WF-025` ile uyarır.
|
|
645
|
+
>
|
|
646
|
+
> **Kimlik/tenant kapsamı da buradan bağlanır** — query kaynaklı ucun yapamadığı şey budur:
|
|
647
|
+
> `"{ company_id: user.company_id, from: input.from }"` (ölçüldü; `middlewareIds` boşsa
|
|
648
|
+
> `500 user is not defined`). Reçete: `platform_guide('microservice')`.
|
|
649
|
+
|
|
650
|
+
- `queryParameters[].name` **`@` ya da `{{ }}` olmadan** yazılır; belirtecin sorgudaki adıyla
|
|
651
|
+
eşleşmelidir.
|
|
652
|
+
- Değer çağrıda bulunamazsa parametre `null` bağlanır — sorgu düşmez, `WHERE` koşulu boşa çıkar.
|
|
653
|
+
- `parameters` bildirilmemiş eski query'lerde belirteçler ham SQL'den okunur; güvenme (string
|
|
654
|
+
literalindeki `@ad`'ı da parametre sanıyor, `query_get` boş `parameterScheme` gösteriyor). Böyle
|
|
655
|
+
bir query'yi `parameters` vererek bir kez `query_update` et.
|
|
@@ -10,6 +10,11 @@ export function listKnowledgeFiles(kind) {
|
|
|
10
10
|
return [];
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* `schemas` MCP kaynağı olarak YAYINLANMAZ (yalnız `guides` ve `examples` kayıtlıdır) ama
|
|
15
|
+
* dosyalar aynı klasör düzeninde durur ve drift testleri onları da okur — şema kaynağı
|
|
16
|
+
* platformun swagger'ından üretiliyor ve bir alanın oradan düşmesi sessizce olur.
|
|
17
|
+
*/
|
|
13
18
|
export function readKnowledgeFile(kind, file) {
|
|
14
19
|
return readFileSync(join(resourcesDirectory, kind, file), 'utf8');
|
|
15
20
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { constraintCatalog } from '../knowledge/backendConstraints.js';
|
|
2
|
+
/** `ngapps://rules/<ad>` kaynakları; docs-lint bu listeyle `ngapps://rules/…` referanslarını denetler. */
|
|
3
|
+
export const ruleResourceNames = ['backend-constraints'];
|
|
4
|
+
/**
|
|
5
|
+
* Backend doğrulayıcı kataloğu tek kaynak olarak koddan üretilir (`backendConstraints.ts`);
|
|
6
|
+
* dosya olarak paketlenmez ki tool açıklaması, lint ve bu kaynak hiçbir zaman ayrışmasın.
|
|
7
|
+
*/
|
|
8
|
+
export function registerRuleResources(server) {
|
|
9
|
+
server.registerResource('rules-index', 'ngapps://rules/index', {
|
|
10
|
+
title: 'Kural kaynakları dizini',
|
|
11
|
+
description: "Gateway'in koddan ürettiği kural katalogları; şu an backend doğrulayıcı aynası.",
|
|
12
|
+
mimeType: 'application/json'
|
|
13
|
+
}, async (uri) => ({
|
|
14
|
+
contents: [{
|
|
15
|
+
uri: uri.href,
|
|
16
|
+
mimeType: 'application/json',
|
|
17
|
+
text: JSON.stringify({ rules: ruleResourceNames.map(name => `ngapps://rules/${name}`) })
|
|
18
|
+
}]
|
|
19
|
+
}));
|
|
20
|
+
server.registerResource('rules-backend-constraints', 'ngapps://rules/backend-constraints', {
|
|
21
|
+
title: 'Backend doğrulama sınırları',
|
|
22
|
+
description: "Platformun 422/409 ile reddedeceği gövde kuralları (uzunluk, zorunluluk, tek primaryKey, DTO/behavior eşleşmesi, dil kodları…) — kaynak referanslı; gateway aynı kuralı istek gitmeden block olarak uygular.",
|
|
23
|
+
mimeType: 'application/json'
|
|
24
|
+
}, async (uri) => ({
|
|
25
|
+
contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify(constraintCatalog(), null, 2) }]
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hash": "0e6bb2b45f8c545b50dc6d6169e7d816d9cb9532ecbaed894307995d537ff3b6",
|
|
3
|
+
"generatedAt": "2026-09-09T09:49:52.511Z",
|
|
4
|
+
"types": 103,
|
|
5
|
+
"files": 73,
|
|
6
|
+
"note": "Şemaları üreten backend kaynaklarının parmak izi. Elle düzenlemeyin: 'npm run generate-schemas' yazar, 'npm run schema:check' denetler.",
|
|
7
|
+
"missing": []
|
|
8
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": {
|
|
3
|
+
"required": [
|
|
4
|
+
"rows"
|
|
5
|
+
],
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"entityId": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"format": "uuid"
|
|
11
|
+
},
|
|
12
|
+
"rows": {
|
|
13
|
+
"type": "array",
|
|
14
|
+
"items": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"additionalProperties": {}
|
|
17
|
+
},
|
|
18
|
+
"nullable": true
|
|
19
|
+
},
|
|
20
|
+
"rowContext": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"additionalProperties": {
|
|
23
|
+
"nullable": true
|
|
24
|
+
},
|
|
25
|
+
"nullable": true
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"additionalProperties": false
|
|
29
|
+
},
|
|
30
|
+
"components": {
|
|
31
|
+
"schemas": {}
|
|
32
|
+
}
|
|
33
|
+
}
|