@appaflytech/zeyrek-ai-mcp 0.0.24 → 0.0.26

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 (81) hide show
  1. package/.env.example +0 -15
  2. package/dist/config.js +0 -11
  3. package/dist/index.js +0 -2
  4. package/dist/knowledge/componentCatalog.js +25 -13
  5. package/dist/knowledge/componentEvents.js +6 -13
  6. package/dist/knowledge/normalize.js +17 -68
  7. package/dist/knowledge/rules.js +49 -137
  8. package/dist/knowledge/styleResolve.js +4 -50
  9. package/dist/knowledge/themeResolve.js +3 -3
  10. package/dist/observability/trace.js +1 -1
  11. package/dist/platform/diagnostics.js +4 -10
  12. package/dist/platform/domSummary.js +1 -1
  13. package/dist/platform/http.js +7 -23
  14. package/dist/platform/responses.js +2 -6
  15. package/dist/platform/{capture/capture.js → screenshot.js} +514 -52
  16. package/dist/platform/secrets.js +0 -9
  17. package/dist/platform/strictArguments.js +12 -68
  18. package/dist/platform/tokenVault.js +4 -187
  19. package/dist/resources/examples/workflow-http-step.json +2 -2
  20. package/dist/resources/guides/component.md +1 -6
  21. package/dist/resources/guides/expressions.md +2 -2
  22. package/dist/resources/guides/functions.md +1 -1
  23. package/dist/resources/guides/layout.md +7 -11
  24. package/dist/resources/guides/microfunction.md +28 -0
  25. package/dist/resources/guides/microservice.md +4 -10
  26. package/dist/resources/guides/middleware.md +1 -5
  27. package/dist/resources/guides/page.md +55 -215
  28. package/dist/resources/guides/theme.md +1 -4
  29. package/dist/resources/guides/translation.md +1 -1
  30. package/dist/resources/guides/workflow.md +9 -12
  31. package/dist/resources/schema-fingerprint.json +2 -2
  32. package/dist/resources/schemas/CreateWorkflowCommand.json +3 -0
  33. package/dist/resources/schemas/PreviewWorkflowCommand.json +3 -0
  34. package/dist/resources/schemas/StepDto.json +12 -9
  35. package/dist/resources/schemas/UpdateWorkflowCommand.json +3 -0
  36. package/dist/server.js +1 -3
  37. package/dist/tools/applications.js +3 -60
  38. package/dist/tools/components.js +10 -50
  39. package/dist/tools/datasources.js +1 -1
  40. package/dist/tools/designSchemaPatch.js +6 -16
  41. package/dist/tools/externalComponents.js +4 -25
  42. package/dist/tools/flows.js +6 -79
  43. package/dist/tools/layouts.js +12 -44
  44. package/dist/tools/microservices.js +10 -26
  45. package/dist/tools/pages.js +67 -303
  46. package/dist/tools/platformInfo.js +2 -6
  47. package/dist/tools/rows.js +1 -7
  48. package/dist/tools/schemaOps.js +1 -1
  49. package/dist/tools/screenWrite.js +5 -6
  50. package/dist/tools/screens.js +3 -90
  51. package/dist/tools/workflows.js +1 -1
  52. package/package.json +1 -1
  53. package/dist/knowledge/mobileComponentCatalog.js +0 -801
  54. package/dist/knowledge/mobileComponentEvents.js +0 -225
  55. package/dist/knowledge/platform/lint.js +0 -312
  56. package/dist/knowledge/platform/mobile.js +0 -78
  57. package/dist/knowledge/platform/mobileRules.js +0 -182
  58. package/dist/knowledge/platform/mobileTabs.js +0 -108
  59. package/dist/knowledge/platform/profile.js +0 -20
  60. package/dist/knowledge/platform/resolve.js +0 -122
  61. package/dist/knowledge/platform/web.js +0 -38
  62. package/dist/knowledge/styleResolveNative.js +0 -510
  63. package/dist/platform/argumentAliases.js +0 -128
  64. package/dist/platform/bodyFile.js +0 -103
  65. package/dist/platform/capture/actions.js +0 -333
  66. package/dist/platform/capture/browser.js +0 -1
  67. package/dist/platform/capture/console-log.js +0 -80
  68. package/dist/platform/capture/index.js +0 -11
  69. package/dist/platform/capture/readiness.js +0 -103
  70. package/dist/platform/capture/summary.js +0 -77
  71. package/dist/platform/capture/target.js +0 -5
  72. package/dist/platform/capture/targets/studio-mobile.js +0 -15
  73. package/dist/platform/capture/targets/studio-web.js +0 -5
  74. package/dist/platform/schemaReadMemory.js +0 -60
  75. package/dist/resources/examples/mobile-app-shell-drawer.json +0 -209
  76. package/dist/resources/examples/mobile-app-shell-stack.json +0 -123
  77. package/dist/resources/examples/mobile-app-shell-tab.json +0 -174
  78. package/dist/resources/examples/mobile-list-detail-form.json +0 -656
  79. package/dist/resources/guides/mobile.md +0 -419
  80. package/dist/tools/mobile.js +0 -203
  81. package/dist/tools/profileWrite.js +0 -45
@@ -4,10 +4,6 @@ Studio'nun tuval tarafı. Buradaki kurallar controller + komut kodundan doğrula
4
4
  (`zeyrek-mcp/docs/13-faz2-envanter.md` §4); veri/mantık tarafı için
5
5
  `platform_guide('entity')`, `('microservice')`, `('workflow')`.
6
6
 
7
- > **Mobil uygulamada** (`type: 'mobile'`) şema ve micro-op'lar aynıdır ama yerleşim yalnız flex'tir
8
- > (blocks çizilmez), görünüm tipli gruplarla yazılır ve `page_create` kökü flex sütun kurar —
9
- > `platform_guide('mobile')`. Bu rehberdeki "dar ekran" notları WEB uygulamasının telefon kırılımıdır.
10
-
11
7
  ## Kuruluş sırası
12
8
 
