@appaflytech/zeyrek-ai-mcp 0.0.20 → 0.0.21

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 (65) hide show
  1. package/README.md +14 -13
  2. package/dist/config.js +0 -2
  3. package/dist/knowledge/componentCatalog.js +940 -215
  4. package/dist/knowledge/componentEvents.js +368 -75
  5. package/dist/knowledge/normalize.js +66 -63
  6. package/dist/knowledge/rules.js +29 -6
  7. package/dist/knowledge/styleResolve.js +1 -1
  8. package/dist/knowledge/themeResolve.js +3 -3
  9. package/dist/platform/diagnostics.js +85 -0
  10. package/dist/platform/domSummary.js +1 -1
  11. package/dist/platform/ifExists.js +129 -0
  12. package/dist/platform/responses.js +2 -1
  13. package/dist/platform/{capture/capture.js → screenshot.js} +509 -23
  14. package/dist/platform/strictArguments.js +22 -2
  15. package/dist/platform/writeDiff.js +58 -31
  16. package/dist/platform/writeView.js +17 -0
  17. package/dist/resources/guides/component.md +9 -6
  18. package/dist/resources/guides/functions.md +32 -3
  19. package/dist/resources/guides/getting-started.md +35 -0
  20. package/dist/resources/guides/layout.md +7 -11
  21. package/dist/resources/guides/page.md +49 -71
  22. package/dist/resources/guides/translation.md +5 -6
  23. package/dist/resources/schema-fingerprint.json +2 -2
  24. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +18 -0
  25. package/dist/server.js +0 -2
  26. package/dist/tools/applications.js +3 -60
  27. package/dist/tools/components.js +10 -50
  28. package/dist/tools/designSchemaPatch.js +13 -18
  29. package/dist/tools/externalComponents.js +4 -25
  30. package/dist/tools/flows.js +38 -51
  31. package/dist/tools/functions.js +20 -10
  32. package/dist/tools/layouts.js +9 -41
  33. package/dist/tools/microservices.js +39 -11
  34. package/dist/tools/pages.js +95 -127
  35. package/dist/tools/platformInfo.js +1 -2
  36. package/dist/tools/schemaOps.js +2 -2
  37. package/dist/tools/screenWrite.js +2 -2
  38. package/dist/tools/screens.js +3 -9
  39. package/dist/tools/workflows.js +39 -12
  40. package/package.json +7 -2
  41. package/dist/knowledge/mobileComponentCatalog.js +0 -331
  42. package/dist/knowledge/mobileComponentEvents.js +0 -50
  43. package/dist/knowledge/platform/lint.js +0 -205
  44. package/dist/knowledge/platform/mobile.js +0 -78
  45. package/dist/knowledge/platform/mobileRules.js +0 -121
  46. package/dist/knowledge/platform/mobileTabs.js +0 -108
  47. package/dist/knowledge/platform/profile.js +0 -20
  48. package/dist/knowledge/platform/resolve.js +0 -122
  49. package/dist/knowledge/platform/web.js +0 -38
  50. package/dist/knowledge/styleResolveNative.js +0 -410
  51. package/dist/platform/capture/actions.js +0 -333
  52. package/dist/platform/capture/browser.js +0 -1
  53. package/dist/platform/capture/index.js +0 -10
  54. package/dist/platform/capture/readiness.js +0 -103
  55. package/dist/platform/capture/summary.js +0 -77
  56. package/dist/platform/capture/target.js +0 -5
  57. package/dist/platform/capture/targets/studio-mobile.js +0 -15
  58. package/dist/platform/capture/targets/studio-web.js +0 -5
  59. package/dist/resources/examples/mobile-app-shell-drawer.json +0 -209
  60. package/dist/resources/examples/mobile-app-shell-stack.json +0 -123
  61. package/dist/resources/examples/mobile-app-shell-tab.json +0 -174
  62. package/dist/resources/examples/mobile-list-detail-form.json +0 -656
  63. package/dist/resources/guides/mobile.md +0 -215
  64. package/dist/tools/mobile.js +0 -203
  65. 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
  ```
@@ -97,8 +93,9 @@ mümkündür ama doğrulama duvarı ve canlı canvas yalnız `page_schema_patch`
97
93
  komponentin iç kimliğidir (aşağıda Kural 2, `FLOW-018`).
98
94
 
99
95
  - **`blocks[].size`'ı komponentin `component_get`'teki `minSize`..`maxSize` aralığında tut.** Dikkat:
100
- katalog varsayılanı aşabiliyor (`page-header` default `h:8`, `maxSize` `h:4`) — varsayılanı körü
101
- körüne kopyalama. Sınır grid kanvasının kuralıdır; API 2026-09-15'ten beri reddetmez, ama aşan
96
+ katalog varsayılanı aşabiliyor (`datepicker` default `h:8`, `maxSize` `h:5`; 18 şemada aynı
97
+ durum, liste zeyrek-frontend `docs/issues.md` ARC-013 — `page-header` 2026-09-18'de sınırı
98
+ 12'ye açarak çıktı) — varsayılanı körü körüne kopyalama. Sınır grid kanvasının kuralıdır; API 2026-09-15'ten beri reddetmez, ama aşan
102
99
  blok kanvasta boyutlandırılamaz (aşağıda Kural 7 "Boyut tuzağı").
103
100
  - **Kurulmuş bir düğümün boyutunu `resize_component` micro-op'u değiştirir.**
104
101
  `{ op: 'resize_component', target: '<elementId>', size: { w, h } }` ızgara boyutunu,
@@ -163,19 +160,32 @@ Sayfa açılışında veri çekmek için `mount` kullanılır ama tek seçenek o
163
160
 
164
161
  Yani "satırı seçince detay getir" (`select`), "kolondan süzünce sunucudan yeniden çek"
165
162
  (`filter`), "sayfa değişince yeni sayfayı çek" (`pagination`), "satıra çift tıklayınca formu aç"
166
- (`doubleClick`) akışları da aynı `set_event` mekanizmasıyla kurulur. Buna karşılık `page-header`
167
- ve `datatable` yalnız `mount` yayar (`datatable`'ınki bilinçli — Kural 1e).
163
+ (`doubleClick`) akışları da aynı `set_event` mekanizmasıyla kurulur. Buna karşılık `datatable`
164
+ yalnız `mount` yayar (bilinçli — Kural 1e); `page-header` 2026-09-18'den beri izdeki öğe
165
+ tıklamasını `clickItem` olarak yayar (`component_get` yükü verir).
168
166
 
169
167
  **Olay adları `on` ÖNEKİ ALMAZ** (`button` → `click`, `form` → `submit`), tek istisna katalogda
170
168
  `texteditor`'dur (`onMount`/`onChange`). **Komponentin desteklemediği bir olay adı verirsen bağ
171
169
  sessizce ölü kalır** — önce `component_get`. Gateway `set_event`'i katalogla karşılaştırır ve
172
170
  uymayan adı **PAGE-008** ile istek gitmeden reddeder.
173
171
 
172
+ **Bir olaya birden fazla akış bağlanabilir — ikinciyi `add_event` ile ekle.** `set_event` olayın
173
+ BÜTÜN bağlarını tek akışa indirir: başlık alanının `change` olayına makale önerisi bağlıyken akıllı
174
+ öneriyi `set_event` ile bağlamak makale önerisini devre dışı bırakır. Gateway bunu **PAGE-034** ile
175
+ istek gitmeden reddeder. Doğru op `{ "op": "add_event", "target": "<elementId>", "event": "change",
176
+ "eventValue": "<ikinci flow id>" }`'dir. Olay tetiklenince bağlı akışların hepsi **paralel ve
177
+ birbirinden bağımsız** koşar: biri hata verirse diğeri etkilenmez, **sıra garantisi yoktur**. Biri
178
+ diğerinin sonucunu bekliyorsa ya da ikisi aynı değişkene/prop'a yazıyorsa ayrı bağ değil,
179
+ `flow-trigger` adımıyla zincir kur (Kural 1c). Mevcut bağı bilerek değiştirmek için `set_event`
180
+ op'una `replaceBoundFlows: true` ekle. **Mobil runtime yalnız ilk akışı koşar** — mobil
181
+ uygulamada olay başına tek akış bağla.
182
+
174
183
  **Olay KALDIRMAK için `remove_event` kullan.** Platformun `set_event` micro-op'u olay silemez:
175
184
  `eventValue: null` verildiğinde kayıt `{ name: 'click' }` olarak (değersiz) kalır, diziden
176
185
  çıkmaz — şemada ölü bağ artığı bırakır. `{ "op": "remove_event", "target": "<elementId>",
177
186
  "event": "click" }` platformun op'udur: olayı diziden çıkarır (yanıtta `removedEvents`); olmayan
178
- bir olayı kaldırmaya çalışmak `missing-event` ile 422 döner. Sayfa düzeyi olaylar için
187
+ bir olayı kaldırmaya çalışmak `missing-event` ile 422 döner. Olaya birden fazla akış bağlıysa
188
+ kaldırılacak akışı `eventValue` ile ver; vermezsen `ambiguous-event` ile 422 döner. Sayfa düzeyi olaylar için
179
189
  `target: "page"`. Referanssız kalan akış silineceği için `allowFlowDeletion` kuralı (G-21) bu op'ta
180
190
  da geçerlidir.
181
191
 
@@ -189,12 +199,14 @@ olaylarında **boştur** (ölçüm 2026-08-25, kaynak okuması: `flow-machine.ts
189
199
  Pratik kural: **`payload` anahtarları aynı zamanda prop adlarıdır; akışta `self.<anahtar>` ile
