@appaflytech/zeyrek-ai-mcp 0.0.5 → 0.0.7
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 +9 -1
- package/README.md +14 -38
- package/dist/config.js +36 -3
- package/dist/knowledge/backendConstraints.js +982 -0
- package/dist/knowledge/componentCatalog.js +549 -92
- package/dist/knowledge/componentEvents.js +120 -25
- package/dist/knowledge/coverage.js +43 -0
- package/dist/knowledge/flowGuards.js +30 -0
- package/dist/knowledge/functionGuards.js +134 -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 +500 -16
- package/dist/knowledge/outlines.js +167 -12
- package/dist/knowledge/policy.js +14 -5
- package/dist/knowledge/propTypes.js +80 -0
- package/dist/knowledge/rules.js +961 -44
- package/dist/knowledge/schemaGuard.js +199 -0
- package/dist/knowledge/styleResolve.js +63 -4
- package/dist/observability/trace.js +27 -3
- package/dist/platform/csv.js +123 -0
- package/dist/platform/errors.js +107 -6
- package/dist/platform/http.js +34 -4
- package/dist/platform/patch.js +27 -0
- package/dist/platform/refs.js +104 -0
- package/dist/platform/responses.js +25 -6
- package/dist/platform/screenshot.js +544 -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/flow-call-function.json +66 -0
- package/dist/resources/examples/function-total.json +70 -0
- package/dist/resources/examples/layout-app-shell.json +1 -1
- package/dist/resources/examples/microfunction-node-sum.json +56 -0
- package/dist/resources/examples/microservice-table-list.json +2 -4
- package/dist/resources/examples/page-dynamic-form.json +3 -3
- package/dist/resources/examples/page-flex-sections.json +99 -0
- package/dist/resources/examples/page-sign-in.json +4 -3
- package/dist/resources/guides/component.md +81 -8
- package/dist/resources/guides/entity.md +712 -20
- package/dist/resources/guides/expressions.md +47 -2
- package/dist/resources/guides/external-component.md +9 -0
- package/dist/resources/guides/functions.md +262 -0
- package/dist/resources/guides/getting-started.md +82 -7
- package/dist/resources/guides/layout.md +53 -10
- package/dist/resources/guides/merge.md +231 -0
- package/dist/resources/guides/microfunction.md +166 -0
- package/dist/resources/guides/microservice.md +287 -15
- package/dist/resources/guides/middleware.md +89 -1
- package/dist/resources/guides/modify-existing.md +23 -0
- package/dist/resources/guides/page.md +402 -49
- package/dist/resources/guides/translation.md +150 -8
- package/dist/resources/guides/view.md +16 -1
- package/dist/resources/guides/workflow.md +199 -28
- 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/AnalyzeImportQuery.json +51 -0
- package/dist/resources/schemas/ApplyMergePlanCommand.json +19 -0
- package/dist/resources/schemas/CreateBulkRowCommand.json +36 -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/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 +145 -3
- 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 +106 -14
- 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 +6 -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 +135 -1
- package/dist/resources/schemas/PreviewQueryCommand.json +5 -2
- package/dist/resources/schemas/PreviewWorkflowCommand.json +45 -9
- 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 +34 -3
- package/dist/resources/schemas/UpdateBulkRowCommand.json +36 -0
- package/dist/resources/schemas/UpdateDatasourceCommand.json +15 -6
- package/dist/resources/schemas/UpdateEntityCommand.json +52 -11
- 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 +147 -4
- 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 +106 -14
- package/dist/server.js +17 -1
- package/dist/tools/access.js +3 -3
- package/dist/tools/activities.js +40 -0
- package/dist/tools/applications.js +1 -1
- package/dist/tools/automations.js +76 -34
- package/dist/tools/common.js +55 -0
- package/dist/tools/components.js +16 -7
- package/dist/tools/datasources.js +83 -21
- package/dist/tools/dependencies.js +1 -1
- package/dist/tools/deployments.js +34 -2
- package/dist/tools/dtos.js +25 -12
- package/dist/tools/entities.js +113 -28
- package/dist/tools/environments.js +52 -0
- package/dist/tools/externalComponents.js +9 -3
- package/dist/tools/files.js +57 -42
- package/dist/tools/flows.js +205 -13
- package/dist/tools/folders.js +7 -2
- package/dist/tools/functions.js +331 -0
- package/dist/tools/globalFunctions.js +63 -0
- package/dist/tools/importSchemas.js +79 -0
- package/dist/tools/imports.js +241 -0
- package/dist/tools/layouts.js +103 -29
- package/dist/tools/merges.js +113 -0
- package/dist/tools/microfunctions.js +155 -0
- package/dist/tools/microservices.js +270 -40
- package/dist/tools/organizations.js +5 -6
- package/dist/tools/pages.js +421 -104
- package/dist/tools/platformInfo.js +155 -11
- package/dist/tools/projects.js +183 -33
- package/dist/tools/queries.js +32 -10
- package/dist/tools/revisions.js +94 -0
- package/dist/tools/rows.js +484 -50
- package/dist/tools/screenWrite.js +68 -0
- package/dist/tools/screens.js +28 -0
- package/dist/tools/templates.js +32 -5
- package/dist/tools/translations.js +24 -8
- package/dist/tools/views.js +20 -10
- package/dist/tools/workflows.js +56 -21
- package/package.json +7 -2
|
@@ -43,23 +43,119 @@ servis formunda görünür ve `microservice_get` outline görünümünde geri ok
|
|
|
43
43
|
(varsayılan 20) ve `offset` alır. Kurulum sırası: `view_create` (aranacak tablo/alanlar +
|
|
44
44
|
analizör) → `view_rebuild` → `source:'view'` microservice. Satış özeti / top-N gibi
|
|
45
45
|
rapor işleri view'e DEĞİL raw query'e aittir (`query_create` + query kaynaklı uç).
|
|
46
|
+
**Alan kapsamı:** view kaynaklı uç `selectFields` boşken yalnız view'ın indekslediği
|
|
47
|
+
alanları + birincil anahtarı döndürür. İndekslenmemiş kolon (maaş, TCKN) kendiliğinden
|
|
48
|
+
gelmez; daha fazlasını istiyorsan `selectFields` ile açıkça iste (İK koşusu M-7).
|
|
46
49
|
- `workflow`: çok adımlı iş mantığı gerekiyorsa microservice'i workflow'a bağla
|
|
47
|
-
(`workflowId`).
|
|
50
|
+
(`workflowId`). **Yanıtı açık bir DTO sözleşmesine bağlamanın tek yolu da budur** — DTO
|
|
51
|
+
alanları uçta değil akıştadır; bkz. aşağıda §"Yanıt sözleşmesi (DTO) uca DEĞİL workflow'a
|
|
52
|
+
bağlanır".
|
|
48
53
|
- `query`: yalnız ham SQL gerçekten şartsa. Politika lint'i her query kullanımında gerekçe
|
|
49
54
|
ister (MS-002, warn).
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
|
|
56
|
+
> **BOŞ STRING PARAMETRE `NULL`'A ÇEVRİLİR — sorgu sessizce 0 satır döner.** Platform
|
|
57
|
+
> önizleme/çalıştırma parametrelerini normalize ederken boş ya da yalnız boşluktan oluşan
|
|
58
|
+
> değeri `null` yapar. `WHERE company_id = @company` yazıp `company: ''` gönderirsen koşul
|
|
59
|
+
> `= NULL` olur ve **hiçbir satırla eşleşmez**: HTTP 200, boş sonuç, hata yok, uyarı yok.
|
|
60
|
+
> Üç koşuda üst üste ölçüldü (09-02, 09-04 birinci ve dördüncü koşu) ve üçünde de teşhis
|
|
61
|
+
> ancak `SELECT (@p IS NULL)` gibi bir sonda ile yapılabildi.
|
|
62
|
+
>
|
|
63
|
+
> **Parametre listesi ZORUNLUDUR.** `@token` kullanan bir sorguyu `query_create` ile
|
|
64
|
+
> kaydederken her belirteci `parameters` içinde `{ name, type, value }` olarak bildir. Eksik
|
|
65
|
+
> bırakılırsa istek **400** döner ve mesaj hangi belirtecin bildirilmediğini adıyla söyler.
|
|
66
|
+
> (2026-09-04'ten önce aynı durum `500 "Please correct the query syntax."` veriyordu ve SQL'i
|
|
67
|
+
> suçluyordu; kaydetme yolu gövdeyi önce bir kez çalıştırıp yanıt şemasını ürettiği için
|
|
68
|
+
> bağlanmamış belirteç sözdizimi hatası gibi görünüyordu.) `value` yalnız kayıt anında
|
|
69
|
+
> kullanılır: SQL doğrulanır ve `returnScheme` ondan üretilir.
|
|
70
|
+
> Yorum satırındaki `{{ad}}`/`@ad` belirteçleri parametre sayılmaz — kaydetme yolu
|
|
71
|
+
> sorguyu yorumlarından arındırdıktan sonra tarar. SQL çalıştırılamazsa kayıt **yine de**
|
|
72
|
+
> oluşur: `returnScheme` boş kalır ve yanıttaki `message` nedeni söyler; SQL'i düzeltip
|
|
73
|
+
> `query_update` ile kaydet.
|
|
74
|
+
>
|
|
75
|
+
> "Filtre yok" demek istiyorsan iki doğru kalıptan birini kullan:
|
|
76
|
+
> `(@company IS NULL OR c.company_id::text = @company)` ya da bir sentinel değer
|
|
77
|
+
> (`'all'`) ve SQL'de ona bakan bir dal. Aynı davranış workflow query adımında da geçerli;
|
|
78
|
+
> oradaki anlatım `platform_guide('workflow')` "Query adımı" bölümünde.
|
|
79
|
+
>
|
|
80
|
+
> **KAPSAM UYARISI: query kaynaklı ucun parametreleri ÇAĞRIDAN gelir.** Middleware'in
|
|
81
|
+
> kurduğu `user` bu yola girmez — kimlik/tenant kapsamını gövdeye yazan bir uç
|
|
82
|
+
> sahtelenebilir (ölçüldü 2026-09-07). Kapsam sunucuda zorlanacaksa sorguyu bir workflow
|
|
83
|
+
> query adımından çağır; reçete aşağıda §"Kimlik kapsaması × uç kaynağı".
|
|
84
|
+
2. **`selectFields` asla boş bırakılmaz.** Boş = platform TÜM alanları döndürür (view kaynaklı
|
|
85
|
+
uçta: yalnız view'ın indekslediği alanlar + birincil anahtar); join'li sorguda maliyet
|
|
86
|
+
katlanır. Join varken boş bırakmak block'tur (MS-001).
|
|
52
87
|
3. **Join'ler ilişkilerden türetilir.** `sourceParameters.joins` öğesi:
|
|
53
88
|
`{ alias, entityId, fieldId, path, joins }` — iç içe join mümkündür. Her join'in getirdiği
|
|
54
89
|
alanlar da `selectFields`'ta `{ alias, fieldId, path, fieldSlug }` ile açıkça seçilir.
|
|
55
90
|
**`path` boş bırakılamaz** — Studio join'li seçimleri yalnız `path` üzerinden eşleştirir
|
|
56
91
|
(aşağıdaki bölüme bak).
|
|
92
|
+
3b. **Kayıtlı ucu önizleme:** `microservice_preview` tam gövde istemez — `id` verirsen gateway
|
|
93
|
+
tanımı platformdan çeker ve yalnız `previewParameters`'ı senden alır (09-04 Y-09). Şekil
|
|
94
|
+
`{ body: [{…}] }` · `{ queryString: {…} }` · `{ routeParams: {…} }`; **tanımsız bir şekil
|
|
95
|
+
sessizce yutulur** ve bütün sayaçlar 0 döner (09-02 M-2).
|
|
57
96
|
4. **HTTP sözleşmesi:** `type: 'rest-api'` + `httpMethod: get|post|put|delete` + `url`
|
|
58
97
|
(route şablonu). Zamanlanmış işler `type: 'schedule-job'`, kuyruk tüketicileri `consumer`.
|
|
98
|
+
4b. **`query_preview` yazma sorgusunu ÇALIŞTIRIR, GERİ ALIR ve BUNU SÖYLEMEZ.**
|
|
99
|
+
`INSERT`/`UPDATE`/`DELETE` önizlediğinde `affectedRowCount` **gerçek** sayıyı döndürür ama
|
|
100
|
+
transaction geri alınır ve tabloda satır kalmaz. **Yanıtta rollback işareti yoktur** — yalnız
|
|
101
|
+
`{ affectedRowCount, elapsedMilliseconds }` gelir (2026-09-07'de ölçüldü; `rolledBack` alanı
|
|
102
|
+
yalnız OKUYAN sorgunun yanıt şeklinde var ve orada hep `false`). Yani sayıya bakan çağıran
|
|
103
|
+
yazdığını sanır: 09-04 4. koşusunda 624 satırlık bir seed böyle "yazıldı" sanıldı. Kalıcı
|
|
104
|
+
yazma için sorguyu kaydedip query kaynaklı bir uçtan ya da workflow'dan çalıştır; kalıcılığın
|
|
105
|
+
tek kanıtı sonradan çekilen `row_list`'tir. **Var olan satırlardan türetilmiş satır üretmenin
|
|
106
|
+
uçtan uca reçetesi** (anahtar sözleşmesi dâhil) `platform_guide('entity')` §"Toplu ve
|
|
107
|
+
türetilmiş satır" bölümündedir; aynı davranış `platform_guide('workflow')` "Query adımı"
|
|
108
|
+
bölümünde de yazılıdır.
|
|
109
|
+
|
|
110
|
+
4c. **Sayfalama toplamı `Total-Count` header'ından gelir.** Sayfalı bir uç kurduğunda toplam
|
|
111
|
+
kayıt sayısı gövdede değil header'dadır (`microservice_execute` yanıtında `headers` altında,
|
|
112
|
+
küçük harfle `total-count`). Tabloya bağlarken sayfa göstergesinin okuduğu sözleşme budur;
|
|
113
|
+
ayrıntı `platform_guide('page')` sayfalama bölümü. Alternatif olarak sorgunun kendisi
|
|
114
|
+
`COUNT(*) OVER()` ile toplamı satıra koyabilir — o zaman header'a hiç bağımlı kalmazsın.
|
|
115
|
+
|
|
59
116
|
5. **Doğrulama akışı:** `microservice_preview` (kaydetmeden) → kaydet → `microservice_execute`
|
|
60
117
|
(gerçek runtime yolu) → sonuç beklenmedikse **aynı parametrelerle `microservice_debug`** —
|
|
61
118
|
adım adım executionItems ağacı döner.
|
|
62
119
|
|
|
120
|
+
## Yanıt sözleşmesi (DTO) uca DEĞİL workflow'a bağlanır (MS-018, block)
|
|
121
|
+
|
|
122
|
+
`returnDtoId` · `parameterDtoId` · `returnBehavior` · `parameterBehavior` **microservice
|
|
123
|
+
komutunda yoktur** (`Create/UpdateMicroserviceCommand`). Gövdeye yazarsan platform 200 döner ve
|
|
124
|
+
alanı sessizce düşürür: uç sözleşmesiz kalır, ne hata ne uyarı gelir (2026-09-09 koşusu `S-2`).
|
|
125
|
+
Gateway bu gövdeyi artık MS-018 ile **platforma hiç göndermeden** reddeder.
|
|
126
|
+
|
|
127
|
+
Yanıt şeklini kaynak belirler:
|
|
128
|
+
|
|
129
|
+
| Kaynak | Yanıt şeklini ne belirler | Açık DTO sözleşmesi |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| `table` | `sourceParameters.selectFields` (+ join alanları) | yok |
|
|
132
|
+
| `query` | sorgunun `returnScheme`'i — kayıt anında SQL'den üretilir | yok |
|
|
133
|
+
| `view` | view'ın indekslediği alanlar + birincil anahtar (`selectFields` ile genişletilir) | yok |
|
|
134
|
+
| `workflow` | akışın `returnDtoId` + `returnBehavior` sözleşmesi | **var** |
|
|
135
|
+
|
|
136
|
+
Yani "yanıtın alanları şu DTO'dan olsun" diyeceksen uç **workflow kaynaklı** kurulur:
|
|
137
|
+
|
|
138
|
+
1. `dto_list` ile mevcut DTO'yu bul (platform entity başına DTO üretir) ya da `dto_create` → `dtoId`
|
|
139
|
+
2. `workflow_create` → `returnDtoId: dtoId` + `returnBehavior: 'object' | 'array' | 'primitive'`.
|
|
140
|
+
WF-002: `type:'workflow'` akışta `returnDtoId` **zorunludur** (yoksa akış `unready` kalır);
|
|
141
|
+
`returnBehavior`'ı boş bırakırsan gateway `object` ile doldurup `gatewayNormalized` der.
|
|
142
|
+
3. `microservice_create` → `source: 'workflow'` + `workflowId` — DTO alanı **uca yazılmaz**.
|
|
143
|
+
4. Aynı uç `middlewareIds` ile kimlik kapsamasını da taşır (§"Kimlik kapsaması × uç kaynağı").
|
|
144
|
+
|
|
145
|
+
Kayıtlı bir akışa sözleşmeyi sonradan bağlamak tek çağrıdır:
|
|
146
|
+
`workflow_patch(id: <workflowId>, ops: [{ op: 'add', path: '/returnDtoId', value: <dtoId> }, { op: 'add', path: '/returnBehavior', value: 'object' }])`.
|
|
147
|
+
|
|
148
|
+
**Sözleşmenin bağlandığını uçtan oku:** workflow kaynaklı uçta `microservice_get` yanıtındaki
|
|
149
|
+
`returnScheme` **DTO'nun alanlarını** taşır; table/query/view kaynaklı uçta şema kaynaktan türer.
|
|
150
|
+
Bağlanmamış sözleşmenin belirtisi budur — uç 200 döner ama `returnScheme` DTO'yu değil kaynağı
|
|
151
|
+
yansıtır (2026-09-09'da ölçüldü: `returnDtoId` yazılan table kaynaklı uçta şema `['id','name']`
|
|
152
|
+
kaldı, DTO'nun beş alanı gelmedi).
|
|
153
|
+
|
|
154
|
+
Sözleşme yalnız **2xx** yanıtlarda uygulanır: 401/422 döndüren bir `response` adımının gövdesi
|
|
155
|
+
DTO'dan süzülmez (WF-026 — `platform_guide('workflow')` §Hata yolu). Sözleşme **süzer, uydurmaz**:
|
|
156
|
+
`bodyExpression`'ın ürettiği DTO dışı alan yanıttan düşer, DTO'da olup üretilmeyen alan gelmez
|
|
157
|
+
(ölçüm: `gizliNot` alanı yanıtta yok, `slot_minutes` de yok).
|
|
158
|
+
|
|
63
159
|
## Asgari doğru table-source microservice (platformda doğrulanmış kurallar)
|
|
64
160
|
|
|
65
161
|
- `operation` enum'u **tam olarak** şudur ([MicroserviceTableOperation](../../../../zeyrek-backend/src/NgApps.Domain/Contexts/Studio/Microservices/MicroserviceTableOperation.cs)):
|
|
@@ -69,18 +165,35 @@ servis formunda görünür ve `microservice_get` outline görünümünde geri ok
|
|
|
69
165
|
yapmasını iki ayrı uç + akışta condition dallanmasıyla kurmayın: tek `operation: 'upsert'`
|
|
70
166
|
ucu yeterlidir. Aynı işlem workflow **table step**'inde de desteklenir
|
|
71
167
|
([TableStep](../../../../zeyrek-backend/src/NgApps.Domain/Contexts/Flow/Workflows/Steps/TableStep.cs)).
|
|
168
|
+
|
|
169
|
+
- **Upsert eşleşmesi `filters` ile kurulur, PK `fields`'a KONMAZ** (ölçüm: İK koşusu M-4,
|
|
170
|
+
2026-09-01). PK'yı `fields`'a koyarsan `AlwaysGeneratedFieldCantBeWritten` alırsın. Doğru şekil:
|
|
171
|
+
`filters`'a `source: "body"` + `isRequired: false` bir id filtresi; gövdede id **varsa** eşleşen
|
|
172
|
+
satır güncellenir, **yoksa** yeni satır açılır. `isRequired: true` yaparsan "yeni kayıt" yolu
|
|
173
|
+
kapanır (id gelmeyince uç reddeder).
|
|
174
|
+
|
|
175
|
+
> **Upsert'te üretilen alan tuzağı.** `operation: 'upsert'` UPDATE yolunda da alan ifadelerini
|
|
176
|
+
> 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.
|
|
72
180
|
- **`count` vardır** — kayıt sayısı için tüm satırları çekip uzunluğuna bakmayın; panel/KPI
|
|
73
181
|
sayaçlarının doğru şekli budur.
|
|
74
182
|
- Gövde kökünde **`entityId` zorunlu**. (Eski "kökte datasourceId zorunlu" bilgisi yanlıştı —
|
|
75
183
|
komutta öyle bir alan yok, gönderilirse yok sayılır; asıl zorunluluk selectFields'taki fieldId.)
|
|
76
|
-
- `selectFields[]`
|
|
77
|
-
|
|
184
|
+
- `selectFields[]` / `filters[]` öğelerinde platform **`fieldId`** ister; gateway'e **`fieldSlug`**
|
|
185
|
+
vermen yeter — kök entity'nin alanları için id'yi gateway çözer ve `gatewayResolved` ile bildirir
|
|
186
|
+
(join'lenen entity'lerin alanlarında hâlâ `fieldId` gerekir). Kök `entityId` de slug olabilir.
|
|
187
|
+
Kök tablo alanlarında alias = **entity'nin slug'ı** ve `path` **yazılmaz**. Alias verilmezse
|
|
78
188
|
`ArgumentNullException(key)`, farklı alias verilirse "missing FROM-clause entry" gelir.
|
|
79
189
|
- `sort` ve `limit` **her zaman** verilir (MS-008, block) — aşağıya bak.
|
|
80
190
|
- Filtrelerde `value` bir **JavaScript ifadesidir** — sabit metin tırnak içinde
|
|
81
|
-
(`"'ACTIVE'"`), dinamik değer ifade olarak (`"input.status"`).
|
|
191
|
+
(`"'ACTIVE'"`), dinamik değer ifade olarak (`"input.status"`). **İki operatör bunun dışındadır:**
|
|
192
|
+
`isnull` ve `isnotnull` değer taşımaz — `value` verilmez, `source` da zorunlu değildir; verirsen
|
|
193
|
+
platform yok sayar, doğrulama da değer beklemez.
|
|
82
194
|
- **Operatör sözlüğü kapalıdır:** `eq · neq · lt · lte · gt · gte · contains · icontains ·
|
|
83
|
-
in · notin · startswith · endswith · istartswith · iendswith
|
|
195
|
+
in · notin · startswith · endswith · istartswith · iendswith · isnull · isnotnull`.
|
|
196
|
+
**`like` YOKTUR** — metin
|
|
84
197
|
araması `contains`/`icontains` iledir. Kritik tuzak: platform bilinmeyen operatörü 400 ile
|
|
85
198
|
reddetmez, **sessizce `eq`'e düşürür** (enum çözümlemesi unknown'da default'a düşer) — uç
|
|
86
199
|
testten geçer ama arama hiçbir şey döndürmez. Gateway MS-012/WF-015 bunu istek gitmeden keser.
|
|
@@ -90,6 +203,11 @@ servis formunda görünür ve `microservice_get` outline görünümünde geri ok
|
|
|
90
203
|
`{ alias, fieldId, fieldSlug }`). Aynı kural workflow table create/update step'lerinde de
|
|
91
204
|
geçerlidir. Boş `returnFields` ile write operasyonu yazarsan MS-009 uyarır; buna karşılık
|
|
92
205
|
write operasyonunda boş `selectFields` **uyarı üretmez** (platform onu zaten yok sayar).
|
|
206
|
+
- **Platformun ürettiği alanları `fields` içine koymayın.** Primary key/identity gibi
|
|
207
|
+
`alwaysGenerated` alanlar yazılırsa istek 400 döner ve hatalı alan slug'larını sayar; bu alanlar
|
|
208
|
+
create'te platformca üretilir, upsert eşleşmesi gerekiyorsa değer `fields` yerine `filters`ta
|
|
209
|
+
taşınır. Incremental alanın create/update zamanlaması ayrı tasarım konusudur; mevcut sınır için
|
|
210
|
+
[`writeOn` tasarımına](../../../../zeyrek-backend/docs/alan-yazma-zamani/01-tasarim.md) bakın.
|
|
93
211
|
|
|
94
212
|
```jsonc
|
|
95
213
|
{
|
|
@@ -208,6 +326,19 @@ karşılamayı imkânsız kılar. Karar kuralı:
|
|
|
208
326
|
"isRequired": false, "children": [], "order": 0 }
|
|
209
327
|
```
|
|
210
328
|
|
|
329
|
+
> **`source: "query-string"` / `"body"` / `"header"` filtresinde `value` VERİLMEZ** (ölçüm: İK
|
|
330
|
+
> koşusu M-2, 2026-09-01). Değer çağrıdan gelir, parametre adı alan slug'ından türer. `value`
|
|
331
|
+
> yazarsan platform onu JS ifadesi sanıp eval eder → `JavaScriptException: <ad> is not defined`
|
|
332
|
+
> ile 500. `value` yalnız `source: "expression"` ve `"static"` kaynaklarında anlamlıdır. Sabit
|
|
333
|
+
> ön-süzme (tenant, aktiflik) `expression` ile yapılır. Gateway **MS-015** lint'i bu
|
|
334
|
+
> kombinasyonu istek platforma gitmeden yakalar.
|
|
335
|
+
|
|
336
|
+
> **Dış kaynaklı filtreye (`query-string` / `body` / `header`) `value` yazılmaz.** Değer çağrıdan
|
|
337
|
+
> gelir; tanımdaki `value` çalışma zamanında yok sayılır — parametre gelmezse filtre atlanır ve uç
|
|
338
|
+
> **süzülmemiş** tam liste döner (2026-09-03 öncesinde aynı alan JS olarak değerlendirilip 500
|
|
339
|
+
> veriyordu; İK koşusu M-2). Tanımdan gelen sabit değer istiyorsan `source: 'static'` ya da
|
|
340
|
+
> `'expression'` kullan.
|
|
341
|
+
|
|
211
342
|
### Dinamik filtre (`enableDynamicFilters`) — süzülebilir tablonun uç şekli
|
|
212
343
|
|
|
213
344
|
`enableDynamicFilters: true` verilen uç, süzme koşullarını **tanımdan değil çağrıdan** alır.
|
|
@@ -267,12 +398,69 @@ hem `joins` ile getirin hem `selectFields`'a koyun; ondan sonra `filters[0][fiel
|
|
|
267
398
|
> (qm kanıtı: `sy-users-get-my-profile`). Ayrıntı ve tarifler: `platform_guide('middleware')`.
|
|
268
399
|
> Middleware bağlamadan `user.` okuyan expression yazarsan MS-011 uyarır — runtime'da
|
|
269
400
|
> `user is not defined` 500'ü yersin.
|
|
401
|
+
>
|
|
402
|
+
> **`middlewareIds`'i `microservice_create` GÖVDESİNDE ver, sonradan patch'leme.** Ucu kurup
|
|
403
|
+
> ardından `microservice_patch` ile `/middlewareIds` yazmak her uç için fazladan bir tur demektir:
|
|
404
|
+
> 2026-09-06 koşusunda dokuz uç kuruldu ve dokuz patch çağrısının dokuzu da yalnız bu yolu yazdı
|
|
405
|
+
> (~3 dk). Alan create gövdesinde zaten kabul ediliyor.
|
|
270
406
|
|
|
271
407
|
> Sayfa tarafındaki karşılığı: kullanıcı ekrandan süzüyorsa (`table` + `filterMode` açık, ya da
|
|
272
408
|
> `datatable` + `isFilterable` kolonlar) uç `enableDynamicFilters: true` olmalı; komponent seçilen
|
|
273
409
|
> koşulları kendi `filters` prop'una yazar ve akış onu uca `filters` parametresi olarak geçirir.
|
|
274
410
|
> Süzme yoksa statik query-string filtreleri yeterlidir — bkz. `platform_guide('page')` Kural 1e.
|
|
275
411
|
|
|
412
|
+
### Kimlik kapsaması × uç kaynağı — query kaynaklı uç BAĞLAM GÖRMEZ
|
|
413
|
+
|
|
414
|
+
Yukarıdaki `source: 'expression'` + `value: 'user.id'` kalıbı **yalnız table kaynaklı** uçlarda
|
|
415
|
+
vardır. Agregasyon/rapor uçları query kaynaklı olduğu için aynı kalıp orada yoktur ve
|
|
416
|
+
**parametrelerinin tamamı çağrıdan gelir** — kapsamı gövdeye yazan bir uç sahtelenebilir.
|
|
417
|
+
|
|
418
|
+
| Uç kaynağı | Parametre/filtre nereden gelir | Kapsam sunucuda zorlanır mı |
|
|
419
|
+
|---|---|---|
|
|
420
|
+
| `table` | `filters[]` · `source:'expression'`, `value:'user.id'` | **Evet** (MS-011 middleware bağını denetler) |
|
|
421
|
+
| `query` | Yalnız çağrının kendisi: **body → query-string → header** (`Query.PrepareQueryParameters` → `FindValue`) | **Hayır** — ifade değerlendirmesi yoktur |
|
|
422
|
+
| `workflow` | Adım ifadeleri; `user.*` bağlı middleware'den gelir | **Evet** (ölçüldü 2026-09-07) |
|
|
423
|
+
| `view` | Arama sözleşmesi (`searchText`) + view'ın indekslediği alanlar | **ölçülmedi** — kapsam şartsa workflow yolunu kullan |
|
|
424
|
+
|
|
425
|
+
Query parametresine ifade kaynağı **eklenemez**: `parameters[].source` komut şemasında yoktur,
|
|
426
|
+
platform anahtarı sessizce atar (gateway `unmappedMembers` ile söyler) ve kayıtlı şema
|
|
427
|
+
`source: 'body'` kalır. Bu bir eksik değil, modülün tanımı: query modülü SQL seviyesinde çalışan
|
|
428
|
+
ham SQL yüzeyidir, istek bağlamını bilmez.
|
|
429
|
+
|
|
430
|
+
**Ölçüm (2026-09-07, aynı sorgu, aynı middleware — middleware `user.owner_key = 'OWNER-A'` kurdu):**
|
|
431
|
+
|
|
432
|
+
| Uç | Gövde | Yanıt |
|
|
433
|
+
|---|---|---|
|
|
434
|
+
| `source:'query'` | `{ owner_key:'OWNER-A' }` | `{ owner_key:'OWNER-A', row_count:3, total:60 }` |
|
|
435
|
+
| `source:'query'` | `{ owner_key:'OWNER-B' }` | `{ owner_key:'OWNER-B', row_count:2, total:300 }` ← **başkasının verisi** |
|
|
436
|
+
| `source:'workflow'` | `{ owner_key:'OWNER-B' }` | `{ owner_key:'OWNER-A', row_count:3, total:60 }` ← gövde **yok sayıldı** |
|
|
437
|
+
| `source:'workflow'` | `{ owner_key:'OWNER-B', min_amount:20 }` | `{ owner_key:'OWNER-A', row_count:2, total:50 }` ← kapsam dışı filtre gövdeden okundu |
|
|
438
|
+
|
|
439
|
+
#### Reçete: kapsanmış agregasyon ucu
|
|
440
|
+
|
|
441
|
+
Sorguyu değiştirmeye gerek yok; onu **bir katman yukarıdan** çağırırsın.
|
|
442
|
+
|
|
443
|
+
1. `query_create` — agregasyonu kapsam parametresiyle yaz:
|
|
444
|
+
`… WHERE company_id = @company_id AND created_at >= @from`, `parameters` ile her belirteci bildir.
|
|
445
|
+
2. `workflow_create` (`type: 'workflow'`) — start → **query adımı** → response. Adımın bağlaması
|
|
446
|
+
kapsamı middleware'den, kalan filtreleri gövdeden alır:
|
|
447
|
+
`rule.expression = "{ company_id: user.company_id, from: input.from }"`
|
|
448
|
+
(bağlamanın iki yazımı ve canlı motorun tuzağı: `platform_guide('workflow')` §"Query adımı").
|
|
449
|
+
3. `microservice_create` — `source: 'workflow'`, `workflowId`, **`middlewareIds` dolu**.
|
|
450
|
+
4. Doğrula: aynı ucu gövdeye **başka birinin** kapsam değerini yazarak çağır; yanıt değişmemeli.
|
|
451
|
+
|
|
452
|
+
`middlewareIds` boşken bu akış `500 JavaScriptException: user is not defined` verir (ölçüldü) —
|
|
453
|
+
MS-011'in workflow tarafındaki karşılığıdır ve gateway o dizinin boş kalmasını göremez, çünkü
|
|
454
|
+
uçtan görünen tek şey `workflowId`'dir.
|
|
455
|
+
|
|
456
|
+
Middleware tarafındaki karşılığı ve `user` değişkenini kuran akış:
|
|
457
|
+
`platform_guide('middleware')` Tarif 3c.
|
|
458
|
+
|
|
459
|
+
**Her agregasyonu sarmalama.** Kapsam gerekmeyen bir özet (herkese açık istatistik, zaten
|
|
460
|
+
middleware'in reddettiği bir panelde tüm şirketleri gösteren yönetici raporu) düz `source:'query'`
|
|
461
|
+
kalır: fazladan workflow, DTO ve response adımı bedavaya gelmez. Ölçü basit — **bu parametreyi
|
|
462
|
+
çağıran seçebilmeli mi?** Hayırsa sarmala.
|
|
463
|
+
|
|
276
464
|
### `sort` ve `limit` her zaman verilir
|
|
277
465
|
|
|
278
466
|
**MS-008 (block).** Platform bunları null bırakır; Studio formu ise `data.sort.name` /
|
|
@@ -285,6 +473,24 @@ Gateway bu kuralları MS-005/MS-006 olarak istek gitmeden denetler; platform val
|
|
|
285
473
|
hatası alırsan `microservice_debug` çıktısıyla raporla — o zaman gerçek bir bug'dır.
|
|
286
474
|
Query source'a kaçış yalnız ham SQL şartsa; query yazarken parser `SELECT` sonrası satır sonu
|
|
287
475
|
kabul etmez — ilk kolon `SELECT` ile aynı satırda olmalı ("Please use a supported query type").
|
|
476
|
+
Kayıtlı query'nin `@ad` / `{{ad}}` belirteçleri uçta **body → query-string → header** sırasıyla
|
|
477
|
+
bağlanır; bunun için parametreler query kaydedilirken `parameters` ile bildirilmiş olmalıdır
|
|
478
|
+
(`platform_guide('workflow')` §"Query adımı"). Davranış `query_preview` ile aynıdır.
|
|
479
|
+
|
|
480
|
+
**`language` AYRILMIŞ bir parametredir.** Ham sorguda `{{language}}` (ya da `@language`)
|
|
481
|
+
kullanırsan platform onu isteğin diliyle kendisi doldurur — `parameters` listesine yazmana gerek
|
|
482
|
+
YOKTUR ve yazarsan doğrulama onu zorunlu saymaz. Çok dilli companion tablosunu elle join eden bir
|
|
483
|
+
raporun dili böyle alınır:
|
|
484
|
+
|
|
485
|
+
```sql
|
|
486
|
+
SELECT p.id, COALESCE(l.title, d.title) AS title
|
|
487
|
+
FROM products p
|
|
488
|
+
LEFT JOIN products_localization l ON l.product_id = p.id AND l.language = {{language}}
|
|
489
|
+
LEFT JOIN products_localization d ON d.product_id = p.id AND d.language = 'en'
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
`query_preview` da aynı parametreyi ekleyerek koşar, yani şema çıkarımı `{{language}}` yüzünden
|
|
493
|
+
"eksik parametre" diye patlamaz.
|
|
288
494
|
|
|
289
495
|
## Middleware'siz uçta çok adımlı yazım ATOMİK DEĞİL (ölçüm 2026-08-19)
|
|
290
496
|
|
|
@@ -328,6 +534,62 @@ kabul etti. Ayrıntı ve doğru rol kapısı tarifi: `platform_guide('middleware
|
|
|
328
534
|
> rota `/{project}/m/{application}/{microservice SLUG'ı}`'dır ( `url` alanı rotaya GİRMEZ) ve
|
|
329
535
|
> `Host: <org>.<suffix>` + `X-Environment` başlıkları zorunludur.
|
|
330
536
|
|
|
537
|
+
## Alias nerede geçerli
|
|
538
|
+
|
|
539
|
+
Alias bir **SQL tablo takma adıdır**: yalnız okunan tarafta anlamı vardır. Sözleşme iki ayrı
|
|
540
|
+
tiple modellenmiştir ve ikisi karıştırılırsa alan sessizce düşer.
|
|
541
|
+
|
|
542
|
+
| Yer | Tip | Alanlar |
|
|
543
|
+
|---|---|---|
|
|
544
|
+
| `selectFields[]` · `returnFields[]` | `TableSelect` | `alias` · `fieldId` · `path` · `fieldSlug` |
|
|
545
|
+
| `filters[]` · `joins[]` | filtre/join | `alias` (+ kendi alanları) |
|
|
546
|
+
| `sourceParameters.alias` | kök alias | join varken ZORUNLU, kök entity'nin slug'ı |
|
|
547
|
+
| **`fields[]` (yazılacak alanlar)** | `TableField` | `fieldId` · `source` · `value` · `folderId` · `order` · `writeOn` — **`alias` YOK** |
|
|
548
|
+
|
|
549
|
+
`fields[]` yalnız `create` / `update` / `upsert` operasyonlarında bulunur ve WHERE değil SET
|
|
550
|
+
üretir: hangi tabloya yazılacağı zaten `entityId` ile bellidir, takma ada ihtiyaç yoktur. Aynı
|
|
551
|
+
`TableField` tipi workflow table adımlarının `rule.fields[]` listesinde de kullanılır.
|
|
552
|
+
|
|
553
|
+
Yazma alanına `alias` koyarsan istek **hata vermez**, alan model bağlamada düşer. Gateway bunu
|
|
554
|
+
istek gitmeden gövdeden çıkarır ve `gatewayNormalized` ile bildirir — böylece `silentlyDropped`
|
|
555
|
+
listesi yalnız gerçek kayıpları gösterir.
|
|
556
|
+
|
|
557
|
+
## Zamanlanmış iş (`type: 'schedule-job'`) — `typeParameters.schedule`
|
|
558
|
+
|
|
559
|
+
Zamanlama tek bir tanımdır; `cronExpression` tek başına verilirse **UTC cron** sayılır (eski gövde).
|
|
560
|
+
Yeni işte tanımı `typeParameters.schedule` ile yazın ve kaydetmeden önce
|
|
561
|
+
`microservice_schedule_forecast` ile sıradaki koşuları görün.
|
|
562
|
+
|
|
563
|
+
| Alan | Değer |
|
|
564
|
+
|---|---|
|
|
565
|
+
| `mode` | `once` · `interval` · `cron` |
|
|
566
|
+
| `timeZoneId` | IANA (`Europe/Istanbul`); yoksa `UTC`. Saatler BU dilimde yorumlanır |
|
|
567
|
+
| `startAt` | yerel tarih-saat, dilimsiz (`2026-09-14T09:00:00`); once/interval için, cron'da `end.type:'after'` ile zorunlu |
|
|
568
|
+
| `every` · `unit` | 1–1000 · `minute` `hour` `day` `week` `month` |
|
|
569
|
+
| `timeOfDay` | `HH:mm` — `day`/`week`/`month` için zorunlu |
|
|
570
|
+
| `daysOfWeek` | `monday`…`sunday` — `week` için en az bir |
|
|
571
|
+
| `daysOfMonth` | 1–31, `-1` = ayın son günü — `month` için en az bir |
|
|
572
|
+
| `cronExpression` | Quartz cron (6–7 alan, `?` zorunlu) — yalnız `cron` modu |
|
|
573
|
+
| `end` | `{type:'never'}` · `{type:'on', at}` · `{type:'after', count}` (1–10000) |
|
|
574
|
+
|
|
575
|
+
```json
|
|
576
|
+
{ "mode": "interval", "timeZoneId": "Europe/Istanbul", "startAt": "2026-09-14T00:00:00",
|
|
577
|
+
"every": 2, "unit": "week", "daysOfWeek": ["tuesday", "thursday"], "timeOfDay": "09:00",
|
|
578
|
+
"end": { "type": "after", "count": 30 } }
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
- Aralık başlangıçtan sayılır: "7 dakikada bir" saat başında sıfırlanmaz, "3 günde bir" ay sonunda
|
|
582
|
+
başa sarmaz, "2 haftada bir" gerçekten iki haftada birdir. Cron'da bunlar DOĞRU İFADE EDİLEMEZ
|
|
583
|
+
(`MON/2` = haftada 3 gün) — bu ihtiyaçlar için `interval` kullanın.
|
|
584
|
+
- `after N` başlangıçtan hesaplanan N'inci koşuda biter; `microservice_schedule_control trigger`
|
|
585
|
+
sayılmaz. Biten iş `microservice_schedule_get`'te `state: 'ended'` görünür.
|
|
586
|
+
- Geçersiz tanım `422` + alan adıyla lokalize mesaj döner (bozuk cron artık `500` değil). `after` ile
|
|
587
|
+
toplam süre sınırlıdır (gün × sayı ≤ 36500, hafta ≤ 5200, ay ≤ 1200).
|
|
588
|
+
- **`schedule` ile `cronExpression` çelişemez.** `microservice_get` ikisini de döndürür; güncellemede
|
|
589
|
+
yalnız `typeParameters.schedule`'ı değiştirin (cron modunda `schedule.cronExpression`). Yalnız
|
|
590
|
+
`cronExpression`'ı değiştiren PUT/PATCH `422 ScheduleCronConflict` alır — sessizce eski cron
|
|
591
|
+
kalmaz. `typeParameters: null` işi zamanlayıcıdan siler.
|
|
592
|
+
|
|
331
593
|
## Sık hatalar
|
|
332
594
|
|
|
333
595
|
- `description` boş (MS-014, block — uç listesinde ne işe yaradığı okunamaz)
|
|
@@ -336,13 +598,23 @@ kabul etti. Ayrıntı ve doğru rol kapısı tarifi: `platform_guide('middleware
|
|
|
336
598
|
- `operation: 'list'` → geçersiz; `get` + `isSingle: false` kullanın (PLT-006)
|
|
337
599
|
- Üst seviye `entityId` eksik (MS-004, warn)
|
|
338
600
|
- Gerekçesiz `source: 'query'` (MS-002, warn)
|
|
601
|
+
- Backend zorunlulukları (MS-017, block — istek gitmeden): `name` ve `url` boş olamaz (update'te
|
|
602
|
+
`slug` da); `queryId`/`entityId`/`workflowId` verilirse boş GUID olamaz; `source: 'expression'`
|
|
603
|
+
alan ve filtrede `value` dolu; tekil filtrede `fieldId`; `writeOn` yalnız `operation: 'upsert'`
|
|
604
|
+
ucunda; join'de `entityId` + `fieldId`. Tam katalog: `ngapps://rules/backend-constraints`.
|
|
605
|
+
- Query kaydı (QRY-001, block): `rawQuery`'deki her `@ad` / `{{ad}}` `parameters[]`'ta
|
|
606
|
+
`{ name, type }` ile bildirilir — yalnız create denetler, update sessiz geçer ve sorgu çalışma
|
|
607
|
+
anında düşer; `slug`/`rawQuery`/`datasourceId` zorunlu; `outputType` `array` | `object`.
|
|
339
608
|
- Execute'ta dönen `httpStatus` microservice'in kendi sonucudur — 4xx/5xx görünce önce
|
|
340
609
|
`microservice_debug` ile hangi adımın ürettiğine bak, tanımı ona göre düzelt.
|
|
341
|
-
- **`microservice_update` / `microservice_patch
|
|
342
|
-
HER ZAMAN 500
|
|
343
|
-
|
|
344
|
-
`
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
`
|
|
348
|
-
|
|
610
|
+
- **`microservice_update` / `microservice_patch` tüm operasyon tiplerinde çalışır.** Eski
|
|
611
|
+
"`operation: 'get'` tipli kayıtta HER ZAMAN 500 (`Application cannot be tracked`)" kuralı P-02
|
|
612
|
+
regresyonuydu; 2026-08-16'da düzeltildi, 2026-09-01 İK koşusunda get ucunda
|
|
613
|
+
`microservice_patch` ile canlı doğrulandı (M-9). Get-tipi bir microservice'i değiştirmek için
|
|
614
|
+
artık delete+create gerekmez. `entity_patch`, `workflow_patch`, `row_update` sağlamdır.
|
|
615
|
+
- **`microservice_patch` tam gövde geri yazar: okunan kayıtta olmayan alan SİLİNİR.** 09-04
|
|
616
|
+
koşusunda gidiş-dönüşte `description` düştü ve MS-014 patch'i bloke etti (Y-16). Gateway artık
|
|
617
|
+
açıklamasız bir patch gövdesini hiç göndermez; hata mesajı düzeltmeyi verir
|
|
618
|
+
(`{ "op": "add", "path": "/description", "value": "…" }`). Patch yanıtındaki `silentlyDropped`
|
|
619
|
+
alanı, gönderilen ama kaydedilmeyen alanları listeler — boş değilse platform bir alanı yutmuş
|
|
620
|
+
demektir.
|
|
@@ -7,6 +7,12 @@ kestirmeden reddetmek (auth guard), (2) isteğin devamında kullanılacak **değ
|
|
|
7
7
|
istenen her uca/sayfaya bağlanır. Buradaki kurallar backend kodundan ve qm projesinin canlı
|
|
8
8
|
kayıtlarından doğrulandı.
|
|
9
9
|
|
|
10
|
+
> **Middleware `microservice_debug` ağacında görünmez.** `executionItems` yalnız ucun kendi
|
|
11
|
+
> adımlarını izler; middleware ucun ÖNÜNDE ayrı bir workflow olarak koşar. Gateway bu boşluğu
|
|
12
|
+
> yanıta `middlewares` alanı ekleyerek kapatır (uca bağlı middleware workflow'ları, adım
|
|
13
|
+
> özetiyle) — kapı 200 dönerken bile açık kalmış olabilir, adımları oradan oku (ölçüm: 09-04
|
|
14
|
+
> koşusu Y-04, Y-03).
|
|
15
|
+
|
|
10
16
|
**Önce "gerekli mi?" sorusu.** Middleware kurulum listesinin zorunlu maddesi değildir: oturum
|
|
11
17
|
kavramı olmayan bir üründe auth middleware'i, ayar tablosu olmayan bir üründe setter gereksizdir
|
|
12
18
|
(karar tablosu: `platform_guide('getting-started')`). Buna karşılık **kimlik kurduysan eksiksiz
|
|
@@ -249,11 +255,35 @@ qm kanıtı: `sy-users-get-my-profile` (`id eq user.id`), `qm-document-revision-
|
|
|
249
255
|
değil, middleware değişkenidir. (Sayfalardaki sabit `patient_id` benzeri geçici çözümlerin
|
|
250
256
|
kalıcı hâli de bu.)
|
|
251
257
|
|
|
258
|
+
## Tarif 3c — Agregasyon (query kaynaklı) ucun kapsaması: sorguyu WORKFLOW'dan çağır
|
|
259
|
+
|
|
260
|
+
Tarif 3 **table kaynaklı** uçlar içindir; expression filtresi orada vardır. Bir KPI/rapor ucu
|
|
261
|
+
ham SQL istediği için query kaynaklıdır ve o yolda expression yoktur: kayıtlı sorgunun
|
|
262
|
+
parametreleri **yalnız çağrıdan** (body → query-string → header) bağlanır, `user` oraya hiç
|
|
263
|
+
girmez. Kapsamı gövdeye koyarsan çağıran başkasının kapsamını yazabilir — 2026-09-07'de ölçüldü:
|
|
264
|
+
middleware `OWNER-A` kimliğini kurmuşken gövdeye `OWNER-B` yazan çağrı `OWNER-B`'nin verisini
|
|
265
|
+
döndürdü.
|
|
266
|
+
|
|
267
|
+
Kapsam bir katman yukarıda kurulur:
|
|
268
|
+
|
|
269
|
+
1. Sorguyu kapsam parametresiyle kaydet (`… WHERE company_id = @company_id`).
|
|
270
|
+
2. Bir `type: 'workflow'` akışı aç: start → **query adımı** → response. Adımın bağlaması
|
|
271
|
+
`rule.expression`'da: `{ company_id: user.company_id, from: input.from }` — kapsam
|
|
272
|
+
middleware'den, kalan filtreler gövdeden.
|
|
273
|
+
3. Ucu `source: 'workflow'` + `middlewareIds` dolu olarak kur.
|
|
274
|
+
|
|
275
|
+
Ölçüm: gövdeye kasten yanlış `company_id` yazıldığında yanıt değişmedi; `middlewareIds` boş
|
|
276
|
+
bırakıldığında akış `500 JavaScriptException: user is not defined` verdi. Reçetenin tamamı
|
|
277
|
+
`platform_guide('microservice')` §"Kimlik kapsaması × uç kaynağı", bağlamanın yazım tuzağı
|
|
278
|
+
`platform_guide('workflow')` §"Query adımı".
|
|
279
|
+
|
|
252
280
|
## Tuzaklar
|
|
253
281
|
|
|
254
282
|
- Expression'daki değişken adı, bağlı middleware'lerden birinin kurduğu adla **birebir**
|
|
255
283
|
eşleşmeli — eşleşmezse runtime'da `user is not defined` 500'ü. Gateway MS-011 uyarır:
|
|
256
|
-
`user.` okuyan expression varken `middlewareIds` boşsa warn alırsın.
|
|
284
|
+
`user.` okuyan expression varken `middlewareIds` boşsa warn alırsın. **Aynı 500'ü workflow
|
|
285
|
+
kaynaklı uçta gateway GÖREMEZ** (uçtan görünen tek şey `workflowId`'dir): `user.*` okuyan bir
|
|
286
|
+
akışı bağladığın uçta `middlewareIds`'i doldurmayı sen garanti edeceksin.
|
|
257
287
|
- `set-user` adı sabittir; ikinci kullanıcı değişkeni gerekiyorsa `variable` step'i kullan.
|
|
258
288
|
- Middleware'i `workflow_preview` ile test etmek sınırlıdır (HTTP bağlamı preview'da yoktur);
|
|
259
289
|
gerçek doğrulama, middleware'i bağladığın ucu `microservice_execute` ile çağırmaktır —
|
|
@@ -265,6 +295,17 @@ kalıcı hâli de bu.)
|
|
|
265
295
|
token'ını KOYMAZ, istek tamamen verdiğin kimlikle gider. Tarayıcı yolunu test etmek için
|
|
266
296
|
token'ı cookie header'ıyla da geçebilirsin (`headers: { Cookie: '<ad>=<token>' }`).
|
|
267
297
|
|
|
298
|
+
## Ön koşul: uygulamanın kullanıcısı olmalı
|
|
299
|
+
|
|
300
|
+
Middleware bağlamadan önce `users` tablosunda satır olduğundan emin ol — `row_list('users')` tek
|
|
301
|
+
çağrı. Yeni projede o tablo **boş** gelir ve Studio operatörü uygulamanın kullanıcısı değildir;
|
|
302
|
+
kapı bağlanınca her istek 401 döner ve bu ancak sayfa boş açılınca fark edilir (09-02 ve 09-04
|
|
303
|
+
koşularında ikisinde de yaşandı).
|
|
304
|
+
|
|
305
|
+
İlk kullanıcıyı açmanın desteklenen tek yolu bootstrap desenidir:
|
|
306
|
+
`platform_guide('getting-started')` §"İlk kullanıcıyı kim açar?". Kısa yol arama — bakım uçları
|
|
307
|
+
(`Sync*`) ürün yüzeyinin parçası değildir ve gateway onları araç olarak yayınlamaz.
|
|
308
|
+
|
|
268
309
|
## Korumalı bir ucu TEST ederken: token ÇEREZDEN okunur
|
|
269
310
|
|
|
270
311
|
`microservice_execute` ile middleware'li bir ucu denerken `Authorization: Bearer <token>` vermek
|
|
@@ -279,3 +320,50 @@ headers: { "Cookie": "ANKET_Token=<token>" } → 200
|
|
|
279
320
|
Token'ı önce giriş ucundan al (`microservice_execute` ile `giris`), sonra `Cookie` başlığıyla
|
|
280
321
|
korumalı ucu çağır. Çerez adı middleware'in `cookie.<ad>` ifadesindedir; `workflow_get` ile oku,
|
|
281
322
|
tahmin etme. **401 alman middleware'in çalıştığının kanıtıdır** — uç bozuk değildir.
|
|
323
|
+
|
|
324
|
+
## Korumalı SAYFAYI görsel doğrulama — jeton bağlama hiç girmeden
|
|
325
|
+
|
|
326
|
+
Giriş ucunun yanıtındaki jeton gateway tarafından maskelenir (`access_token: "***"`), yani jetonu
|
|
327
|
+
okuyup elle taşıyamazsın — ve taşımaya çalışmak uygulamanın yanıt sözleşmesini geçici olarak
|
|
328
|
+
bozmak demektir (ölçüm 2026-09-04, benchmark 4. koşu). Doğru yol dört adımdır:
|
|
329
|
+
|
|
330
|
+
1. `microservice_execute` ile giriş ucunu çağır. Yanıtta jeton `***`, ama `tokenRefs` alanında
|
|
331
|
+
maskelenen her JWT için kısa ömürlü bir referans döner: `{ "body.access_token": "tok_…" }`.
|
|
332
|
+
2. `page_screenshot` (ya da `page_runtime_get`) çağrısına `asUser: "tok_…"` ver. Gateway referansı
|
|
333
|
+
kendi içinde çözer; jeton ne yanıta ne günlüğe girer. Referans 15 dakika geçerlidir, süresi
|
|
334
|
+
dolarsa çağrı **hata verir** — sessizce kimliksiz isteğe düşmez.
|
|
335
|
+
3. Uygulamanın kendi oturum çerezi ayrı bir addaysa (`cookie.CORE_Token` gibi) onu
|
|
336
|
+
`cookies: { "CORE_Token": "…" }` ile ekle; `asUser` her zaman `NG_AccessToken` adıyla taşınır.
|
|
337
|
+
4. Kapının gerçekten kapalı olduğunu `page_runtime_get(anonymous: true)` ile kanıtla: beklenen
|
|
338
|
+
sonuç `middlewareBlocked: true` + 401'dir.
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
## Korumalı ucu teşhis etmek: `asUser`
|
|
342
|
+
|
|
343
|
+
Bir uca `middlewareIds` bağladığın anda `microservice_execute`, `microservice_preview` ve
|
|
344
|
+
`microservice_debug` gateway'in **servis jetonuyla** gider ve o jeton uygulamanın kendi
|
|
345
|
+
`users` tablosuna çözülmez — üçü de 401 döner. Ölçüldü 2026-09-05: agregasyonlar korumaya
|
|
346
|
+
alındıktan sonra kuru koşu ve adım adım teşhis araçlarının ikisi de kullanılamaz hâle geldi.
|
|
347
|
+
|
|
348
|
+
Üçü de artık `asUser` (ve gerekiyorsa `cookies`) alır ve jetonu **hem** `Authorization` başlığında
|
|
349
|
+
**hem** `NG_AccessToken` çerezinde taşır — middleware jetonu çerezden okuduğu için tek kanal
|
|
350
|
+
yetmiyordu:
|
|
351
|
+
|
|
352
|
+
```jsonc
|
|
353
|
+
// 1) uygulamanın kendi giriş ucunu anonim çağır, jeton referansını al
|
|
354
|
+
{ "tool": "microservice_execute", "application": "<app>", "microservice": "sign-in",
|
|
355
|
+
"anonymous": true, "body": { "email": "…", "password": "…" } }
|
|
356
|
+
// → tokenRefs: { "body.access_token": "tok_…" } (jeton hiç görünmez, 15 dk geçerli)
|
|
357
|
+
|
|
358
|
+
// 2) korumalı ucu O KİMLİKLE çalıştır
|
|
359
|
+
{ "tool": "microservice_debug", "application": "<app>", "microservice": "funnel",
|
|
360
|
+
"asUser": "tok_…", "body": { … } }
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Uygulaman jetonu kendi çerez adından okuyorsa (`CORE_Token` gibi) `cookies: { CORE_Token: "<jwt>" }`
|
|
364
|
+
ver. `anonymous: true` ile `asUser` birlikte verilemez — biri kimliksiz isteği, diğeri belirli bir
|
|
365
|
+
üyenin kimliğiyle atılan isteği ister.
|
|
366
|
+
|
|
367
|
+
`microservice_debug` yanıtındaki `middlewareNote` artık gerçeği söyler: middleware koştu ve
|
|
368
|
+
geçirdi mi, yoksa isteği kesti mi. Not eskiden ucun LİSTE kaydına bakıyordu ve liste DTO'su
|
|
369
|
+
`middlewareIds` taşımadığı için bağlı bir uçta bile "bağlı değil" diyordu.
|
|
@@ -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
|
|