13
9
  ```
@@ -226,7 +222,7 @@ döndürür; hata yok, sayfalama yok. (Bağımsız `pagination` komponenti bu tu
226
222
  | `dropdown.search` · `multi-select.search` | `{ searchText }` | `self.searchText` |
227
223
  | `tabs.tab` | `{ selected }` | `self.selected` ya da `event.data.selected` |
228
224
  | `chart.dataPointClick` | `{ name, seriesName, value, dataIndex, row }` | `self.row` (kaynak satırın tamamı) |
229
- | `repeater.change` · `repeater.select` | `{ selectedIndex }` | `self.selectedIndex` · `self.selectedItem` (akış satır bağlamında koşmaz, `item`/`Row` boş); satırdaki bir düğmenin akışında setter'ın yazım kapsamı OLAYIN kaynağı değil HEDEFİN ağaçtaki yeriyle belirlenir — satırın şablonu içindeki bir hedefe satır bazlı (`_repeaterValues`), dışındaki bir hedefe (modal, sayfa düzeyi metin) sayfa kapsamında yazılır (ZM-08, 2026-09-26); iç içe repeater zaten `PAGE-013` ile reddedilir, ama bir DIŞ repeater'ın şablonuna İÇ satırdan yazan bir akış varsa yazım dış satırın değil İÇ satırın kimliğiyle anahtarlanır — bilinen açık, PAGE-013 riski düşük tutar |
225
+ | `repeater.change` · `repeater.select` | `{ selectedIndex }` | `self.selectedIndex` · `self.selectedItem` (akış satır bağlamında koşmaz, `item`/`Row` boş) |
230
226
  | `html` aksiyonu (`fireEvent`) | ikinci argüman | **`event.data`** |
231
227
  | `kanban.cardMove` | `{ id, row, from, to }` | **`event.data`** (self'e yazılmaz) |
232
228
  | `kanban.cardAdd` · `kanban.cardRemove` | `{ column }` · `{ id, row, column }` | **`event.data`** (self'e yazılmaz; kart eklenmez/gizlenmez, akış yazıp `rows`'u tazeler) |
@@ -249,8 +245,7 @@ dalı bulamaz ve akışı **sessizce durdurur** (`flow-engine.ts:79`); Studio da
249
245
  `sourceBranch === 'always'` ile çizdiği için panelde **Start kartından sonrası boş görünür**.
250
246
  İstisnalar: `condition` → dal adı rule id'sidir (ve o id bir **GUID**'dir — aşağıdaki tuzak 6),
251
247
  `confirm` → `yes|no|always`, `microservice` →
252
- `always` (eski akışlarda `success` de çalışır) **+ `error`** — bağlarsan hata anında `always`
253
- yerine ondan sürer (2026-09-26, ADR 0004; ayrıntı aşağıdaki §"4xx de hatadır").
248
+ `always` (eski akışlarda `success` de çalışır).
254
249
 
255
250
  **2. `iteratees[].type` yalnız `change` | `fill`.** `setter.ts` başka değerde hiçbir dala
256
251
  girmez — adım çalışır, hiçbir şey yapmaz. `change` tek prop'a değer yazar, `fill` diziyi
@@ -376,42 +371,36 @@ Satır eşlemeli tablo yüklemesinin tam şekli (yükleniyor bayrağı → uç
376
371
  göstermek error flow'un işidir.
377
372
 
378
373
  > **4xx de hatadır ve `always` dalı seni KURTARMAZ.** `microservice.ts` `.catch` bloğu
379
- > reddedilen her istekte koşar — 401/403/404/422 dâhil — ve storage'a HER ZAMAN
380
- > `{ data: null, headers: null, error: { status, message, body } }` yazar (ADR 0004,
381
- > 2026-09-26 — eskiden hata gövdesi `data`'ya yazılıyordu). `.finally` sonra ÜÇ yoldan birini
382
- > dener, SIRAYLA:
374
+ > reddedilen her istekte koşar — 401/403/404/422 dâhil. Sonrası iki yoldan biridir ve ikisi de
375
+ > "ekranda hiçbir şey olmadı" ile biter:
383
376
  >
384
- > 1. **Adımın kendi `error` dalı BAĞLIYSA** akış oradan sürer — `always` **hiç koşmaz**
385
- > (`hasBranch('error')`). Bu dal `Steps.<ad>.error` okuyabilir; ana akışın kalanı hiç çalışmaz.
386
- > 2. **`error` dalı yoksa, `errorSteps` VARSA** `engine.onError` true döner ve `.finally` `return`
387
- > eder — yine `always` koşmaz, flow'un hata akışı devralır (aşağıdaki karşılaştırma tablosu).
388
- > 3. **İkisi de yoksa** `always` koşar, ama `Steps.<ad>.data` artık **NULL**dır — başarı gövdesi
389
- > değil, hiç gövde değil. Sıradaki bir `condition` `!!Steps.signIn.data.token` gibi bir
390
- > ifadeyi `null.token` üzerinden dener; `runCode` hatayı yutar (K2), ifade `undefined` döner ve
391
- > akış sessizce diğer dala düşer — `else` dalı bağlı değilse akış orada biter. `data`yı bir
392
- > liste prop'una yazan bir setter artık patlayan bir nesne değil `null` görür (repeater/table
393
- > `null`'ı boş liste sayar), ama hata OLDUĞUNU fark etmeden geçer — gateway bunu **FLOW-028**
394
- > ile uyarır.
377
+ > 1. **Hata yolu VARSA** `engine.onError` true döner ve `.finally` `return` eder —
378
+ > `engine.next('always')` **hiç çağrılmaz**. Yani `always` ile `errorSteps` birbirini dışlar;
379
+ > ikisini birden kuramazsın, hata yolu ana akışın devamını devralır.
380
+ > 2. **Hata yolu YOKSA** `always` koşar, ama storage artık `{ error, data }`'dır ve
381
+ > `Steps.<ad>.data` başarı gövdesi değil **hata gövdesidir**. Sıradaki `condition`
382
+ > `!!Steps.signIn.data.token` gibi bir ifadeyi `undefined` üzerinden değerlendirir, sessizce
383
+ > diğer dala düşer ve `else` dalı bağlı değilse akış orada biter.
395
384
  >
396
385
  > **`errorSteps` yalnız `start` taşıyorsa hata yolu YOKTUR:** `hasErrorFlow`
397
386
  > `errorTasks.some(t => t.type !== 'start')` arar. Start'ın ardına en az bir adım bağla —
398
387
  > gateway `FLOW-021` ile uyarır.
399
388
  >
400
- > **Mobil uygulama:** mobil runtime (`@ng-apps/ui-native` `NativeRuntime`) `errorSteps`'i web gibi
401
- > `errorTasks`'a eşler — hata yolu iki platformda aynı koşar.
389
+ > **Mobilde `errorSteps` diye bir şey YOK.** `ScreenRuntime.tsx` `mapFlowsToMachine` yalnız
390
+ > `tasks` üretir (web `Runtime.svelte` ayrıca `errorTasks` verir), yani mobil uygulamada
391
+ > `hasErrorFlow` her zaman false: hata yolu hiç koşmaz ve akış yukarıdaki 2. yoldan —
392
+ > `always` + hata gövdeli storage — devam eder. Mobil sayfada hata yolunu `condition
393
+ > Steps.<adımAdı>.error` ile kur.
402
394
 
403
- > **Hata metni birden çok yerde durur, hepsi aynı şey değildir (2026-09-26 itibarıyla, ADR 0004).**
395
+ > **Hata metni ÜÇ ayrı yerde durur ve ikisi kullanıcıya gösterilecek metin DEĞİLDİR.**
404
396
  > `onError` hata akışını koşturmadan önce `machine.setStorage('error', errorInfo)` yapar
405
- > (`flow-engine.ts`), yani hata akışının adımları `Steps.error`'ı okuyabilir; patlayan adımın
406
- > KENDİ storage'ı ise (bağlı `error` dalı da `always` da) `Steps.<adımAdı>.error` nesnesini taşır:
397
+ > (`flow-engine.ts`), yani hata akışının adımları `Steps.error`'ı okuyabilir:
407
398
  >
408
399
  > | İfade | Ne taşır | Kaynak |
409
400
  > |---|---|---|
410
- > | **`Steps.error.message`** | **Yalnız `errorSteps` içinde** — ucun kendi mesajı, `err.reason` → HTTP durum metni → `'Service request failed'`. Yanında `Steps.error.code` · `Steps.error.step.name` (patlayan adım) · `Steps.error.step.data` (ucun hata gövdesi; parametre ifadesi patladıysa `null`) gelir | `microservice.ts` `err.reason \|\| HttpStatusText[err.code]` → `flow-engine.ts` `onError` |
411
- > | `Steps.<adımAdı>.error.message` | Patlayan adımın KENDİ storage'ında ucun mesajı — `error` dalında da `always`'te de okunur, sıra aynı: `err.reason` → HTTP durum metni → `'Service request failed'` | `microservice.ts` `.catch` |
412
- > | `Steps.<adımAdı>.error.status` | HTTP durum KODU (sayı) — parametre ifadesi patladıysa `null` | `microservice.ts` `.catch` |
413
- > | `Steps.<adımAdı>.error.body` | Ucun hata gövdesi — eski `Steps.<adımAdı>.data`'nın taşındığı yer | `microservice.ts` `.catch` |
414
- > | `Steps.<adımAdı>.data` | **HER ZAMAN `null`**'dır — başarı gövdesi değil, hiçbir gövde değil (eskiden hata gövdesiydi) | `microservice.ts` `.catch` |
401
+ > | **`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` |
402
+ > | `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]` |
403
+ > | `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` |
415
404
  >
416
405
  > **`alert` adımının `message`'ı DÜZ METİNDİR — ifade yazarsan ekranda o ifade görünür.**
417
406
  > `alert.ts` `task.argument.message`'ı doğrudan `toast.error()`'a geçirir ve `args` hiçbir yerde
@@ -439,24 +428,15 @@ göstermek error flow'un işidir.
439
428
  > `{ "type": "confirm", "args": { "message": "Bu risk ve 4 aksiyonu silinecek.", "title": "Riski sil",
440
429
  > "confirmText": "Sil", "cancelText": "Vazgeç" } }`.
441
430
 
442
- > **Hangi yolu seçeceksin — adımın kendi `error` dalı mı, `errorSteps` mi, ana akışta
443
- > `condition` mı?** Bir hatada sırayla denenir (yukarıdaki 4xx bölümü) — üçü birden TANIMLI
444
- > olabilir ama aynı anda yalnız biri koşar: **`error` dalı bağlıysa o kazanır**, yoksa
445
- > `errorSteps`, ikisi de yoksa `always` + `condition`:
446
- >
447
- > | | adımın kendi `error` dalı (g-02) | `errorSteps` | ana akışta `condition !!Steps.<adımAdı>.error` |
448
- > |---|---|---|---|
449
- > | Kapsam | yalnız BU adımın hatası | akıştaki HERHANGİ bir adımın hatası | yalnız BU adımın hatası |
450
- > | Ana akışın kalanı | **koşmaz** — bu dal devralır | **koşmaz** — hata akışı devralır | koşar, dalı sen seçersin |
451
- > | Yükleniyor bayrağı · modal kapatma · tablo tazeleme | dalda **yeniden kurmak zorundasın** | hata akışında **yeniden kurmak zorundasın**; kurmazsan bayrak açık kalır | zaten ana akışta duruyor |
452
- > | Hata metni | `Steps.<adımAdı>.error.message` | `Steps.error.message` (yukarıdaki tablo) | `Steps.<adımAdı>.error.message`; hata olduğunu `!!Steps.<adımAdı>.error` söyler — `.error.status` parametre ifadesi patladıysa `null`dur, o yolu KAÇIRIR |
453
- > | Ne zaman doğru | hata anında BU adımın sonrası **tamamen başka bir yola** sapacaksa | 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) |
431
+ > **Hangi yolu seçeceksin — `errorSteps` mi, ana akışta `condition` mı?** İkisi birden
432
+ > kurulamaz (yukarıdaki 1. madde), yani bu bir tercih değil bir karar:
454
433
  >
455
- > **"Ana akışta condition" sütunu `.error`'u okumalı, `.data`'yı değil.** `Steps.<adımAdı>.data`'nın
456
- > DOLU/BOŞ olmasına bakarak başarı/hata ayırmak (`data.token` gibi bir alanın varlığını yoklamak)
457
- > artık yanıltıcıdır — `data` hata anında zaten `null`'dur (yukarıdaki §"4xx de hatadır"). Böyle bir
458
- > `condition`'ı gateway **FLOW-028** ile uyarır; adıma ayrıca bir `error` dalı bağlayın (aşağıdaki
459
- > 7c örneği) — `error` dalı bağlıysa uyarı düşer, çünkü hata artık `always`'e hiç uğramaz.
434
+ > | | `errorSteps` | ana akışta `condition Steps.<adımAdı>.error` |
435
+ > |---|---|---|
436
+ > | Ana akışın kalanı | **koşmaz** — hata akışı devralır | koşar, dalı sen seçersin |
437
+ > | 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 |
438
+ > | Hata metni | `Steps.error.message` (yukarıdaki tablo) | `Steps.<adımAdı>.data.message`, hata olduğunu `Steps.<adımAdı>.error` söyler |
439
+ > | 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) |
460
440
 
461
441
  Zorunlu filtresi olan uçlarda (`patient-*`, `doctor-appointments` gibi `isRequired: true`
462
442
  filtreli microservice'ler) parametreyi adımda ver, yoksa uç `MissingParameterException` atar:
@@ -533,21 +513,21 @@ Tarif: `platform_guide('middleware')`.
533
513
 
534
514
  **Sözlükler** (`StepType.cs`, `StepParameterValueType.cs` — hepsi küçük harf):
535
515
  `start · microservice · setter · setcookie · validation · condition · redirect · alert ·
