@appaflytech/zeyrek-ai-mcp 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +8 -3
- package/.env.production.example +2 -0
- package/README.md +229 -193
- package/dist/config.js +20 -2
- package/dist/knowledge/backendConstraints.js +897 -0
- package/dist/knowledge/componentCatalog.js +196 -42
- package/dist/knowledge/coverage.js +43 -0
- package/dist/knowledge/flowGuards.js +30 -0
- package/dist/knowledge/guideSections.js +49 -0
- package/dist/knowledge/hydrate.js +97 -0
- package/dist/knowledge/languageCodes.js +36 -0
- package/dist/knowledge/languages.js +105 -0
- package/dist/knowledge/layoutSummary.js +10 -0
- package/dist/knowledge/localization.js +51 -0
- package/dist/knowledge/normalize.js +449 -16
- package/dist/knowledge/outlines.js +136 -12
- package/dist/knowledge/propTypes.js +80 -0
- package/dist/knowledge/rules.js +618 -43
- package/dist/knowledge/schemaGuard.js +199 -0
- package/dist/knowledge/styleResolve.js +63 -4
- package/dist/observability/trace.js +27 -3
- package/dist/platform/errors.js +46 -4
- package/dist/platform/http.js +33 -4
- package/dist/platform/patch.js +27 -0
- package/dist/platform/refs.js +104 -0
- package/dist/platform/responses.js +9 -2
- package/dist/platform/screenshot.js +527 -16
- package/dist/platform/secrets.js +40 -0
- package/dist/platform/tokenVault.js +89 -0
- package/dist/platform/writeDiff.js +281 -0
- package/dist/resources/examples/layout-app-shell.json +1 -1
- package/dist/resources/examples/microservice-table-list.json +2 -4
- package/dist/resources/examples/page-dynamic-form.json +2 -2
- package/dist/resources/examples/page-flex-sections.json +99 -0
- package/dist/resources/examples/page-sign-in.json +3 -2
- package/dist/resources/guides/component.md +69 -8
- package/dist/resources/guides/entity.md +404 -16
- package/dist/resources/guides/expressions.md +44 -2
- package/dist/resources/guides/external-component.md +9 -0
- package/dist/resources/guides/getting-started.md +77 -7
- package/dist/resources/guides/layout.md +53 -10
- package/dist/resources/guides/microservice.md +226 -13
- package/dist/resources/guides/middleware.md +89 -1
- package/dist/resources/guides/page.md +383 -46
- package/dist/resources/guides/translation.md +126 -8
- package/dist/resources/guides/view.md +16 -1
- package/dist/resources/guides/workflow.md +198 -27
- package/dist/resources/knowledge.js +5 -0
- package/dist/resources/rules.js +27 -0
- package/dist/resources/schema-fingerprint.json +8 -0
- package/dist/resources/schemas/CreateBulkRowCommand.json +33 -0
- package/dist/resources/schemas/CreateDatasourceCommand.json +15 -6
- package/dist/resources/schemas/CreateDiscoveredEntitiesCommand.json +19 -8
- package/dist/resources/schemas/CreateEntityCommand.json +52 -12
- package/dist/resources/schemas/CreateMicroserviceCommand.json +26 -2
- package/dist/resources/schemas/CreateQueryCommand.json +56 -3
- package/dist/resources/schemas/CreateRowCommand.json +38 -0
- package/dist/resources/schemas/CreateViewCommand.json +13 -10
- package/dist/resources/schemas/CreateWorkflowCommand.json +95 -14
- package/dist/resources/schemas/GetRowsQuery.json +3 -0
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +16 -0
- package/dist/resources/schemas/PreviewQueryCommand.json +5 -2
- package/dist/resources/schemas/PreviewWorkflowCommand.json +34 -9
- package/dist/resources/schemas/StepDto.json +23 -3
- package/dist/resources/schemas/UpdateBulkRowCommand.json +33 -0
- package/dist/resources/schemas/UpdateDatasourceCommand.json +15 -6
- package/dist/resources/schemas/UpdateEntityCommand.json +49 -10
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +28 -3
- package/dist/resources/schemas/UpdateQueryCommand.json +13 -3
- package/dist/resources/schemas/UpdateRowCommand.json +40 -0
- package/dist/resources/schemas/UpdateViewCommand.json +15 -10
- package/dist/resources/schemas/UpdateWorkflowCommand.json +95 -14
- package/dist/server.js +4 -0
- package/dist/tools/access.js +3 -3
- package/dist/tools/applications.js +1 -1
- package/dist/tools/automations.js +63 -30
- package/dist/tools/common.js +39 -0
- package/dist/tools/components.js +16 -7
- package/dist/tools/datasources.js +83 -21
- package/dist/tools/deployments.js +34 -2
- package/dist/tools/dtos.js +25 -12
- package/dist/tools/entities.js +113 -28
- package/dist/tools/externalComponents.js +9 -3
- package/dist/tools/files.js +20 -6
- package/dist/tools/flows.js +110 -11
- package/dist/tools/folders.js +7 -2
- package/dist/tools/globalFunctions.js +63 -0
- package/dist/tools/layouts.js +103 -29
- package/dist/tools/microservices.js +229 -38
- package/dist/tools/organizations.js +5 -6
- package/dist/tools/pages.js +365 -100
- package/dist/tools/platformInfo.js +152 -11
- package/dist/tools/projects.js +183 -33
- package/dist/tools/queries.js +32 -10
- package/dist/tools/rows.js +159 -45
- package/dist/tools/screenWrite.js +59 -0
- package/dist/tools/screens.js +28 -0
- package/dist/tools/translations.js +24 -8
- package/dist/tools/views.js +20 -10
- package/dist/tools/workflows.js +33 -16
- package/package.json +6 -3
|
@@ -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
|
|
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
|
|
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
|
|
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,11 +442,81 @@ 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
482
|
confirm · flow-trigger · storage · navigate · code · download · 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` | ✅ | ✅ | `flow-engine.ts` — motorun kendisi |
|
|
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
|
|
@@ -355,6 +548,10 @@ Toplam kayıt sayısı `Total-Count` header'ından gelir (`TableMicroserviceExec
|
|
|
355
548
|
`isSingle: false` olduğu sürece) — `totalRows`'u yukarıdaki guard'lı ifadeyle yaz. Gateway
|
|
356
549
|
parametreleri geçmeyi unutursan `FLOW-013` ile uyarır.
|
|
357
550
|
|
|
551
|
+
Ucun gerçekten `Total-Count` döndüğünü sayfayı kurmadan **önce** doğrula:
|
|
552
|
+
`microservice_execute(...)` yanıtındaki `headers['total-count']` dolu olmalı; boşsa `sort`/`limit`
|
|
553
|
+
verilmemiş bir tablo kaynağı vardır ve sayfa göstergesi `NaN / N` olur (ölçüm: İK koşusu M-8/E-4).
|
|
554
|
+
|
|
358
555
|
> **`replace_prop` Prop sarmalı DEĞİL ham değer alır** — `PageSchemaMicroOpApplier.cs:77`
|
|
359
556
|
> `new Prop(PropValueType.Static) { Data = op.Value }` kurar. `{ "type": "static", "data": true }`
|
|
360
557
|
> gönderirsen sarmalın kendisi `Data`'ya yazılır ve platform onu `Dictionary<string, Prop>` diye
|
|
@@ -394,8 +591,9 @@ Türkçe başlık `props.title` / `props.text` / `props.label` / `props.pageTitl
|
|
|
394
591
|
> Aynı sebeple akış ifadelerinde komponente **`name` ile** erişilir (`tbl_mng.selectedRow`);
|
|
395
592
|
> `elementId` ile eşit tutmazsan `element:` alanı çalışır ama ifadedeki değişken `undefined` kalır.
|
|
396
593
|
>
|
|
397
|
-
> Gateway bunu **PAGE-009** ile
|
|
398
|
-
>
|
|
594
|
+
> Gateway bunu **PAGE-009** ile HER sayfa ve layout yazma yolunda istek gitmeden reddeder:
|
|
595
|
+
> `page_create`, `page_update(schema)`, `add_component`, `layout_create`, `layout_update(views)`
|
|
596
|
+
> ve `layout_patch`.
|
|
399
597
|
|
|
400
598
|
## Kural 1d — Sayfa iskeleti: `page_container` ve boyutlandırma
|
|
401
599
|
|
|
@@ -633,13 +831,18 @@ aynı prop grubunu o da alır. Grup katalogda tanımlıdır, yani şemadan kurul
|
|
|
633
831
|
|
|
634
832
|
| Prop | Değerler (varsayılan **kalın**) | Ne yapar |
|
|
635
833
|
|---|---|---|
|
|
636
|
-
| `layout` | **`flex`** · `grid` | `flex`: akış düzeni. `grid`: 12 kolonluk ızgara (Kural 1f). |
|
|
834
|
+
| `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
835
|
| `direction` | **`row`** · `column` | `flex-direction`; hangi hizalamanın ANA eksen olduğunu belirler. |
|
|
638
836
|
| `horizontalAlign` | **`left`** · `center` · `right` · `stretch` | `row`'da ana eksen (`justify-content`), `column`'da çapraz eksen (`align-items`). |
|
|
639
837
|
| `verticalAlign` | **`top`** · `middle` · `bottom` · `stretch` | `row`'da çapraz eksen, `column`'da ana eksen (rolleri `horizontalAlign` ile takas). |
|
|
640
838
|
| `size` | **`shrink`** · `grow` | Çocuklara `flex: 0 1 auto` / `1 1 auto`. |
|
|
641
|
-
| `gap` | `none` · `small` · **`medium`** · `large` | 0 /
|
|
642
|
-
| `wrap` |
|
|
839
|
+
| `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. |
|
|
840
|
+
| `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. |
|
|
841
|
+
|
|
842
|
+
**`form` da bu grubun tamamını taşır (2026-09-01):** varsayılanları container ile aynı
|
|
843
|
+
(`flex` · `row` · `left` · `top` · `shrink` · `medium` · `wrap` açık). "Form'a layout yazılmaz"
|
|
844
|
+
eski bilgidir. (Platform kataloğu güncel şemayı `component_get`'te göstermiyorsa kayıt
|
|
845
|
+
yenilenmemiştir — ARC-024.)
|
|
643
846
|
|
|
644
847
|
`stretch` iki eksende farklı anlama gelir: **ana** eksende `space-between` (çocukları uçlara
|
|
645
848
|
dağıtır), **çapraz** eksende gerçekten doldurur.
|
|
@@ -654,27 +857,37 @@ prop'una bakar (`isFlexLayout`). İki sonucu var:
|
|
|
654
857
|
ızgara alırsın — Studio'dan sürüklenen kardeş kapsayıcı flex gelirken seninki grid kalır.
|
|
655
858
|
|
|
656
859
|
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
|
|
658
|
-
|
|
659
|
-
istiyorsan
|
|
860
|
+
seti açıkça taşır: `flex` · `row` · `left` · `top` · `shrink` · `medium` · `wrap` açık.
|
|
861
|
+
`row` + `wrap` açık + `w: 12` çocuklar alt satıra sararak dikey akar; net bir dikey akış
|
|
862
|
+
istiyorsan yine de `direction: 'column'` yazmak daha okunur (ya da `layout: 'grid'`e dön).
|
|
863
|
+
**`wrap`'i kapatırsan** alt alta düşünülmüş `w: 12` çocuklar TEK SATIRA sıkışır.
|
|
660
864
|
|
|
661
865
|
**Ne zaman flex?** Yan yana buton/aksiyon grubu, toolbar, rozet dizisi, ortalanmış giriş kartı,
|
|
662
866
|
"kalanı doldursun" yerleşimleri. Alt alta akan form alanları için ızgara da doğrudur — orada flex
|
|
663
867
|
istiyorsan `direction: 'column'` şart, `row` ile alanlar tek satıra sıkışır.
|
|
664
868
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
1.
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
869
|
+
Beş şeyi bilmeden flex kurma:
|
|
870
|
+
|
|
871
|
+
1. **Çocuğun genişliği `appearance.widthType`'tan gelir (2026-09-01); 12 kolon yalnız
|
|
872
|
+
FALLBACK'tir.** Dört cevap, öncelik sırasıyla:
|
|
873
|
+
- `widthType: 'fill'` — kabın tüm genişliği (satırda `flex:1 1 100%`, sütunda
|
|
874
|
+
`align-self:stretch`); string taşımaz, taşırsa bile ezer.
|
|
875
|
+
- `widthType: 'fixed'` + `widthString` — sabit ölçü, serbest CSS uzunluğu (`"240px"`,
|
|
876
|
+
`"50%"`, `"10vw"`, `calc(...)`). Geçersiz string sessizce düşer ve span'a dönülür.
|
|
877
|
+
- `widthType: 'auto'` — içerik kadar (`flex: 0 1 auto`).
|
|
878
|
+
- `widthType` YOK (eski kayıtlar) — `blocks[].size.w` payı: `row`'da `flex-basis: w/12`,
|
|
879
|
+
`column`'da `width: w/12` (`gap` payı düşülür; `column` + `horizontalAlign:'stretch'`
|
|
880
|
+
istisna — tam genişlik). Izgara ↔ flex geçişi bu fallback sayesinde kayıpsızdır.
|
|
881
|
+
Şemayı sen kuruyorsan çocuğa `widthType`'ı AÇIKÇA yaz. Studio'nun kendi bırakma kuralı:
|
|
882
|
+
kapsayıcı türü kaplar (`container`/`box`/`form`) `'fixed'` + `"50%"`, diğer her şey `'auto'`.
|
|
672
883
|
2. **`position.y` artık yalnız SIRADIR.** Flex çocuklar `y`, sonra `x` sırasına göre dizilir;
|
|
673
884
|
aradaki boşluklar çizilmez. Yine de bitişik ver (0,1,2…): kapsayıcı ileride `grid`'e
|
|
674
885
|
döndürülürse şema geçerli kalsın. Gateway bu yüzden **flex kapsayıcının İÇİNDE PAGE-010
|
|
675
886
|
boşluk uyarısı üretmez** (ızgarada üretmeye devam eder).
|
|
676
887
|
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'`
|
|
888
|
+
olması için `appearance.heightType: 'fixed'` vermelisin — ölçü `heightString`'den
|
|
889
|
+
(serbest CSS uzunluğu, ör. `"30vh"`), o yoksa `size.h × 10px`'ten gelir. `heightString`
|
|
890
|
+
yalnız `heightType:'fixed'` iken okunur; tek başına yazmak hiçbir şey yapmaz. **İstisna
|
|
678
891
|
`page_container`**: `states.isWrapper: true` olduğu için zaten `min-height: 80vh` alır
|
|
679
892
|
(Kural 1f), dolayısıyla dikey hizalama onda kutu boyu vermeden de çalışır. Üçüncü yol
|
|
680
893
|
`heightType: 'fill'` (2026-08-28): çocuk kabın bıraktığı yeri alır — sütunda `flex: 1 1 auto`,
|
|
@@ -684,6 +897,10 @@ Dört şeyi bilmeden flex kurma:
|
|
|
684
897
|
4. **`layout: 'grid'` iken diğer altı prop ÖLÜDÜR.** Katalogda tanımlı oldukları için
|
|
685
898
|
doğrulama duvarı susar, renderer da okumaz: ızgara kapsayıcıya `direction: 'column'` yazmak
|
|
686
899
|
sessizce hiçbir şey yapmaz. Gateway bunu **PAGE-015 (uyarı)** ile söyler.
|
|
900
|
+
5. **Flex düzeni kırılım BİLMEZ.** `direction`/`gap`/hizalama masaüstü ve mobilde AYNIDIR;
|
|
901
|
+
sıra ve span'lar Desktop (1024) bloğundandır — Studio, mobil kırılım düzenlenirken flex
|
|
902
|
+
bölgeyi salt-okunur kilitler. Kırılım bilen yalnız `blocks[]` ve `appearance.hideOn`'dur;
|
|
903
|
+
mobilde farklı davranış gereken satır için `layout: 'grid'` kullan (Kural 1f mobil notu).
|
|
687
904
|
|
|
688
905
|
```jsonc
|
|
689
906
|
// Ortalanmış giriş kartı — style ile CSS hack'i YOK, kabın kendi düzeni
|
|
@@ -701,6 +918,33 @@ Dört şeyi bilmeden flex kurma:
|
|
|
701
918
|
{ "op": "replace_prop", "target": "row_actions", "prop": "gap", "value": "small" }
|
|
702
919
|
```
|
|
703
920
|
|
|
921
|
+
**Mini tarif — sıkı dizilim (küçük bileşenleri dip dibe getirmek).** Buton/rozet/ikon dizisi
|
|
922
|
+
gibi bitişik duracak elemanlar için ÜÇ şart birden gerekir; biri eksikse arada boşluk kalır:
|
|
923
|
+
|
|
924
|
+
1. Her çocuğa **`appearance.widthType: 'auto'`** — içerik kadar yer kaplar (`flex: 0 1 auto`).
|
|
925
|
+
Yazılmazsa eski 12 kolon payı geçerlidir ve çocuk kolonunu doldurur, bitişemez.
|
|
926
|
+
2. Kaba **`gap: 'none'`** (ya da ham ince değer: `"2px"`, `"4px"` — alan `allowCustom`).
|
|
927
|
+
3. Her çocuğa **`appearance.marginType: 'none'`** — en çok atlanan şart: `marginType`
|
|
928
|
+
yazılmamış düğüm `normal` sayılır ve her kenara 4px basar (`spacing.ts`
|
|
929
|
+
`CANVAS_NORMAL_MARGIN`), yani `gap:'none'` olsa bile komşular arasında 8px kalır.
|
|
930
|
+
|
|
931
|
+
```jsonc
|
|
932
|
+
// Bitişik rozet dizisi: kap + iki çocuktan biri (diğeri aynı desen)
|
|
933
|
+
{ "elementId": "badge_row", "type": "container", "kind": "component",
|
|
934
|
+
"props": { "layout": { "type": "static", "data": "flex" },
|
|
935
|
+
"direction": { "type": "static", "data": "row" },
|
|
936
|
+
"gap": { "type": "static", "data": "none" } },
|
|
937
|
+
"children": [
|
|
938
|
+
{ "elementId": "badge_1", "type": "button", "kind": "component",
|
|
939
|
+
"appearance": { "widthType": "auto", "marginType": "none", "heightType": "auto" },
|
|
940
|
+
"blocks": [{ "breakpoint": 1024, "size": { "w": 2, "h": 4 }, "position": { "x": 0, "y": 0 } }] }
|
|
941
|
+
] }
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
"Şu ikisi bitişik, şu uzak" gibi eşit olmayan aralıklar için `gap` yetmez (kapta tekildir) —
|
|
945
|
+
bitişik elemanları `gap:'none'` bir İÇ kapsayıcıda gruplayıp grupları dış kapta normal
|
|
946
|
+
`gap` ile diz.
|
|
947
|
+
|
|
704
948
|
> Düzen işi `style` prop'una AİT DEĞİL. Kural 1h'deki `style` reçeteleri tema/görsellik içindir;
|
|
705
949
|
> `display:flex` gibi düzen kurallarını oraya yazmak kabın kendi düzeniyle çakışır (PAGE-014'teki
|
|
706
950
|
> ölçüm: string style ile kart 66px'e çöktü). Yerleşim bu prop grubuyla, tema `style` ile kurulur.
|
|
@@ -776,8 +1020,10 @@ UYGULAMAZ** — koordinatları aynen kaydeder (aşağı itme yalnız `page_creat
|
|
|
776
1020
|
> - Ekranda sürekli `Expression error: Cannot read properties of null (reading '0')` toast'ı çıkıyor
|
|
777
1021
|
> (iç repeater bir kez `item` olmadan da değerlendiriliyor).
|
|
778
1022
|
>
|
|
779
|
-
> **Gateway bunu `PAGE-013` ile istek gitmeden reddediyor**
|
|
780
|
-
> `
|
|
1023
|
+
> **Gateway bunu `PAGE-013` ile istek gitmeden reddediyor** — `page_create` / `page_update(schema)` /
|
|
1024
|
+
> `layout_create` / `layout_update(views)` / `layout_patch` gönderilen ağaca, `page_schema_patch` hem
|
|
1025
|
+
> eklenen alt ağaca hem op'lar UYGULANDIKTAN SONRAKİ ağaca bakarak. Layout'ta da geçerlidir: kırılma
|
|
1026
|
+
> `_repeaterValues` geri yazmasındadır, barındıranın sayfa mı layout mu olduğuna bakmaz.
|
|
781
1027
|
>
|
|
782
1028
|
> **Yapılacak:** satır içi listeyi tek bir `textarea`'da **satır başına bir öğe** olarak topla
|
|
783
1029
|
> (`options_text`), kaydederken `split('\n')`'le böl. Ölçülmüş çalışan sürüm: anket editörü
|
|
@@ -805,6 +1051,14 @@ yapmanın yolu budur — ölçülmüş kurallar (anket-doldur, 2026-08-19):
|
|
|
805
1051
|
> Bu kural TEMA/GÖRSELLİK içindir. Çocukların dizilimi (ortalama, yaslama, aralık, "kalanı
|
|
806
1052
|
> doldur") `style` ile değil kapsayıcının kendi `layout` prop grubuyla kurulur — Kural 1f-2.
|
|
807
1053
|
|
|
1054
|
+
> **Stil anahtarları camelCase'dir: `minHeight`, `fontSize`, `letterSpacing`.** Kebab-case anahtar
|
|
1055
|
+
> (`min-height`) platform tarafından KABUL EDİLİR, `page_schema_get` ile aynen geri okunur ve
|
|
1056
|
+
> runtime onu HİÇ UYGULAMAZ; tek işaret tarayıcı konsolundaki tek satırdır ve `page_screenshot`
|
|
1057
|
+
> konsolu döndürmez. 2026-09-05 koşusunun en pahalı yanlış teşhisi buydu (~15 dk) ve yanlış teşhis
|
|
1058
|
+
> düğümleri silip yeniden kurmaya, o da 20 setter'ın sessizce kopmasına yol açtı. Gateway artık
|
|
1059
|
+
> kebab-case anahtarı camelCase'e çevirir ve `gatewayNormalized` ile bildirir; seçici anahtarlara
|
|
1060
|
+
> (`&__body`, `:hover`, `--ng-*`) dokunmaz.
|
|
1061
|
+
|
|
808
1062
|
**1. Temayı tek yerden çevir: `page_container.style` içinde `--ng-*` değişkenlerini ez.**
|
|
809
1063
|
Runtime bütün renk/tipografi/form tokenlarını CSS değişkeni olarak basar
|
|
810
1064
|
(`Theme.svelte`: `--ng-accent-primary`, `--ng-accent-hover`, `--ng-background-surface`,
|
|
@@ -991,7 +1245,7 @@ budur — bir preset ya da `componentStyles` sizin değerinizi eziyorsa `styleLa
|
|
|
991
1245
|
| Değişiklik | Tool | Neden |
|
|
992
1246
|
|---|---|---|
|
|
993
1247
|
| 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 |
|
|
1248
|
+
| 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
1249
|
|
|
996
1250
|
Platformun `PUT /pages/...` ucu **replace**'tir: gönderilmeyen `schema`/`events`/`roleIds`
|
|
997
1251
|
alanları silinir. Gateway bu yüzden `page_update`'te sayfayı önce okur, yalnız verdiğin
|
|
@@ -1018,6 +1272,17 @@ Yanıt üç alan döner: `applied` (uygulanan op sayısı), **`appliedPatch`** (
|
|
|
1018
1272
|
olarak hangi JSON Pointer'a ne yaptığı — RFC 6902 biçiminde; "gerçekten yalnız o komponente mi
|
|
1019
1273
|
dokunuldu" sorusunun kanıtı) ve **`newVersion`** (`UpdatedAt.Ticks`).
|
|
1020
1274
|
|
|
1275
|
+
> **`appliedPatch` gövdesi VARSAYILAN OLARAK iskelettir.** Girdi `{ op, path }` döner; eklenen
|
|
1276
|
+
> düğüm `component` altında yalnız `id`/`elementId`/`name`/`type`/`children` taşır. Kanıt zaten
|
|
1277
|
+
> path'tedir — `value` senin aynı turda gönderdiğin gövdenin yankısıdır ve tek bir `set_event`
|
|
1278
|
+
> yaması bile düğümün bütün prop'larını geri getiriyordu. Aynı kural `page_create` yanıtındaki
|
|
1279
|
+
> `schema` için de geçerlidir (çözülmüş layout düğümleri dâhil). Tam gövde: `view: 'full'`.
|
|
1280
|
+
>
|
|
1281
|
+
> **"Kaydedildi mi" sorusunu `appliedPatch` zaten cevaplamıyor** (aşağıdaki `silentlyDropped`
|
|
1282
|
+
> bölümü): yama 200 döner ve pointer'ı gösterir, ama alanın kayda geçtiğini söylemez. Onu gateway
|
|
1283
|
+
> yamadan sonra şemayı okuyup gönderdiğinle karşılaştırarak söyler. Kırpma bu yüzden kanıt kaybı
|
|
1284
|
+
> değildir; `view: 'full'`e yalnız gerçekten platformun ham gövdesini incelerken düş.
|
|
1285
|
+
|
|
1021
1286
|
**Sürüm kontrolü platformda var ama gateway bugün KULLANMIYOR.** Platform gövdede `baseVersion`
|
|
1022
1287
|
(long tick) kabul eder ve tutmazsa 409 verir; `page_state.baseVersion` bu değeri döner.
|
|
1023
1288
|
`page_schema_patch` bu alanı geçirmez — bayat plan koruması gateway tarafında
|
|
@@ -1204,9 +1469,21 @@ altın örneklerde** — şemayı ve akışları oradan kopyalayıp uyarla:
|
|
|
1204
1469
|
| Detay / profil | `ngapps://examples/page-detail-profile` |
|
|
1205
1470
|
| Dinamik form (alanlar veriden) | `ngapps://examples/page-dynamic-form` (Kural 1g + 1h) |
|
|
1206
1471
|
|
|
1207
|
-
> Gateway
|
|
1472
|
+
> Gateway üç yarım kurulumu yakalar: **FORM-001** (`form` eklendi, `submit` bağlanmadı),
|
|
1208
1473
|
> **FORM-002** (akışta POST/PUT adımı var ama hiç `source:'body'` parametresi yok → gövde boş
|
|
1209
|
-
> gider)
|
|
1474
|
+
> gider) ve **FORM-003** (formun `submit`'i bağlı ama içindeki butonun `click`'i bağlı değil).
|
|
1475
|
+
>
|
|
1476
|
+
> **FORM-003 neden var:** `button` varsayılan olarak `type="button"` çizilir; form içinde bile
|
|
1477
|
+
> HTML form submit'i HİÇ doğmaz — butona tıklamak da alanda Enter da uca istek göndermez ve
|
|
1478
|
+
> **hiçbir hata çıkmaz**. `ngapps://examples/page-sign-in`'i harfiyen izleyen bir giriş sayfası bu
|
|
1479
|
+
> yüzden tıklanamaz kalıyordu (ölçüldü 2026-09-05); teşhis yalnız gerçek tıklamayla mümkün oldu
|
|
1480
|
+
> (`page_screenshot` `actions`). İki çözümden biri yeter:
|
|
1481
|
+
>
|
|
1482
|
+
> 1. Butona **`props.type = 'submit'`** ver — katalogdaki `type` prop'u bu değeri destekliyor ve
|
|
1483
|
+
> idiomatik yol budur.
|
|
1484
|
+
> 2. Ya da AYNI akışı butonun `click` olayına da bağla.
|
|
1485
|
+
>
|
|
1486
|
+
> `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
1487
|
> middleware'i var ama giriş sayfası yok, yazma ucu var ama sayfa yok.
|
|
1211
1488
|
|
|
1212
1489
|
**Adlandırma:** çoğul = liste sayfası, tekil = form sayfası (`Departmanlar` / `Departman`).
|
|
@@ -1235,6 +1512,17 @@ maxLength/pattern — sözlük `component_get`'te) orada listelenir.
|
|
|
1235
1512
|
] }
|
|
1236
1513
|
```
|
|
1237
1514
|
|
|
1515
|
+
**Mesajı çeviriye bağlamak: `t:` öneki.** `message` düz bir metindir ve translation prop'u ALMAZ;
|
|
1516
|
+
çeviri anahtarı mesajın kendisine önek olarak yazılır:
|
|
1517
|
+
|
|
1518
|
+
```jsonc
|
|
1519
|
+
{ "type": "required", "message": "t:form.emailRequired", "value": true, "isActive": true }
|
|
1520
|
+
```
|
|
1521
|
+
|
|
1522
|
+
Runtime `t:` ile başlayan mesajı anahtar sayar ve normal fallback zincirinden çözer (aktif dil →
|
|
1523
|
+
varsayılan dil → anahtarın kendisi); önek yoksa metin olduğu gibi gösterilir. Çözüm çalışma
|
|
1524
|
+
anında olduğu için şema varsayılanlarına dokunmak gerekmez.
|
|
1525
|
+
|
|
1238
1526
|
Geçerli `type` değerleri: `required` · `email` · `regex` · `max-length` · `min-length` ·
|
|
1239
1527
|
`max-value` · `min-value` · `value-options`. Üç tuzak ölçüldü (crm koşumu B-9):
|
|
1240
1528
|
|
|
@@ -1268,18 +1556,29 @@ start → [setter] page_container.isLoading = true
|
|
|
1268
1556
|
└─ else → [setter] CREATE etiketleri
|
|
1269
1557
|
```
|
|
1270
1558
|
|
|
1271
|
-
> **Condition adımı `always` dalını kural dallarıyla BİRLİKTE taşır
|
|
1272
|
-
>
|
|
1273
|
-
>
|
|
1559
|
+
> **Condition adımı `always` dalını kural dallarıyla BİRLİKTE taşır** — ama `always` her hâlükârda
|
|
1560
|
+
> KOŞMAZ. Motor onu yalnız **eşleşen dalın** bitişinden çağırır:
|
|
1561
|
+
>
|
|
1562
|
+
> ```ts
|
|
1563
|
+
> // condition.ts — always'in TEK çıkışı eşleşen dalın callback'idir
|
|
1564
|
+
> engine.next(rule.id, { ...definition, completed: () => engine.next('always', definition) })
|
|
1565
|
+
> ```
|
|
1566
|
+
>
|
|
1567
|
+
> Yani şu üç hâlde `always` **hiç** koşmaz: `rules` boş · `rules[0].type !== 'if'` · hiçbir ifade
|
|
1568
|
+
> tutmuyor ve boş ifadeli bir `else` yok. **Yükleniyor bayrağını `always` ile kapatıyorsan
|
|
1569
|
+
> zinciri boş ifadeli `else` ile kapatmak ZORUNDASIN** — yukarıdaki iskelette `else` dalı tam da
|
|
1570
|
+
> bu yüzden var. `else`'siz bir zincirde ifade tutmazsa bayrak açık kalır ve sayfa sonsuza kadar
|
|
1571
|
+
> yükleniyor görünür. Gateway `FLOW-020` bunu uyarıyla söyler.
|
|
1274
1572
|
>
|
|
1275
|
-
>
|
|
1276
|
-
>
|
|
1277
|
-
> ile reddedilir. Dal adı da o GUID'in kendisidir (`branch.name === rule.id`), yani iki yerde de
|
|
1278
|
-
> okunabilir ad kullanamazsın.
|
|
1573
|
+
> Sözleşmenin tamamı (GUID id zorunluluğu, dal adı = rule id, `else` fallback kuralı, zincir
|
|
1574
|
+
> sırası) aşağıdaki tuzak 6'da.
|
|
1279
1575
|
>
|
|
1280
|
-
> **Kural ifadesi patlarsa
|
|
1281
|
-
>
|
|
1282
|
-
>
|
|
1576
|
+
> **Kural ifadesi patlarsa kural EŞLEŞMEMİŞ sayılır** — `runCode` `undefined` döner,
|
|
1577
|
+
> `Boolean(undefined)` false'tur — ve zincir bir sonraki kurala, oradan `else`'e geçer. Ama bu
|
|
1578
|
+
> tamamen sessiz değildir: hata işaretlenir ve sıradaki `engine.next` onu tüketip **hata yolu
|
|
1579
|
+
> varsa akışı oraya saptırır** (`flow-engine.ts` `consumeExpressionError`), yani beklediğin dal
|
|
1580
|
+
> yerine `errorSteps` koşar. Bu yüzden condition ifadeleri guard'lı yazılır — özellikle
|
|
1581
|
+
> `Page.user` okuyanlar (Kural 8).
|
|
1283
1582
|
|
|
1284
1583
|
**İki ayrı ucun sonucunu tek tabloya yazmak:** `mapping` tek kaynak alır, o yüzden birleştirmeyi
|
|
1285
1584
|
`value.type: 'code'` ile yap — ilgisiz kayıtları da orada süz:
|
|
@@ -1337,20 +1636,24 @@ start → [setter] btn_save.isLoading = true
|
|
|
1337
1636
|
|
|
1338
1637
|
- **Upsert deseni:** tek POST ucu hem create hem update yapar — `id` query-string'den, alanlar
|
|
1339
1638
|
`source:'body'`'den. Entity başına iki uç yazmaya gerek yok.
|
|
1340
|
-
- **
|
|
1341
|
-
ana akışın kalanını
|
|
1639
|
+
- **Form akışında hata yolunu `condition Steps.<adımAdı>.error` ile kur**, `errorSteps` ile
|
|
1640
|
+
değil: `errorSteps` ana akışın kalanını devralır, yani yükleniyor bayrağını kapatma · modal'ı
|
|
1641
|
+
kapatma · tabloyu tazeleme adımlarını hata akışında yeniden kurman gerekir — kurmazsan bayrak
|
|
1642
|
+
açık kalır. İki yolun karşılaştırması ve hata metninin nerede durduğu Kural 1c'nin §hata yolu
|
|
1643
|
+
bloğunda.
|
|
1342
1644
|
- Geri bildirim `notification` komponentiyle verilir (`kind` · `header` · `content` · `timeout` ·
|
|
1343
1645
|
`showCloseButton` · `style`), `alert` adımıyla değil.
|
|
1344
1646
|
|
|
1345
1647
|
> **`isHidden`: ŞEMAYA yazmak ile SETTER ile yazmak AYRI yollardır.** Runtime tarafı ortak:
|
|
1346
1648
|
> `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
|
|
1348
|
-
> katalogla sınırlıdır
|
|
1349
|
-
>
|
|
1350
|
-
>
|
|
1351
|
-
>
|
|
1352
|
-
> `
|
|
1353
|
-
>
|
|
1649
|
+
> `isHidden` yazınca komponent katalogda o prop'u tanımlamasa bile gizlenir. **Şema yolu
|
|
1650
|
+
> katalogla sınırlıdır** ama artık neredeyse her komponent tanımlıyor: **101 kaydın 99'u**
|
|
1651
|
+
> (ölçüm 2026-09-08; 2026-08-26'daki toplu ekleme öncesi 81'de 37 idi). Tanımlamayan yalnız
|
|
1652
|
+
> iki kap var: **`slot` · `widget-area`** — onların içindekini gizlemek için sarmalayıcı
|
|
1653
|
+
> kullan. Eskiden tanımlamayan `text` · `table` · `datatable` · `dropdown` · `multi-select` ·
|
|
1654
|
+
> `tag-input` · `tabs` · `notification` · `toast` · `datepicker` ailesi gibi komponentlere
|
|
1655
|
+
> artık doğrudan `props.isHidden` yazılabilir; sırf gizlemek için `container`'a sarmak
|
|
1656
|
+
> GEREKMEZ. Tek doğru kaynak `component_get` + `page_schema_validate` kuru koşusudur.
|
|
1354
1657
|
>
|
|
1355
1658
|
> **`appearance.isHidden` bir kaçış yolu DEĞİLDİR:** kaydedilir ama runtime hiçbir yerde okumaz
|
|
1356
1659
|
> (renderer yalnız `props.isHidden`'a bakar) — komponent görünmeye devam eder. Başlangıçta gizli
|
|
@@ -1540,6 +1843,21 @@ hiçbiri** bağlı değildi; üç portalın da rol menüsü boş çıkıyor, pan
|
|
|
1540
1843
|
> `Host: <org>.<suffix>` + `X-Environment` başlıklarıyla. Ham `curl` yerine tool'u kullanmak
|
|
1541
1844
|
> yeterlidir.
|
|
1542
1845
|
>
|
|
1846
|
+
> **Yerleşimi görüntüsüz ölçmek.** Taşma/çakışma şüphesinde `page_screenshot(layoutReport: true)`:
|
|
1847
|
+
> `layoutSummary.overflowing` boş değilse içeriğine sığmayan kutu, `outsideViewport` boş değilse
|
|
1848
|
+
> hiç görünmeyen düğüm var; `zeroSized` çizilmemiş komponenti gösterir. Runtime düğümleri
|
|
1849
|
+
> `data-element-id` basmıyorsa yanıt `layoutReportUnavailable` der — tool tahmin üretmez.
|
|
1850
|
+
>
|
|
1851
|
+
> **Üye kimliğiyle doğrulama (`asUser`).** Kapının kapalı olduğunu görmek yarısıdır; açık
|
|
1852
|
+
> olduğunu görmek diğer yarısı. `page_runtime_get` ve `page_screenshot` aynı `asUser` alanını
|
|
1853
|
+
> alır: uygulamanın kendi giriş ucundan (`microservice_execute`) aldığın üye jetonunu verirsin,
|
|
1854
|
+
> gateway o jetonu **hem `Authorization` başlığında hem `NG_AccessToken` çerezinde** taşır.
|
|
1855
|
+
> Çerez okuyan bir middleware ile başlık okuyan bir middleware aynı çağrıdan geçer — iki tool da
|
|
1856
|
+
> aynı kimlik kanalını kullanır. `page_screenshot` ayrıca `cookies: {ad: değer}` ile uygulamanın
|
|
1857
|
+
> kendi oturum çerezlerini enjekte eder. `asUser`/`cookies` ile `anonymous` birlikte verilemez;
|
|
1858
|
+
> gateway'in servis jetonu (varsayılan kimlik) uygulamanın `users` tablosuna çözülmeyebilir —
|
|
1859
|
+
> korumalı sayfada boş panel görüyorsan önce `identity` alanına bak, sonra `asUser` ile tekrarla.
|
|
1860
|
+
>
|
|
1543
1861
|
> `page.roleIds` bu dalla birlikte de kapı değildir: rol ayrımını sayfa değil **uç** yapar.
|
|
1544
1862
|
|
|
1545
1863
|
> **Rol okurken dizi bekleme.** `set-user` DTO'su `roles` dizisini çoğu kurulumda düşürür
|
|
@@ -1603,6 +1921,24 @@ micro-op hattına dönün.
|
|
|
1603
1921
|
> setter'ı sessizce hiçbir şey yazmadı — sayfa boş liste ile açıldı, konsolda hata yok.
|
|
1604
1922
|
> `flow_update` ile aynı gövdeyi yeniden kaydetmek düzeltti. Kural: **şemadan bir düğüm sildiysen,
|
|
1605
1923
|
> o düğümü hedefleyen her flow'u yeniden kaydet.**
|
|
1924
|
+
>
|
|
1925
|
+
> **Akış silen yama artık istek gönderilmeden REDDEDİLİR.** Platform referanssız kalan akışı
|
|
1926
|
+
> KALICI siler; uyarı yamadan sonra geldiğinde "önce yedekle" tavsiyesi uygulanamıyordu (09-05
|
|
1927
|
+
> koşusunda sekiz adımlı giriş akışı sıfırdan yeniden yazıldı). Aynı kontrol `set_event` ve
|
|
1928
|
+
> `remove_event` için de çalışır — bir olayın bağını değiştirmek de akış öldürür ve o yolda hiç
|
|
1929
|
+
> uyarı yoktu. Silinmesini bilerek istiyorsanız çağrıyı `allowFlowDeletion: true` ile tekrarlayın;
|
|
1930
|
+
> yanıt `deletedFlows` ile hangi akışların gittiğini listeler.
|
|
1931
|
+
>
|
|
1932
|
+
> **FLOW-018 artık silinen düğümün ALT AĞACINI da görüyor.** Eskiden yalnız op'un kendi
|
|
1933
|
+
> `target`'ına bakılıyordu: bir kapsayıcı silinince ÇOCUĞUNA yazan setter sessizce kopuyor ve
|
|
1934
|
+
> uyarı hiç çıkmıyordu (09-05, `sign_in_form` → `btn_sign_in`).
|
|
1935
|
+
>
|
|
1936
|
+
> **Gateway artık bunu söylüyor (FLOW-018).** `remove_component` içeren bir yamada gateway sayfanın
|
|
1937
|
+
> akışlarını okur ve silinen düğümü hedefleyen setter adımlarını uyarı olarak listeler: hangi akış,
|
|
1938
|
+
> hangi adım, hangi hedef. Uyarıyı gördüğünde yapılacak tek şey `flow_update` ile aynı gövdeyi
|
|
1939
|
+
> yeniden kaydetmektir. Ters yönü (`silinen düğümün referans verdiği` akışların platformca kalıcı
|
|
1940
|
+
> silinmesi) ayrı bir uyarı kapsar; ikisi birlikte çıkabilir. Ölçüm 2026-09-04 (benchmark 4. koşu):
|
|
1941
|
+
> uyarı yokken aynı tuzak ~8 dakika teşhis aldı ve yalnız ekran görüntüsüyle görüldü.
|
|
1606
1942
|
|
|
1607
1943
|
## Bilinen sınırlar
|
|
1608
1944
|
|
|
@@ -1667,10 +2003,11 @@ micro-op hattına dönün.
|
|
|
1667
2003
|
`isHidden` prop'u yok (Kural 1g'deki sarmalayıcı çözümü). Bir prop'u kullanmadan önce
|
|
1668
2004
|
`component_get`'e bak; eksikse ürün sahibine katalog güncellemesi olarak bildir.
|
|
1669
2005
|
|
|
1670
|
-
- **`container.title` `states.isWrapper: true` iken başlık ÇİZMEZ.**
|
|
2006
|
+
- **`container.title` varsayılanı boştur ve `states.isWrapper: true` iken başlık ÇİZMEZ.** Başlıksız
|
|
2007
|
+
normal container da `__header` bloğu üretmez; bant istiyorsan `title` değerini açıkça yaz.
|
|
2008
|
+
Wrapper kaplar salt düzen
|
|
1671
2009
|
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
|
|
1673
|
-
varsayılan "Container title" göründü). Kart başlığını garantiye almak istiyorsan kabın
|
|
2010
|
+
`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
2011
|
`title`'ına güvenme, **içine bir `text` komponenti** koy.
|
|
1675
2012
|
- **Kod prop'unun ifadesi `ref`'te ve `{{ }}` sarılı olmalı.** `{type:'code', ref:"'' + Row.value"}`
|
|
1676
2013
|
(süssüz) ekrana ifadenin **kendisini** basar; ifade yalnız `data`'da olursa prop **boş**
|