@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.
Files changed (145) hide show
  1. package/.env.example +2 -2
  2. package/.env.production.example +9 -1
  3. package/README.md +14 -38
  4. package/dist/config.js +36 -3
  5. package/dist/knowledge/backendConstraints.js +982 -0
  6. package/dist/knowledge/componentCatalog.js +549 -92
  7. package/dist/knowledge/componentEvents.js +120 -25
  8. package/dist/knowledge/coverage.js +43 -0
  9. package/dist/knowledge/flowGuards.js +30 -0
  10. package/dist/knowledge/functionGuards.js +134 -0
  11. package/dist/knowledge/guideSections.js +49 -0
  12. package/dist/knowledge/hydrate.js +97 -0
  13. package/dist/knowledge/languageCodes.js +36 -0
  14. package/dist/knowledge/languages.js +105 -0
  15. package/dist/knowledge/layoutSummary.js +10 -0
  16. package/dist/knowledge/localization.js +51 -0
  17. package/dist/knowledge/normalize.js +500 -16
  18. package/dist/knowledge/outlines.js +167 -12
  19. package/dist/knowledge/policy.js +14 -5
  20. package/dist/knowledge/propTypes.js +80 -0
  21. package/dist/knowledge/rules.js +961 -44
  22. package/dist/knowledge/schemaGuard.js +199 -0
  23. package/dist/knowledge/styleResolve.js +63 -4
  24. package/dist/observability/trace.js +27 -3
  25. package/dist/platform/csv.js +123 -0
  26. package/dist/platform/errors.js +107 -6
  27. package/dist/platform/http.js +34 -4
  28. package/dist/platform/patch.js +27 -0
  29. package/dist/platform/refs.js +104 -0
  30. package/dist/platform/responses.js +25 -6
  31. package/dist/platform/screenshot.js +544 -16
  32. package/dist/platform/secrets.js +40 -0
  33. package/dist/platform/tokenVault.js +89 -0
  34. package/dist/platform/writeDiff.js +281 -0
  35. package/dist/resources/examples/flow-call-function.json +66 -0
  36. package/dist/resources/examples/function-total.json +70 -0
  37. package/dist/resources/examples/layout-app-shell.json +1 -1
  38. package/dist/resources/examples/microfunction-node-sum.json +56 -0
  39. package/dist/resources/examples/microservice-table-list.json +2 -4
  40. package/dist/resources/examples/page-dynamic-form.json +3 -3
  41. package/dist/resources/examples/page-flex-sections.json +99 -0
  42. package/dist/resources/examples/page-sign-in.json +4 -3
  43. package/dist/resources/guides/component.md +81 -8
  44. package/dist/resources/guides/entity.md +712 -20
  45. package/dist/resources/guides/expressions.md +47 -2
  46. package/dist/resources/guides/external-component.md +9 -0
  47. package/dist/resources/guides/functions.md +262 -0
  48. package/dist/resources/guides/getting-started.md +82 -7
  49. package/dist/resources/guides/layout.md +53 -10
  50. package/dist/resources/guides/merge.md +231 -0
  51. package/dist/resources/guides/microfunction.md +166 -0
  52. package/dist/resources/guides/microservice.md +287 -15
  53. package/dist/resources/guides/middleware.md +89 -1
  54. package/dist/resources/guides/modify-existing.md +23 -0
  55. package/dist/resources/guides/page.md +402 -49
  56. package/dist/resources/guides/translation.md +150 -8
  57. package/dist/resources/guides/view.md +16 -1
  58. package/dist/resources/guides/workflow.md +199 -28
  59. package/dist/resources/knowledge.js +5 -0
  60. package/dist/resources/rules.js +27 -0
  61. package/dist/resources/schema-fingerprint.json +8 -0
  62. package/dist/resources/schemas/AnalyzeImportQuery.json +51 -0
  63. package/dist/resources/schemas/ApplyMergePlanCommand.json +19 -0
  64. package/dist/resources/schemas/CreateBulkRowCommand.json +36 -0
  65. package/dist/resources/schemas/CreateDatasourceCommand.json +15 -6
  66. package/dist/resources/schemas/CreateDiscoveredEntitiesCommand.json +19 -8
  67. package/dist/resources/schemas/CreateEntityCommand.json +52 -12
  68. package/dist/resources/schemas/CreateEnvironmentCommand.json +31 -0
  69. package/dist/resources/schemas/CreateGlobalFunctionCommand.json +95 -0
  70. package/dist/resources/schemas/CreateImportPlanCommand.json +278 -0
  71. package/dist/resources/schemas/CreateMergePlanCommand.json +34 -0
  72. package/dist/resources/schemas/CreateMicrofunctionCommand.json +117 -0
  73. package/dist/resources/schemas/CreateMicrofunctionRuntimeCommand.json +51 -0
  74. package/dist/resources/schemas/CreateMicroserviceCommand.json +145 -3
  75. package/dist/resources/schemas/CreateQueryCommand.json +56 -3
  76. package/dist/resources/schemas/CreateRowCommand.json +38 -0
  77. package/dist/resources/schemas/CreateViewCommand.json +13 -10
  78. package/dist/resources/schemas/CreateWorkflowCommand.json +106 -14
  79. package/dist/resources/schemas/DataJobDto.json +267 -0
  80. package/dist/resources/schemas/ExportRowsCommand.json +172 -0
  81. package/dist/resources/schemas/Filter.json +3 -1
  82. package/dist/resources/schemas/GetRowsQuery.json +6 -1
  83. package/dist/resources/schemas/GlobalFunctionDto.json +89 -0
  84. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +249 -0
  85. package/dist/resources/schemas/ImportAnalysisDto.json +401 -0
  86. package/dist/resources/schemas/ImportPlanDto.json +260 -0
  87. package/dist/resources/schemas/ImportSampleDto.json +90 -0
  88. package/dist/resources/schemas/InvokeMicrofunctionCommand.json +25 -0
  89. package/dist/resources/schemas/PreviewMicroserviceCommand.json +135 -1
  90. package/dist/resources/schemas/PreviewQueryCommand.json +5 -2
  91. package/dist/resources/schemas/PreviewWorkflowCommand.json +45 -9
  92. package/dist/resources/schemas/ResolveMergeConflictsCommand.json +58 -0
  93. package/dist/resources/schemas/RevertMergePlanCommand.json +19 -0
  94. package/dist/resources/schemas/RunImportCommand.json +62 -0
  95. package/dist/resources/schemas/StepDto.json +34 -3
  96. package/dist/resources/schemas/UpdateBulkRowCommand.json +36 -0
  97. package/dist/resources/schemas/UpdateDatasourceCommand.json +15 -6
  98. package/dist/resources/schemas/UpdateEntityCommand.json +52 -11
  99. package/dist/resources/schemas/UpdateGlobalFunctionCommand.json +66 -0
  100. package/dist/resources/schemas/UpdateMicrofunctionCommand.json +121 -0
  101. package/dist/resources/schemas/UpdateMicrofunctionRuntimeCommand.json +54 -0
  102. package/dist/resources/schemas/UpdateMicroserviceCommand.json +147 -4
  103. package/dist/resources/schemas/UpdateQueryCommand.json +13 -3
  104. package/dist/resources/schemas/UpdateRowCommand.json +40 -0
  105. package/dist/resources/schemas/UpdateViewCommand.json +15 -10
  106. package/dist/resources/schemas/UpdateWorkflowCommand.json +106 -14
  107. package/dist/server.js +17 -1
  108. package/dist/tools/access.js +3 -3
  109. package/dist/tools/activities.js +40 -0
  110. package/dist/tools/applications.js +1 -1
  111. package/dist/tools/automations.js +76 -34
  112. package/dist/tools/common.js +55 -0
  113. package/dist/tools/components.js +16 -7
  114. package/dist/tools/datasources.js +83 -21
  115. package/dist/tools/dependencies.js +1 -1
  116. package/dist/tools/deployments.js +34 -2
  117. package/dist/tools/dtos.js +25 -12
  118. package/dist/tools/entities.js +113 -28
  119. package/dist/tools/environments.js +52 -0
  120. package/dist/tools/externalComponents.js +9 -3
  121. package/dist/tools/files.js +57 -42
  122. package/dist/tools/flows.js +205 -13
  123. package/dist/tools/folders.js +7 -2
  124. package/dist/tools/functions.js +331 -0
  125. package/dist/tools/globalFunctions.js +63 -0
  126. package/dist/tools/importSchemas.js +79 -0
  127. package/dist/tools/imports.js +241 -0
  128. package/dist/tools/layouts.js +103 -29
  129. package/dist/tools/merges.js +113 -0
  130. package/dist/tools/microfunctions.js +155 -0
  131. package/dist/tools/microservices.js +270 -40
  132. package/dist/tools/organizations.js +5 -6
  133. package/dist/tools/pages.js +421 -104
  134. package/dist/tools/platformInfo.js +155 -11
  135. package/dist/tools/projects.js +183 -33
  136. package/dist/tools/queries.js +32 -10
  137. package/dist/tools/revisions.js +94 -0
  138. package/dist/tools/rows.js +484 -50
  139. package/dist/tools/screenWrite.js +68 -0
  140. package/dist/tools/screens.js +28 -0
  141. package/dist/tools/templates.js +32 -5
  142. package/dist/tools/translations.js +24 -8
  143. package/dist/tools/views.js +20 -10
  144. package/dist/tools/workflows.js +56 -21
  145. package/package.json +7 -2
@@ -78,9 +78,30 @@ mümkündür ama doğrulama duvarı ve canlı canvas yalnız `page_schema_patch`
78
78
  her turda çözümlenmiş metinle EZER — anahtar yalnız `ref`'te yaşar, `data`'ya yazıp