536
- confirm · flow-trigger · storage · navigate · code · download · function · share · end`
516
+ confirm · flow-trigger · storage · navigate · code · download · function · end`
537
517
  değer tipleri: `static · page · property · storage · variable · code · item · state`
538
518
 
539
519
  > **Sözlükte olmak KOŞACAĞI anlamına gelmez — koşan tipler barındırıcıdan gelir.** Motor yedi
540
520
  > tip register eder, gerisini uygulama ekler. Bir sayfa TEK bir uygulamaya aittir
541
521
  > (`Page.ApplicationId`) ve uygulamanın tipi `web` ya da `mobile`'dır (`ApplicationType.cs`), yani
542
522
  > sayfanın barındırıcısı bellidir — matris "hangi tip sende çalışır"ı söyler, iki barındırıcıda
543
- > birden koşmayı değil (web `Runtime.svelte`, mobil uygulama `@ng-apps/ui-native` `NativeRuntime`):
523
+ > birden koşmayı değil (web `Runtime.svelte`, mobil `ScreenRuntime.tsx`):
544
524
  >
545
- > | Adım tipi | Web | Mobil uygulama | Nerede register ediliyor |
525
+ > | Adım tipi | Web | Mobil | Nerede register ediliyor |
546
526
  > |---|---|---|---|
547
- > | `start` · `setter` · `code` · `condition` · `microservice` · `validation` · `flow-trigger` · `function` | ✅ | ✅ | `flow-engine.ts` — motorun kendisi |
548
- > | `alert` · `redirect` · `setcookie` · `storage` | ✅ | ✅ | barındırıcı; mobilde `setcookie` cihaz deposuna yazar (`MOB-005`) |
549
- > | `confirm` · `download` · `share` | ✅ | ✅ | `Runtime.svelte` · `runtime-tasks.ts` (`download` mobilde açma/paylaşım — `MOB-005`; `share` aşağıda) |
550
- > | `navigate` | ❌ | ✅ (`redirect` takma adı) | web'deki karşılığı `redirect`; gateway `redirect`'e çevirir |
527
+ > | `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) |
528
+ > | `alert` · `redirect` · `setcookie` · `storage` | ✅ | ✅ | uygulama; mobilde `redirect` navigate, `setcookie` storage uygulamasına eşlenir |
529
+ > | `confirm` · `download` | ✅ | ❌ | yalnız `Runtime.svelte` |
530
+ > | `navigate` | ❌ | ✅ | yalnız `ScreenRuntime.tsx` — web'deki karşılığı `redirect` |
551
531
  > | `end` · `query` | ❌ | ❌ | hiçbir yerde — üstelik `query` backend sözlüğünde de yok (`StepType.cs` onu saymaz), yalnız frontend enum'unda duruyor |
552
532
  >
553
533
  > **Register edilmemiş bir tipe gelen akış SESSİZCE durur.** `flow-engine.ts` `process()`
@@ -583,19 +563,6 @@ değer tipleri: `static · page · property · storage · variable · code · it
583
563
  > adımında ve `{{ }}` bağlamasında `Functions.<ad>(…)` ile de çağrılır; gateway bilinmeyen adı ve
584
564
  > fazla argümanı FLOW-025 ile uyarır. Tam gövde `ngapps://examples/flow-call-function`, kurallar
585
565
  > **`platform_guide('functions')`**.