190
200
  oku** (ya da `value { type:'property', ref:{ source:'component', element, property } }` ile).
191
201
  `event.data` yalnız `params` ile gelen olaylarda dolar — `html` komponentinin `fireEvent`
192
- aksiyonları (`platform_guide('html')`) ve **2026-08-27 kuşağı komponentler** (`eventcalendar` ·
193
- `importwizard` · `kanban` · `signature` · `stepper`): bu kuşak `params`'ı da gönderir, yani
194
- yükleri `event.data.<anahtar>` ile okunur; `kanban` ve `eventcalendar` yükü `self`'e HİÇ
195
- yazmaz (`component_get` çıktısındaki sözleşme notları ayrımı söyler). Sessiz hata örneği:
196
- sayfalama akışını `event.data.limit`'e bağlarsan sorgu `LIMIT null OFFSET null` ile koşar ve
197
- **tüm satırları** döndürür; hata yok, sayfalama yok.
202
+ aksiyonları (`platform_guide('html')`) ve **`params`'ı da gönderen komponentler**
203
+ (`eventcalendar` · `importwizard` · `kanban` · `signature` · `stepper` · `tabs` ·
204
+ `tree-view` · `pagination`): bunların yükü `event.data.<anahtar>` ile de okunur; `kanban` ve
205
+ `eventcalendar` yükü `self`'e HİÇ yazmaz (`component_get` çıktısındaki sözleşme notları ayrımı
206
+ söyler). Sessiz hata örneği: **tablonun kendi** sayfalama akışını (`table.pagination`)
207
+ `event.data.limit`'e bağlarsan sorgu `LIMIT null OFFSET null` ile koşar ve **tüm satırları**
208
+ döndürür; hata yok, sayfalama yok. (Bağımsız `pagination` komponenti bu tuzağa girmez, yükünü
209
+ `params` ile de gönderir.)
198
210
 
199
211
  | Komponent · olay | Yük (aynı zamanda prop adları) | Akışta nereden okunur |
200
212
  |---|---|---|
@@ -204,16 +216,18 @@ sayfalama akışını `event.data.limit`'e bağlarsan sorgu `LIMIT null OFFSET n
204
216
  | `table.select` · `doubleClick` | — | `self.selectedRow` |
