@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.
- package/.env.example +2 -2
- package/.env.production.example +8 -0
- package/README.md +9 -8
- package/dist/config.js +18 -3
- package/dist/knowledge/backendConstraints.js +88 -0
- package/dist/knowledge/componentCatalog.js +415 -68
- package/dist/knowledge/componentEvents.js +120 -25
- package/dist/knowledge/functionGuards.js +134 -0
- package/dist/knowledge/normalize.js +512 -25
- package/dist/knowledge/outlines.js +31 -0
- package/dist/knowledge/policy.js +14 -5
- package/dist/knowledge/propTypes.js +5 -4
- package/dist/knowledge/rules.js +453 -6
- package/dist/knowledge/styleResolve.js +6 -1
- package/dist/platform/csv.js +123 -0
- package/dist/platform/errors.js +62 -3
- package/dist/platform/http.js +11 -2
- package/dist/platform/responses.js +16 -4
- package/dist/platform/screenshot.js +98 -9
- package/dist/platform/strictArguments.js +32 -0
- package/dist/platform/writeDiff.js +6 -3
- package/dist/resources/examples/flow-call-function.json +66 -0
- package/dist/resources/examples/function-total.json +70 -0
- package/dist/resources/examples/microfunction-node-sum.json +56 -0
- package/dist/resources/examples/page-dynamic-form.json +1 -1
- package/dist/resources/examples/page-sign-in.json +2 -2
- package/dist/resources/guides/component.md +14 -2
- package/dist/resources/guides/entity.md +321 -17
- package/dist/resources/guides/expressions.md +9 -0
- package/dist/resources/guides/functions.md +262 -0
- package/dist/resources/guides/getting-started.md +7 -0
- package/dist/resources/guides/layout.md +6 -0
- package/dist/resources/guides/merge.md +231 -0
- package/dist/resources/guides/microfunction.md +166 -0
- package/dist/resources/guides/microservice.md +166 -7
- package/dist/resources/guides/modify-existing.md +23 -0
- package/dist/resources/guides/page.md +101 -22
- package/dist/resources/guides/translation.md +35 -10
- package/dist/resources/guides/workflow.md +51 -2
- package/dist/resources/schema-fingerprint.json +4 -4
- package/dist/resources/schemas/AnalyzeImportQuery.json +51 -0
- package/dist/resources/schemas/ApplyMergePlanCommand.json +19 -0
- package/dist/resources/schemas/CreateBulkRowCommand.json +3 -0
- package/dist/resources/schemas/CreateEnvironmentCommand.json +31 -0
- package/dist/resources/schemas/CreateGlobalFunctionCommand.json +95 -0
- package/dist/resources/schemas/CreateImportPlanCommand.json +278 -0
- package/dist/resources/schemas/CreateMergePlanCommand.json +34 -0
- package/dist/resources/schemas/CreateMicrofunctionCommand.json +117 -0
- package/dist/resources/schemas/CreateMicrofunctionRuntimeCommand.json +51 -0
- package/dist/resources/schemas/CreateMicroserviceCommand.json +123 -2
- package/dist/resources/schemas/CreateWorkflowCommand.json +17 -3
- package/dist/resources/schemas/DataJobDto.json +267 -0
- package/dist/resources/schemas/ExportRowsCommand.json +172 -0
- package/dist/resources/schemas/Filter.json +3 -1
- package/dist/resources/schemas/GetRowsQuery.json +3 -1
- package/dist/resources/schemas/GlobalFunctionDto.json +89 -0
- package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +249 -0
- package/dist/resources/schemas/ImportAnalysisDto.json +401 -0
- package/dist/resources/schemas/ImportPlanDto.json +260 -0
- package/dist/resources/schemas/ImportSampleDto.json +90 -0
- package/dist/resources/schemas/InvokeMicrofunctionCommand.json +25 -0
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +123 -2
- package/dist/resources/schemas/PreviewWorkflowCommand.json +17 -3
- package/dist/resources/schemas/ResolveMergeConflictsCommand.json +58 -0
- package/dist/resources/schemas/RevertMergePlanCommand.json +19 -0
- package/dist/resources/schemas/RunImportCommand.json +62 -0
- package/dist/resources/schemas/StepDto.json +17 -3
- package/dist/resources/schemas/UpdateBulkRowCommand.json +3 -0
- package/dist/resources/schemas/UpdateEntityCommand.json +3 -1
- package/dist/resources/schemas/UpdateGlobalFunctionCommand.json +66 -0
- package/dist/resources/schemas/UpdateMicrofunctionCommand.json +121 -0
- package/dist/resources/schemas/UpdateMicrofunctionRuntimeCommand.json +54 -0
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +123 -2
- package/dist/resources/schemas/UpdateWorkflowCommand.json +17 -3
- package/dist/server.js +17 -4
- package/dist/tools/activities.js +40 -0
- package/dist/tools/automations.js +14 -5
- package/dist/tools/common.js +16 -0
- package/dist/tools/dependencies.js +1 -1
- package/dist/tools/environments.js +52 -0
- package/dist/tools/files.js +51 -50
- package/dist/tools/flows.js +104 -5
- package/dist/tools/functions.js +331 -0
- package/dist/tools/importSchemas.js +79 -0
- package/dist/tools/imports.js +241 -0
- package/dist/tools/layouts.js +4 -4
- package/dist/tools/merges.js +113 -0
- package/dist/tools/microfunctions.js +155 -0
- package/dist/tools/microservices.js +112 -9
- package/dist/tools/pages.js +188 -66
- package/dist/tools/platformInfo.js +4 -1
- package/dist/tools/queries.js +72 -6
- package/dist/tools/revisions.js +94 -0
- package/dist/tools/rows.js +342 -22
- package/dist/tools/screenWrite.js +11 -2
- package/dist/tools/templates.js +32 -5
- package/dist/tools/workflows.js +28 -6
- 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
|
|
163
|
-
`operation: 'get'` + `isSingle: false`, tek kayıt için
|
|
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).
|
|
178
|
-
>
|
|
179
|
-
>
|
|
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
|
|
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
|
|