586
- >
587
- > **`share` adımı ("Share")** metin ve bağlantı paylaşır: `args: { title, message, path }`. `title`
588
- > DÜZ METİNDİR (ifade yazılırsa FLOW-022 uyarır); `message` ve `path` `storage.value` gibi
589
- > İFADEDİR — düz metin tırnak ister (`"'Şuna bak'"`, `"'https://…/urun/' + Page.queryParams.id"`).
590
- > Bağlantının adı `url` DEĞİL `path`'tir: backend `Title`/`Message`/`Path` alanlarında saklar ve
591
- > tanımadığı anahtarı 200 ile sessizce düşürür (FLOW-027 `url`/`link`/`text`'i ve tırnaksız adresi
592
- > bloklar). Bağlantı ŞEMALI TAM ADRES olmalı (`https://…`, `mailto:…`): şemasız değer (`www.…`,
593
- > `urun/42`) adres sayılmaz, metnin sonuna eklenir. İfadenin sonucu yalnız dize ya da sayıysa
594
- > paylaşılır; `false` (`koşul && 'x'`), `null` ve nesne boş sayılır. Cihazda paylaşım sayfası açılır
595
- > (Android'de bağlantı metnin sonuna eklenir), web'de tarayıcının paylaşım penceresi, yoksa ya da
596
- > reddederse metin + bağlantı panoya yazılır ve bildirim çıkar. Tek dal `always`: iOS'ta sayfa
597
- > kapanınca, Android'de seçici açılır açılmaz (RN seçicinin kapanışını bildirmez) sürer; metin de
598
- > bağlantı da boşsa hiçbir şey açılmaz, akış hemen sürer.
599
566
 
600
567
  > Bir microservice adımı kaydedildiğinde platform `args.microserviceSchema`'yı
601
568
  > (parameterScheme + returnScheme + `isReturnArray`) kendisi doldurur — `flow_get` ile geri
@@ -894,7 +861,7 @@ kullanır: `page.mappers.ts` `mapPageLayoutToPreview` — layout varsa çizilen
894
861
  > `add_component` ile yeniden kurmaktır (sonrasında Kural 2'deki flow yeniden kaydetme adımı
895
862
  > ZORUNLU olur).
896
863
 
897
- Dar ekran notu: <768px'te ızgara tek kolona düşer (`RenderComponent` media query'si) — y sırası
864
+ Mobil not: <768px'te ızgara tek kolona düşer (`RenderComponent` media query'si) — y sırası
898
865
  dikey sıraya dönüşür, x/w yok sayılır. Yerleşimi masaüstü (breakpoint 1024) bloğuyla kur.
899
866
 
900
867
  ## Kural 1f-2 — Kapsayıcı düzeni: `flex` (varsayılan) ↔ `grid`
@@ -983,10 +950,10 @@ Beş şeyi bilmeden flex kurma:
983
950
  4. **`layout: 'grid'` iken diğer altı prop ÖLÜDÜR.** Katalogda tanımlı oldukları için
984
951
  doğrulama duvarı susar, renderer da okumaz: ızgara kapsayıcıya `direction: 'column'` yazmak
985
952
  sessizce hiçbir şey yapmaz. Gateway bunu **PAGE-015 (uyarı)** ile söyler.
986
- 5. **Flex düzeni kırılım BİLMEZ.** `direction`/`gap`/hizalama masaüstü ve dar ekranda AYNIDIR;
987
- sıra ve span'lar Desktop (1024) bloğundandır — Studio, dar ekran kırılımı düzenlenirken flex
953
+ 5. **Flex düzeni kırılım BİLMEZ.** `direction`/`gap`/hizalama masaüstü ve mobilde AYNIDIR;
954
+ sıra ve span'lar Desktop (1024) bloğundandır — Studio, mobil kırılım düzenlenirken flex
988
955
  bölgeyi salt-okunur kilitler. Kırılım bilen yalnız `blocks[]` ve `appearance.hideOn`'dur;
989
- dar ekranda farklı davranış gereken satır için `layout: 'grid'` kullan (Kural 1f dar ekran notu).
956
+ mobilde farklı davranış gereken satır için `layout: 'grid'` kullan (Kural 1f mobil notu).
990
957
 
991
958
  ```jsonc
992
959
  // Ortalanmış giriş kartı — style ile CSS hack'i YOK, kabın kendi düzeni
@@ -1113,22 +1080,15 @@ UYGULAMAZ** — koordinatları aynen kaydeder (aşağı itme yalnız `page_creat
1113
1080
  > SONRAKİ ağaca bakarak. Layout'ta da geçerlidir: kırılma
1114
1081
  > `_repeaterValues` geri yazmasındadır, barındıranın sayfa mı layout mu olduğuna bakmaz.
1115
1082
  >
1116
- > **Mobil uygulamada** başlıklar altında gruplu liste (güne/kategoriye göre) iç içe repeater
1117
- > gerektirmez: tek `grouped-list` (`groupBy` + başlık `{{ Section.title }}` + öğe şablonu) —
1118
- > `platform_guide('mobile')` §Güne göre görev listesi. PAGE-013 mesajı mobilde bunu önerir.
1119
- >
1120
1083
  > **Yapılacak:** satır içi listeyi tek bir `textarea`'da **satır başına bir öğe** olarak topla
1121
1084
  > (`options_text`), kaydederken `split('\n')`'le böl. Ölçülmüş çalışan sürüm: anket editörü
1122
1085
  > (`anket-admin/anket-duzenle`). Gerçekten satır satır düzenleme gerekiyorsa iç listeyi AYRI bir
1123
1086
  > sayfada/modalda yönet — iç içe repeater bunu karşılamıyor.
1124
1087
 
1125
1088
  > **Repeater satırını akıştan silmek/eklemek:** repeater ÇOCUĞUNDAKİ bir butonun click akışında
1126
- > tıklanan satır olay makineye gitmeden SEÇİLİR, yani `q_list.selectedIndex` o satırdır — her runtime
1127
- > sürümünde. Hedef repeater'ın KENDİSİ olduğu için `rows`'a yazmak serbesttir (`isRepeaterSelf` dalı
1128
- > satır-değeri yoluna girmez). Desen:
1129
- > `q_list.rows = (q_list.rows || []).filter(function(r, i){ return i !== q_list.selectedIndex; })`.
1130
- > `RowIndex` de aynı satırı verir, ama yalnız ARC-121 düzeltmesini (2026-09-27) taşıyan runtime'da;
1131
- > eskisinde akışta tanımsızdı.
1089
+ > `RowIndex` doğru satırı verir, ve hedef repeater'ın KENDİSİ olduğu için `rows`'a yazmak serbesttir
1090
+ > (`isRepeaterSelf` dalı satır-değeri yoluna girmez). Ölçülmüş desen:
1091
+ > `q_list.rows = (q_list.rows || []).filter(function(r, i){ return i !== RowIndex; })`.
1132
1092
  > Ekleme aynı şekilde `.slice()` + `push` ile yapılır; satır numarasını ekledikten sonra yeniden ata.
1133
1093
 
1134
1094
  **Gönderimi saklamak:** satır başına normalize kayıt yerine tek `TEXT` kolonda anlık görüntü
@@ -1137,45 +1097,6 @@ kendisi nesneye çevirir; Studio tablosunda `[object Object]` görünmesi normal
1137
1097
  (`platform_guide('entity')` → "TEXT kolonunda JSON"). Ekranın görsel tarafı için **Kural 1h**:
1138
1098
  tema `--ng-*` değişkenleriyle tek yerden çevrilir, `html` kaçış kapısına gerek kalmaz.
1139
1099
 