205
217
  | `table.selectionChange` | — | `self.selectedRows` |
206
218
  | `datatable.mount` | — | `self.filters` · `self.sortField` · `self.sortType` · `self.offset` |
207
- | `pagination.change` | `{ offset, limit }` | `self.offset` · `self.limit` |
219
+ | `pagination.change` | `{ offset, limit }` | `self.offset` · `self.limit` ya da `event.data.offset` · `event.data.limit` |
208
220
  | `textinput/textarea/password.change` | `{ value }` | `self.value` |
209
221
  | `dropdown.change` · `multi-select.change` | `{ value }` | `self.value` |
210
222
  | `dropdown.search` · `multi-select.search` | `{ searchText }` | `self.searchText` |
211
- | `tabs.tab` | `{ selected }` | `self.selected` |
223
+ | `tabs.tab` | `{ selected }` | `self.selected` ya da `event.data.selected` |
212
224
  | `chart.dataPointClick` | `{ name, seriesName, value, dataIndex, row }` | `self.row` (kaynak satırın tamamı) |
213
- | `repeater.change` | `{ selectedIndex }` | `item` / `Row` satır bağlamı |
225
+ | `repeater.change` · `repeater.select` | `{ selectedIndex }` | `self.selectedIndex` · `self.selectedItem` (akış satır bağlamında koşmaz, `item`/`Row` boş) |
214
226
  | `html` aksiyonu (`fireEvent`) | ikinci argüman | **`event.data`** |
