@appaflytech/zeyrek-ai-mcp 0.0.6 → 0.0.8

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.
Files changed (98) hide show
  1. package/.env.example +2 -2
  2. package/.env.production.example +8 -0
  3. package/README.md +9 -8
  4. package/dist/config.js +18 -3
  5. package/dist/knowledge/backendConstraints.js +88 -0
  6. package/dist/knowledge/componentCatalog.js +415 -68
  7. package/dist/knowledge/componentEvents.js +120 -25
  8. package/dist/knowledge/functionGuards.js +134 -0
  9. package/dist/knowledge/normalize.js +512 -25
  10. package/dist/knowledge/outlines.js +31 -0
  11. package/dist/knowledge/policy.js +14 -5
  12. package/dist/knowledge/propTypes.js +5 -4
  13. package/dist/knowledge/rules.js +453 -6
  14. package/dist/knowledge/styleResolve.js +6 -1
  15. package/dist/platform/csv.js +123 -0
  16. package/dist/platform/errors.js +62 -3
  17. package/dist/platform/http.js +11 -2
  18. package/dist/platform/responses.js +16 -4
  19. package/dist/platform/screenshot.js +98 -9
  20. package/dist/platform/strictArguments.js +32 -0
  21. package/dist/platform/writeDiff.js +6 -3
  22. package/dist/resources/examples/flow-call-function.json +66 -0
  23. package/dist/resources/examples/function-total.json +70 -0
  24. package/dist/resources/examples/microfunction-node-sum.json +56 -0
  25. package/dist/resources/examples/page-dynamic-form.json +1 -1
  26. package/dist/resources/examples/page-sign-in.json +2 -2
  27. package/dist/resources/guides/component.md +14 -2
  28. package/dist/resources/guides/entity.md +321 -17
  29. package/dist/resources/guides/expressions.md +9 -0
  30. package/dist/resources/guides/functions.md +262 -0
  31. package/dist/resources/guides/getting-started.md +7 -0
  32. package/dist/resources/guides/layout.md +6 -0
  33. package/dist/resources/guides/merge.md +231 -0
  34. package/dist/resources/guides/microfunction.md +166 -0
  35. package/dist/resources/guides/microservice.md +166 -7
  36. package/dist/resources/guides/modify-existing.md +23 -0
  37. package/dist/resources/guides/page.md +101 -22
  38. package/dist/resources/guides/translation.md +35 -10
  39. package/dist/resources/guides/workflow.md +51 -2
  40. package/dist/resources/schema-fingerprint.json +4 -4
  41. package/dist/resources/schemas/AnalyzeImportQuery.json +51 -0
  42. package/dist/resources/schemas/ApplyMergePlanCommand.json +19 -0
  43. package/dist/resources/schemas/CreateBulkRowCommand.json +3 -0
  44. package/dist/resources/schemas/CreateEnvironmentCommand.json +31 -0
  45. package/dist/resources/schemas/CreateGlobalFunctionCommand.json +95 -0
  46. package/dist/resources/schemas/CreateImportPlanCommand.json +278 -0
  47. package/dist/resources/schemas/CreateMergePlanCommand.json +34 -0
  48. package/dist/resources/schemas/CreateMicrofunctionCommand.json +117 -0
  49. package/dist/resources/schemas/CreateMicrofunctionRuntimeCommand.json +51 -0
  50. package/dist/resources/schemas/CreateMicroserviceCommand.json +123 -2
  51. package/dist/resources/schemas/CreateWorkflowCommand.json +17 -3
  52. package/dist/resources/schemas/DataJobDto.json +267 -0
  53. package/dist/resources/schemas/ExportRowsCommand.json +172 -0
  54. package/dist/resources/schemas/Filter.json +3 -1
  55. package/dist/resources/schemas/GetRowsQuery.json +3 -1
  56. package/dist/resources/schemas/GlobalFunctionDto.json +89 -0
  57. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +249 -0
  58. package/dist/resources/schemas/ImportAnalysisDto.json +401 -0
  59. package/dist/resources/schemas/ImportPlanDto.json +260 -0
  60. package/dist/resources/schemas/ImportSampleDto.json +90 -0
  61. package/dist/resources/schemas/InvokeMicrofunctionCommand.json +25 -0
  62. package/dist/resources/schemas/PreviewMicroserviceCommand.json +123 -2
  63. package/dist/resources/schemas/PreviewWorkflowCommand.json +17 -3
  64. package/dist/resources/schemas/ResolveMergeConflictsCommand.json +58 -0
  65. package/dist/resources/schemas/RevertMergePlanCommand.json +19 -0
  66. package/dist/resources/schemas/RunImportCommand.json +62 -0
  67. package/dist/resources/schemas/StepDto.json +17 -3
  68. package/dist/resources/schemas/UpdateBulkRowCommand.json +3 -0
  69. package/dist/resources/schemas/UpdateEntityCommand.json +3 -1
  70. package/dist/resources/schemas/UpdateGlobalFunctionCommand.json +66 -0
  71. package/dist/resources/schemas/UpdateMicrofunctionCommand.json +121 -0
  72. package/dist/resources/schemas/UpdateMicrofunctionRuntimeCommand.json +54 -0
  73. package/dist/resources/schemas/UpdateMicroserviceCommand.json +123 -2
  74. package/dist/resources/schemas/UpdateWorkflowCommand.json +17 -3
  75. package/dist/server.js +17 -4
  76. package/dist/tools/activities.js +40 -0
  77. package/dist/tools/automations.js +14 -5
  78. package/dist/tools/common.js +16 -0
  79. package/dist/tools/dependencies.js +1 -1
  80. package/dist/tools/environments.js +52 -0
  81. package/dist/tools/files.js +51 -50
  82. package/dist/tools/flows.js +104 -5
  83. package/dist/tools/functions.js +331 -0
  84. package/dist/tools/importSchemas.js +79 -0
  85. package/dist/tools/imports.js +241 -0
  86. package/dist/tools/layouts.js +4 -4
  87. package/dist/tools/merges.js +113 -0
  88. package/dist/tools/microfunctions.js +155 -0
  89. package/dist/tools/microservices.js +112 -9
  90. package/dist/tools/pages.js +188 -66
  91. package/dist/tools/platformInfo.js +4 -1
  92. package/dist/tools/queries.js +72 -6
  93. package/dist/tools/revisions.js +94 -0
  94. package/dist/tools/rows.js +342 -22
  95. package/dist/tools/screenWrite.js +11 -2
  96. package/dist/tools/templates.js +32 -5
  97. package/dist/tools/workflows.js +28 -6
  98. package/package.json +3 -1