79
79
  güvenme (`code` prop'uyla aynı davranış). Tam şekil, fallback zinciri ve `translation_*`
80
80
  tool'ları için `platform_guide('translation')`.
81
+ - **Kurulmuş bir düğümün prop TİPİNİ `set_prop_type` micro-op'u değiştirir.**
82
+ `{ op: 'set_prop_type', target: '<elementId>', prop: 'content', propType: 'translation', ref: 'dashboard.kpi.total' }`
83
+ bir `static` prop'u çeviriye, `propType: 'code'` + `ref: '<ifade>'` koda, `propType: 'static'` +
84
+ `data: <değer>` sabite bağlar. Bu bir **gateway emülasyonudur**: `replace_prop` gönderilen ham
85
+ değeri her zaman `static` Prop'una sarar ve sarmalanmış Prop nesnesini reddeder, yani prop tipini
86
+ yazamaz. Op olmadan tek yol düğümü `remove_component` + `add_component` ile yeniden kurmaktı;
87
+ 2026-09-06 koşusunda on bir etiket bu yolla kuruldu ve onlara yazan **dokuz setter iteratee'si**
88
+ platform tarafından sessizce silindi (üç KPI kartı boş kaldı). Taşıyıcı alan tipe göre değişir —
89
+ `static` değeri `data`'da, `code` ve `translation` `ref`'te taşır; eksik taşıyıcı istek
90
+ gönderilmeden reddedilir ve `page_schema_validate` aynı kararı verir.
91
+
81
92
  - **`blocks[].size`, komponentin `component_get`'teki `maxSize`'ını aşamaz.** Dikkat: katalog
82
93
  varsayılanı aşabiliyor (`page-header` default `h:8`, `maxSize` `h:4`) — varsayılanı körü körüne
83
94
  kopyalama, doğrulayıcı `"Height of 'page-header' must be between 1 and 4."` ile reddeder.
95
+ - **Kurulmuş bir düğümün boyutunu `resize_component` micro-op'u değiştirir.**
96
+ `{ op: 'resize_component', target: '<elementId>', size: { w, h } }` ızgara boyutunu,
97
+ `{ …, appearance: { heightType: 'fixed', heightString: '340px' } }` flex ölçüsünü yazar; ikisi
98
+ aynı op'ta verilebilir, `breakpoint` varsayılanı 1024'tür. Bu bir **gateway emülasyonudur**:
99
+ platformun micro-op sözlüğünde boyut yoktur ve `move_component` gövdesine konan `size` 200 dönüp
100
+ SESSİZCE düşer (bu yüzden gateway artık onu reddeder ve buraya yönlendirir). Op şemayı okuyup
101
+ sayfayı tam gövdeyle geri yazar. Ebeveynin düzeni yazdığın alanı etkisiz kılıyorsa (flex kabın
102
+ içine `size`, ızgaranın içine `appearance`) yanıt `PAGE-019` uyarısı taşır — istek yine geçer.
103
+ **Düğümü silip yeniden kurmayın:** o yol ona yazan akış setter'larını sessizce öldürür
104
+ (`FLOW-018`, aşağıda Kural 2).
84
105
  - **Aynı ızgara hücrelerini iki komponente veremezsin.** Studio'da komponent tuvale bırakıldığında
85
106
  çakışan kardeşleri aşağı itme işini studio-api'nin sayfa kurma servisi yapar
86
107
  (`SchemaHelper.reorderComponents` → `draggableElement.moveItem`); komple şema yazan `page_create`
@@ -189,14 +210,15 @@ Adım gövdesi `StepManagementSchema`: `{ stepId, name, type, kind, args, branch
189
210
  **`branches[].nextStepId` bir GUID değil, hedef adımın `stepId` STRING'idir**
190
211
  (`allSteps.TryGetValue(b.NextStepId)`).
191
212
 
192
- Bu adımda platformun sessizce yuttuğu beş tuzak var — hepsi isteği 200 döndürür, akış yine de
213
+ Bu adımda platformun sessizce yuttuğu altı tuzak var — hepsi isteği 200 döndürür, akış yine de
193
214
  ölü ya da yarım çalışır. Gateway hepsini yakalar (FLOW-004…012), ama şekli baştan doğru yazın:
194
215
 
195
216
  **1. Dal adı motorun anahtarıdır, etiket değil.** Runtime dal kimliğini `branch.name`'den üretir
196
217
  (`Runtime.svelte:329`) ve her adım `engine.next('always')` çağırır. Ad `always` değilse motor
197
218
  dalı bulamaz ve akışı **sessizce durdurur** (`flow-engine.ts:79`); Studio da zinciri
198
219
  `sourceBranch === 'always'` ile çizdiği için panelde **Start kartından sonrası boş görünür**.
199
- İstisnalar: `condition` → dal adı rule id'sidir, `confirm` → `yes|no|always`, `microservice` →
220
+ İstisnalar: `condition` → dal adı rule id'sidir (ve o id bir **GUID**'dir — aşağıdaki tuzak 6),
221
+ `confirm` → `yes|no|always`, `microservice` →
200
222
  `always` (eski akışlarda `success` de çalışır).
201
223
 
202
224
  **2. `iteratees[].type` yalnız `change` | `fill`.** `setter.ts` başka değerde hiçbir dala
@@ -226,6 +248,37 @@ key'ini düz anahtar ver, iç içe yolu `ref`'e yaz: `"parent_name": { "type": "
226
248
  anahtar her satırda taşınır. `type` sözlüğü: `item` (kaynak alanı), `code` (satır başına JS,
227
249
  satır `Row` değişkenindedir), diğerleri sabit.
228
250
 
251
+ **6. `condition` adımının gövdesi `args.rules`'tur — backend workflow'unun `rule.items` şekli
252
+ DEĞİL.** Sayfa akışını başka bir motor koşar (`ng-apps-flow/tasks/condition/condition.ts`) ve o
253
+ motor yalnız şu sözleşmeyi tanır. Workflow şekli yazılırsa istek 200 döner, adım kaydedilir,
254
+ Studio çizer ve **kural hiç değerlendirilmez** — akış dalsız kalır. Gateway `FLOW-020` ile
255
+ yakalar.
256
+
257
+ ```jsonc
258
+ { "stepId": "guard", "name": "Token var mı", "type": "condition", "kind": "normal",
259
+ "args": { "rules": [
260
+ { "id": "0198e2a1-4c31-7a10-9b44-1f0c5d2e6a01", "expression": "!!Steps.signIn.data.token", "type": "if" },
261
+ { "id": "0198e2a1-4c31-7a10-9b44-1f0c5d2e6a02", "expression": "", "type": "else" } ] },
262
+ "branches": [ { "id": "<GUID>", "name": "0198e2a1-4c31-7a10-9b44-1f0c5d2e6a01", "nextStepId": "go_home" },
263
+ { "id": "<GUID>", "name": "0198e2a1-4c31-7a10-9b44-1f0c5d2e6a02", "nextStepId": "show_error" },
264
+ { "id": "<GUID>", "name": "always", "nextStepId": "hide_spinner" } ] }
265
+ ```
266
+
267
+ > Dal adları okunabilir değil, **kuralın GUID'inin kendisi** — `branches[].name === rules[].id`.
268
+ > Okunabilir ad iki uçta birden tutmaz (aşağıdaki tabloda ilk satır).
269
+
270
+ | Kural | Neden | Kaynak |
271
+ |---|---|---|
272
+ | **`rules[].id` GERÇEK bir GUID olmalı** | Backend alanı `Guid`'e çevirir; `"ok"` gibi okunabilir bir ad isteği `The JSON value could not be converted to System.Guid. Path: $.flow.steps[N].args.rules[0].id` ile reddeder. Dal adı da aynı GUID olduğu için iki yerde birden okunabilir ad kullanamazsınız | `StepManagementSchema.cs` `StepManagementRule.Id` |
273
+ | **`id`'yi hiç vermemek dalı sessizce ÖLDÜRÜR** | Alan boşsa backend `Guid.CreateVersion7()` ile kendi GUID'ini üretir; yazdığınız `branches[].name` ona asla eşleşmez, istek 200 döner ve dal hiç koşmaz. Her kural için taze GUID üretip iki yere de aynısını yazın | `StepManagementSchema.cs:549` varsayılan değer |
274
+ | **İlk kural `type:'if'` olmak ZORUNDA** | Motor zinciri yalnız `rules[0].type === 'if'` iken başlatır; değilse adım hiçbir dala girmez ve akış sessizce biter | `condition.ts` son blok |
275
+ | **Dal adı kuralın `id`'sidir** | `engine.next(rule.id)` → `Runtime.svelte:330` `branch.name`'i `branch.id`'ye çevirir → `flow-engine.ts:93` dalı adıyla arar. Her `rules[].id` için aynı adlı bir `branches[]` girdisi olmalı | `condition.ts` |
276
+ | **`else` yalnız `expression` BOŞKEN fallback'tir** | Koşul `!rule.expression && rule.type === 'else'`; dolu `else` normal karşılaştırmaya döner ve hiçbir kural tutmazsa akış dalsız biter | `condition.ts` |
277
+ | **Zincir dizi SIRASIYLA yürür** | Tutmayan kural `rules[index + 1]`'e geçer — `else-if` sırası diziden gelir, `order` alanından değil | `condition.ts` `process()` |
278
+ | `type` kümesi `if` · `else-if` · `else` | `ConditionArgumentRuleType` | `condition.types.ts` |
279
+ | **`always` YALNIZ bir dal eşleştiğinde koşar** | Motor `always`'i eşleşen dalın `completed`'ından çağırır (boş ifadeli `else` dalında ayrıca `stopped`'ta da). `rules` boşsa, `rules[0].type !== 'if'` ise ya da hiçbir ifade tutmayıp fallback `else` yoksa `engine.next('always')` **hiç çağrılmaz** — ayrıntı ve tuzağı için aşağıdaki §"Condition adımı `always` dalını…" | `condition.ts:55-61` |
280
+ | `branches` nesne biçimini de kabul eder | Dizi yerine `{ "<dal adı>": "<nextStepId>" }` yazılabilir; motor ikisini de aynı `{ id, nextStepId }` şekline eşler. Dizi biçimini tercih edin — `branches[].id` alanını orada verebiliyorsunuz | `Runtime.svelte` `mapStepBranches` |
281
+
229
282
  ```jsonc
230
283
  // akışı başlatan adım — dal adı 'always' olmak zorunda
231
284
  { "stepId": "start", "name": "Start", "type": "start", "kind": "normal", "args": {},
@@ -259,6 +312,16 @@ satır `Row` değişkenindedir), diğerleri sabit.
259
312
  > göndermeden reddeder. `element` değerini `page_schema_get` çıktısındaki `elementId` ile doğrula,
260
313
  > uydurma.
261
314
 
315
+ > **DOLU ama var olmayan `element` FLOW-017'nin KAPSAMI DIŞINDADIR — onu FLOW-024 söyler.**
316
+ > FLOW-017 yalnız alanın boş olduğunu görür; henüz kurulmamış bir düğümün id'sini yazarsan alan
317
+ > dolu görünür, kural susar ve platform `element`i **null** kaydeder — sonuç aynıdır: adım koşar,
318
+ > hiçbir şey yazmaz (ölçüm: 2026-09-09 koşusu `S-14`, `search_hint` düğümü akıştan sonra
319
+ > kurulmuştu). Gateway `flow_create`/`flow_update`/`flow_patch` sırasında barındırıcının şemasını
320
+ > okuyup hedefi arar ve bulamazsa **FLOW-024 (uyarı)** düşürür; yazmayı durdurmaz, çünkü "önce
321
+ > akışı kur, sonra düğümü" meşru bir sıradır. Doğru sıra: düğümü `page_schema_patch add_component`
322
+ > ile kur, sonra akışı `flow_update` ile **aynı gövdeyle** yeniden kaydet — kaydedilen `element`
323
+ > null olduğu için `flow_patch`'in `[element=…]` seçicisi onu bulamaz.
324
+
262
325
  Satır eşlemeli tablo yüklemesinin tam şekli (yükleniyor bayrağı → uç → satırlar + toplam kayıt)
263
326
  `ngapps://examples/flow-load-table`'dadır; setter'ın kritik iki iteratee'si şöyle görünür:
264
327
 
@@ -279,7 +342,67 @@ Satır eşlemeli tablo yüklemesinin tam şekli (yükleniyor bayrağı → uç
279
342
 
280
343
  `errorSteps` verirsen (start dışında en az bir adım) hata anında `engine.onError` true döner ve
281
344
  **ana akışın kalan adımları hiç çalışmaz** — yükleniyor bayrağını kapatmak, hata mesajını
282
- göstermek error flow'un işidir (`alert` adımı: `args: { message, alertType: 'error' }`).
345
+ göstermek error flow'un işidir.
346
+
347
+ > **4xx de hatadır ve `always` dalı seni KURTARMAZ.** `microservice.ts` `.catch` bloğu
348
+ > reddedilen her istekte koşar — 401/403/404/422 dâhil. Sonrası iki yoldan biridir ve ikisi de
349
+ > "ekranda hiçbir şey olmadı" ile biter:
350
+ >
351
+ > 1. **Hata yolu VARSA** `engine.onError` true döner ve `.finally` `return` eder —
352
+ > `engine.next('always')` **hiç çağrılmaz**. Yani `always` ile `errorSteps` birbirini dışlar;
353
+ > ikisini birden kuramazsın, hata yolu ana akışın devamını devralır.
354
+ > 2. **Hata yolu YOKSA** `always` koşar, ama storage artık `{ error, data }`'dır ve
355
+ > `Steps.<ad>.data` başarı gövdesi değil **hata gövdesidir**. Sıradaki `condition`
356
+ > `!!Steps.signIn.data.token` gibi bir ifadeyi `undefined` üzerinden değerlendirir, sessizce
357
+ > diğer dala düşer ve `else` dalı bağlı değilse akış orada biter.
358
+ >
359
+ > **`errorSteps` yalnız `start` taşıyorsa hata yolu YOKTUR:** `hasErrorFlow`
360
+ > `errorTasks.some(t => t.type !== 'start')` arar. Start'ın ardına en az bir adım bağla —
361
+ > gateway `FLOW-021` ile uyarır.
362
+ >
363
+ > **Mobilde `errorSteps` diye bir şey YOK.** `ScreenRuntime.tsx` `mapFlowsToMachine` yalnız
364
+ > `tasks` üretir (web `Runtime.svelte` ayrıca `errorTasks` verir), yani mobil uygulamada
365
+ > `hasErrorFlow` her zaman false: hata yolu hiç koşmaz ve akış yukarıdaki 2. yoldan —
366
+ > `always` + hata gövdeli storage — devam eder. Mobil sayfada hata yolunu `condition
367
+ > Steps.<adımAdı>.error` ile kur.
368
+
369
+ > **Hata metni ÜÇ ayrı yerde durur ve ikisi kullanıcıya gösterilecek metin DEĞİLDİR.**
370
+ > `onError` hata akışını koşturmadan önce `machine.setStorage('error', errorInfo)` yapar
371
+ > (`flow-engine.ts`), yani hata akışının adımları `Steps.error`'ı okuyabilir:
372
+ >
373
+ > | İfade | Ne taşır | Kaynak |
374
+ > |---|---|---|
375
+ > | **`Steps.error.message`** | **Ucun kendi mesajı** — `err.response.data.message`; boşsa HTTP durum metnine düşer. **Kullanıcıya gösterilecek metin budur.** Yanında `Steps.error.code` · `Steps.error.step.name` (patlayan adım) · `Steps.error.step.data` (ucun gövdesi) gelir | `microservice.ts` `err.reason \|\| HttpStatusText[err.code]` → `flow-engine.ts` `onError` |
376
+ > | `Steps.<adımAdı>.error` | Yalnız HTTP **durum metni** — 401 için `'Unauthorized'`. Hata OLDUĞUNU anlamaya yarar, göstermeye değil | `microservice.ts` `.catch` `HttpStatusText[err.code]` |
377
+ > | `Steps.<adımAdı>.data` | Ucun **hata gövdesi** (`err.response.data`) — başarı gövdesi değil. `.message` alanı burada da vardır | `microservice.ts` `.catch` |
378
+ >
379
+ > **`alert` adımının `message`'ı DÜZ METİNDİR — ifade yazarsan ekranda o ifade görünür.**
380
+ > `alert.ts` `task.argument.message`'ı doğrudan `toast.error()`'a geçirir ve `args` hiçbir yerde
381
+ > değerlendirilmez (`Runtime.svelte` `argument: step.args`): `{ "type": "alert", "args": {
382
+ > "message": "Steps.error.message", "alertType": "error" } }` kullanıcıya harfi harfine
383
+ > `Steps.error.message` gösterir. Sabit bir uyarı yetiyorsa `alert` en ucuz adımdır; **ucun ne
384
+ > dediğini göstereceksen bir `setter` (ya da `code`) adımı zorunludur** — `value.type: 'code'`
385
+ > ifadeyi orada gerçekten çalıştırır:
386
+ >
387
+ > ```jsonc
388
+ > // errorSteps: start → bu setter. Metni bir notification/text komponentine yazar.
389
+ > { "stepId": "show_error", "name": "Hatayı göster", "type": "setter", "kind": "normal",
390
+ > "args": { "iteratees": [
391
+ > { "type": "change", "element": "error_note", "property": "content", "source": "component",
392
+ > "mapping": { "source": "", "mappings": {} },
393
+ > "value": { "type": "code", "ref": "Steps.error?.message ?? 'İşlem başarısız'" } }] },
394
+ > "branches": [{ "id": "<GUID>", "name": "always", "nextStepId": null }] }
395
+ > ```
396
+
397
+ > **Hangi yolu seçeceksin — `errorSteps` mi, ana akışta `condition` mı?** İkisi birden
398
+ > kurulamaz (yukarıdaki 1. madde), yani bu bir tercih değil bir karar:
399
+ >
400
+ > | | `errorSteps` | ana akışta `condition Steps.<adımAdı>.error` |
401
+ > |---|---|---|
402
+ > | Ana akışın kalanı | **koşmaz** — hata akışı devralır | koşar, dalı sen seçersin |
403
+ > | Yükleniyor bayrağı · modal kapatma · tablo tazeleme | hata akışında **yeniden kurmak zorundasın**; kurmazsan bayrak açık kalır | zaten ana akışta duruyor |
404
+ > | Hata metni | `Steps.error.message` (yukarıdaki tablo) | `Steps.<adımAdı>.data.message`, hata olduğunu `Steps.<adımAdı>.error` söyler |
405
+ > | Ne zaman doğru | hata anında akış **tamamen başka bir yola** sapacaksa (başarısız giriş, yetkisiz sayfa) | kalan adımların çoğu hata hâlinde de koşacaksa — **form gönderimlerinin varsayılanı budur** (Kural 7) |
283
406
 
284
407
  Zorunlu filtresi olan uçlarda (`patient-*`, `doctor-appointments` gibi `isRequired: true`
285
408
  filtreli microservice'ler) parametreyi adımda ver, yoksa uç `MissingParameterException` atar:
@@ -319,15 +442,93 @@ Tarif: `platform_guide('middleware')`.
319
442
  - Adım hedef akışı **bekler** (`await engine.run`), sonra `always` dalından devam eder.
320
443
  - Gateway boş/yarım `args`'ı **FLOW-014** ile yakalar.
321
444
 
445
+ > **`code` adımının gövdesi `args.value` alanındadır — düz JS metni olarak.** Runtime onu
446
+ > `(async () => { <value> })()` içinde koşturur (`code.ts:18`), yani `await` serbesttir ve dönüş
447
+ > değeri akışa taşınmaz; etkiyi `Page`/`state`/komponent yazarak üretirsin. **Alan boşsa adım
448
+ > hata vermeden NO-OP olur** ve akış hiçbir şey yapmadan devam eder.
449
+ >
450
+ > ```jsonc
451
+ > { "stepId": "sync_filters", "name": "sync_filters", "type": "code", "kind": "normal",
452
+ > "args": { "value": "state.page.month = flt_month.value" },
453
+ > "branches": [{ "id": "<GUID>", "name": "always", "nextStepId": "reload" }] }
454
+ > ```
455
+ >
456
+ > `args.expression` / `args.script` gibi uydurma anahtarlar `StepManagementArgument` sözleşmesinde
457
+ > YOKTUR ve platform onları **sessizce düşürür**: 2026-09-05 koşusunda akış koştu, filtre hiçbir
458
+ > şey yapmadı ve teşhis ~10 dakika sürdü. Gateway artık ikisini birden yakalar — **FLOW-019**
459
+ > gövdesiz `code` adımını istek gitmeden reddeder, akış yazmasından sonra da gövdeyi geri okuyup
460
+ > farkı `silentlyDropped` ile bildirir.
461
+ >
462
+ > **Çoğu zaman `code` adımına hiç gerek yok:** filtre değerini sayfa değişkenine yazmak yerine
463
+ > değeri doğrudan komponent prop'undan okuyun (`value: { type: 'property', ref: { source:
464
+ > 'component', element: 'flt_month', property: 'value' } }`, ya da bir `code` ifadesinde
465
+ > `flt_month.value`) ve olayı doğrudan yükleme akışına bağlayın — ara adım kırılgan bir katman ekler.
466
+
467
+ > **Tek bir ifadeyi düzeltmek için tüm gövdeyi yeniden göndermeyin: `flow_patch` var.** Dizi
468
+ > öğelerinde indeks yerine seçici kullanın —
469
+ > `/steps[stepId=paint]/args/iteratees[element=tbl_funnel]/mapping/mappings/share/ref`. Adım ve
470
+ > iteratee sırası platformda değişebilir; indeksle yazılan patch yanlış öğeye dokunur.
471
+
472
+ > **`states` bir prop DEĞİL düğüm alanıdır** (`isWrapper`, `isScrollable`, `isSticky`,
473
+ > `isDroppable`, `isFloating`, `isQuickStack`): `replace_prop` onu yazamaz. Kurulmuş bir düğümde
474
+ > değiştirmek için `resize_component`'e `states` verin —
475
+ > `{ op: 'resize_component', target: 'row_kpi', states: { isWrapper: false } }`. Eskiden tek yol
476
+ > düğümü silip yeniden kurmaktı ve 09-05 koşusunda bunun bedeli 20 setter'ın kopmasıydı.
477
+ > **`isWrapper: true` olan her kapsayıcıya runtime `min-height: 80vh` veriyor** — dokuz düğüm
478
+ > sayfaya ~1600px ölü boşluk eklemişti; `style` ile ezilemez, gerekmiyorsa `false` bırakın.
479
+
322
480
  **Sözlükler** (`StepType.cs`, `StepParameterValueType.cs` — hepsi küçük harf):
323
481
  `start · microservice · setter · setcookie · validation · condition · redirect · alert ·
324
- confirm · flow-trigger · storage · navigate · code · download · end`
482
+ confirm · flow-trigger · storage · navigate · code · download · function · end`
325
483
  değer tipleri: `static · page · property · storage · variable · code · item · state`
326
484
 
485
+ > **Sözlükte olmak KOŞACAĞI anlamına gelmez — koşan tipler barındırıcıdan gelir.** Motor yedi
486
+ > tip register eder, gerisini uygulama ekler. Bir sayfa TEK bir uygulamaya aittir
487
+ > (`Page.ApplicationId`) ve uygulamanın tipi `web` ya da `mobile`'dır (`ApplicationType.cs`), yani
488
+ > sayfanın barındırıcısı bellidir — matris "hangi tip sende çalışır"ı söyler, iki barındırıcıda
489
+ > birden koşmayı değil (web `Runtime.svelte`, mobil `ScreenRuntime.tsx`):
490
+ >
491
+ > | Adım tipi | Web | Mobil | Nerede register ediliyor |
492
+ > |---|---|---|---|
493
+ > | `start` · `setter` · `code` · `condition` · `microservice` · `validation` · `flow-trigger` · `function` | ✅ | ✅ | `flow-engine.ts` — motorun kendisi (`function` mobilde kayıtlıdır ama mobil runtime `Functions`'ı boş kurar — K11, çağrı çalışmaz) |
494
+ > | `alert` · `redirect` · `setcookie` · `storage` | ✅ | ✅ | uygulama; mobilde `redirect` navigate, `setcookie` storage uygulamasına eşlenir |
495
+ > | `confirm` · `download` | ✅ | ❌ | yalnız `Runtime.svelte` |
496
+ > | `navigate` | ❌ | ✅ | yalnız `ScreenRuntime.tsx` — web'deki karşılığı `redirect` |
497
+ > | `end` · `query` | ❌ | ❌ | hiçbir yerde — üstelik `query` backend sözlüğünde de yok (`StepType.cs` onu saymaz), yalnız frontend enum'unda duruyor |
498
+ >
499
+ > **Register edilmemiş bir tipe gelen akış SESSİZCE durur.** `flow-engine.ts` `process()`
500
+ > callback bulamazsa hiçbir şey yapmaz: `next()` yok, `completed`/`stopped` yok, hata yok, log
501
+ > yok. Akışın kalanı ölür — üstelik `run()`'ın promise'i hiç çözülmediği için
502
+ > `flowRunFinished()` koşmaz: `__ngAppsFlowActivity.running` sıfıra inmez ve
503
+ > `page_screenshot`'ın hazır bekleyişi her eylemde bütçesini sonuna kadar yakar.
504
+ >
505
+ > Gateway iki hâli **kendisi düzeltir** ve `gatewayNormalized` ile söyler: `navigate` → `redirect`
506
+ > (argüman şekli aynı, `redirect` iki barındırıcıda da koşar) ve ölü `end` adımı gövdeden düşer
507
+ > (ona işaret eden dal `nextStepId: null` olur). `FLOW-023` bunların arkasındaki emniyet kemeridir:
508
+ > `end`/`query` kalırsa **bloklar**, iki barındırıcıya birden özel tip taşıyan gövdeyi uyarır. Tek
509
+ > barındırıcıya özel bir tipi (`confirm`/`download`) tek başına kullanmak kusur değildir — gateway
510
+ > sayfanın hangi uygulamada olduğunu bilmez, doğru tipi bu matristen SEN seçersin.
511
+ >
512
+ > **`end` adımı bir tuzaktır.** Studio kataloğunda bir tip olarak duruyor
513
+ > (`event-actions.constants.ts` `FlowTaskType.End`; ekleme menüsü onu eler) ve eski akışlar bu
514
+ > düğümü taşıyabiliyor (`event-actions.mappers.ts`) — ama Studio'nun varsayılan şeması End
515
+ > düğümü YARATMAZ (`DEFAULT_SCHEMA` `endId`'yi üretir ve kullanmaz) ve motor onu register etmez. Düğümün VARLIĞI zararsızdır; zararlı olan **bir dalın oraya işaret
516
+ > etmesidir** — akış o adıma girer ve çıkamaz. Akış, son adımın dalına `nextStepId: null`
517
+ > verilerek bitirilir. İronik olan şu: var olmayan bir `stepId`'ye işaret etmek daha güvenlidir,
518
+ > çünkü motor hedefi bulamayınca `completed`/`stopped`'ı düzgün çağırır.
519
+
327
520
  > `code` adımının içinde ve `value.type:'code'` ifadelerinde kullanılabilen bağlam
328
521
  > (`Page.*`, komponentlere adıyla erişim, `state.page/app`, `Steps`, `self`/`item`/`event`,
329
522
  > `cookie.get/set`, `await`) ve `value.type` çözümleme tablosu için
330
523
  > **`platform_guide('expressions')`** — uydurma erişim adı sessizce `undefined` üretir.
524
+ >
525
+ > **`function` adımı ("Call function")** bir kullanıcı fonksiyonunu çağırır: `args: { functionId, functionName,
526
+ > parameters: [{ name, value }] }` — `functionId` zorunlu ve gerçek (`function_list`; FLOW-024 block),
527
+ > `parameters[].name` fonksiyonun bildirimindeki adla eşleşir, `value` şekli `microservice` adımıyla
528
+ > aynıdır. Çıktı `Steps.<adımAdı>.data` (hata `.error.message`), dal `always`. Aynı fonksiyon `code`
529
+ > adımında ve `{{ }}` bağlamasında `Functions.<ad>(…)` ile de çağrılır; gateway bilinmeyen adı ve
530
+ > fazla argümanı FLOW-025 ile uyarır. Tam gövde `ngapps://examples/flow-call-function`, kurallar
531
+ > **`platform_guide('functions')`**.
331
532
 
332
533
  > Bir microservice adımı kaydedildiğinde platform `args.microserviceSchema`'yı
333
534
  > (parameterScheme + returnScheme + `isReturnArray`) kendisi doldurur — `flow_get` ile geri
@@ -355,6 +556,10 @@ Toplam kayıt sayısı `Total-Count` header'ından gelir (`TableMicroserviceExec
355
556
  `isSingle: false` olduğu sürece) — `totalRows`'u yukarıdaki guard'lı ifadeyle yaz. Gateway
356
557
  parametreleri geçmeyi unutursan `FLOW-013` ile uyarır.
357
558
 
559
+ Ucun gerçekten `Total-Count` döndüğünü sayfayı kurmadan **önce** doğrula:
560
+ `microservice_execute(...)` yanıtındaki `headers['total-count']` dolu olmalı; boşsa `sort`/`limit`
561
+ verilmemiş bir tablo kaynağı vardır ve sayfa göstergesi `NaN / N` olur (ölçüm: İK koşusu M-8/E-4).
562
+
358
563
  > **`replace_prop` Prop sarmalı DEĞİL ham değer alır** — `PageSchemaMicroOpApplier.cs:77`
359
564
  > `new Prop(PropValueType.Static) { Data = op.Value }` kurar. `{ "type": "static", "data": true }`
360
565
  > gönderirsen sarmalın kendisi `Data`'ya yazılır ve platform onu `Dictionary<string, Prop>` diye
@@ -394,8 +599,9 @@ Türkçe başlık `props.title` / `props.text` / `props.label` / `props.pageTitl
394
599
  > Aynı sebeple akış ifadelerinde komponente **`name` ile** erişilir (`tbl_mng.selectedRow`);
395
600
  > `elementId` ile eşit tutmazsan `element:` alanı çalışır ama ifadedeki değişken `undefined` kalır.
396
601
  >
397
- > Gateway bunu **PAGE-009** ile `add_component`, `page_update(schema)` ve `layout_update(views)`
398
- > yollarında istek gitmeden reddeder.
602
+ > Gateway bunu **PAGE-009** ile HER sayfa ve layout yazma yolunda istek gitmeden reddeder:
603
+ > `page_create`, `page_update(schema)`, `add_component`, `layout_create`, `layout_update(views)`
604
+ > ve `layout_patch`.
399
605
 
400
606
  ## Kural 1d — Sayfa iskeleti: `page_container` ve boyutlandırma
401
607
 
@@ -614,8 +820,9 @@ kullanır: `page.mappers.ts` `mapPageLayoutToPreview` — layout varsa çizilen
614
820
  >
615
821
  > Kural: **`isWrapper` yalnız gerçekten sayfa boyu kaplaması gereken kap içindir**
616
822
  > (`page_container` böyledir ve öyle kalmalı). Sadece "başlık/çerçeve çizilmesin" diye wrapper
617
- > yapma — o iş `container` için `style` ile (`background:'transparent'`, `border:'none'`),
618
- > `form` için `hideBorders`/`hidePadding` prop'larıyla yapılır. **`states` için micro-op
823
+ > yapma — o iş `container` için de `form` için de `style` ile yapılır (`background:'transparent'`,
824
+ > `border:'none'`, `padding:0`). `form`'un eski `hideBorders`/`hidePadding` prop'ları
825
+ > 2026-09-09'da şemadan kaldırıldı — bileşen onları hiçbir zaman okumuyordu, no-op'tu. **`states` için micro-op
619
826
  > YOKTUR:** yanlış `isWrapper`'ı düzeltmenin tek yolu düğümü `remove_component` +
620
827
  > `add_component` ile yeniden kurmaktır (sonrasında Kural 2'deki flow yeniden kaydetme adımı
621
828
  > ZORUNLU olur).
@@ -633,13 +840,18 @@ aynı prop grubunu o da alır. Grup katalogda tanımlıdır, yani şemadan kurul
633
840
 
634
841
  | Prop | Değerler (varsayılan **kalın**) | Ne yapar |
635
842
  |---|---|---|
636
- | `layout` | **`flex`** · `grid` | `flex`: akış düzeni. `grid`: 12 kolonluk ızgara (Kural 1f). |
843
+ | `layout` | **`flex`** · `grid` | `flex`: akış düzeni. `grid`: 12 kolonluk mutlak ızgara (Kural 1f). Grubu taşıyan kaplar: `container`/`page_container` · `form` (2026-09-01'den) · `box`/`aibox` · `layout` ve `widget-area` (2026-09-03) — hepsinde değer kümesi `flex·grid`; yalnız `box-section` tek değerlidir (`flex`). `box`/`aibox`'ın eski üçüncü değeri `cssgrid` (akan gerçek `display:grid`) 2026-09-02'de seçenek olmaktan çıktı: yeni yazımda `invalid-enum-value` verir, o değerle kayıtlı düğümler çizilmeye devam eder. |
637
844
  | `direction` | **`row`** · `column` | `flex-direction`; hangi hizalamanın ANA eksen olduğunu belirler. |
638
845
  | `horizontalAlign` | **`left`** · `center` · `right` · `stretch` | `row`'da ana eksen (`justify-content`), `column`'da çapraz eksen (`align-items`). |
639
846
  | `verticalAlign` | **`top`** · `middle` · `bottom` · `stretch` | `row`'da çapraz eksen, `column`'da ana eksen (rolleri `horizontalAlign` ile takas). |
640
847
  | `size` | **`shrink`** · `grow` | Çocuklara `flex: 0 1 auto` / `1 1 auto`. |
641
- | `gap` | `none` · `small` · **`medium`** · `large` | 0 / 8 / 16 / 32px. |
642
- | `wrap` | **kapalı** · açık | `flex-wrap`; kapalıyken taşan çocuklar sıkışır, alta inmez. |
848
+ | `gap` | `none` · `small` · **`medium`** · `large` **ya da ham CSS** | Preset'ler tema değişkenidir: 0 / `var(--ng-spacing-sm)` / `--ng-spacing-md` / `--ng-spacing-lg` (varsayılan temada 8/16/32px). Alan `allowCustom`'dır: `"18px"` ya da `"var(--ng-spacing-xl)"` gibi ham değer de geçer. `box-section`/`aibox`'taki sayısal `gapCustom` doluysa preset'i ezer. |
849
+ | `wrap` | kapalı · **açık** | `flex-wrap`. **Varsayılan 2026-09-01'de açık oldu:** `row` + `w:12` çocuklar artık alt satıra sararak dikey akar. Kapatırsan taşan çocuklar tek satıra sıkışır. |
850
+
851
+ **`form` da bu grubun tamamını taşır (2026-09-01):** varsayılanları container ile aynı
852
+ (`flex` · `row` · `left` · `top` · `shrink` · `medium` · `wrap` açık). "Form'a layout yazılmaz"
853
+ eski bilgidir. (Platform kataloğu güncel şemayı `component_get`'te göstermiyorsa kayıt
854
+ yenilenmemiştir — ARC-024.)
643
855
 
644
856
  `stretch` iki eksende farklı anlama gelir: **ana** eksende `space-between` (çocukları uçlara
645
857
  dağıtır), **çapraz** eksende gerçekten doldurur.
@@ -654,27 +866,37 @@ prop'una bakar (`isFlexLayout`). İki sonucu var:
654
866
  ızgara alırsın — Studio'dan sürüklenen kardeş kapsayıcı flex gelirken seninki grid kalır.
655
867
 
656
868
  Gateway'in kendi eklediği kök kapsayıcı (`page_create`'te şemada `page_container` yoksa) bu yüzden
657
- seti açıkça taşır: `flex` · `row` · `left` · `top` · `shrink` · `medium`. **`row` + `wrap` kapalı
658
- demek, alt alta düşünülmüş `w: 12` çocukların TEK SATIRA sıkışması demek** — dikey akan bir sayfa
659
- istiyorsan kapsayıcıya `direction: 'column'` yaz (ya da `layout: 'grid'`e dön).
869
+ seti açıkça taşır: `flex` · `row` · `left` · `top` · `shrink` · `medium` · `wrap` açık.
870
+ `row` + `wrap` açık + `w: 12` çocuklar alt satıra sararak dikey akar; net bir dikey akış
871
+ istiyorsan yine de `direction: 'column'` yazmak daha okunur (ya da `layout: 'grid'`e dön).
872
+ **`wrap`'i kapatırsan** alt alta düşünülmüş `w: 12` çocuklar TEK SATIRA sıkışır.
660
873
 
661
874
  **Ne zaman flex?** Yan yana buton/aksiyon grubu, toolbar, rozet dizisi, ortalanmış giriş kartı,
662
875
  "kalanı doldursun" yerleşimleri. Alt alta akan form alanları için ızgara da doğrudur — orada flex
663
876
  istiyorsan `direction: 'column'` şart, `row` ile alanlar tek satıra sıkışır.
664
877
 
665
- Dört şeyi bilmeden flex kurma:
666
-
667
- 1. **Genişlik yine 12 kolondur — içerik genişliği DEĞİL.** Çocuğun `blocks[].size.w`'si
668
- `row`'da `flex-basis: w/12`, `column`'da `width: w/12` olur (`gap` payı formülden düşülür,
669
- böylece `w` toplamı 12 olan satır tam kapanır). Bu bilinçli bir tercih: ızgara ↔ flex geçişi
670
- kayıpsızdır ve genişlik şemadan ifade edilebilir kalır. `column` + `horizontalAlign: 'stretch'`
671
- tek istisnadır — orada çocuk tam genişlik olur.
878
+ Beş şeyi bilmeden flex kurma:
879
+
880
+ 1. **Çocuğun genişliği `appearance.widthType`'tan gelir (2026-09-01); 12 kolon yalnız
881
+ FALLBACK'tir.** Dört cevap, öncelik sırasıyla:
882
+ - `widthType: 'fill'` — kabın tüm genişliği (satırda `flex:1 1 100%`, sütunda
883
+ `align-self:stretch`); string taşımaz, taşırsa bile ezer.
884
+ - `widthType: 'fixed'` + `widthString` — sabit ölçü, serbest CSS uzunluğu (`"240px"`,
885
+ `"50%"`, `"10vw"`, `calc(...)`). Geçersiz string sessizce düşer ve span'a dönülür.
886
+ - `widthType: 'auto'` — içerik kadar (`flex: 0 1 auto`).
887
+ - `widthType` YOK (eski kayıtlar) — `blocks[].size.w` payı: `row`'da `flex-basis: w/12`,
888
+ `column`'da `width: w/12` (`gap` payı düşülür; `column` + `horizontalAlign:'stretch'`
889
+ istisna — tam genişlik). Izgara ↔ flex geçişi bu fallback sayesinde kayıpsızdır.
890
+ Şemayı sen kuruyorsan çocuğa `widthType`'ı AÇIKÇA yaz. Studio'nun kendi bırakma kuralı:
891
+ kapsayıcı türü kaplar (`container`/`box`/`form`) `'fixed'` + `"50%"`, diğer her şey `'auto'`.
672
892
  2. **`position.y` artık yalnız SIRADIR.** Flex çocuklar `y`, sonra `x` sırasına göre dizilir;
673
893
  aradaki boşluklar çizilmez. Yine de bitişik ver (0,1,2…): kapsayıcı ileride `grid`'e
674
894
  döndürülürse şema geçerli kalsın. Gateway bu yüzden **flex kapsayıcının İÇİNDE PAGE-010
675
895
  boşluk uyarısı üretmez** (ızgarada üretmeye devam eder).
676
896
  3. **Flex kapsayıcının yüksekliği içeriğine oturur.** `verticalAlign`'ın dağıtacak boşluğu
677
- olması için `appearance.heightType: 'fixed'` + `size.h` vermelisin. **İstisna
897
+ olması için `appearance.heightType: 'fixed'` vermelisin — ölçü `heightString`'den
898
+ (serbest CSS uzunluğu, ör. `"30vh"`), o yoksa `size.h × 10px`'ten gelir. `heightString`
899
+ yalnız `heightType:'fixed'` iken okunur; tek başına yazmak hiçbir şey yapmaz. **İstisna
678
900
  `page_container`**: `states.isWrapper: true` olduğu için zaten `min-height: 80vh` alır
679
901
  (Kural 1f), dolayısıyla dikey hizalama onda kutu boyu vermeden de çalışır. Üçüncü yol
680
902
  `heightType: 'fill'` (2026-08-28): çocuk kabın bıraktığı yeri alır — sütunda `flex: 1 1 auto`,
@@ -684,6 +906,10 @@ Dört şeyi bilmeden flex kurma:
684
906
  4. **`layout: 'grid'` iken diğer altı prop ÖLÜDÜR.** Katalogda tanımlı oldukları için
685
907
  doğrulama duvarı susar, renderer da okumaz: ızgara kapsayıcıya `direction: 'column'` yazmak
686
908
  sessizce hiçbir şey yapmaz. Gateway bunu **PAGE-015 (uyarı)** ile söyler.
909
+ 5. **Flex düzeni kırılım BİLMEZ.** `direction`/`gap`/hizalama masaüstü ve mobilde AYNIDIR;
910
+ sıra ve span'lar Desktop (1024) bloğundandır — Studio, mobil kırılım düzenlenirken flex
911
+ bölgeyi salt-okunur kilitler. Kırılım bilen yalnız `blocks[]` ve `appearance.hideOn`'dur;
912
+ mobilde farklı davranış gereken satır için `layout: 'grid'` kullan (Kural 1f mobil notu).
687
913
 
688
914
  ```jsonc
689
915
  // Ortalanmış giriş kartı — style ile CSS hack'i YOK, kabın kendi düzeni
@@ -701,6 +927,33 @@ Dört şeyi bilmeden flex kurma:
701
927
  { "op": "replace_prop", "target": "row_actions", "prop": "gap", "value": "small" }
702
928
  ```
703
929
 
930
+ **Mini tarif — sıkı dizilim (küçük bileşenleri dip dibe getirmek).** Buton/rozet/ikon dizisi
931
+ gibi bitişik duracak elemanlar için ÜÇ şart birden gerekir; biri eksikse arada boşluk kalır:
932
+
933
+ 1. Her çocuğa **`appearance.widthType: 'auto'`** — içerik kadar yer kaplar (`flex: 0 1 auto`).
934
+ Yazılmazsa eski 12 kolon payı geçerlidir ve çocuk kolonunu doldurur, bitişemez.
935
+ 2. Kaba **`gap: 'none'`** (ya da ham ince değer: `"2px"`, `"4px"` — alan `allowCustom`).
936
+ 3. Her çocuğa **`appearance.marginType: 'none'`** — en çok atlanan şart: `marginType`
937
+ yazılmamış düğüm `normal` sayılır ve her kenara 4px basar (`spacing.ts`
938
+ `CANVAS_NORMAL_MARGIN`), yani `gap:'none'` olsa bile komşular arasında 8px kalır.
939
+
940
+ ```jsonc
941
+ // Bitişik rozet dizisi: kap + iki çocuktan biri (diğeri aynı desen)
942
+ { "elementId": "badge_row", "type": "container", "kind": "component",
943
+ "props": { "layout": { "type": "static", "data": "flex" },
944
+ "direction": { "type": "static", "data": "row" },
945
+ "gap": { "type": "static", "data": "none" } },
946
+ "children": [
947
+ { "elementId": "badge_1", "type": "button", "kind": "component",
948
+ "appearance": { "widthType": "auto", "marginType": "none", "heightType": "auto" },
949
+ "blocks": [{ "breakpoint": 1024, "size": { "w": 2, "h": 4 }, "position": { "x": 0, "y": 0 } }] }
950
+ ] }
951
+ ```
952
+
953
+ "Şu ikisi bitişik, şu uzak" gibi eşit olmayan aralıklar için `gap` yetmez (kapta tekildir) —
954
+ bitişik elemanları `gap:'none'` bir İÇ kapsayıcıda gruplayıp grupları dış kapta normal
955
+ `gap` ile diz.
956
+
704
957
  > Düzen işi `style` prop'una AİT DEĞİL. Kural 1h'deki `style` reçeteleri tema/görsellik içindir;
705
958
  > `display:flex` gibi düzen kurallarını oraya yazmak kabın kendi düzeniyle çakışır (PAGE-014'teki
706
959
  > ölçüm: string style ile kart 66px'e çöktü). Yerleşim bu prop grubuyla, tema `style` ile kurulur.
@@ -776,8 +1029,10 @@ UYGULAMAZ** — koordinatları aynen kaydeder (aşağı itme yalnız `page_creat
776
1029
  > - Ekranda sürekli `Expression error: Cannot read properties of null (reading '0')` toast'ı çıkıyor
777
1030
  > (iç repeater bir kez `item` olmadan da değerlendiriliyor).
778
1031
  >
779
- > **Gateway bunu `PAGE-013` ile istek gitmeden reddediyor** (`page_create` / `page_update(schema)` ve
780
- > `page_schema_patch`'te op'lar UYGULANDIKTAN SONRAKİ ağaca bakarak).
1032
+ > **Gateway bunu `PAGE-013` ile istek gitmeden reddediyor** — `page_create` / `page_update(schema)` /
1033
+ > `layout_create` / `layout_update(views)` / `layout_patch` gönderilen ağaca, `page_schema_patch` hem
1034
+ > eklenen alt ağaca hem op'lar UYGULANDIKTAN SONRAKİ ağaca bakarak. Layout'ta da geçerlidir: kırılma
1035
+ > `_repeaterValues` geri yazmasındadır, barındıranın sayfa mı layout mu olduğuna bakmaz.
781
1036
  >
782
1037
  > **Yapılacak:** satır içi listeyi tek bir `textarea`'da **satır başına bir öğe** olarak topla
783
1038
  > (`options_text`), kaydederken `split('\n')`'le böl. Ölçülmüş çalışan sürüm: anket editörü
@@ -805,6 +1060,14 @@ yapmanın yolu budur — ölçülmüş kurallar (anket-doldur, 2026-08-19):
805
1060
  > Bu kural TEMA/GÖRSELLİK içindir. Çocukların dizilimi (ortalama, yaslama, aralık, "kalanı
806
1061
  > doldur") `style` ile değil kapsayıcının kendi `layout` prop grubuyla kurulur — Kural 1f-2.
807
1062
 
1063
+ > **Stil anahtarları camelCase'dir: `minHeight`, `fontSize`, `letterSpacing`.** Kebab-case anahtar
1064
+ > (`min-height`) platform tarafından KABUL EDİLİR, `page_schema_get` ile aynen geri okunur ve
1065
+ > runtime onu HİÇ UYGULAMAZ; tek işaret tarayıcı konsolundaki tek satırdır ve `page_screenshot`
1066
+ > konsolu döndürmez. 2026-09-05 koşusunun en pahalı yanlış teşhisi buydu (~15 dk) ve yanlış teşhis
1067
+ > düğümleri silip yeniden kurmaya, o da 20 setter'ın sessizce kopmasına yol açtı. Gateway artık
1068
+ > kebab-case anahtarı camelCase'e çevirir ve `gatewayNormalized` ile bildirir; seçici anahtarlara
1069
+ > (`&__body`, `:hover`, `--ng-*`) dokunmaz.
1070
+
808
1071
  **1. Temayı tek yerden çevir: `page_container.style` içinde `--ng-*` değişkenlerini ez.**
809
1072
  Runtime bütün renk/tipografi/form tokenlarını CSS değişkeni olarak basar
810
1073
  (`Theme.svelte`: `--ng-accent-primary`, `--ng-accent-hover`, `--ng-background-surface`,
@@ -875,6 +1138,13 @@ yapmazsan ekran "platform mavisi" görünür; marka rengine çevirmek tek satır
875
1138
  BÜTÜN girdileri yuvarlar; aynı şeyi komponent komponent `&__input { borderRadius }` yazarak
876
1139
  yapmak hem uzun sürer hem de yeni komponent eklendiğinde tutarsızlık üretir.
877
1140
 
1141
+ **Koyu tema karesi için sayfada `theme-toggle` bulunması gerekmez.** Ziyaretçinin tema tercihi
1142
+ çerezde değil `localStorage`'da (`zeyrek-viewer-theme-mode`) yaşar ve tema store'u onu sayfa
1143
+ açılırken bir kez okur; `page_screenshot` `colorScheme: 'dark' | 'light'` parametresi tercihi
1144
+ sayfa script'lerinden ÖNCE eker. İki temayı da doğrulamak, tasarıma düğme eklemeden iki çağrıdır
1145
+ (aynı tool'un `language` parametresi ikinci dil için aynı işi yapar —
1146
+ `platform_guide('translation')`).
1147
+
878
1148
  ### 1h-3 — Ölçülmüş hazır bloklar (anket ekranından, olduğu gibi kullanılabilir)
879
1149
 
880
1150
  ```jsonc
@@ -991,7 +1261,7 @@ budur — bir preset ya da `componentStyles` sizin değerinizi eziyorsa `styleLa
991
1261
  | Değişiklik | Tool | Neden |
992
1262
  |---|---|---|
993
1263
  | Komponent ekle/sil/taşı, prop, binding, event | `page_schema_patch` | Doğrulama duvarı + açık Studio canvas'ına SignalR canlı yayını + eşzamanlı yazar kilidi yalnız bu yolda çalışır |
994
- | Ad, slug, browserTitle, layout, roller, middleware | `page_update` | Üstbilgi alanları micro-op sözlüğünde yok |
1264
+ | Ad, slug, browserTitle, `browserTitleKey`, layout, roller, middleware | `page_update` | Üstbilgi alanları micro-op sözlüğünde yok. `browserTitleKey` sekme başlığını çeviri anahtarına bağlar: verilirse başlık sözlükten çözülür, boşsa `browserTitle` kullanılır. Başlık sayfa yüklenirken çözülür ve canlı dil değişimini izlemez (`platform_guide('translation')`) |
995
1265
 
996
1266
  Platformun `PUT /pages/...` ucu **replace**'tir: gönderilmeyen `schema`/`events`/`roleIds`
997
1267
  alanları silinir. Gateway bu yüzden `page_update`'te sayfayı önce okur, yalnız verdiğin
@@ -1018,6 +1288,17 @@ Yanıt üç alan döner: `applied` (uygulanan op sayısı), **`appliedPatch`** (
1018
1288
  olarak hangi JSON Pointer'a ne yaptığı — RFC 6902 biçiminde; "gerçekten yalnız o komponente mi
1019
1289
  dokunuldu" sorusunun kanıtı) ve **`newVersion`** (`UpdatedAt.Ticks`).
1020
1290
 
1291
+ > **`appliedPatch` gövdesi VARSAYILAN OLARAK iskelettir.** Girdi `{ op, path }` döner; eklenen
1292
+ > düğüm `component` altında yalnız `id`/`elementId`/`name`/`type`/`children` taşır. Kanıt zaten
1293
+ > path'tedir — `value` senin aynı turda gönderdiğin gövdenin yankısıdır ve tek bir `set_event`
1294
+ > yaması bile düğümün bütün prop'larını geri getiriyordu. Aynı kural `page_create` yanıtındaki
1295
+ > `schema` için de geçerlidir (çözülmüş layout düğümleri dâhil). Tam gövde: `view: 'full'`.
1296
+ >
1297
+ > **"Kaydedildi mi" sorusunu `appliedPatch` zaten cevaplamıyor** (aşağıdaki `silentlyDropped`
1298
+ > bölümü): yama 200 döner ve pointer'ı gösterir, ama alanın kayda geçtiğini söylemez. Onu gateway
1299
+ > yamadan sonra şemayı okuyup gönderdiğinle karşılaştırarak söyler. Kırpma bu yüzden kanıt kaybı
1300
+ > değildir; `view: 'full'`e yalnız gerçekten platformun ham gövdesini incelerken düş.
1301
+
1021
1302
  **Sürüm kontrolü platformda var ama gateway bugün KULLANMIYOR.** Platform gövdede `baseVersion`
1022
1303
  (long tick) kabul eder ve tutmazsa 409 verir; `page_state.baseVersion` bu değeri döner.
1023
1304
  `page_schema_patch` bu alanı geçirmez — bayat plan koruması gateway tarafında
@@ -1204,9 +1485,21 @@ altın örneklerde** — şemayı ve akışları oradan kopyalayıp uyarla:
1204
1485
  | Detay / profil | `ngapps://examples/page-detail-profile` |
1205
1486
  | Dinamik form (alanlar veriden) | `ngapps://examples/page-dynamic-form` (Kural 1g + 1h) |
1206
1487
 
1207
- > Gateway iki yarım kurulumu yakalar: **FORM-001** (`form` eklendi, `submit` bağlanmadı) ve
1488
+ > Gateway üç yarım kurulumu yakalar: **FORM-001** (`form` eklendi, `submit` bağlanmadı),
1208
1489
  > **FORM-002** (akışta POST/PUT adımı var ama hiç `source:'body'` parametresi yok → gövde boş
1209
- > gider). `project_overview` ayrıca proje düzeyi boşlukları döndürür (`coverageGaps`): kimlik
1490
+ > gider) ve **FORM-003** (formun `submit`'i bağlı ama içindeki butonun `click`'i bağlı değil).
1491
+ >
1492
+ > **FORM-003 neden var:** `button` varsayılan olarak `type="button"` çizilir; form içinde bile
1493
+ > HTML form submit'i HİÇ doğmaz — butona tıklamak da alanda Enter da uca istek göndermez ve
1494
+ > **hiçbir hata çıkmaz**. `ngapps://examples/page-sign-in`'i harfiyen izleyen bir giriş sayfası bu
1495
+ > yüzden tıklanamaz kalıyordu (ölçüldü 2026-09-05); teşhis yalnız gerçek tıklamayla mümkün oldu
1496
+ > (`page_screenshot` `actions`). İki çözümden biri yeter:
1497
+ >
1498
+ > 1. Butona **`props.type = 'submit'`** ver — katalogdaki `type` prop'u bu değeri destekliyor ve
1499
+ > idiomatik yol budur.
1500
+ > 2. Ya da AYNI akışı butonun `click` olayına da bağla.
1501
+ >
1502
+ > `submit` olayını forma bağlamak tek başına yetmez; gateway ikisi de yoksa uyarır. `project_overview` ayrıca proje düzeyi boşlukları döndürür (`coverageGaps`): kimlik
1210
1503
  > middleware'i var ama giriş sayfası yok, yazma ucu var ama sayfa yok.
1211
1504
 
1212
1505
  **Adlandırma:** çoğul = liste sayfası, tekil = form sayfası (`Departmanlar` / `Departman`).
@@ -1235,6 +1528,17 @@ maxLength/pattern — sözlük `component_get`'te) orada listelenir.
1235
1528
  ] }
1236
1529
  ```
1237
1530
 
1531
+ **Mesajı çeviriye bağlamak: `t:` öneki.** `message` düz bir metindir ve translation prop'u ALMAZ;
1532
+ çeviri anahtarı mesajın kendisine önek olarak yazılır:
1533
+
1534
+ ```jsonc
1535
+ { "type": "required", "message": "t:form.emailRequired", "value": true, "isActive": true }
1536
+ ```
1537
+
1538
+ Runtime `t:` ile başlayan mesajı anahtar sayar ve normal fallback zincirinden çözer (aktif dil →
1539
+ varsayılan dil → anahtarın kendisi); önek yoksa metin olduğu gibi gösterilir. Çözüm çalışma
1540
+ anında olduğu için şema varsayılanlarına dokunmak gerekmez.
1541
+
1238
1542
  Geçerli `type` değerleri: `required` · `email` · `regex` · `max-length` · `min-length` ·
1239
1543
  `max-value` · `min-value` · `value-options`. Üç tuzak ölçüldü (crm koşumu B-9):
1240
1544
 
@@ -1268,18 +1572,29 @@ start → [setter] page_container.isLoading = true
1268
1572
  └─ else → [setter] CREATE etiketleri
1269
1573
  ```
1270
1574
 
1271
- > **Condition adımı `always` dalını kural dallarıyla BİRLİKTE taşır.** `always` her hâlükârda koşar
1272
- > (yükleniyor bayrağını kapatmanın yolu budur), kural dalları (`branch.name` = **rule id**) eşleşene
1273
- > göre. `rules`: `{ id, expression, type:'if' }` + `{ id, expression:'', type:'else' }`.
1575
+ > **Condition adımı `always` dalını kural dallarıyla BİRLİKTE taşır** — ama `always` her hâlükârda
1576
+ > KOŞMAZ. Motor onu yalnız **eşleşen dalın** bitişinden çağırır:
1274
1577
  >
1275
- > **`rules[].id` GERÇEK bir GUID olmalı** — okunabilir bir ad (`"rule_ok"`) verirsen istek
1276
- > `The JSON value could not be converted to System.Guid. Path: $.flow.steps[N].args.rules[0].id`
1277
- > ile reddedilir. Dal adı da o GUID'in kendisidir (`branch.name === rule.id`), yani iki yerde de
1278
- > okunabilir ad kullanamazsın.
1578
+ > ```ts
1579
+ > // condition.ts — always'in TEK çıkışı eşleşen dalın callback'idir
1580
+ > engine.next(rule.id, { ...definition, completed: () => engine.next('always', definition) })
1581
+ > ```
1279
1582
  >
1280
- > **Kural ifadesi patlarsa akış hata vermez, kuralı EŞLEŞMEMİŞ sayar** ve sessizce `else`'e
1281
- > gider. Bu yüzden condition ifadeleri guard'lı yazılır — özellikle `Page.user` okuyanlar
1282
- > (Kural 8).
1583
+ > Yani şu üç hâlde `always` **hiç** koşmaz: `rules` boş · `rules[0].type !== 'if'` · hiçbir ifade
1584
+ > tutmuyor ve boş ifadeli bir `else` yok. **Yükleniyor bayrağını `always` ile kapatıyorsan
1585
+ > zinciri boş ifadeli `else` ile kapatmak ZORUNDASIN** — yukarıdaki iskelette `else` dalı tam da
1586
+ > bu yüzden var. `else`'siz bir zincirde ifade tutmazsa bayrak açık kalır ve sayfa sonsuza kadar
1587
+ > yükleniyor görünür. Gateway `FLOW-020` bunu uyarıyla söyler.
1588
+ >
1589
+ > Sözleşmenin tamamı (GUID id zorunluluğu, dal adı = rule id, `else` fallback kuralı, zincir
1590
+ > sırası) aşağıdaki tuzak 6'da.
1591
+ >
1592
+ > **Kural ifadesi patlarsa kural EŞLEŞMEMİŞ sayılır** — `runCode` `undefined` döner,
1593
+ > `Boolean(undefined)` false'tur — ve zincir bir sonraki kurala, oradan `else`'e geçer. Ama bu
1594
+ > tamamen sessiz değildir: hata işaretlenir ve sıradaki `engine.next` onu tüketip **hata yolu
1595
+ > varsa akışı oraya saptırır** (`flow-engine.ts` `consumeExpressionError`), yani beklediğin dal
1596
+ > yerine `errorSteps` koşar. Bu yüzden condition ifadeleri guard'lı yazılır — özellikle
1597
+ > `Page.user` okuyanlar (Kural 8).
1283
1598
 
1284
1599
  **İki ayrı ucun sonucunu tek tabloya yazmak:** `mapping` tek kaynak alır, o yüzden birleştirmeyi
1285
1600
  `value.type: 'code'` ile yap — ilgisiz kayıtları da orada süz:
@@ -1337,20 +1652,24 @@ start → [setter] btn_save.isLoading = true
1337
1652
 
1338
1653
  - **Upsert deseni:** tek POST ucu hem create hem update yapar — `id` query-string'den, alanlar
1339
1654
  `source:'body'`'den. Entity başına iki uç yazmaya gerek yok.
1340
- - **Hata yolunu `errorSteps` ile kurma**, `condition Steps.<adımAdı>.error` ile kur: `errorSteps`
1341
- ana akışın kalanını hiç çalıştırmaz, yükleniyor bayrağı açık kalır.
1655
+ - **Form akışında hata yolunu `condition Steps.<adımAdı>.error` ile kur**, `errorSteps` ile
1656
+ değil: `errorSteps` ana akışın kalanını devralır, yani yükleniyor bayrağını kapatma · modal'ı
1657
+ kapatma · tabloyu tazeleme adımlarını hata akışında yeniden kurman gerekir — kurmazsan bayrak
1658
+ açık kalır. İki yolun karşılaştırması ve hata metninin nerede durduğu Kural 1c'nin §hata yolu
1659
+ bloğunda.
1342
1660
  - Geri bildirim `notification` komponentiyle verilir (`kind` · `header` · `content` · `timeout` ·
1343
1661
  `showCloseButton` · `style`), `alert` adımıyla değil.
1344
1662
 
1345
1663
  > **`isHidden`: ŞEMAYA yazmak ile SETTER ile yazmak AYRI yollardır.** Runtime tarafı ortak:
1346
1664
  > `RenderComponent` her düğümü `{#if !props.isHidden}` ile çizer, yani akıştaki setter
1347
- > `isHidden` yazınca komponent katalogda o prop'u tanımlamasa bile gizlenir. **Şema yolu ise
1348
- > katalogla sınırlıdır:** `props.isHidden`'ı düğüme yazmak, komponent onu tanımlamıyorsa
1349
- > `unknown-prop` ile REDDEDİLİR (81 kaydın 36'sı tanımlar; ölçüm 2026-08-25). Tanımlamayanlar
1350
- > arasında sık kullanılanlar: **`text` · `table` · `datatable` · `dropdown` · `multi-select` ·
1351
- > `tag-input` · `tabs` · `checkbox` · `switch` · `switcher` · `card` · `modal` · `drawer` ·
1352
- > `repeater` · `notification` · `toast` · `datepicker` ailesi · `breadcrumb-title`.**
1353
- > Tek doğru kaynak `component_get` + `page_schema_validate` kuru koşusudur.
1665
+ > `isHidden` yazınca komponent katalogda o prop'u tanımlamasa bile gizlenir. **Şema yolu
1666
+ > katalogla sınırlıdır** ama artık neredeyse her komponent tanımlıyor: **101 kaydın 99'u**
1667
+ > (ölçüm 2026-09-08; 2026-08-26'daki toplu ekleme öncesi 81'de 37 idi). Tanımlamayan yalnız
1668
+ > iki kap var: **`slot` · `widget-area`** — onların içindekini gizlemek için sarmalayıcı
1669
+ > kullan. Eskiden tanımlamayan `text` · `table` · `datatable` · `dropdown` · `multi-select` ·
1670
+ > `tag-input` · `tabs` · `notification` · `toast` · `datepicker` ailesi gibi komponentlere
1671
+ > artık doğrudan `props.isHidden` yazılabilir; sırf gizlemek için `container`'a sarmak
1672
+ > GEREKMEZ. Tek doğru kaynak `component_get` + `page_schema_validate` kuru koşusudur.
1354
1673
  >
1355
1674
  > **`appearance.isHidden` bir kaçış yolu DEĞİLDİR:** kaydedilir ama runtime hiçbir yerde okumaz
1356
1675
  > (renderer yalnız `props.isHidden`'a bakar) — komponent görünmeye devam eder. Başlangıçta gizli
@@ -1540,6 +1859,21 @@ hiçbiri** bağlı değildi; üç portalın da rol menüsü boş çıkıyor, pan
1540
1859
  > `Host: <org>.<suffix>` + `X-Environment` başlıklarıyla. Ham `curl` yerine tool'u kullanmak
1541
1860
  > yeterlidir.
1542
1861
  >
1862
+ > **Yerleşimi görüntüsüz ölçmek.** Taşma/çakışma şüphesinde `page_screenshot(layoutReport: true)`:
1863
+ > `layoutSummary.overflowing` boş değilse içeriğine sığmayan kutu, `outsideViewport` boş değilse
1864
+ > hiç görünmeyen düğüm var; `zeroSized` çizilmemiş komponenti gösterir. Runtime düğümleri
1865
+ > `data-element-id` basmıyorsa yanıt `layoutReportUnavailable` der — tool tahmin üretmez.
1866
+ >
1867
+ > **Üye kimliğiyle doğrulama (`asUser`).** Kapının kapalı olduğunu görmek yarısıdır; açık
1868
+ > olduğunu görmek diğer yarısı. `page_runtime_get` ve `page_screenshot` aynı `asUser` alanını
1869
+ > alır: uygulamanın kendi giriş ucundan (`microservice_execute`) aldığın üye jetonunu verirsin,
1870
+ > gateway o jetonu **hem `Authorization` başlığında hem `NG_AccessToken` çerezinde** taşır.
1871
+ > Çerez okuyan bir middleware ile başlık okuyan bir middleware aynı çağrıdan geçer — iki tool da
1872
+ > aynı kimlik kanalını kullanır. `page_screenshot` ayrıca `cookies: {ad: değer}` ile uygulamanın
1873
+ > kendi oturum çerezlerini enjekte eder. `asUser`/`cookies` ile `anonymous` birlikte verilemez;
1874
+ > gateway'in servis jetonu (varsayılan kimlik) uygulamanın `users` tablosuna çözülmeyebilir —
1875
+ > korumalı sayfada boş panel görüyorsan önce `identity` alanına bak, sonra `asUser` ile tekrarla.
1876
+ >
1543
1877
  > `page.roleIds` bu dalla birlikte de kapı değildir: rol ayrımını sayfa değil **uç** yapar.
1544
1878
 
1545
1879
  > **Rol okurken dizi bekleme.** `set-user` DTO'su `roles` dizisini çoğu kurulumda düşürür
@@ -1603,6 +1937,24 @@ micro-op hattına dönün.
1603
1937
  > setter'ı sessizce hiçbir şey yazmadı — sayfa boş liste ile açıldı, konsolda hata yok.
1604
1938
  > `flow_update` ile aynı gövdeyi yeniden kaydetmek düzeltti. Kural: **şemadan bir düğüm sildiysen,
1605
1939
  > o düğümü hedefleyen her flow'u yeniden kaydet.**
1940
+ >
1941
+ > **Akış silen yama artık istek gönderilmeden REDDEDİLİR.** Platform referanssız kalan akışı
1942
+ > KALICI siler; uyarı yamadan sonra geldiğinde "önce yedekle" tavsiyesi uygulanamıyordu (09-05
1943
+ > koşusunda sekiz adımlı giriş akışı sıfırdan yeniden yazıldı). Aynı kontrol `set_event` ve
1944
+ > `remove_event` için de çalışır — bir olayın bağını değiştirmek de akış öldürür ve o yolda hiç
1945
+ > uyarı yoktu. Silinmesini bilerek istiyorsanız çağrıyı `allowFlowDeletion: true` ile tekrarlayın;
1946
+ > yanıt `deletedFlows` ile hangi akışların gittiğini listeler.
1947
+ >
1948
+ > **FLOW-018 artık silinen düğümün ALT AĞACINI da görüyor.** Eskiden yalnız op'un kendi
1949
+ > `target`'ına bakılıyordu: bir kapsayıcı silinince ÇOCUĞUNA yazan setter sessizce kopuyor ve
1950
+ > uyarı hiç çıkmıyordu (09-05, `sign_in_form` → `btn_sign_in`).
1951
+ >
1952
+ > **Gateway artık bunu söylüyor (FLOW-018).** `remove_component` içeren bir yamada gateway sayfanın
1953
+ > akışlarını okur ve silinen düğümü hedefleyen setter adımlarını uyarı olarak listeler: hangi akış,
1954
+ > hangi adım, hangi hedef. Uyarıyı gördüğünde yapılacak tek şey `flow_update` ile aynı gövdeyi
1955
+ > yeniden kaydetmektir. Ters yönü (`silinen düğümün referans verdiği` akışların platformca kalıcı
1956
+ > silinmesi) ayrı bir uyarı kapsar; ikisi birlikte çıkabilir. Ölçüm 2026-09-04 (benchmark 4. koşu):
1957
+ > uyarı yokken aynı tuzak ~8 dakika teşhis aldı ve yalnız ekran görüntüsüyle görüldü.
1606
1958
 
1607
1959
  ## Bilinen sınırlar
1608
1960
 
@@ -1667,10 +2019,11 @@ micro-op hattına dönün.
1667
2019
  `isHidden` prop'u yok (Kural 1g'deki sarmalayıcı çözümü). Bir prop'u kullanmadan önce
1668
2020
  `component_get`'e bak; eksikse ürün sahibine katalog güncellemesi olarak bildir.
1669
2021
 
1670
- - **`container.title` `states.isWrapper: true` iken başlık ÇİZMEZ.** Wrapper kaplar salt düzen
2022
+ - **`container.title` varsayılanı boştur ve `states.isWrapper: true` iken başlık ÇİZMEZ.** Başlıksız
2023
+ normal container da `__header` bloğu üretmez; bant istiyorsan `title` değerini açıkça yaz.
2024
+ Wrapper kaplar salt düzen
1671
2025
  elemanıdır; başlığı da `__header` bloğunu da render etmez (klinik ölçümü: `__header` sayısı 0).
1672
- `isWrapper: false` olan kapta başlık normal çizilir (İK ölçümü: başlık verilmeyen kapta
1673
- varsayılan "Container title" göründü). Kart başlığını garantiye almak istiyorsan kabın
2026
+ `isWrapper: false` olan ve başlığı açıkça verilen kapta başlık normal çizilir. Kart başlığını garantiye almak istiyorsan kabın
1674
2027
  `title`'ına güvenme, **içine bir `text` komponenti** koy.
1675
2028
  - **Kod prop'unun ifadesi `ref`'te ve `{{ }}` sarılı olmalı.** `{type:'code', ref:"'' + Row.value"}`
1676
2029
  (süssüz) ekrana ifadenin **kendisini** basar; ifade yalnız `data`'da olursa prop **boş**