215
227
  | `kanban.cardMove` | `{ id, row, from, to }` | **`event.data`** (self'e yazılmaz) |
228
+ | `kanban.cardAdd` · `kanban.cardRemove` | `{ column }` · `{ id, row, column }` | **`event.data`** (self'e yazılmaz; kart eklenmez/gizlenmez, akış yazıp `rows`'u tazeler) |
216
229
  | `eventcalendar.eventMove` | `{ id, row, start, end, previousStart, previousEnd }` | **`event.data`** (self'e yazılmaz) |
230
+ | `eventcalendar.monthChange` · `eventcalendar.viewChange` · `eventcalendar.eventCreate` | `{ month, year, view, start, end }` · `{ view, start, end }` · `{ start, end, allDay }` | **`event.data`** (self'e yazılmaz; veri sorgusunu kesişimle bağla: başlangıç < `end`+1 gün ve bitiş >= `start`) |
217
231
  | `importwizard.complete` | `{ rows, errors, fileName, total }` | `self.rows`… ya da `event.data` |
218
232
  | `stepper.stepChange` | `{ currentStep, previous }` | `self.currentStep` ya da `event.data` |
219
233
  | `signature.change` | `{ value }` | `self.value` ya da `event.data.value` |
@@ -372,8 +386,11 @@ göstermek error flow'un işidir.
372
386
  > `errorTasks.some(t => t.type !== 'start')` arar. Start'ın ardına en az bir adım bağla —
373
387
  > gateway `FLOW-021` ile uyarır.
374
388
  >
375
- > **Mobil uygulama:** mobil runtime (`@ng-apps/ui-native` `NativeRuntime`) `errorSteps`'i web gibi
376
- > `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.
377
394
 
378
395
  > **Hata metni ÜÇ ayrı yerde durur ve ikisi kullanıcıya gösterilecek metin DEĞİLDİR.**
379
396
  > `onError` hata akışını koşturmadan önce `machine.setStorage('error', errorInfo)` yapar
@@ -503,14 +520,14 @@ değer tipleri: `static · page · property · storage · variable · code · it
503
520
  > tip register eder, gerisini uygulama ekler. Bir sayfa TEK bir uygulamaya aittir
504
521
  > (`Page.ApplicationId`) ve uygulamanın tipi `web` ya da `mobile`'dır (`ApplicationType.cs`), yani
505
522
  > sayfanın barındırıcısı bellidir — matris "hangi tip sende çalışır"ı söyler, iki barındırıcıda
506
- > 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`):
507
524
  >
508
- > | Adım tipi | Web | Mobil uygulama | Nerede register ediliyor |
525
+ > | Adım tipi | Web | Mobil | Nerede register ediliyor |
509
526
  > |---|---|---|---|
510
- > | `start` · `setter` · `code` · `condition` · `microservice` · `validation` · `flow-trigger` · `function` | ✅ | ✅ | `flow-engine.ts` — motorun kendisi |
511
- > | `alert` · `redirect` · `setcookie` · `storage` | ✅ | ✅ | barındırıcı; mobilde `setcookie` cihaz deposuna yazar (`MOB-005`) |
512
- > | `confirm` · `download` | ✅ | ✅ | `Runtime.svelte` · `runtime-tasks.ts` (`download` mobilde açma/paylaşım — `MOB-005`) |
513
- > | `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` |
514
531
  > | `end` · `query` | ❌ | ❌ | hiçbir yerde — üstelik `query` backend sözlüğünde de yok (`StepType.cs` onu saymaz), yalnız frontend enum'unda duruyor |
515
532
  >
516
533
  > **Register edilmemiş bir tipe gelen akış SESSİZCE durur.** `flow-engine.ts` `process()`
@@ -844,7 +861,7 @@ kullanır: `page.mappers.ts` `mapPageLayoutToPreview` — layout varsa çizilen
844
861
  > `add_component` ile yeniden kurmaktır (sonrasında Kural 2'deki flow yeniden kaydetme adımı
845
862
  > ZORUNLU olur).
846
863
 
847
- 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ı
848
865
  dikey sıraya dönüşür, x/w yok sayılır. Yerleşimi masaüstü (breakpoint 1024) bloğuyla kur.
849
866
 
850
867
  ## Kural 1f-2 — Kapsayıcı düzeni: `flex` (varsayılan) ↔ `grid`
@@ -933,10 +950,10 @@ Beş şeyi bilmeden flex kurma:
933
950
  4. **`layout: 'grid'` iken diğer altı prop ÖLÜDÜR.** Katalogda tanımlı oldukları için
934
951
  doğrulama duvarı susar, renderer da okumaz: ızgara kapsayıcıya `direction: 'column'` yazmak
935
952
  sessizce hiçbir şey yapmaz. Gateway bunu **PAGE-015 (uyarı)** ile söyler.
936
- 5. **Flex düzeni kırılım BİLMEZ.** `direction`/`gap`/hizalama masaüstü ve dar ekranda AYNIDIR;
937
- 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
938
955
  bölgeyi salt-okunur kilitler. Kırılım bilen yalnız `blocks[]` ve `appearance.hideOn`'dur;
939
- 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).
940
957
 
941
958
  ```jsonc
942
959
  // Ortalanmış giriş kartı — style ile CSS hack'i YOK, kabın kendi düzeni
@@ -1080,45 +1097,6 @@ kendisi nesneye çevirir; Studio tablosunda `[object Object]` görünmesi normal
1080
1097
  (`platform_guide('entity')` → "TEXT kolonunda JSON"). Ekranın görsel tarafı için **Kural 1h**:
1081
1098
  tema `--ng-*` değişkenleriyle tek yerden çevrilir, `html` kaçış kapısına gerek kalmaz.
1082
1099
 
1083
- ## Kural 1g-2 — Mobil davranış: dört ayar, dört ayrı sahip
1084
-
1085
- Mobil listelerin davranışı TEK bileşende toplanmaz. Hangi ayarın kimde olduğunu bilmeden yazılan
1086
- şema sessizce çalışmaz — prop var olmayan bileşene yazılır ve `page_schema_patch` onu düşürmez,
1087
- çizer yok sayar.
1088
-
1089
- | Davranış | Sahip bileşen | Prop / olay |
1090
- |---|---|---|
1091
- | Çekerek yenile | `scroll-view` (listeyi SARAN kap) | `refreshable: true` + `refresh` olayı |
1092
- | Sonsuz kaydırma | `scroll-view` | `scrollEnd` olayı (prop yok) |
1093
- | Kaydırma eylemleri | `repeater` | `swipeActions: [{ key, label, tone, icon }]` + `swipe` olayı, payload `{ key, index, row }` |
1094
- | Satıra dokunma | `repeater` | `itemPressable: true` + `itemPress` olayı, payload `{ index, row }` |
1095
-
1096
- Çekerek yenileyi `repeater`'a yazmak en sık hatadır: liste kendi kaydırmasını yapmaz, onu saran
1097
- `scroll-view` yapar. `repeater` kökteyse (kap yok) yenileme hiç çizilmez.
1098
-
1099
- Satıra dokunmanın kartın `click`'iyle yapılan eski yolu mobilde bırakıldı: `itemPress` satır
1100
- bağlamını payload'da taşır ve seçimi (`selectedIndex`) de yazar, yani akış satırı
1101
- `<tekrarlayıcı>.selectedItem` ile okumaya devam eder.
1102
-
1103
- ### `redirect.presentation`
1104
-
1105
- `redirect` adımının `args.presentation` alanı ekranın NASIL açıldığını söyler ve kapalı bir küme
1106
- alır:
1107
-
1108
- - `push` — yığına ekler, geri düğmesi önceki ekrana döner (**varsayılan**; alan yazılmayabilir)
1109
- - `modal` — alttan açılan ayrı bir sunum; geri onu kapatır, altındaki ekran yerinde kalır
1110
- - `replace` — geçerli ekranı değiştirir, geçmişe girmez (giriş → ana ekran için doğru olan)
1111
-
1112
- Küme dışı bir değer **MOB-008** uyarısıdır ve backend doğrulayıcısı 422 döner. Alanı hiç yazmamak
1113
- kusur değildir.
1114
-
1115
- **Sekme hedefinde `modal` çalışmaz.** Hedef sayfa bir sekmeyse gezinme her zaman `navigate`'e
1116
- düşer: sekme yığını kendi geçmişini tutar ve modal onu kırardı. `presentation`ı yazabilirsiniz,
1117
- çizer sessizce yok sayar — sekme dışı bir sayfaya modal istiyorsanız o sayfayı sekme listesinden
1118
- çıkarın.
1119
-
1120
- Web uygulamasında alan yok sayılır; gateway web profilinde bu konuda bulgu üretmez.
1121
-
1122
1100
  ## Kural 1h — Tasarım: `style` prop'u ve tema değişkenleri
1123
1101
 
1124
1102
  Her komponentin `style` prop'u vardır ve emotion `css()` bloğudur: iç seçiciler, pseudo-class'lar
@@ -1338,7 +1316,7 @@ budur — bir preset ya da `componentStyles` sizin değerinizi eziyorsa `styleLa
1338
1316
  | Değişiklik | Tool | Neden |
1339
1317
  |---|---|---|
1340
1318
  | 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 |
1341
- | 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')`) |
1319
+ | 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 canlı dil değişimini izler; anahtarın o dilde değeri yoksa varsayılan dile düşer (`platform_guide('translation')`) |
1342
1320
 
1343
1321
  Platformun `PUT /pages/...` ucu **replace**'tir: gönderilmeyen `schema`/`events`/`roleIds`
1344
1322
  alanları silinir. Gateway bu yüzden `page_update`'te sayfayı önce okur, yalnız verdiğin
@@ -1853,7 +1831,7 @@ bağlanır, filtre `source:'expression'` + `value:'user.id'` olur.
1853
1831
  | Kimlik alanları | `email` · `password` |
1854
1832
  | Dosya | `fileUpload` (dropzone) · `fileInput` · `filebutton` · `file-viewer` |
1855
1833
  | Liste | `table` · `datatable` (Kural 1e) · `repeater` (kart listesi VE dinamik form — Kural 1g) · `tree-view` (hiyerarşi; `isSearchable` ile istemci içi arama) · `timeline` (tarihli olay akışı) |
1856
- | Pano / takvim | `kanban` (durum kolonlarında sürüklenebilir kartlar; taşıma `cardMove` ile `event.data`'dan okunur, kalıcılık AKIŞIN işidir) · `eventcalendar` (ay/hafta/gün; veri `rows`'a akışla yazılır, `monthChange` tazeleme kancasıdır, `month` 1-tabanlı) |
1834
+ | Pano / takvim | `kanban` (durum kolonlarında sürüklenebilir kartlar; taşıma `cardMove` ile `event.data`'dan okunur, kalıcılık AKIŞIN işidir) · `eventcalendar` (ay/hafta/gün/ajanda; veri `rows`'a akışla yazılır, `monthChange`/`viewChange` görünen `start`/`end` aralığıyla tazeleme kancasıdır) |
1857
1835
  | Kayıt detayı | `detailview` — tek kaydı etiket/değer ızgarası basar (alan başına format, iç içe alan yolu); OLAY YAYMAZ, tıklanabilirlik gerekiyorsa kapsayıcıya sar |
1858
1836
  | Adımlı akış | `stepper` — tabs gibi her adım kendi droppable görünümünü taşır; ileri gidiş `canProceed` kapısıyla (`{{ form1.isValid === true }}` biçimi), adım `currentStep` setter'ıyla sürülür |
1859
1837
  | İmza / CSV içe aktarma | `signature` (değer PNG data-URL ya da ham SVG; `change` setter'lı) · `importwizard` (3 adımlı sihirbaz; temiz+hatalı satırlar `complete` yükünde — satırları uca yazmak akışın işidir) |
@@ -175,11 +175,10 @@ motor olmasıdır (tarayıcı JS'i ve Jint).
175
175
  verilmişse sekme başlığı çeviri sözlüğünden çözülür; anahtar boşsa `browserTitle` olduğu gibi
176
176
  kullanılır. İkisi de boşsa sayfa adı yazılır.
177
177
 
178
- > **Sekme başlığı SAYFA YÜKLENİRKEN çözülür, canlı dil değişimini İZLEMEZ.** Ölçüldü 2026-09-08
179
- > (yerel runtime): `language-selector` ile dil değiştirildiğinde sayfa içeriği ve layout başlığı
180
- > anında yeni dile geçiyor, sekme başlığı ise açılıştaki dilde kalıyor; aynı dille sayfa yeniden
181
- > yüklendiğinde başlık doğru geliyor. Sebep `Runtime.svelte`'te dilin bir `const` olarak bir kez
182
- > çözülmesi. Sekme başlığının dilini doğrulayacaksan **yeniden yükleyerek** doğrula.
178
+ > **Sekme başlığı canlı dil değişimini İZLER.** `language-selector` ile dil değiştirildiğinde
179
+ > sayfa içeriğiyle birlikte sekme başlığı da yeni dilde çözülür; yeniden yükleme gerekmez
180
+ > (ölçüldü 2026-09-11). Anahtarın seçilen dilde değeri yoksa projenin varsayılan diline düşer.
181
+ > 2026-09-08 ölçümündeki "açılıştaki dilde kalır" davranışı düzeltildi.
183
182
 
184
183
  ## Doğrulama mesajları: `t:` öneki
185
184
 
@@ -209,7 +208,7 @@ gerekmez — `schema.ts`'e dokunulmaz, katalog yeniden yüklenmez.
209
208
  `translation_update` artık uygulamanın bütün sayfalarının önbellek satırlarını düşürüyor
210
209
  (`RefreshPageCacheWhenTranslationChangedCommand`), okuma yolu cache-aside olduğu için bir
211
210
  sonraki `page_runtime_get` taze değeri kurar. Yazmadan hemen sonra okuyabilirsin.
212
- - Mobil uygulama runtime'ı (`@ng-apps/ui-native`) web ile aynı akış motorunu ve dil seçimini kullanır; cihazda ölçülene kadar kanıtlı olan web'dir.
211
+ - Mobil runtime (`apps/mobile`) bu özelliği henüz beslemiyor — yalnız web.
213
212
 
214
213
  ## Backend doğrulama sınırları (TR-001)
215
214
 
@@ -1,6 +1,6 @@
1
1
  {
2
- "hash": "05c7864d58e308973805f7becee1578ce9eddad196abcdf7eebb43b1e7677549",
3
- "generatedAt": "2026-09-19T20:19:15.052Z",
2
+ "hash": "f37265d598ea468deb2157165891629c2e88c7fd2238e82ec60cda7f58f7de4c",
3
+ "generatedAt": "2026-09-18T12:57:15.416Z",
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.",
@@ -95,6 +95,20 @@
95
95
  "$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.Dependencies.DependencyNode"
96
96
  },
97
97
  "nullable": true
98
+ },
99
+ "bindings": {
100
+ "type": "array",
101
+ "items": {
102
+ "$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.Dependencies.DependencyNode"
103
+ },
104
+ "nullable": true
105
+ },
106
+ "functions": {
107
+ "type": "array",
108
+ "items": {
109
+ "$ref": "#/components/schemas/NgApps.Domain.Contexts.Shared.Dependencies.DependencyNode"
110
+ },
111
+ "nullable": true
98
112
  }
99
113
  },
100
114
  "additionalProperties": false
@@ -189,6 +203,10 @@
189
203
  },
190
204
  "stepKind": {
191
205
  "$ref": "#/components/schemas/NgApps.Domain.Contexts.Studio.Flows.StepKind"
206
+ },
207
+ "propertyName": {
208
+ "type": "string",
209
+ "nullable": true
192
210
  }
193
211
  },