@@ -0,0 +1,166 @@
1
+ # Microfunction Rehberi
2
+
3
+ Microfunction, kullanıcının yazdığı **tek bir fonksiyonun** platformun dışında, kendi
4
+ runtime'ında koşmasıdır: Node ya da Python kodu kaydedilir, yayınlanır, workflow adımı onu
5
+ çağırır ve çıktısı sonraki adımlara akar. Platformun JavaScript ifade motoru (global function'lar,
6
+ code step) sürecin İÇİNDE koşar; microfunction ise ayrı bir runtime'dadır — bu yüzden ağır iş,
7
+ üçüncü parti kütüphane ve zaman aşımı riski taşıyan işler oraya taşınır.
8
+
9
+ Kayıtlar **proje + environment** kapsamlıdır (`development` ile `production` ayrı kayıtlardır);
10
+ `microfunction_list` bir uygulamaya değil projeye bakar. Süzme ve sayfalama uçta yapılır:
11
+ `searchTerm` ad, slug ve açıklamada arar, `status` durum süzgecidir, `pageIndex`/`pageLength` sayfa
12
+ verir (gateway kendi çağrısında 200 gönderir; platform varsayılanı 10'dur).
13
+
14
+ ## Ne zaman microfunction, ne zaman code step
15
+
16
+ | İhtiyaç | Doğru yer |
17
+ |---|---|
18
+ | Birkaç satır dönüşüm, alan eşleme, koşul | `code` step / ifade (aynı süreç, en ucuz) |
19
+ | İfadelerde çıplak adla çağrılacak yardımcı | global function (`global_function_create`, JS) |
20
+ | Kütüphane gerektiren iş (kriptografi, PDF, görüntü, parse) | microfunction (zip kaynak) |
21
+ | Python gereken iş | microfunction — platformun ifade motoru YALNIZ JavaScript'tir |
22
+ | Uzun süren/CPU yiyen iş | microfunction (kendi bütçesi, API sürecini bloke etmez) |
23
+
24
+ Global function'lar JS'tir ve Python fonksiyonlarına bağlanmaz; microfunction çağrısı yalnız
25
+ workflow adımından (ve test için `microfunction_invoke`'tan) yapılır.
26
+
27
+ ## Çalışma zamanı sözleşmesi (protocol 1)
28
+
29
+ Kullanıcı kodu **tek bir handler** dışa aktarır. Inline kaynakta dosya adı SABİTTİR: Node'da
30
+ `function.js`, Python'da `function.py`; entrypoint `function.handler`'dır ve gönderilmez.
31
+
32
+ ```js
33
+ // node — function.js
34
+ exports.handler = async (args, context) => {
35
+ return { total: args.a + args.b, environment: context.environment }
36
+ }
37
+ ```
38
+
39
+ ```python
40
+ # python — function.py
41
+ def handler(args, context):
42
+ return {"total": args["a"] + args["b"], "environment": context["environment"]}
43
+ ```
44
+
45
+ - `args` — adımın `rule.expression`'ından üretilen argüman nesnesi. Fonksiyonun
46
+ `parameterDtoId`'si yoksa `{}` gelir.
47
+ - `context` — **salt okunur anlık görüntü**. İçine yazmak hiçbir şeyi değiştirmez; akışa dönen
48
+ tek kanal fonksiyonun DÖNÜŞ DEĞERİdir.
49
+
50
+ `context` şekli (ölçüldü, `MicrofunctionStep.BuildContext`):
51
+
52
+ ```jsonc
53
+ {
54
+ "input": {}, // akışın parameterDto girdisi
55
+ "variables": {}, // workflow değişkenleri (middleware'in kurduğu 'user' dahil)
56
+ "steps": { "<adım adı>": { "data": {}, "error": { "code": null, "message": null, "type": null } } },
57
+ "user": { "id": "…", "email": "…", "roles": [] },
58
+ "request": { "headers": {}, "queryString": {} },
59
+ "triggerSource": {},
60
+ "language": "tr",
61
+ "project": "<proje slug'ı>",
62
+ "environment": "development"
63
+ }
64
+ ```
65
+
66
+ **`request` yalnız `headers` + `queryString` taşır** ve `authorization` · `cookie` ·
67
+ `x-impersonated-user-id` başlıkları AYIKLANIR (ölçüldü 2026-09-10) — token'ı fonksiyona taşımaya
68
+ çalışmayın, taşınmaz. Çerez okuma yolu yoktur.
69
+
70
+ Yanıt zarfını shim üretir; `microfunction_invoke` bunu olduğu gibi döner:
71
+
72
+ ```jsonc
73
+ { "protocol": 1, "ok": true, "output": { "total": 3 }, "error": null, "logs": [], "durationMs": 12 }
74
+ ```
75
+
76
+ - `ok: false` ⇒ `error: { type, message, stack }` ve adım **fail dalına** düşer.
77
+ - `logs` yalnız `preview: true` çağrılarında dolar (`console.log` / `print` yakalanır). Normal
78
+ koşumda log toplanmaz — hata ayıklarken `microfunction_invoke(preview: true)` kullanın.
79
+ - İstek gövdesi (args + context) 5 MB'ı aşarsa adım `MicrofunctionPayloadTooLargeException` ile
80
+ fail dalına düşer: bütün tabloyu fonksiyona geçirmeyin, işi fonksiyona taşıyacak kadarını geçirin.
81
+
82
+ ## Yaşam döngüsü: kayıt yayınlanmadan ÇALIŞMAZ
83
+
84
+ ```
85
+ draft ──publish──▶ publishing ──▶ published ──update──▶ published + hasUnpublishedChanges
86
+ └────────▶ publish-failed (publishError)
87
+ ```
88
+
89
+ 1. `microfunction_create` kaydı **draft** açar. `publish: true` verirseniz aynı çağrıda yayın istenir.
90
+ 2. Yayın **asenkrondur**: çağrı `publishing` döner, kuyruk paketi runtime'a kurar ve bir `probe`
91
+ çağrısıyla duman testi yapar. Sözdizimi/import hatası **yayın anında** `publish-failed` olur —
92
+ koşumda değil. Durumu `microfunction_get` ile birkaç saniye arayla okuyun.
93
+ 3. Yayındaki kaydı `microfunction_update` ile değiştirirseniz runtime **ESKİ sürümü koşmaya
94
+ devam eder**: `hasUnpublishedChanges: true` olur (`revision` ≠ `publishedRevision`). Yeni kodu
95
+ canlıya almak için `microfunction_publish`.
96
+ 4. `microfunction_delete` runtime'daki fonksiyonu da kaldırır; bir workflow adımı kaydı
97
+ kullanıyorsa 400 ile reddedilir.
98
+
99
+ ## Workflow adımı (WF-MF-001)
100
+
101
+ Adım tipi `microfunction`; `workflow`, `automation` ve `middleware` akışlarının hepsinde
102
+ kullanılabilir. Kuralı iki alan taşır:
103
+
104
+ ```jsonc
105
+ {
106
+ "id": "<GUID>",
107
+ "name": "toplam",
108
+ "type": "microfunction",
109
+ "description": "İki sayıyı microfunction'da toplar.",
110
+ "rule": {
111
+ "microfunctionId": "<published kaydın id'si>",
112
+ "expression": "({ a: input.a, b: input.b })"
113
+ },
114
+ "branches": [
115
+ { "id": "<GUID>", "name": "success", "type": "success", "nextStepId": "<sonraki adım>" },
116
+ { "id": "<GUID>", "name": "fail", "type": "fail", "nextStepId": "<hata adımı>" }
117
+ ]
118
+ }
119
+ ```
120
+
121
+ - `microfunctionId` **zorunludur** ve gateway kaydı çağrıdan önce okur: durum `published` değilse
122
+ (ya da kayıt o ortamda yoksa) istek platforma GÖNDERİLMEZ. Adım taslak bir fonksiyona bağlıysa
123
+ akış kaydedilir, koşar ve sessizce fail dalına düşer (`MicrofunctionNotPublishedException`) —
124
+ ön-denetimin varlık sebebi budur.
125
+ - `expression` argüman nesnesini üreten JavaScript ifadesidir; şemayı `microfunction_get`
126
+ çıktısındaki `parameterScheme` verir. Fonksiyonun parametre DTO'su varken ifade boşsa gateway
127
+ uyarır (fonksiyon `args` içinde hiçbir alan göremez).
128
+ - Çıktı sonraki adımlara `Steps.<adım adı>.data` ile akar; şemasını `returnDtoId` belirler.
129
+ - Adım **senkrondur**: akış fonksiyon dönene kadar bekler. Zaman aşımı fonksiyonun
130
+ `timeoutSeconds` bütçesidir, aşılırsa fail dalı.
131
+ - `workflow_preview` adımı GERÇEK runtime'da koşturur; preview'ın rollback garantisi fonksiyonun
132
+ dış dünyada yaptığı işi geri ALMAZ.
133
+
134
+ Tam gövde örneği: `ngapps://examples/microfunction-node-sum`.
135
+
136
+ ## Built-In ve AWS Lambda farkı
137
+
138
+ | | `built-in` | `aws-lambda` |
139
+ |---|---|---|
140
+ | Nerede koşar | Platformun kendi Fission kümesi | Müşterinin AWS hesabı |
141
+ | Runtime kaydı | YOK — `runtimeId` verilmez | `microfunction_runtime_create` ile zorunlu |
142
+ | Zaman aşımı tavanı | 300 s | 900 s |
143
+ | `memoryMb` | kaydedilir, küme limiti geçerlidir | gerçekten uygulanır |
144
+ | Ölçüm alanları | `billedDurationMs`/`memoryUsedMb` boş | Lambda raporundan dolar |
145
+
146
+ `azure-functions` enum'da tanımlıdır ama v1'de reddedilir (Faz 2). Lambda hesabı kimlik
147
+ bilgilerini düz metin tutar (Datasource emsali) ve DTO'da maskeli döner — dar yetkili bir IAM
148
+ kullanıcısı verin, `roleArn` fonksiyonun koşacağı execution rolüdür ve **zorunludur** —
149
+ deseni tutmayan hesap gateway'de durur (MFR-001, block). Kaydettikten sonra
150
+ `microfunction_runtime_test_connection` ile doğrulayın.
151
+
152
+ ## Sınırlar (v1)
153
+
154
+ - **Bağımlılık build'i yok:** inline kod yalnız standart kütüphanedir; bağımlılık zip içinde gelir.
155
+ - **MCP'den zip yükleme ve indirme yok** (`sourceKind: 'archive'` kaydı açılabilir, dosya
156
+ Studio'dan yüklenir) — Faz 2. Yüklenmiş zip platform ucunda okunabilir durumdadır
157
+ (`GET /{proje}/microfunctions/{id}/archive`, `application/zip`) ve Studio inspector'ında bir
158
+ indirme düğmesi taşır.
159
+ - `timeoutSeconds` ve `memoryMb` komutta non-nullable int'tir: **göndermezseniz 0 gider ve platform
160
+ 422 döner.** Gateway değer uydurmaz, eksikliği çağrıdan önce söyler (MF-001, block; ürün
161
+ varsayılanları 30 / 256). Aynı kural provider ↔ `runtimeId` eşleşmesini, inline kaynakta `code`
162
+ zorunluluğunu ve env anahtarlarını da çağrıdan önce denetler.
163
+ - Env değişkenleri düz metin saklanır; anahtar `^[A-Z_][A-Z0-9_]*$`, toplam ≤ 4 KB. Sır yönetimi
164
+ için kullanmayın.
165
+ - Asenkron (fire-and-forget) çağrı, preview ekranı, microservice'in doğrudan microfunction kaynağı
166
+ olması ve metering Faz 2'dedir.
@@ -77,6 +77,12 @@ servis formunda görünür ve `microservice_get` outline görünümünde geri ok
77
77
  > (`'all'`) ve SQL'de ona bakan bir dal. Aynı davranış workflow query adımında da geçerli;
78
78
  > oradaki anlatım `platform_guide('workflow')` "Query adımı" bölümünde.
79
79
  >
80
+ > **`(@p = '' OR kolon = @p)` YAZMA** — "filtre boşsa hepsini getir" dalı hiçbir zaman
81
+ > çalışmaz, çünkü boş değer `NULL` bağlanır. Değeri form bileşeninden gelen parametrede
82
+ > dokunulmamış alanın `null` ya da `''` göndermesi fark etmez; ikisi de `NULL` olur
83
+ > (2026-09-15 bulgusu: pano 0 kart, `COALESCE`/`IS NULL` ile 141). Gateway bu kalıbı
84
+ > `query_create`/`query_update`/`query_preview`'da **QRY-007** (warn) ile işaretler.
85
+ >
80
86
  > **KAPSAM UYARISI: query kaynaklı ucun parametreleri ÇAĞRIDAN gelir.** Middleware'in
81
87
  > kurduğu `user` bu yola girmez — kimlik/tenant kapsamını gövdeye yazan bir uç
82
88
  > sahtelenebilir (ölçüldü 2026-09-07). Kapsam sunucuda zorlanacaksa sorguyu bir workflow
@@ -116,6 +122,11 @@ servis formunda görünür ve `microservice_get` outline görünümünde geri ok
116
122
  5. **Doğrulama akışı:** `microservice_preview` (kaydetmeden) → kaydet → `microservice_execute`
117
123
  (gerçek runtime yolu) → sonuç beklenmedikse **aynı parametrelerle `microservice_debug`** —
118
124
  adım adım executionItems ağacı döner.
125
+ Çağrı parametrelerini (sorgu parametresi, filtre değeri) üst düzey `parameters: { ad: değer }`
126
+ ile ver; gateway GET'te query-string'e, POST/PUT'ta gövdeye koyar. Değeri NULL bağlanan query
127
+ parametresini debug yanıtı `unboundParameters` ile söyler — ağaçta o satırın `value` anahtarı
128
+ görünmez. Tool'un tanımadığı bir üst düzey argüman artık reddedilir (GW-005); 2026-09-15'e
129
+ kadar `parameters` hata vermeden atılıyordu ve dört farklı filtre aynı gövdeyi döndürdü (G-13).
119
130
 
120
131
  ## Yanıt sözleşmesi (DTO) uca DEĞİL workflow'a bağlanır (MS-018, block)
121
132
 
@@ -159,8 +170,9 @@ DTO'dan süzülmez (WF-026 — `platform_guide('workflow')` §Hata yolu). Sözle
159
170
  ## Asgari doğru table-source microservice (platformda doğrulanmış kurallar)
160
171
 
161
172
  - `operation` enum'u **tam olarak** şudur ([MicroserviceTableOperation](../../../../zeyrek-backend/src/NgApps.Domain/Contexts/Studio/Microservices/MicroserviceTableOperation.cs)):
162
- `get · create · update · delete · upsert · count`. **`list` yoktur** — liste için
163
- `operation: 'get'` + `isSingle: false`, tek kayıt için `isSingle: true`.
173
+ `get · create · update · delete · upsert · count · bulk-create · bulk-update · bulk-delete`.
174
+ **`list` yoktur** — liste için `operation: 'get'` + `isSingle: false`, tek kayıt için
175
+ `isSingle: true`.
164
176
  - **`upsert` vardır ve tercih edilmelidir.** Aynı formun hem yeni kayıt hem düzenleme
165
177
  yapmasını iki ayrı uç + akışta condition dallanmasıyla kurmayın: tek `operation: 'upsert'`
166
178
  ucu yeterlidir. Aynı işlem workflow **table step**'inde de desteklenir
@@ -174,9 +186,42 @@ DTO'dan süzülmez (WF-026 — `platform_guide('workflow')` §Hata yolu). Sözle
174
186
 
175
187
  > **Upsert'te üretilen alan tuzağı.** `operation: 'upsert'` UPDATE yolunda da alan ifadelerini
176
188
  > yeniden değerlendirir; sicil/kod gibi üretilen bir değeri `source: 'expression'` ile yazarsan
177
- > güncellemede **sessizce değişir** (İK koşusu M-3: EMP-0005 → EMP-0006). Alan bazlı
178
- > `writeOn: create | update | always` platformda **yok**; o gelene kadar oluşturma ve güncelleme
179
- > için iki ayrı uç kurun. Gateway **MS-016** ile uyarır.
189
+ > güncellemede **sessizce değişir** (İK koşusu M-3: EMP-0005 → EMP-0006). Çözüm alan bazlı
190
+ > **`writeOn: create | update | always`**'dir (varsayılan `always`) ve 2026-09-04'ten beri
191
+ > platformdadır: üretilen alana `writeOn: 'create'` verirsen upsert'in UPDATE dalı o alanı satıra
192
+ > hiç koymaz (`ToRow(entityDto, writeOn)` iki satırı ayrı kurar). `writeOn` YALNIZ
193
+ > `operation: 'upsert'` ucunda anlamlıdır — başka operasyonda `always` dışında bir değer
194
+ > **MS-017** ile reddedilir. Gateway **MS-016** ile uyarır; alan `writeOn: 'create'` taşıyorsa
195
+ > susar. **`writeOn` bir "kısmi güncelleme" bayrağı DEĞİLDİR** — hangi DALIN yazacağını söyler,
196
+ > "gövdede gelmeyen alanı atla" demez (aşağıdaki §Güncelleme sözleşmesi).
197
+ - **Toplu yazma için `bulk-create` / `bulk-update` / `bulk-delete` vardır.** Aynı tabloya N satır
198
+ yazmak için akışta döngü kurmayın: bu üç uç gövdedeki **JSON diziyi** tek çağrıda işler
199
+ ([TableMicroserviceExecutor](../../../../zeyrek-backend/src/NgApps.Domain/Contexts/Studio/Microservices/Executors/TableMicroserviceExecutor.cs)).
200
+ Kurallar:
201
+ - Gövde bir **dizi** olur; her eleman bir satırdır. `bulk-delete` gövdesinde yalnız birincil
202
+ anahtar alanı aranır ve tek bir `IN` filtresine çevrilir.
203
+ - `filters` **kullanılmaz** — satırlar ve anahtarlar gövdeden okunur.
204
+ - Tek istekte en fazla **1000 satır** (`EntityConstants.BulkRowLimit`); aşılırsa
205
+ `BulkRowLimitException` (422).
206
+ - Parti **hep-ya-hiç**tir: bir satır doğrulamadan geçmezse `BulkRowFailedException` hangi
207
+ satırın (index) patladığını söyler ve hiçbir satır yazılmaz.
208
+ - **Dosya alanı olan tablolarda `bulk-create`/`bulk-update` da desteklenir** — her satırın
209
+ dosya (ve çoka-çok dosya) alanı, tekil `create`/`update` ile **aynı format** üzerinden
210
+ (`{ type, fileName, value, clone, override, id }`) satır satır `fileService`'e gönderilir;
211
+ artık dosya alanı yüzünden 422 dönmez. Aynı entegrasyon workflow **table step**'inde de
212
+ vardır (satır dizisindeki dosya değeri de aynı formatı izler).
213
+ - **Bulk upsert yoktur.**
214
+ - `bulk-update` gövdesinde birincil anahtar **bulunur ve zorunludur** — tekil `update`'in
215
+ aksine satırı belirleyen filtre değil, gövdedeki anahtardır. `UpdateRowsAsync` bu anahtarı
216
+ `SET` listesinden dışlayıp `WHERE`'e taşır, bu yüzden alan listesinde görünmesi doğrudur ve
217
+ GENERATED ALWAYS koruması onu es geçer.
218
+ - Workflow **table step**'inde de aynı üç işlem vardır; orada satır dizisi adımın `expression`
219
+ alanından (JS) gelir, gövdeden değil. **Ancak studio'nun workflow table formunda bu
220
+ `expression` alanı için editör henüz yoktur** — akış adımında bulk seçilirse satır dizisi
221
+ girilemez ve adım `MissingParameterException` ile düşer. v1'de bulk yalnız microservice
222
+ ucundan kullanılır.
223
+ - Adımda tanımlı ama değeri boş bırakılan alanlar gövdeden/expression'dan gelen veriyi
224
+ **ezmez**; yalnız değeri dolu olan sabitler her satıra uygulanır.
180
225
  - **`count` vardır** — kayıt sayısı için tüm satırları çekip uzunluğuna bakmayın; panel/KPI
181
226
  sayaçlarının doğru şekli budur.
182
227
  - Gövde kökünde **`entityId` zorunlu**. (Eski "kökte datasourceId zorunlu" bilgisi yanlıştı —
@@ -188,9 +233,12 @@ DTO'dan süzülmez (WF-026 — `platform_guide('workflow')` §Hata yolu). Sözle
188
233
  `ArgumentNullException(key)`, farklı alias verilirse "missing FROM-clause entry" gelir.
189
234
  - `sort` ve `limit` **her zaman** verilir (MS-008, block) — aşağıya bak.
190
235
  - Filtrelerde `value` bir **JavaScript ifadesidir** — sabit metin tırnak içinde
191
- (`"'ACTIVE'"`), dinamik değer ifade olarak (`"input.status"`).
236
+ (`"'ACTIVE'"`), dinamik değer ifade olarak (`"input.status"`). **İki operatör bunun dışındadır:**
237
+ `isnull` ve `isnotnull` değer taşımaz — `value` verilmez, `source` da zorunlu değildir; verirsen
238
+ platform yok sayar, doğrulama da değer beklemez.
192
239
  - **Operatör sözlüğü kapalıdır:** `eq · neq · lt · lte · gt · gte · contains · icontains ·
193
- in · notin · startswith · endswith · istartswith · iendswith`. **`like` YOKTUR** — metin
240
+ in · notin · startswith · endswith · istartswith · iendswith · isnull · isnotnull`.
241
+ **`like` YOKTUR** — metin
194
242
  araması `contains`/`icontains` iledir. Kritik tuzak: platform bilinmeyen operatörü 400 ile
195
243
  reddetmez, **sessizce `eq`'e düşürür** (enum çözümlemesi unknown'da default'a düşer) — uç
196
244
  testten geçer ama arama hiçbir şey döndürmez. Gateway MS-012/WF-015 bunu istek gitmeden keser.
@@ -230,6 +278,61 @@ DTO'dan süzülmez (WF-026 — `platform_guide('workflow')` §Hata yolu). Sözle
230
278
  }
231
279
  ```
232
280
 
281
+ ## Güncelleme sözleşmesi: yazılan alan kümesi TANIMDAN gelir, gövdeden DEĞİL
282
+
283
+ `create` / `update` / `upsert` ucunda **SET listesi `fields[]`'tir**; gövde yalnız o alanların
284
+ DEĞERİNİ taşır. Studio'daki karşılığı "Oluşturulacak veya güncellenecek alanlar" ekranındaki
285
+ **İstek alanları** listesidir: önce hangi alanların yazılacağı seçilir, gövde sonra gelir.
286
+ İki yön de sessizdir, ikisi de 200 döner (ölçüm: 2026-09-15, `emrah/test`, `development`):
287
+
288
+ | Tanımda (`fields[]`) | Gövdede | Sonuç |
289
+ |---|---|---|
290
+ | alan **var** | anahtar **yok** | kolona **NULL yazılır** — eski değer silinir |
291
+ | alan **var** | anahtar var | değer yazılır |
292
+ | alan **yok** | anahtar var | **yok sayılır** — o alan bu uçtan hiç değiştirilemez |
293
+
294
+ Kod yolu: gövdede anahtar yoksa alan `null` değerini alır
295
+ (`MicroserviceRuntimeCacheDto.SetSourceEntityFieldAndFilterValue`, `:145-148`), `ToRow` Default
296
+ modlu **bütün** alanları sözlüğe basar (`:169-175`) ve `UpdateRowAsync` SET listesini doğrudan o
297
+ sözlüğün anahtarlarından kurar (`PostgreSqlEntityConnector.cs:262-273`; null → `DBNull.Value`).
298
+ "Yalnız gövdede gelen alanı yaz" diye bir bayrak **yoktur**.
299
+
300
+ Ölçülen üç vaka (`pu_test`: `title` · `owner` · `status`):
301
+
302
+ | # | Uç tanımı | Gövde | Sonuç |
303
+ |---|---|---|---|
304
+ | 1 | `fields: [title, owner, status]` | `{ id, status: 'done' }` | 200 — `status` değişti, **`title` ve `owner` NULL** oldu (`entity_audit_trails` ikisini de yalnız `previousValue` ile gösteriyor) |
305
+ | 2 | `fields: [status]` | `{ id, status, title: '…', owner: '…' }` | 200 — yalnız `status` değişti; listelenmeyen iki alan **yazılmadı** |
306
+ | 3 | `fields: [title, owner, status]`, `status` kolonu NOT NULL | `{ id, title }` | **400 `RowValidationFailed`** ("Please complete all required fields") — satır hiç değişmedi |
307
+
308
+ Yani kolon `nullable` ise kayıp **sessizdir**, NOT NULL ise istek **gürültülü** düşer. Kanban'da
309
+ kart sürüklemek, satır içi tek alan düzenlemek, "arşivle" düğmesi — hepsi 1. satırın tuzağıdır:
310
+ kart doğru sütuna geçer, başlığı ve sorumlusu silinir.
311
+
312
+ ### Kısmi güncellemenin üç doğru yolu
313
+
314
+ 1. **Eylem başına uç (varsayılan tercih).** Kartı taşıyan uç yalnız `status` yazar, başlığı
315
+ düzenleyen uç yalnız `title`: `fields[]` = o eylemin gerçekten yazdığı alanlar. Fazladan okuma
316
+ yok, eşzamanlı düzenlemede birbirini ezme yok, yetki yüzeyi de dar kalır (2. ölçüm bunun
317
+ kanıtıdır — uç, gövdeye konan `title`/`owner`'ı yok sayar).
318
+ 2. **Tam form ucunda gövde de tam olur.** Düzenleme formu kaydediyorsa gövde `fields[]`'teki HER
319
+ alanı taşır; kullanıcının dokunmadığı alan da forma yüklendiği hâliyle geri gönderilir. Uçta
320
+ yapılacak bir şey yoktur — eksik gönderen istemci alanı siler.
321
+ 3. **Oku-birleştir (alan kümesi ancak çağrı anında belliyse).** Akışta önce `table get`, sonra
322
+ `table update`; gelmeyen alan okunan değere düşer:
323
+
324
+ ```js
325
+ typeof input.title !== 'undefined' && input.title !== null ? input.title : read_row.data.title
326
+ ```
327
+
328
+ Ölçüldü: `{ id, status }` gövdesiyle `title` ve `owner` korundu, `status` yazıldı. Bedeli iki
329
+ veritabanı turu ve **son yazan kazanır** — okuma ile yazma arasında başkasının yazdığı alan
330
+ geri alınır. Bu yüzden 1. yol varken bu yola girilmez.
331
+
332
+ > Aynı kural workflow **table step**'inde birebir geçerlidir; orada değer gövdeden değil
333
+ > ifadeden gelir ve `undefined` dönen ifade de `null` yazar —
334
+ > `platform_guide('workflow')` §"Table update adımı".
335
+
233
336
  ## İlişki alanı: `row_list` NESNE döner, uç/step JOIN'siz DÜZ FK döner
234
337
 
235
338
  Aynı alan iki yoldan farklı şekilde gelir ve bu fark sessizce yanlış sonuç üretir:
@@ -531,6 +634,62 @@ kabul etti. Ayrıntı ve doğru rol kapısı tarifi: `platform_guide('middleware
531
634
  > rota `/{project}/m/{application}/{microservice SLUG'ı}`'dır ( `url` alanı rotaya GİRMEZ) ve
532
635
  > `Host: <org>.<suffix>` + `X-Environment` başlıkları zorunludur.
533
636
 
637
+ ## Alias nerede geçerli
638
+
639
+ Alias bir **SQL tablo takma adıdır**: yalnız okunan tarafta anlamı vardır. Sözleşme iki ayrı
640
+ tiple modellenmiştir ve ikisi karıştırılırsa alan sessizce düşer.
641
+
642
+ | Yer | Tip | Alanlar |
643
+ |---|---|---|
644
+ | `selectFields[]` · `returnFields[]` | `TableSelect` | `alias` · `fieldId` · `path` · `fieldSlug` |
645
+ | `filters[]` · `joins[]` | filtre/join | `alias` (+ kendi alanları) |
646
+ | `sourceParameters.alias` | kök alias | join varken ZORUNLU, kök entity'nin slug'ı |
647
+ | **`fields[]` (yazılacak alanlar)** | `TableField` | `fieldId` · `source` · `value` · `folderId` · `order` · `writeOn` — **`alias` YOK** |
648
+
649
+ `fields[]` yalnız `create` / `update` / `upsert` operasyonlarında bulunur ve WHERE değil SET
650
+ üretir: hangi tabloya yazılacağı zaten `entityId` ile bellidir, takma ada ihtiyaç yoktur. Aynı
651
+ `TableField` tipi workflow table adımlarının `rule.fields[]` listesinde de kullanılır.
652
+
653
+ Yazma alanına `alias` koyarsan istek **hata vermez**, alan model bağlamada düşer. Gateway bunu
654
+ istek gitmeden gövdeden çıkarır ve `gatewayNormalized` ile bildirir — böylece `silentlyDropped`
655
+ listesi yalnız gerçek kayıpları gösterir.
656
+
657
+ ## Zamanlanmış iş (`type: 'schedule-job'`) — `typeParameters.schedule`
658
+
659
+ Zamanlama tek bir tanımdır; `cronExpression` tek başına verilirse **UTC cron** sayılır (eski gövde).
660
+ Yeni işte tanımı `typeParameters.schedule` ile yazın ve kaydetmeden önce
661
+ `microservice_schedule_forecast` ile sıradaki koşuları görün.
662
+
663
+ | Alan | Değer |
664
+ |---|---|
665
+ | `mode` | `once` · `interval` · `cron` |
666
+ | `timeZoneId` | IANA (`Europe/Istanbul`); yoksa `UTC`. Saatler BU dilimde yorumlanır |
667
+ | `startAt` | yerel tarih-saat, dilimsiz (`2026-09-14T09:00:00`); once/interval için, cron'da `end.type:'after'` ile zorunlu |
668
+ | `every` · `unit` | 1–1000 · `minute` `hour` `day` `week` `month` |
669
+ | `timeOfDay` | `HH:mm` — `day`/`week`/`month` için zorunlu |
670
+ | `daysOfWeek` | `monday`…`sunday` — `week` için en az bir |
671
+ | `daysOfMonth` | 1–31, `-1` = ayın son günü — `month` için en az bir |
672
+ | `cronExpression` | Quartz cron (6–7 alan, `?` zorunlu) — yalnız `cron` modu |
673
+ | `end` | `{type:'never'}` · `{type:'on', at}` · `{type:'after', count}` (1–10000) |
674
+
675
+ ```json
676
+ { "mode": "interval", "timeZoneId": "Europe/Istanbul", "startAt": "2026-09-14T00:00:00",
677
+ "every": 2, "unit": "week", "daysOfWeek": ["tuesday", "thursday"], "timeOfDay": "09:00",
678
+ "end": { "type": "after", "count": 30 } }
679
+ ```
680
+
681
+ - Aralık başlangıçtan sayılır: "7 dakikada bir" saat başında sıfırlanmaz, "3 günde bir" ay sonunda
682
+ başa sarmaz, "2 haftada bir" gerçekten iki haftada birdir. Cron'da bunlar DOĞRU İFADE EDİLEMEZ
683
+ (`MON/2` = haftada 3 gün) — bu ihtiyaçlar için `interval` kullanın.
684
+ - `after N` başlangıçtan hesaplanan N'inci koşuda biter; `microservice_schedule_control trigger`
685
+ sayılmaz. Biten iş `microservice_schedule_get`'te `state: 'ended'` görünür.
686
+ - Geçersiz tanım `422` + alan adıyla lokalize mesaj döner (bozuk cron artık `500` değil). `after` ile
687
+ toplam süre sınırlıdır (gün × sayı ≤ 36500, hafta ≤ 5200, ay ≤ 1200).
688
+ - **`schedule` ile `cronExpression` çelişemez.** `microservice_get` ikisini de döndürür; güncellemede
689
+ yalnız `typeParameters.schedule`'ı değiştirin (cron modunda `schedule.cronExpression`). Yalnız
690
+ `cronExpression`'ı değiştiren PUT/PATCH `422 ScheduleCronConflict` alır — sessizce eski cron
691
+ kalmaz. `typeParameters: null` işi zamanlayıcıdan siler.
692
+
534
693
  ## Sık hatalar
535
694
 
536
695
  - `description` boş (MS-014, block — uç listesinde ne işe yaradığı okunamaz)
@@ -25,6 +25,29 @@ yeniden yazımlarda.
25
25
  `view:'part'` ile doğrulayarak yaz.
26
26
  - Silme yerine `replace` tercih et; `remove` kullanacaksan önce o path'i `part` ile görüntüle.
27
27
  - Yanıttaki outline özeti değişikliğin uygulandığı hâli gösterir — teyit için oku.
28
+ - **Kullanıcı fonksiyonunda patch aracı yok:** `function_update` tam gövde yazar ama vermediğin
29
+ alanları mevcut kayıttan doldurur — yalnız `body` göndermen yeter (fonksiyonun tek büyük alanı
30
+ gövdedir). Adı değiştirmeden önce `dependency_graph` (`module:'ui-function'`) ile çağıranları
31
+ bul: `{{ }}`/`code` ifadelerindeki `Functions.<eskiAd>(` çağrıları metinseldir ve kırılır.
32
+
33
+ ## Değiştirmeden önce geçmişe bak
34
+
35
+ Platform her tanım yazmasını append-only bir deftere düşürür. Bir kaydı değiştirmeden önce son
36
+ revizyonunu okumak, başka birinin işinin üstüne yazmayı önler:
37
+
38
+ ```
39
+ revision_list {projectId, module:'page', recordId, pageLength: 3}
40
+ → son satırda revisionNo, operation, actor ve source
41
+ revision_diff {projectId, module:'page', recordId}
42
+ → son iki sürüm arasındaki alan bazlı fark + summaryText
43
+ ```
44
+
45
+ `source` işin nereden geldiğini söyler: `mcp` bu gateway'in kendi izidir, `studio` bir insanın
46
+ Studio'da yaptığıdır, `merge` / `deployment` / `template` / `revert` ise taşıma yollarıdır.
47
+ Son revizyon `studio` ise ve dakikalar önceyse, üstüne yazmadan önce kullanıcıya sor.
48
+
49
+ Gövdenin tamamı gerekirse `revision_get {projectId, id}` — ama büyük sayfalarda MB'lar tutar ve
50
+ yanıt kırpılabilir; ne değiştiğini anlamak için `revision_diff` yeter.
28
51
 
29
52
  ## Uyum kuralları
30
53