1140
- ## Kural 1g-2 — Mobil davranış: dört ayar, dört ayrı sahip
1141
-
1142
- Mobil listelerin davranışı TEK bileşende toplanmaz. Hangi ayarın kimde olduğunu bilmeden yazılan
1143
- şema sessizce çalışmaz — prop var olmayan bileşene yazılır ve `page_schema_patch` onu düşürmez,
1144
- çizer yok sayar.
1145
-
1146
- | Davranış | Sahip bileşen | Prop / olay |
1147
- |---|---|---|
1148
- | Çekerek yenile | `scroll-view` (listeyi SARAN kap) | `refreshable: true` + `refresh` olayı |
1149
- | Sonsuz kaydırma | `scroll-view` | `scrollEnd` olayı (prop yok) |
1150
- | Kaydırma eylemleri | `repeater` | `swipeActions: [{ key, label, tone, icon }]` + `swipe` olayı, payload `{ key, index, row }` |
1151
- | Satıra dokunma | `repeater` | `itemPressable: true` + `itemPress` olayı, payload `{ index, row }` |
1152
-
1153
- Çekerek yenileyi `repeater`'a yazmak en sık hatadır: liste kendi kaydırmasını yapmaz, onu saran
1154
- `scroll-view` yapar. `repeater` kökteyse (kap yok) yenileme hiç çizilmez.
1155
-
1156
- Satıra dokunmanın kartın `click`'iyle yapılan eski yolu mobilde bırakıldı: `itemPress` satır
1157
- bağlamını payload'da taşır ve seçimi (`selectedIndex`) de yazar, yani akış satırı
1158
- `<tekrarlayıcı>.selectedItem` ile okumaya devam eder.
1159
-
1160
- ### `redirect.presentation`
1161
-
1162
- `redirect` adımının `args.presentation` alanı ekranın NASIL açıldığını söyler ve kapalı bir küme
1163
- alır:
1164
-
1165
- - `push` — yığına ekler, geri düğmesi önceki ekrana döner (**varsayılan**; alan yazılmayabilir)
1166
- - `modal` — alttan açılan ayrı bir sunum; geri onu kapatır, altındaki ekran yerinde kalır
1167
- - `replace` — geçerli ekranı değiştirir, geçmişe girmez (giriş → ana ekran için doğru olan)
1168
-
1169
- Küme dışı bir değer **MOB-008** uyarısıdır ve backend doğrulayıcısı 422 döner. Alanı hiç yazmamak
1170
- kusur değildir.
1171
-
1172
- **Sekme hedefinde `modal` çalışmaz.** Hedef sayfa bir sekmeyse gezinme her zaman `navigate`'e
1173
- düşer: sekme yığını kendi geçmişini tutar ve modal onu kırardı. `presentation`ı yazabilirsiniz,
1174
- çizer sessizce yok sayar — sekme dışı bir sayfaya modal istiyorsanız o sayfayı sekme listesinden
1175
- çıkarın.
1176
-
1177
- Web uygulamasında alan yok sayılır; gateway web profilinde bu konuda bulgu üretmez.
1178
-
1179
1100
  ## Kural 1h — Tasarım: `style` prop'u ve tema değişkenleri
1180
1101
 
1181
1102
  Her komponentin `style` prop'u vardır ve emotion `css()` bloğudur: iç seçiciler, pseudo-class'lar
@@ -1402,16 +1323,6 @@ alanları silinir. Gateway bu yüzden `page_update`'te sayfayı önce okur, yaln
1402
1323
  alanları değiştirip tam gövdeyi geri yazar (`layout_update` ve `component_update` de aynı).
1403
1324
  Yine de `schema` parametresini elle doldurursan okuduğun hâli değil, **verdiğin liste** yazılır.
1404
1325
 
1405
- **`page_update` sürümsüz yazmaz (PAGE-039).** Platform sayfa PUT'unu `baseVersion` olmadan reddeder.
1406
- `baseVersion` vermezsen gateway bu sayfada en son gördüğü sürümü gönderir: `page_get` ya da
1407
- `page_schema_get` yanıtındaki `version`, `page_schema_patch`'in `newVersion`'ı ya da önceki
1408
- `page_update`'in yazdığı sürüm. Hiçbiri yoksa istek **gönderilmez** — önce oku. Sayfa o sürümden beri
1409
- değiştiyse (Studio'da açık sekme, başka ajan) 409 döner; mesaj güncel sürümü ve son yazmayı (zaman,
1410
- kullanıcı, kaynak, revizyon) söyler ve hiçbir şey yazılmaz. Doğru yol yeniden okuyup değişikliği
1411
- `page_schema_patch` ile yapmaktır; aradaki değişikliği bilerek ezmek için `force: true` son sürümü
1412
- okuyup onun üstüne yazar ve yanıt `forced: true` taşır. Sebep: Bitki Bakım koşusunda sürümsüz bir
1413
- tam gövde yazımı ana sayfayı ve profili boşalttı, akışları sildirdi (14:02).
1414
-
1415
1326
  ### Atomiklik: 500 KB'lık şemada tek komponente dokunmak
1416
1327
 
1417
1328
  `page_schema_patch` şemanın tamamını göndermez — yalnız op'ları gönderir. Tam gövde ne LLM
@@ -1421,8 +1332,7 @@ ve geri yazar. Sözleşme (`PatchPageSchemaCommandHandler`):
1421
1332
  | Aşama | Ne yapar |
1422
1333
  |---|---|
1423
1334
  | Kilit | Sayfa başına 60 sn'lik dağıtık kilit; başka bir aktör yazıyorsa istek `PageSchemaLockedException` ile döner (409) |
1424
- | Sürüm | `baseVersion` verdiysen `UpdatedAt.Ticks` ile karşılaştırılır; tutmazsa `PageSchemaVersionConflictException` (409) ve **hiçbir op uygulanmaz** — bütün op'lar etkisizse hariç (aşağıdaki "Tekrar" satırı) |
1425
- | Tekrar | `add_component`'in `elementId`'si zaten varsa ve düğüm istenen ebeveynde, istenen içerikle duruyorsa op **etkisizdir** (hata değil; konum karşılaştırılmaz). Hedef düğümü değiştirmeyen `replace_prop`/`set_*`/`add_event` da etkisizdir. Bütün op'lar etkisizse yama yazılmaz, sürüm artmaz ve eski `baseVersion`'a rağmen 200 `noop: true` döner; sürüm eskiyse `stale: true` ve `newVersion` sizin gönderdiğinizdir. Aynı id'de farklı düğüm hâlâ 422 `duplicate-id`'dir |
1335
+ | Sürüm | `baseVersion` verdiysen `UpdatedAt.Ticks` ile karşılaştırılır; tutmazsa `PageSchemaVersionConflictException` (409) ve **hiçbir op uygulanmaz** |
1426
1336
  | Uygulama | Her op hedefini ağaçta arar (`Find` → JSON Pointer) ve **yalnız o düğüme** dokunur; kardeşler, üst düğümler ve diğer alt ağaçlar bit düzeyinde korunur |
1427
1337
  | Hep-ya-hiç | Op'lar önce bellekte uygulanır; **tek bir hata** (bilinmeyen op, bulunamayan hedef, tekrar eden elementId, doğrulama) tüm komutu düşürür — kısmi yazma yoktur |
1428
1338
  | Doğrulama | Tam şema `PageSchemaValidator`'dan geçer (422 + alan bazlı `errors`) |
@@ -1431,18 +1341,7 @@ ve geri yazar. Sözleşme (`PatchPageSchemaCommandHandler`):
1431
1341
 