194
212
  "additionalProperties": false
package/dist/server.js CHANGED
@@ -39,7 +39,6 @@ import { registerMergeTools } from "./tools/merges.js";
39
39
  import { registerRevisionTools } from "./tools/revisions.js";
40
40
  import { registerActivityTools } from "./tools/activities.js";
41
41
  import { registerDtoTools } from "./tools/dtos.js";
42
- import { registerMobileTools } from "./tools/mobile.js";
43
42
  const moduleRegistrations = {
44
43
  platform: registerPlatformTools,
45
44
  project: registerProjectTools,
@@ -81,7 +80,6 @@ const moduleRegistrations = {
81
80
  merge: registerMergeTools,
82
81
  activity: registerActivityTools,
83
82
  revision: registerRevisionTools,
84
- mobile: registerMobileTools,
85
83
  };
86
84
  export function createGatewayServer(platform) {
87
85
  const server = rejectUnknownArguments(instrumentServer(new McpServer({ name: "ngapps", version: "0.1.0" }), platform.config));
@@ -1,44 +1,6 @@
1
1
  import { guid, pagingParams, readOnly, writes, updates, destructive } from './common.js';
2
2
  import { handle } from '../platform/responses.js';
3
- import { forgetApplication, readApplicationPlatform, resolveApplication } from '../knowledge/platform/resolve.js';
4
- import { mobileTabsProblems, readMobileTabs } from '../knowledge/platform/mobileTabs.js';
5
- import { findingLine } from '../knowledge/platform/profile.js';
6
3
  import { z } from 'zod';
7
- /**
8
- * MOB-007 (sekme ayarı) — `properties.mobile.tabs` yazan mobil uygulama çağrısının denetimi. Yazım
9
- * platforma YİNE gider (D3; backend `properties`'i doğrulamaz): bulgu `platformWarnings`'e düşer.
10
- * Sayfa ve widget listesi okunamazsa o denetimler atlanır, biçim denetimi yine koşar.
11
- */
12
- export async function mobileTabsWarnings(platform, applicationId, projectSlug, homepageId, properties) {
13
- const tabs = readMobileTabs(properties);
14
- if (tabs === undefined)
15
- return [];
16
- const pages = applicationId && projectSlug
17
- ? await platform.tenant('GET', projectSlug, `/pages/${applicationId}`, { query: { pageIndex: 0, pageLength: 200 } })
18
- .then(response => (response?.data ?? []).map(page => ({ id: String(page.id ?? '') })))
19
- .catch(() => undefined)
20
- : undefined;
21
- const widgetIds = applicationId && projectSlug
22
- ? await platform.tenant('GET', projectSlug, `/components/${applicationId}`, { query: { pageIndex: 0, pageLength: 999 } })
23
- .then(response => new Set((response?.data ?? []).filter(entry => entry.kind === 'widget').map(entry => String(entry.id ?? ''))))
24
- .catch(() => undefined)
25
- : undefined;
26
- return mobileTabsProblems(tabs, {
27
- ...(pages ? { pages } : {}),
28
- ...(homepageId ? { homepageId } : {}),
29
- ...(widgetIds ? { widgetIds } : {})
30
- }).map(message => findingLine({
31
- code: 'MOB-007',
32
- severity: 'warn',
33
- message,
34
- guide: "platform_guide('mobile') §Gezinme"
35
- }));
36
- }
37
- function withPlatformWarnings(response, warnings) {
38
- if (warnings.length === 0 || !response || typeof response !== 'object' || Array.isArray(response))
39
- return response;
40
- return { ...response, platformWarnings: warnings };
41
- }
42
4
  export function registerApplicationTools(server, platform) {
43
5
  const config = platform.config;
44
6
  server.registerTool('application_list', {
@@ -72,14 +34,7 @@ export function registerApplicationTools(server, platform) {
72
34
  notFoundPageId: guid.optional()
73
35
  },
74
36
  annotations: writes
75
- }, handle(config, async ({ projectId, ...body }) => {
76
- const warnings = readApplicationPlatform(body.type) === 'mobile'
77
- ? await mobileTabsWarnings(platform, undefined, undefined, undefined, body.properties)
78
- : [];
79
- const response = await platform.org('POST', `/applications/${projectId}`, { body });
80
- forgetApplication(platform);
81
- return withPlatformWarnings(response, warnings);
82
- }));
37
+ }, handle(config, ({ projectId, ...body }) => platform.org('POST', `/applications/${projectId}`, { body })));
83
38
  server.registerTool('application_update', {
84
39
  title: 'Application güncelle',
85
40
  description: 'Application bilgilerini günceller; homepageId zorunludur (mevcut değeri application_get ile alın).',
@@ -94,23 +49,11 @@ export function registerApplicationTools(server, platform) {
94
49
  notFoundPageId: guid.optional()
95
50
  },
96
51
  annotations: updates
97
- }, handle(config, async ({ id, ...body }) => {
98
- const current = await resolveApplication(platform, id);
99
- const warnings = current?.platform === 'mobile'
100
- ? await mobileTabsWarnings(platform, id, current.projectSlug, body.homepageId, body.properties)
101
- : [];
102
- const response = await platform.org('PUT', `/applications/${id}`, { body });
103
- forgetApplication(platform, id);
104
- return withPlatformWarnings(response, warnings);
105
- }));
52
+ }, handle(config, ({ id, ...body }) => platform.org('PUT', `/applications/${id}`, { body })));
106
53
  server.registerTool('application_delete', {
107
54
  title: 'Application sil',
108
55
  description: 'Application\'ı kalıcı olarak siler.',
109
56
  inputSchema: { id: guid },
110
57
  annotations: destructive
111
- }, handle(config, async (args) => {
112
- const response = await platform.org('DELETE', `/applications/${args.id}`);
113
- forgetApplication(platform, args.id);
114
- return response;
115
- }));
58
+ }, handle(config, args => platform.org('DELETE', `/applications/${args.id}`)));
116
59
  }
@@ -1,40 +1,25 @@
1
1
  import { guid, projectParam, environmentParam, readOnly, writes, updates, destructive } from './common.js';
2
- import { normalizeComponentDefaults, componentDefaultsNote, clampBlockSizes, blockSizeNote, normalizeHeightTypes, heightTypeNote, normalizeSizeStrings, sizeStringNote, normalizeDroppableStates, withNormalization } from '../knowledge/normalize.js';
2
+ import { normalizeComponentDefaults, componentDefaultsNote, clampBlockSizes, blockSizeNote, normalizeHeightTypes, heightTypeNote, normalizeSizeStrings, sizeStringNote, withNormalization } from '../knowledge/normalize.js';
3
3
  import { eventContractsFor, eventPayloadNote } from '../knowledge/componentEvents.js';
4
4
  import { componentPresetDefaults, readProjectTheme } from '../knowledge/themeSchema.js';
5
5
  import { knowledgeFor, knowledgeNote, APPEARANCE_TOKEN_SETS, STATE_FLAG_NOTES, INTERNAL_ROLES_BY_TYPE } from '../knowledge/componentCatalog.js';
6
- import { MOBILE_STATE_FLAG_NOTES, mobileComponentKnowledge } from '../knowledge/mobileComponentCatalog.js';
7
- import { mobileComponentEventContracts } from '../knowledge/mobileComponentEvents.js';
8
6
  import { componentUpdateBody, fetchHost, schemaParam, unwrap } from './screens.js';