1432
1342
  Yanıt üç alan döner: `applied` (uygulanan op sayısı), **`appliedPatch`** (her op'un şemada tam
1433
1343
  olarak hangi JSON Pointer'a ne yaptığı — RFC 6902 biçiminde; "gerçekten yalnız o komponente mi
1434
- dokunuldu" sorusunun kanıtı) ve **`newVersion`** (`UpdatedAt.Ticks`). Etkisiz op varsa `unchanged`
1435
- (elementId listesi) ve `alreadyApplied` cümlesi gelir; hepsi etkisizse `noop: true`.
1436
-
1437
- **Yanıt kaybolursa aynı gövdeyle tekrarla.** Ağ koptu, zaman aşımı oldu ve yamanın uygulanıp
1438
- uygulanmadığını bilmiyorsan aynı `page_schema_patch`'i **aynı gövde ve aynı `baseVersion`** ile
1439
- yeniden gönder. Uygulanmışsa `noop: true` + `alreadyApplied` döner, hiçbir şey ikinci kez yazılmaz;
1440
- uygulanmamışsa yama şimdi uygulanır. `add_component` (gövdede `id` verme — platform her istekte yeni
1441
- `id` üretir, karşılaştırma onu yok sayar), aynı değeri yazan `replace_prop`/`set_*` ve aynı bağı kuran
1442
- `add_event` tekrarda etkisizdir. İki istisna: `remove_component` ikinci kez `unknown-target` döner — o
1443
- durumda `page_schema_get` ile bak; eklediğin düğümün bir prop'unu aynı yamanın sonraki op'u
1444
- değiştirdiyse tekrar `duplicate-id` alır. Yanıt `stale: true` taşıyorsa sayfa sürümünden beri başka bir
1445
- yazımla da değişmiştir: devam etmeden önce yeniden oku. `idempotencyKey` yoktur ve gerekmez.
1344
+ dokunuldu" sorusunun kanıtı) ve **`newVersion`** (`UpdatedAt.Ticks`).
1446
1345
 
1447
1346
  > **`appliedPatch` gövdesi VARSAYILAN OLARAK iskelettir.** Girdi `{ op, path }` döner; eklenen
1448
1347
  > düğüm `component` altında yalnız `id`/`elementId`/`name`/`type`/`children` taşır. Kanıt zaten
@@ -1462,29 +1361,12 @@ yamanın `baseVersion`'ıdır. Kontrol platformda atomiktir (satır kilidi + sü
1462
1361
  `UPDATE`'te), yani iki çağrı arasına giren yazarı da yakalar. `baseVersion` vermezsen gateway yalnız
1463
1362
  bu çağrıda zaten okuduğu sayfanın sürümünü gönderir; hiç okumadıysa yama sürümsüz gider ve son
1464
1363
  yazan kazanır. Eski `expectedUpdatedAt` hâlâ çalışır ama `baseVersion`'ın yerini tutmaz.
1465
-
1466
- **Studio da sürüm gönderir (2026-09-26, ZM-27).** Önceden Studio'da açık kalan bir sekme, yayını
1467
- kaçırdığı yamalarının üstüne kendi eski (bir kez boş) şemasını yazıyor ve bağı kalmayan akışları
1468
- sildiriyordu. Artık Studio'nun her kaydı sürüm taşır: eski sekme 409 alır ve taslağını senin
1469
- yazdığının üstüne birleştirir. `revision_list`'te yamandan sonra `source: studio` satırı görürsen bu
1470
- artık bir üzerine yazma değil, birleştirilmiş bir kayıttır — yine de `revision_diff` ile bak.
1471
1364
  Yanıttaki `touched`, kaydı değişen elementId'leri listeler (eklenen alt ağaç dâhil).
1472
1365
 
1473
1366
  > **Büyük şemada çalışma sırası:** `mode:'summary'` ile ağacı çıkar (props yok, 500 KB'lık sayfada
1474
1367
  > bile küçük) → hedefin `elementId`'sini al → gerekiyorsa `mode:'subtree'` ile yalnız o dalı oku →
1475
1368
  > op'ları `page_schema_validate` ile kuru koştur → `page_schema_patch`. `mode:'full'` yalnız
1476
1369
  > gerçekten tüm şema gerektiğinde çağrılır.
1477
- >
1478
- > **`full` sığmazsa hata verir, kırpmaz.** Yanıt boyut sınırını aşan şemada `mode:'full'` hata döner
1479
- > ve düğüm sayısını söyler. Tamamı gerekiyorsa `cursor:'0'` ile oku ve `nextCursor` gelmeyene kadar
1480
- > sür: her parça `items[]` taşır, kalem `parentElementId` düğümünün `children[index]`'inin yerine
1481
- > geçer (`parentElementId` yoksa kök dizinin `[index]`'i); alt ağacı sığmayan düğüm kabuk gelir
1482
- > (`children: [{ elementId, deferred: true }]`) ve sonraki kalemler onu doldurur. Toplanan düğüm sayısı
1483
- > `nodeCount`'a eşit değilse okuma eksiktir. Okuma arasında sayfa değişirse 409 — baştan başla.
1484
- > `allowTruncated:true` kırpılmış gövdeyi açıkça verir (`truncated: true`); o gövdeye dayanan
1485
- > `page_schema_patch` PAGE-038 uyarısı taşır. **`page_update`'e kırpık ya da yarım şema gönderme:**
1486
- > PUT tam REPLACE'tir, eksik düğümler geri dönüşsüz silinir — gateway düğüm eksilten şemayı
1487
- > `allowNodeLoss:true` olmadan PAGE-037 ile reddeder.
1488
1370
 
1489
1371
  > **`remove_component`'in yan etkisi — tek istisna.** Sayfa kaydedilirken artık hiçbir komponent
1490
1372
  > olayının, prop'unun ya da sayfa olayının referans vermediği akışlar platformca **kalıcı olarak
@@ -1909,24 +1791,15 @@ page_container
1909
1791
  ```
1910
1792
  start → [setter] btn.isLoading = true, btn.isDisabled = true, notification gizle
1911
1793
  → [microservice] sign-in (POST; email + password body'den)
1912
- ├─ error → [setter] btn.isLoading=false, btn.isDisabled=false,
1913
- │ notification.content =
1914
- │ { type:'code', ref:'Steps.signIn.error?.message ?? "Giriş başarısız"' }
1915
- └─ always → [condition] !!Steps.signIn.data.token
1916
- ├─ always → [setter] buton durumunu sıfırla
1917
- ├─ if → [setcookie] { name:'APP_Token', value:'Steps.signIn.data.token',
1918
- │ expiresInHours: 240 }
1919
- │ → [redirect] hedef sayfaya
1920
- └─ else → [setter] notification.content =
1921
- { type:'code', ref:'Steps.signIn.error?.message ?? "Giriş başarısız"' }
1794
+ → [condition] !!Steps.signIn.data.token
1795
+ ├─ always → [setter] buton durumunu sıfırla
1796
+ ├─ if → [setcookie] { name:'APP_Token', value:'Steps.signIn.data.token',
1797
+ │ expiresInHours: 240 }
1798
+ │ → [redirect] hedef sayfaya
1799
+ └─ else → [setter] notification.content =
1800
+ { type:'code', ref:'Steps.signIn.data.message || "Giriş başarısız"' }
1922
1801
  ```
1923
1802
 
1924
- - **`sign-in` adımının `error` dalı burada ZORUNLUDUR, süs değil.** Dal bağlı değilken bu şablonun
1925
- `condition`'ı `Steps.signIn.data.token`'ı okur ve gateway'i **FLOW-028** ile uyarır (yukarıdaki
1926
- "Hangi yolu seçeceksin" notu): hata anında `data` `null`'dur, token okuması sessizce `undefined`
1927
- döner. Dal bağlanınca hata onun üzerinden sürer — `always`/`condition` yalnız BAŞARIDA çalışır,
1928
- yani `data.token` orada gerçek bir iş kuralıdır (uç 200 dönüp token'sız yanıt verirse), hata
1929
- algılama YÖNTEMİ değil.
1930
1803
  - **Cookie adı middleware'in okuduğu adla birebir aynı olmalı** (`cookie.APP_Token` —
1931
1804
  `platform_guide('middleware')` Tarif 1). Uyuşmazlık sessizce "hep 401" demektir.
1932
1805
  - `redirect` adımı `isRaw: true` iken `path` **çok satırlı JS bloğudur** (son ifade değeri döner) —
@@ -2116,14 +1989,9 @@ hiçbiri** bağlı değildi; üç portalın da rol menüsü boş çıkıyor, pan
2116
1989
  > (`dto_get` ile bak: genelde `role`, `role_name`, `roles_csv` vardır). Sayfa tarafında CSV
2117
1990
  > kullan — ayrıntı ve şablon `platform_guide('expressions')` §2.
2118
1991
  >
2119
- > **Uç hata dönerse `.data` NULL'dur, hata gövdesi değil (ADR 0004, 2026-09-26).** 2026-09-26'ya
2120
- > kadar `Steps.x.data` 401/404 sonrası hata gövdesiydi ve `rows || []` bunu yakalamıyordu (nesne
2121
- > truthy) → `rows.filter is not a function` / `(items ?? []).map is not a function`; artık uç hata
2122
- > dönünce `data` **null**'dur ve bu adım boş veriyle koşar — `rows` gibi bir listeye bağlarsan
2123
- > bileşen `null`'ı boş liste sayar, `Array.isArray(...) ? ... : []` sarmalamaya artık gerek yok.
2124
- > Hata OLDUĞUNU fark etmeden geçmemek için `error` dalı bağlayın (yukarıdaki §"4xx de hatadır",
2125
- > gateway bunu bağlı değilken **FLOW-028** ile uyarır); hata gövdesini görmek istiyorsan
2126
- > `Steps.x.error.body`'yi okuyun.
1992
+ > **Uç hata dönerse `.data` dizi değildir.** 401/404 sonrası `Steps.x.data` bir nesnedir ve
1993
+ > `rows || []` bunu yakalamaz (nesne truthy) → `rows.filter is not a function` /
1994
+ > `(items ?? []).map is not a function`. `Array.isArray(Steps.x?.data) ? Steps.x.data : []` yaz.
2127
1995
 
2128
1996
  ## ⚠️ `page_schema_patch` `html` komponentini reddediyor — katalogda mükerrer kayıt (2026-08-19)
2129
1997
 
@@ -2186,31 +2054,6 @@ micro-op hattına dönün.
2186
2054
  > uyarı yoktu. Silinmesini bilerek istiyorsanız çağrıyı `allowFlowDeletion: true` ile tekrarlayın;
2187
2055
  > yanıt `deletedFlows` ile hangi akışların gittiğini listeler.
2188
2056
  >
2189
- > **Silinen akış geri kurulabilir (2026-09-26, ZM-27).** Sayfa kaydının sildiği akış artık revizyon
2190
- > defterine `operation: delete` satırı olarak düşer (kaynağı `studio` ya da `mcp`). `flow_restore`
2191
- > akışı son revizyonundaki ad, slug ve adımlarla AYNI id ile yeniden kurar; olaya bağlamaz —
2192
- > geri geldikten sonra `set_event`. İki sınır: revizyon saklama süresi (budanan akış 404) ve
2193
- > adımların hedeflediği komponentler — akış bir komponenti tetikleyen/parametre olarak
2194
- > gösteriyorsa o komponent şemada durmalıdır (canlı ölçüldü: `flow_restore` "Trigger Element Id"
2195
- > dış anahtarına çarpar).
2196
- >
2197
- > **Boşalan sayfa: `page_restore` (2026-09-26).** Sayfayı ve akışlarını birlikte geri kurar:
2198
- > `revision_list(module: 'page', recordId: <pageId>)` → boşalmadan önceki revizyonu bul (`source` ve
2199
- > `correlationId` yardım eder; `revision_get` ile içeriğine bak) → `page_restore({ revisionNo })`.
2200
- > Platform önce eksik akışları adımsız kurar, sonra şemayı eski komponent id'leriyle yazar, sonra
2201
- > adımları yazar — akış→komponent ve olay→akış dış anahtarları bu sırayla tek transaction'da çözülür.
2202
- > Yanıt `restoredFlows` ve `deletedFlows` (N'den sonra bağlanmış, şimdi yetim kalan) döner.
2203
- > Revizyonu kalmamış bir akış varsa 409 ve hiçbir şey yazılmaz.
2204
- >
2205
- > **Doğru revizyonu seç.** Şemayı yüklemeyen komutların (`UpdateProjectCommand`,
2206
- > `UpdateApplicationCommand`…) yazdığı sayfa revizyonları komponent taşımaz; komponenti olan sayfayı
2207
- > böyle bir revizyona döndürmek 409 `PageRevisionEmptyException` ile reddedilir (bilerek boşaltmak için
2208
- > `allowEmpty: true`). `correlationId`'si `PatchPageSchemaCommand` ya da `UpdatePageCommand` olan
2209
- > revizyonu seç. İki sınır daha: N'den beri silinen layout/rol/middleware/özel komponent ya da başka
2210
- > sayfanın aldığı slug geri yüklemeyi dış anahtar/benzersizlik hatasıyla düşürür (transaction geri
2211
- > alınır, veri kaybı yok); yalnız başka bir akışın adımından çağrılan (olaya bağlı olmayan) akışlar
2212
- > geri kurulmaz — onlar için `flow_restore`.
2213
- >
2214
2057
  > **FLOW-018 artık silinen düğümün ALT AĞACINI da görüyor.** Eskiden yalnız op'un kendi
2215
2058
  > `target`'ına bakılıyordu: bir kapsayıcı silinince ÇOCUĞUNA yazan setter sessizce kopuyor ve
2216
2059
  > uyarı hiç çıkmıyordu (09-05, `sign_in_form` → `btn_sign_in`).
@@ -2254,9 +2097,6 @@ micro-op hattına dönün.
2254
2097
  style + Kural 1h deseniyle yeniden kurulunca kart 400px'e ve ortaya oturdu. Gateway bunu **PAGE-014 (uyarı)** ile
2255
2098
  yanıtın `layoutWarnings` alanında bildirir. **Düzeni `style` ile kurmaya hiç kalkışma:**
2256
2099
  ortalama/yaslama/aralık işi kapsayıcının kendi `layout: 'flex'` prop grubuna aittir (Kural 1f-2).
2257
- **İstisna `html`:** onun `style`'ı yazarın işaretlemesine kapsamlı giren CSS metnidir (web'de iç
2258
- seçicili sınıf, mobilde belgenin stil bloğu) — string asıl biçimdir ve PAGE-014 onda susar. Mobilde
2259
- `html`'e nesne `style` verme: çizilmez (MOB-002).
2260
2100
  - **Menüde "bulunduğun sayfa" vurgusu: `sidebar`/`layout`'ta `activeHref`, `header`'da
2261
2101
  `activeNavHref`.** `sidebar` ve `layout` menü ağacını ortak renderer'la çizer: `activeHref` boşken
2262
2102
  tarayıcıdaki adrese uyan satırı kendileri vurgular, prop yazılırsa o satır vurgulanır (akıştan
@@ -98,10 +98,7 @@ theme_update({ theme: {
98
98
  ```
99
99
 
100
100
  **Yazı tipi ve ölçek:** `fontFamily` panelin Google Fonts listesinden bir ad olmalı — runtime
101
- fontu ADIYLA Google'dan çeker, tanınmayan ad sessizce sans-serif'e düşer (THEME-008). Mobilde de
102
- aynı kural geçerlidir: cihaz aynı adı Google Fonts'tan TTF olarak indirip `expo-font` ile yükler
103
- (400 ve 700 kalınlık) — Android'de kalın yüz SENTETİKTİR (iOS gerçek kalın dosyayı çizer,
104
- ZM-10, 2026-09-26).
101
+ fontu ADIYLA Google'dan çeker, tanınmayan ad sessizce sans-serif'e düşer (THEME-008).
105
102
 
106
103
  ```jsonc
107
104
  theme_update({ theme: {
@@ -208,7 +208,7 @@ gerekmez — `schema.ts`'e dokunulmaz, katalog yeniden yüklenmez.
208
208
  `translation_update` artık uygulamanın bütün sayfalarının önbellek satırlarını düşürüyor
209
209
  (`RefreshPageCacheWhenTranslationChangedCommand`), okuma yolu cache-aside olduğu için bir
210
210
  sonraki `page_runtime_get` taze değeri kurar. Yazmadan hemen sonra okuyabilirsin.
211
- - Mobil uygulama runtime'ı (`@ng-apps/ui-native`, Expo) web ile aynı sözlüğü ve motoru kullanır (2026-09-25, plans/mobil-coklu-dil): `language-selector` mobil katalogda, cihazda dil sırası uygulama içi seçim → kayıtlı seçim → cihaz dili → varsayılan (`?lang` yalnız `/preview`'da), seçim uygulama çapında ve kalıcı, sekme etiketi `t:<anahtar>`, `X-Data-Language` sonraki isteklerle gider. Ayrıntı `platform_guide('mobile')` §Çok dil.
211
+ - Mobil runtime (`apps/mobile`) bu özelliği henüz beslemiyor — yalnız web.
212
212
 
213
213
  ## Backend doğrulama sınırları (TR-001)
214
214
 
@@ -373,7 +373,7 @@ gidilir, hiçbiri tutmazsa `else` dalı yürür:
373
373
 
374
374
  | Step | workflow | automation | middleware |
375
375
  |------|:-:|:-:|:-:|
376
- | start, condition, code, loop, table, query, http, workflow, email, file-upload | ✓ | ✓ | ✓ |
376
+ | start, condition, code, loop, table, query, http, workflow, microfunction, email, file-upload | ✓ | ✓ | ✓ |
377
377
  | variable (Set Variable), set-user, setcookie, redirect | – | – | ✓ |
378
378
  | response | ✓ | – | ✓ |
379
379
  | convert | ✓ | – | – |
@@ -426,13 +426,15 @@ bakar (`HttpStep.cs:32,42,59`).
426
426
  | Yanıt JSON değil | Gövde **sessizce** boş nesne olur (`:92`) — XML dönen uçtan veri de hata da alamazsınız |
427
427
  | Adım adında boşluk | Çıktıya adım adıyla erişilir; ad geçerli JS tanımlayıcısı olmalı (`call_roles`, `Call Roles` değil) |
428
428
 
429
- **Çıktıyı okurken şemaya değil ölçüme güvenin (2026-09-16).** `workflow_step_schema('http')`
430
- `returnScheme`'i kök seviyede `{ httpStatusCode, data }` ilan eder, ama koşumda ifade bağlamındaki
431
- adım `{ data, meta: { elapsedTime, httpStatusCode, totalCount }, error }` şeklindedir:
429
+ **Çıktının şekli (ölçüldü 2026-09-16).** Koşumda ifade bağlamındaki adım
430
+ `{ data, meta: { elapsedTime, httpStatusCode, totalCount }, error }` şeklindedir.
431
+ `workflow_step_schema('http')` `returnScheme`'i yalnız gövdeyi anlatır — adsız, tipsiz
432
+ (`anonymous`) tek girdi, çünkü dış yanıtın şekli bilinmez; zarf her adımda aynıdır ve şemada
433
+ yer almaz:
432
434
 
433
435
  - gövde → **`<adım>.data`**
434
436
  - durum kodu → **`<adım>.meta.httpStatusCode`**
435
- - `<adım>.httpStatusCode` → **undefined** (şemanın vaat ettiği ad çalışmaz)
437
+ - `<adım>.httpStatusCode` → **undefined**
436
438
 
437
439
  Tam örnek ve POST varyantı: `ngapps://examples/workflow-http-step`.
438
440
 
@@ -519,6 +521,7 @@ Tek uçta "başlık + N alt kayıt" yazmanın yolu budur (anket + sorular + seç
519
521
  `fields[].value` / `filters[].value` ifadelerinde `loopItem.<alan>` yazılır (ölçüldü 2026-09-16:
520
522
  `table` çocuğunun filtresinde `loopItem.slug` → `'super-admin'`); `input` ve önceki adımlar
521
523
  (`createSurvey.data.id`) da görünmeye devam eder.
524
+ - **`microfunction` çocuğunda `loopItem` argüman ifadesinde görünür** (`stepRule.expression`, loop'un motorunda değerlendirilir); fonksiyon öğeyi yalnız `args` ile alır. Ayrıntı: `platform_guide('microfunction')` §Workflow adımı → Loop içinde.
522
525
  - **`code` çocuğunda `loopItem` YOKTUR (ölçüm 2026-09-16).** `code` adımı kendi JS motorunu kurar
523
526
  ve `LoopStep`'in `loopItem` ataması oraya ulaşmaz: adım **`Error: loopItem is not defined`** ile
524
527
  düşer, o yinelemenin çıktısında `result` hiç oluşmaz. Motorda görünenler `input` · `system` ·
@@ -648,15 +651,9 @@ Tam örnek, ölçülen çıktı şekli ve `code` çocuğu tuzağının çıkış
648
651
 
649
652
  ```js
650
653
  // dizi (isSingle:false) · nesne (isSingle:true) · düz değer (yalnız pk dönen yazma)
651
- (x.data && typeof x.data !== 'string' && typeof x.data.length === 'number' ? (x.data[0] && x.data[0].id) : (x.data && x.data.id !== undefined ? x.data.id : x.data))
654
+ (Array.isArray(x.data) ? (x.data[0] && x.data[0].id) : (x.data && x.data.id !== undefined ? x.data.id : x.data))
652
655
  ```
653
656
 
654
- Diziyi `Array.isArray` ile değil `.length` ile tanıyın: 2026-09-27'den önceki backend'de tablo
655
- adımının listesi Jint'e sarılı bir CLR nesnesi olarak iniyordu ve `Array.isArray(x.data)` `false`
656
- dönüyordu — koşuda (2026-09-24) giriş akışı bu yüzden her kullanıcıyı 401 ile reddetti
657
- (`zeyrek-backend/docs/incident-log.md` #89). `.length`, `.map`, `.filter` o sürümde de çalışıyordu;
658
- düzeltilmiş backend'de `Array.isArray` de doğrudur.
659
-
660
657
  Şekli bilmiyorsan bu yazımı kullan; `workflow_preview` çıktısında `steps[].output`'a bakarak
661
658
  hangi vakada olduğunu da görebilirsin.
662
659
 
@@ -1,6 +1,6 @@
1
1
  {
2
- "hash": "466761837eb9a463fe5984ca119fc04fbdc946cf363177b71efd1b195b8729ca",
3
- "generatedAt": "2026-09-27T17:47:09.197Z",
2
+ "hash": "06f7d6b64937424fcbe7a9c8751e90a5224556e0c970199fb199cfa3a147c7d2",
3
+ "generatedAt": "2026-09-28T09:04:34.182Z",
4
4
  "types": 186,
5
5
  "files": 108,
6
6
  "note": "Şemaları üreten backend kaynaklarının parmak izi. Elle düzenlemeyin: 'npm run generate-schemas' yazar, 'npm run schema:check' denetler.",
@@ -134,6 +134,9 @@
134
134
  },
135
135
  "nullable": true
136
136
  },
137
+ "returnBehavior": {
138
+ "$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.DataTransferObjects.DataTransferObjectBehavior"
139
+ },
137
140
  "relationTree": {
138
141
  "$ref": "#/components/schemas/NgApps.Domain.Contexts.Datastore.Entities.EntityRelationDto"
139
142
  }
@@ -128,6 +128,9 @@
128
128
  },
129
129
  "nullable": true
130
130
  },
131
+ "returnBehavior": {
132
+ "$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.DataTransferObjects.DataTransferObjectBehavior"
133
+ },
131
134
  "relationTree": {
132
135
  "$ref": "#/components/schemas/NgApps.Domain.Contexts.Datastore.Entities.EntityRelationDto"
133
136
  }
@@ -45,6 +45,9 @@
45
45
  },
46
46
  "nullable": true
47
47
  },
48
+ "returnBehavior": {
49
+ "$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.DataTransferObjects.DataTransferObjectBehavior"
50
+ },
48
51
  "relationTree": {
49
52
  "$ref": "#/components/schemas/NgApps.Domain.Contexts.Datastore.Entities.EntityRelationDto"
50
53
  }
@@ -413,6 +416,15 @@
413
416
  },
414
417
  "additionalProperties": false
415
418
  },
419
+ "NgApps.Domain.Contexts.Shared.DataTransferObjects.DataTransferObjectBehavior": {
420
+ "enum": [
421
+ "primitive",
422
+ "object",
423
+ "array"
424
+ ],
425
+ "type": "string",
426
+ "format": ""
427
+ },
416
428
  "NgApps.Domain.Contexts.Datastore.Entities.EntityRelationDto": {
417
429
  "type": "object",
418
430
  "properties": {
@@ -804,15 +816,6 @@
804
816
  "type": "string",
805
817
  "format": ""
806
818
  },
807
- "NgApps.Domain.Contexts.Shared.DataTransferObjects.DataTransferObjectBehavior": {
808
- "enum": [
809
- "primitive",
810
- "object",
811
- "array"
812
- ],
813
- "type": "string",
814
- "format": ""
815
- },
816
819
  "NgApps.Domain.Contexts.Datastore.Entities.EntityType": {
817
820
  "enum": [
818
821
  "normal",
@@ -134,6 +134,9 @@
134
134
  },
135
135
  "nullable": true
136
136
  },
137
+ "returnBehavior": {
138
+ "$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.DataTransferObjects.DataTransferObjectBehavior"
139
+ },
137
140
  "relationTree": {
138
141
  "$ref": "#/components/schemas/NgApps.Domain.Contexts.Datastore.Entities.EntityRelationDto"
139
142
  }