9
7
  import { PlatformApiError } from '../platform/errors.js';
10
8
  import { handle } from '../platform/responses.js';
11
- import { applicationTypeField, resolveProfile } from '../knowledge/platform/resolve.js';
12
- import { mobileComponentNotes } from '../knowledge/platform/mobileRules.js';
13
9
  import { z } from 'zod';
14
- const typeParam = z.enum(['web', 'mobile']).optional().describe('Hedef platform (ComponentType); verilmezse uygulamanın tipi — mobil uygulamada mobile');
10
+ const typeParam = z.enum(['web', 'mobile']).optional().describe('Hedef platform; varsayılan web');
15
11
  const kindParam = z.enum(['component', 'widget']).optional()
16
12
  .describe("component: sayfaya konan tekil eleman. widget: kendi şeması olan kapsayıcı (container/modal/drawer)");
17
13
  const widgetTypeParam = z.enum(['container', 'modal', 'drawer']).optional()
18
14
  .describe("kind:'widget' iken zorunlu");
19
- /**
20
- * Uç `type` verilmezse WEB kataloğunu döner (`GetComponentsQuery` `Type ?? Web`); mobil uygulamanın
21
- * paleti, doğrulayıcısı ve widget'ları `type=mobile` satırlarıdır. Profil mobil derse sorgu tipi
22
- * taşır; web'de sorgu profil öncesiyle aynıdır (G1 kilidi).
23
- */
24
15
  async function listComponents(platform, project, environment, applicationId, scope) {
25
16
  const path = scope === 'all' ? `/components/${applicationId}/all` : `/components/${applicationId}`;
26
- const catalogType = scope === 'all' ? 'web' : (await resolveProfile(platform, applicationId)).profile.catalogType;
27
17
  const response = await platform.tenant('GET', project, path, {
28
18
  environment,
29
- query: scope === 'all' ? undefined : { pageIndex: 0, pageLength: 999, ...(catalogType === 'mobile' ? { type: 'mobile' } : {}) }
19
+ query: scope === 'all' ? undefined : { pageIndex: 0, pageLength: 999 }
30
20
  });
31
21
  return response?.data ?? [];
32
22
  }
33
- /** Uygulamanın kayıtlı bileşen slug'ları (mobil profilin MOB-003 denetimi). */
34
- export async function fetchCatalogSlugs(platform, project, environment, applicationId) {
35
- const components = await listComponents(platform, project, environment, applicationId);
36
- return new Set(components.map(component => String(component.slug ?? '')).filter(slug => slug.length > 0));
37
- }
38
23
  /**
39
24
  * Yerleşim normalizasyonlarının ikisi de aynı katalog listesinden beslenir; tek okumada
40
25
  * çıkarılır ki yazma yolları fazladan istek atmasın. Uygulamanın kendi sözlüğü okunur
@@ -53,17 +38,12 @@ export async function fetchComponentLayoutRules(platform, project, environment,
53
38
  export function componentLayoutRules(components) {
54
39
  const maxSizes = new Map();
55
40
  const autoHeights = new Map();
56
- const droppable = new Map();
57
41
  for (const component of components) {
58
42
  const slug = typeof component.slug === 'string' ? component.slug : undefined;
59
43
  if (!slug)
60
44
  continue;
61
45
  if (typeof component.isDefaultAutoHeight === 'boolean')
62
46
  autoHeights.set(slug, component.isDefaultAutoHeight);
63
- // Kap bilgisi sözlükten gelir; düğümün `states.isDroppable`ı onu izler (Studio paleti de
64
- // aynı alanı katalogdan yazar). `true` gören tip kap sayılır.
65
- if (typeof component.isDroppable === 'boolean')
66
- droppable.set(slug, component.isDroppable);
67
47
  const blocks = (component.definition ?? {}).blocks;
68
48
  if (!Array.isArray(blocks))
69
49
  continue;
@@ -78,7 +58,7 @@ export function componentLayoutRules(components) {
78
58
  });
79
59
  }
80
60
  }
81
- return { maxSizes, autoHeights, droppable };
61
+ return { maxSizes, autoHeights };
82
62
  }
83
63
  /**
84
64
  * Katalog okuması başarısız olsa da yazma isteği gitmeli, ama iki normalizasyonun düşüş davranışı
@@ -89,21 +69,14 @@ export function componentLayoutRules(components) {
89
69
  * varsayılanını (`fixed`, `DesignComponentManagementSchema.cs:24`) kabul etmek demektir; en fazla
90
70
  * sekiz tipte (auth-layout/html/image/layout/qrcode/table/text-editor/video) fazladan yükseklik
91
71
  * üretir, atlamak ise her tipte içerik kırpar.
92
- * - `states.isDroppable` atlanır — katalog okunamadığında hangi tipin kap olduğu bilinmez ve
93
- * uydurulmaz; düğüm bugünkü hâliyle yazılır.
94
72
  */
95
73
  export async function applyCatalogLayoutRules(platform, project, environment, applicationId, nodes) {
96
74
  try {
97
75
  const rules = await fetchComponentLayoutRules(platform, project, environment, applicationId);
98
- return {
99
- clamped: clampBlockSizes(nodes, rules.maxSizes),
100
- heights: normalizeHeightTypes(nodes, rules.autoHeights),
101
- sizes: normalizeSizeStrings(nodes),
102
- states: normalizeDroppableStates(nodes, rules.droppable)
103
- };
76
+ return { clamped: clampBlockSizes(nodes, rules.maxSizes), heights: normalizeHeightTypes(nodes, rules.autoHeights), sizes: normalizeSizeStrings(nodes) };
104
77
  }
105
78
  catch {
106
- return { clamped: [], heights: normalizeHeightTypes(nodes, new Map()), sizes: normalizeSizeStrings(nodes), states: [] };
79
+ return { clamped: [], heights: normalizeHeightTypes(nodes, new Map()), sizes: normalizeSizeStrings(nodes) };
107
80
  }
108
81
  }
109
82
  /**
@@ -143,7 +116,6 @@ export function registerComponentTools(server, platform) {
143
116
  }, handle(config, async ({ project, environment, applicationId, scope, includeHidden }) => {
144
117
  const components = await listComponents(platform, project, environment, applicationId, scope);
145
118
  return {
146
- ...applicationTypeField(await resolveProfile(platform, applicationId)),
147
119
  components: components
148
120
  .filter(component => includeHidden === true || component.isHide !== true)
149
121
  .map(component => ({
@@ -189,15 +161,6 @@ export function registerComponentTools(server, platform) {
189
161
  : [];
190
162
  const componentSlug = typeof component.slug === 'string' ? component.slug : undefined;
191
163
  const knowledge = knowledgeFor(componentSlug);
192
- // Mobil uygulamada kayıt mobil kataloğun satırıdır (`listComponents` type=mobile); davranış
193
- // notları web runtime'ından gelir (`knowledge` — mobil şema web sınıfını genişletir), bileşenin
194
- // mobil farkları `mobileKnowledge`'ta, bütün mobil bileşenlere geçen notlar `mobileNotes`'ta (G4).
195
- // Web ikizi olmayan bileşende (`app-bar`, `tooltip`…) bilgi yalnız `mobileKnowledge`'tadır; olay
196
- // yükleri de önce mobil sözlükten okunur (`mobileComponentEvents.ts`).
197
- const mobile = (await resolveProfile(platform, applicationId)).profile.platform === 'mobile';
198
- const mobileKnowledge = mobile && componentSlug !== undefined && Object.hasOwn(mobileComponentKnowledge, componentSlug)
199
- ? mobileComponentKnowledge[componentSlug]
200
- : undefined;
201
164
  // S-3 — `defaults` HAM katalogdur; Studio'da bırakılan düğüm ise temanın bileşen preseti
202
165
  // kaplanmış katalogdan kurulur (`withThemeComponentDefaults`). Tema okunamazsa (uç düşer,
203
166
  // yetki yoksa) alan yanıta HİÇ girmez: uydurulmuş bir varsayılan yanlış bilgidir.
@@ -214,7 +177,7 @@ export function registerComponentTools(server, platform) {
214
177
  isDroppable: component.isDroppable,
215
178
  props: definition.props,
216
179
  defaults: definition.defaults,
217
- events: eventContractsFor(componentSlug, eventNames, mobile ? mobileComponentEventContracts : undefined),
180
+ events: eventContractsFor(componentSlug, eventNames),
218
181
  eventPayloadNote,
219
182
  ...(knowledge
220
183
  ? {
@@ -225,7 +188,7 @@ export function registerComponentTools(server, platform) {
225
188
  },
226
189
  ...(knowledge.guide ? { guide: knowledge.guide } : {})
227
190
  }
228
- : mobileKnowledge ? {} : { knowledgeNote }),
191
+ : { knowledgeNote }),
229
192
  ...(componentSlug && INTERNAL_ROLES_BY_TYPE[componentSlug]
230
193
  ? {
231
194
  internalRoles: INTERNAL_ROLES_BY_TYPE[componentSlug],
@@ -233,9 +196,8 @@ export function registerComponentTools(server, platform) {
233
196
  }
234
197
  : {}),
235
198
  ...(themeDefaults ? { themeDefaults } : {}),
236
- ...(mobile ? { platform: 'mobile', ...(mobileKnowledge ? { mobileKnowledge } : {}), mobileNotes: mobileComponentNotes(componentSlug) } : {}),
237
199
  appearanceValues: APPEARANCE_TOKEN_SETS,
238
- stateFlags: mobile ? { ...STATE_FLAG_NOTES, ...MOBILE_STATE_FLAG_NOTES } : STATE_FLAG_NOTES,
200
+ stateFlags: STATE_FLAG_NOTES,
239
201
  validations: definition.validations,
240
202
  sizes: definition.blocks
241
203
  };
@@ -272,13 +234,11 @@ export function registerComponentTools(server, platform) {
272
234
  const catalog = (body.schema ?? []).length > 0
273
235
  ? await applyCatalogLayoutRules(platform, project, environment, applicationId, body.schema)
274
236
  : { clamped: [], heights: [], sizes: [] };
275
- // Mobil uygulamanın widget'ı mobil katalog satırıdır; tip verilmezse uygulamanın tipi.
276
- const defaultType = body.type ?? (await resolveProfile(platform, applicationId)).profile.catalogType;
277
237
  return platform.tenant('POST', project, `/components/${applicationId}`, {
278
238
  environment,
279
239
  body: {
280
240
  kind: 'component',
281
- type: defaultType,
241
+ type: 'web',
282
242
  categories: [],
283
243
  definition: {},
284
244
  schema: [],