@appaflytech/zeyrek-ai-mcp 0.0.7 → 0.0.9

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 (54) hide show
  1. package/README.md +27 -21
  2. package/dist/config.js +2 -0
  3. package/dist/knowledge/backendConstraints.js +3 -0
  4. package/dist/knowledge/componentCatalog.js +172 -33
  5. package/dist/knowledge/componentEvents.js +35 -4
  6. package/dist/knowledge/errorPath.js +1 -1
  7. package/dist/knowledge/normalize.js +474 -23
  8. package/dist/knowledge/propTypes.js +5 -4
  9. package/dist/knowledge/rules.js +113 -6
  10. package/dist/knowledge/styleResolve.js +52 -5
  11. package/dist/knowledge/themeResolve.js +936 -0
  12. package/dist/knowledge/themeRules.js +221 -0
  13. package/dist/knowledge/themeSchema.js +335 -0
  14. package/dist/platform/domSummary.js +144 -0
  15. package/dist/platform/http.js +10 -2
  16. package/dist/platform/screenshot.js +492 -29
  17. package/dist/platform/screenshotMemory.js +55 -0
  18. package/dist/platform/strictArguments.js +32 -0
  19. package/dist/platform/writeDiff.js +6 -3
  20. package/dist/resources/examples/layout-app-shell.json +1 -1
  21. package/dist/resources/examples/page-sign-in.json +1 -1
  22. package/dist/resources/examples/theme-brand.json +162 -0
  23. package/dist/resources/guides/component.md +8 -2
  24. package/dist/resources/guides/expressions.md +6 -0
  25. package/dist/resources/guides/getting-started.md +6 -0
  26. package/dist/resources/guides/layout.md +36 -26
  27. package/dist/resources/guides/microservice.md +160 -6
  28. package/dist/resources/guides/page.md +165 -59
  29. package/dist/resources/guides/theme.md +210 -0
  30. package/dist/resources/guides/translation.md +13 -10
  31. package/dist/resources/guides/workflow.md +141 -7
  32. package/dist/resources/schema-fingerprint.json +2 -2
  33. package/dist/resources/schemas/CreateMicroserviceCommand.json +4 -1
  34. package/dist/resources/schemas/CreateWorkflowCommand.json +4 -1
  35. package/dist/resources/schemas/PreviewMicroserviceCommand.json +4 -1
  36. package/dist/resources/schemas/PreviewWorkflowCommand.json +4 -1
  37. package/dist/resources/schemas/StepDto.json +4 -1
  38. package/dist/resources/schemas/UpdateMicroserviceCommand.json +4 -1
  39. package/dist/resources/schemas/UpdateWorkflowCommand.json +4 -1
  40. package/dist/server.js +52 -42
  41. package/dist/tools/components.js +8 -0
  42. package/dist/tools/designSchemaPatch.js +152 -0
  43. package/dist/tools/flows.js +24 -21
  44. package/dist/tools/layouts.js +8 -8
  45. package/dist/tools/microservices.js +74 -10
  46. package/dist/tools/pages.js +275 -332
  47. package/dist/tools/projects.js +66 -9
  48. package/dist/tools/queries.js +72 -6
  49. package/dist/tools/schemaOps.js +280 -0
  50. package/dist/tools/screenWrite.js +2 -1
  51. package/dist/tools/screens.js +0 -7
  52. package/dist/tools/themes.js +163 -0
  53. package/dist/tools/workflows.js +10 -6
  54. package/package.json +1 -1
@@ -0,0 +1,55 @@
1
+ import { createHash } from 'node:crypto';
2
+ /** Alan sırasından bağımsız anahtar: aynı istek her çağrıda aynı sha256'yı üretmeli. */
3
+ function stable(value) {
4
+ if (Array.isArray(value))
5
+ return value.map(stable);
6
+ if (value && typeof value === 'object') {
7
+ const source = value;
8
+ return Object.keys(source).sort().reduce((target, key) => {
9
+ if (source[key] !== undefined)
10
+ target[key] = stable(source[key]);
11
+ return target;
12
+ }, {});
13
+ }
14
+ return value;
15
+ }
16
+ export function captureKey(parts) {
17
+ return createHash('sha256').update(JSON.stringify(stable(parts))).digest('hex');
18
+ }
19
+ export function imageHash(image) {
20
+ return createHash('sha256').update(image).digest('hex');
21
+ }
22
+ export class CaptureMemory {
23
+ limit;
24
+ entries = new Map();
25
+ constructor(limit = 50) {
26
+ this.limit = limit;
27
+ }
28
+ recall(key) {
29
+ return this.entries.get(key);
30
+ }
31
+ remember(key, entry) {
32
+ // Yeniden yazılan anahtar halkanın SONUNA gider: sık çekilen sayfa düşmesin.
33
+ this.entries.delete(key);
34
+ this.entries.set(key, entry);
35
+ while (this.entries.size > this.limit) {
36
+ const oldest = this.entries.keys().next().value;
37
+ if (oldest === undefined)
38
+ break;
39
+ this.entries.delete(oldest);
40
+ }
41
+ }
42
+ get size() {
43
+ return this.entries.size;
44
+ }
45
+ }
46
+ /**
47
+ * SÜREÇ düzeyinde tek bellek.
48
+ *
49
+ * HTTP taşıması her POST için YENİ bir gateway sunucusu kuruyor (`index.ts` `app.post('/mcp')`
50
+ * → `createGatewayServer`), yani `registerPageTools` istek başına koşuyor. Bellek o fonksiyonun
51
+ * içinde yaratıldığında her çağrı boş bir halkayla başlıyor ve `diff` her seferinde "ilk kare"
52
+ * diyordu — ölçüldü 2026-09-16, dört ardışık çağrının dördü de `baselineAt` yok. Stdio
53
+ * taşımasında sunucu oturum boyu yaşadığı için kusur orada görünmüyordu.
54
+ */
55
+ export const sharedCaptureMemory = new CaptureMemory();
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ function isRawShape(value) {
3
+ if (!value || typeof value !== 'object' || '_def' in value)
4
+ return false;
5
+ return Object.values(value).every(entry => entry instanceof z.ZodType);
6
+ }
7
+ /**
8
+ * GW-005 — tanınmayan üst düzey argüman REDDEDİLİR.
9
+ *
10
+ * SDK ham şekli `z.object(shape)` ile sarar ve zod'un varsayılanı bilinmeyen anahtarı hata vermeden
11
+ * ATMAKTIR: şemada olmayan bir alan doğrulamadan geçer, handler'a hiç ulaşmaz ve çağrı başarıyla
12
+ * biter. 2026-09-15 G-13'te `microservice_execute`/`microservice_debug`/`query_preview`'a verilen
13
+ * `parameters` böyle kayboldu — dört farklı filtre aynı gövdeyi döndü ve ölçüm aracı çağıranı
14
+ * olmayan bir sorgu kusuruna yönlendirdi. Tek tek tool'lara alan eklemek sınıfı kapatmaz; sessizlik
15
+ * burada, SDK'ya şema verilmeden önce kaldırılır.
16
+ */
17
+ export function rejectUnknownArguments(server) {
18
+ const registerTool = server.registerTool.bind(server);
19
+ server.registerTool = ((name, config, callback) => {
20
+ if (!isRawShape(config.inputSchema))
21
+ return registerTool(name, config, callback);
22
+ const shape = config.inputSchema;
23
+ const accepted = Object.keys(shape).join(', ');
24
+ const inputSchema = z.object(shape, {
25
+ errorMap: (issue, context) => issue.code === 'unrecognized_keys'
26
+ ? { message: `${name} şu üst düzey argümanları tanımıyor: ${issue.keys.map(key => `'${key}'`).join(', ')}. Tanınmayan alan sessizce yok sayılmaz — çağrı hiç gönderilmedi. Bu tool'un okuduğu alanlar: ${accepted}.` }
27
+ : { message: context.defaultError }
28
+ }).strict();
29
+ return registerTool(name, { ...config, inputSchema }, callback);
30
+ });
31
+ return server;
32
+ }
@@ -1,3 +1,4 @@
1
+ import { PROP_VALUE_TYPES } from '../knowledge/normalize.js';
1
2
  import { logStep } from '../observability/trace.js';
2
3
  const maxDrops = 20;
3
4
  const maxDepth = 12;
@@ -214,9 +215,11 @@ export function unwrapProps(value) {
214
215
  const record = value;
215
216
  const isProp = typeof record.type === 'string' && (Object.hasOwn(record, 'data') || Object.hasOwn(record, 'ref'));
216
217
  if (isProp) {
217
- // `code` ve `translation` prop'larında taşıyıcı alan `ref`'tir; `data` yalnız tasarım zamanı
218
- // yedeğidir (platform_guide('translation')).
219
- const carrier = record.type === 'code' || record.type === 'translation'
218
+ // Platform `static` dışındaki her tipte değeri `ref`'e yazar (Prop ctor'u,
219
+ // DesignComponentManagementSchema.cs:666); `data` ya boştur ya türetilmiştir (file URL'i, page
220
+ // slug'ı, translation tasarım yedeği). `data`'yı taşıyıcı saymak bağlı akışı her yazmada
221
+ // "kaydedilen null" gösteriyordu (S-7).
222
+ const carrier = record.type !== 'static' && PROP_VALUE_TYPES.has(record.type)
220
223
  ? (Object.hasOwn(record, 'ref') ? record.ref : record.data)
221
224
  : (Object.hasOwn(record, 'data') ? record.data : record.ref);
222
225
  return unwrapProps(carrier);
@@ -6,7 +6,7 @@
6
6
  "sourceRef": "platform_guide('layout') Kural 5a/5b; zeyrek-frontend apps/studio/src/features/layout/layout.functions.ts (getDefaultLayout), packages/ng-apps-screen-builder/src/flex-layout.ts (getFlexChildStyle), packages/ng-apps-ui/src/shared/render/render.functions.ts"
7
7
  },
8
8
  "_rules": {
9
- "viewsNotSchema": "Layout'ta şema alanının adı 'views'tir; micro-op hattı yoktur, değişiklik layout_update ile tam gövde olarak yazılır (LAY-001).",
9
+ "viewsNotSchema": "Layout'ta şema alanının adı 'views'tir (LAY-001). Kurulu layout'ta hedefli değişiklik layout_schema_patch micro-op'larıyla yazılır; tam ağaç layout_update ile.",
10
10
  "singleSlot": "TEK slot. Sayfa şeması HER slot'a ayrı ayrı kopyalanır — iki slot sayfayı iki kez çizer ve elementId'leri tekrarlar (LAY-002 / LAY-006).",
11
11
  "propValueField": "Statik prop'un değeri 'data' alanındadır ({ type:'static', ref:null, data }); 'ref' referans tipleri (flow/file) içindir. Ham değer yazarsanız gateway sarmalar ve normalizasyon notu döner.",
12
12
  "slotRowIsOpenEnded": "Slot'un grid satırı açık uçludur (runtime 'y / auto' yazar): sayfa uzadıkça slot uzar. Slot'a sabit yükseklik vermeye çalışma.",
@@ -13,7 +13,7 @@
13
13
  "rawRedirect": "redirect isRaw:true iken path ÇOK SATIRLI JS bloğudur ve son ifadenin değeri hedef adrestir. 'Korunan sayfaya gitmek isterken login'e düşen kullanıcıyı geri gönderme' deseni budur; yoksa sabit bir sayfaya gidilir (pageId + path).",
14
14
  "objectProp": "Prop değeri nesne olabilir: icon → { type:'static', ref:{ name:'progress_activity' } }.",
15
15
  "pageIsPublic": "Giriş sayfasına middlewareIds BAĞLANMAZ (guard'lı olsaydı kullanıcı giriş yapamazdı). Buna karşılık diğer sayfalar ve korunan uçlar middlewareIds ile bağlanır.",
16
- "notificationIsHidden": "notification'ın şemasında isHidden 2026-08-26'dan beri VARDIR: props.isHidden'ı doğrudan bildirime yazabilirsin. Bu örnekteki box_message sarmalayıcısı o dönemin kalıntısıdır (crm koşumu B-10) ve tek bir bildirim için ARTIK GEREKMEZ — burada duruyor çünkü şeridi bir kaba sarıp birden çok parçayı birlikte gösterip gizliyor. appearance.isHidden ise hiçbir zaman çözüm DEĞİLDİR — runtime onu hiç okumaz.",
16
+ "notificationIsHidden": "notification'ın şemasında isHidden 2026-08-26'dan beri VARDIR: props.isHidden'ı doğrudan bildirime yazabilirsin. Bu örnekteki box_message sarmalayıcısı o dönemin kalıntısıdır (crm koşumu B-10) ve tek bir bildirim için ARTIK GEREKMEZ — burada duruyor çünkü şeridi bir kaba sarıp birden çok parçayı birlikte gösterip gizliyor. appearance'ta ise isHidden alanı YOKTUR (2026-09-15'te kaldırıldı) — görünürlük yalnız props.isHidden'dır.",
17
17
  "validationShape": "Validation gövdesi DÖRT alan taşır: { type, message, value, isActive }. 'name' anahtarı JsonIgnore'dur — {name, value, message} yazarsan tip enum varsayılanına düşer ve alan sessizce REGEX doğrulamasına döner. Tip adları TİRELİDİR (max-length / min-length / max-value / min-value); 'maxLength' backend'e yazılır ama runtime doğrulayıcı onu tanımaz ve doğrulama hiç koşmaz. Gateway düzeltebildiğini düzeltir, kalanını PAGE-016 ile reddeder."
18
18
  },
19
19
  "pageCreateArgs": {
@@ -0,0 +1,162 @@
1
+ {
2
+ "_meta": {
3
+ "synthetic": true,
4
+ "note": "Studio tema panelinin ürettiği kayıtla aynı şekil. Yalnız SAPAN değerler yazılır: typeScale/radiusScale/spacingScale/actions dokunulmayan kademeleri taşımaz, böylece platform varsayılanı değişince onları izlemeye devam ederler. Preset gövdeleri sabit hex değil var(--ng-*) kullanır — preset de temayı izlesin.",
5
+ "usage": "theme_update({ theme: <themeUpdateArgs.theme> }) — kısmi yazma; tamamını kurmak için replace: true. componentPresets tipleri doğrulansın istiyorsanız applicationId verin (THEME-011)."
6
+ },
7
+ "_rules": [
8
+ "shadow.color altı haneli hex OLMALI; başka yazım üç gölgeyi birden görünmez yapar (THEME-004).",
9
+ "Oranlar 0 < r <= 20; aralık dışı değer runtime'da sessizce yok sayılır (THEME-007).",
10
+ "mode:'dark' yazılacaksa paletteDark da yazılır — karanlıkta runtime palette'e BAKMAZ (THEME-009).",
11
+ "componentPresets bir kaskad değil BAŞLANGIÇ değeridir: mevcut düğümlere dokunmaz; bir tip en fazla 5 versiyon taşır ve defaultVersion versiyonlar arasında olmalıdır (THEME-002).",
12
+ "componentStyles EMEKLİ: panel ilk kayıtta onu componentPresets'e taşır ve canlı kaskad kopar (THEME-003). Bu örnek onu hiç taşımaz."
13
+ ],
14
+ "themeUpdateArgs": {
15
+ "theme": {
16
+ "mode": "light",
17
+ "palette": {
18
+ "accent": {
19
+ "primary": "#4F46E5",
20
+ "hover": "#4338CA",
21
+ "muted": "#EEF2FF",
22
+ "subtle": "#F5F7FF"
23
+ },
24
+ "background": {
25
+ "canvas": "#F8FAFC",
26
+ "surface": "#FFFFFF",
27
+ "surfaceAlt": "#F1F5F9"
28
+ },
29
+ "border": {
30
+ "primary": "#E2E8F0",
31
+ "secondary": "#94A3B8"
32
+ },
33
+ "text": {
34
+ "primary": "#0F172A",
35
+ "secondary": "#475569",
36
+ "disabled": "#94A3B8"
37
+ },
38
+ "status": {
39
+ "success": "#15803D",
40
+ "warning": "#B45309",
41
+ "error": "#B91C1C",
42
+ "info": "#F1F5F9"
43
+ }
44
+ },
45
+ "paletteDark": {
46
+ "accent": {
47
+ "primary": "#818CF8",
48
+ "hover": "#A5B4FC",
49
+ "muted": "#1E1B4B",
50
+ "subtle": "#151338"
51
+ },
52
+ "background": {
53
+ "canvas": "#0B1120",
54
+ "surface": "#111827",
55
+ "surfaceAlt": "#0F172A"
56
+ },
57
+ "border": {
58
+ "primary": "#1F2937",
59
+ "secondary": "#475569"
60
+ },
61
+ "text": {
62
+ "primary": "#E2E8F0",
63
+ "secondary": "#94A3B8",
64
+ "disabled": "#475569"
65
+ },
66
+ "status": {
67
+ "success": "#34D399",
68
+ "warning": "#FBBF24",
69
+ "error": "#F87171",
70
+ "info": "#1F2937"
71
+ }
72
+ },
73
+ "fontFamily": "Inter Tight",
74
+ "headingFontFamily": "Sora",
75
+ "fontSize": "15px",
76
+ "fontWeight": "400",
77
+ "typeScale": {
78
+ "h1": 2.5,
79
+ "small": 0.8
80
+ },
81
+ "spacing": "12px",
82
+ "spacingScale": {
83
+ "xl": 5
84
+ },
85
+ "borderRadius": "8px",
86
+ "radiusScale": {
87
+ "lg": 2
88
+ },
89
+ "shadow": {
90
+ "offsetX": 0,
91
+ "offsetY": 6,
92
+ "blur": 12,
93
+ "spread": -2,
94
+ "color": "#1E1B4B",
95
+ "opacity": 18
96
+ },
97
+ "defaultInputSize": "md",
98
+ "actions": {
99
+ "blue": "#4F46E5",
100
+ "red": "#E11D48"
101
+ },
102
+ "presets": {
103
+ "kart": {
104
+ "padding": "16px",
105
+ "borderRadius": "var(--ng-radius-lg)",
106
+ "background": "var(--ng-background-surface)",
107
+ "border": "1px solid var(--ng-border-primary)",
108
+ "boxShadow": "var(--ng-shadow-sm)",
109
+ "transition": "border-color 140ms ease, box-shadow 140ms ease",
110
+ "&:hover": {
111
+ "borderColor": "var(--ng-accent-primary)",
112
+ "boxShadow": "var(--ng-shadow-md)"
113
+ }
114
+ },
115
+ "sessizMetin": {
116
+ "color": "var(--ng-text-secondary)",
117
+ "fontSize": "var(--ng-font-size-small)"
118
+ }
119
+ },
120
+ "componentPresets": {
121
+ "button": {
122
+ "defaultVersion": "V1",
123
+ "versions": {
124
+ "V1": {
125
+ "props": {
126
+ "size": "lg"
127
+ },
128
+ "appearance": {
129
+ "marginType": "custom",
130
+ "marginValues": {
131
+ "top": 0,
132
+ "right": 0,
133
+ "bottom": 12,
134
+ "left": 0
135
+ }
136
+ }
137
+ },
138
+ "V2": {
139
+ "props": {
140
+ "size": "sm",
141
+ "type": "secondary"
142
+ }
143
+ }
144
+ }
145
+ },
146
+ "container": {
147
+ "defaultVersion": "V1",
148
+ "versions": {
149
+ "V1": {
150
+ "props": {
151
+ "layout": "flex",
152
+ "direction": "row",
153
+ "gap": "medium",
154
+ "wrap": true
155
+ }
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
@@ -60,7 +60,10 @@ Doğrulama mesajını çeviriye bağlamak ayrı bir sözleşmedir (`t:` öneki,
60
60
  (`eventcalendar` · `importwizard` · `kanban` · `signature` · `stepper`) dolar — `kanban` ve
61
61
  `eventcalendar` yükü `self`'e HİÇ yazmaz, yalnız `event.data` ile okunur (ayrım
62
62
  `component_get` sözleşme notlarında).
63
- - Akış bağlama: `flow_create` → `page_schema_patch set_event`. İstisna: `html` komponentinin
63
+ - Akış bağlama: `flow_create` → `set_event` (sayfada `page_schema_patch`, layout'ta
64
+ `layout_schema_patch`, widget'ta `component_schema_patch`). Akış isteği barındırıcının şemasını
65
+ yazmaz; bağ yalnız bu yamayla kurulur, silmede de önce `remove_event` sonra `flow_delete`.
66
+ İstisna: `html` komponentinin
64
67
  aksiyonları kendi `flow` prop'uyla bağlanır (`platform_guide('html')`).
65
68
 
66
69
  ## Stil
@@ -87,6 +90,9 @@ Widget, kendi komponent ağacını taşıyan yeniden kullanılabilir pakettir (`
87
90
  `elementId`'leri kullanır; Studio düzenleyicisinin gösterdiği `__widget__` yer tutucusu
88
91
  yalnız editör katmanıdır (kayıt anında gerçek id'ye çevrilir) — API'den yazarken yer
89
92
  tutucu KULLANMA.
93
+ 4. **Ağacı değiştirmek:** `component_schema_patch` (widget kaydının `id`'si) sayfa ile aynı
94
+ micro-op'ları `PATCH /components/{app}/{id}/schema`'ya yazar; `component_update` ise slug alan
95
+ tam gövde PUT'tur. Widget'ın düzey olayı yoktur, `remove_event` yalnız komponent hedefler.
90
96
 
91
97
  ## `states` ve `appearance` sözlükleri
92
98
 
@@ -117,7 +123,7 @@ Her şema düğümünde iki sözlük vardır; ikisi de ortak render katmanında
117
123
  | `widthType` | `cover` · `contain` · `auto` · `fixed` · `fill` | İlk ikisi görsel/medya sığdırma. Kalanı **flex (ve eski cssgrid) kabın çocuğunun genişlik modu** (2026-09-01): `auto` içerik kadar, `fixed` `widthString`'den, `fill` kabın tüm genişliği (satırda `flex:1 1 100%`, sütunda `align-self:stretch`). **Yazılmazsa eski 12 kolon `blocks.size.w` payı geçerlidir** — öncelik: `fill` > `fixed` > `auto` > span |
118
124
  | `widthString` / `heightString` | CSS uzunluğu | Sabit ölçü; **yalnız ilgili `*Type: 'fixed'` iken okunur** (aksi PAGE-017 uyarısı). Kabul: çıplak sayı (px sayılır) · `px % vw vh vmin vmax rem em ch` birimli değer · `calc(...)`. Negatif/`pt`/`fr`/`auto` GEÇMEZ — platform kaydeder ama panel ve runtime sessizce düşürür (PAGE-018). Eski `widthPx` alanı 2026-09-01'de kaldırıldı |
119
125
  | `marginType` / `marginValue` | `normal` · `none` · `custom` + px | Dış boşluk: **yazılmazsa `normal` sayılır** = her kenara 4px (`spacing.ts` `CANVAS_NORMAL_MARGIN`); custom=`marginValue`. Bileşenleri dip dibe dizmek için `none` ŞART — `gap:'none'` olsa bile normal margin komşular arasında 8px bırakır (sıkı dizilim tarifi: `platform_guide('page')` Kural 1f-2) |
120
- | `paddingType` / `paddingValue` | `normal` · `none` · `custom` + px | Droppable kapların iç boşluğu: normal=10px |
126
+ | `paddingType` / `paddingValue` | `normal` · `none` · `custom` + px | İç boşluk: normal=10px. **Yalnız droppable kaplarda ve tipli stil modelindeki yapraklarda (box · text · container · statcard · icon · form) çizilir**; `slot`, kabuk kökleri (`layout`/`layout-shell`) ve `modal`/`drawer`/`auth-layout` hiç almaz — platform 200 döner, ekran değişmez (PAGE-029). Değerler piksel SAYISIDIR: `24`, `"24px"` değil (PAGE-030) |
121
127
  | `alignType` | `left` · `center` · `right` | İçerik hizalama (destekleyen komponentlerde) |
122
128
  | `aspectRatio` | sayı | En-boy oranı kilidi (medya komponentleri) |
123
129
 
@@ -103,6 +103,7 @@ dalından devam eder.
103
103
  | `event` | `{name, data, source: {id, props}}` |
104
104
  | `cookie` | `cookie.get(name)` / `cookie.set(name, value, {expiresInHours, path})` / `cookie.remove(name)` — tarayıcı cookie'si |
105
105
  | `setComponentProperty(name, key, value)` / `getComponentProperty(name, key)` | fonksiyon alternatifi |
106
+ | `resetForm(name)` | Formu sıfırlar: alanlar başlangıç değerine döner, form "gönderilmemiş" olur, doğrulama mesajları silinir. Kayıt sonrası "yeni kayıt" için alanları tek tek `null`'a çekme — gönderilmiş formda her biri "zorunlu alan" mesajı çıkarır. Ad ya da komponent değişkeni alır: `resetForm('risk_form')` / `resetForm(risk_form)`. **Yalnız UI flow kodunda** |
106
107
  | `LocalStorage` · `Widget` · `params` | yerel veri · widget bağlamı · olay parametreleri |
107
108
  | `t(key)` | Çeviri anahtarını çözer: aktif dil → projenin varsayılan dili → anahtarın kendisi. Boş string de "eksik" sayılır. Sözlük `machine.context.state.translations`'tan gelir; dil `language-selector` ile değişince bir sonraki çağrı yeni dili görür. **Yalnız UI flow kodunda vardır** — backend ifadelerinde karşılığı `Loc()`'tur (`platform_guide('workflow')`) | `t('home.welcome')` |
108
109
  | `log(...)` | console (proxy'leri temizler) |
@@ -130,6 +131,11 @@ prop `type: 'code'` olur, **ifade `ref` alanına `{{ }}` içinde** yazılır, `d
130
131
  değerini taşır:
131
132
  `"text": { "type": "code", "data": "Button text", "ref": "{{ state.page.MyTest.isActive ? 'Test' : 'FalseTest' }}" }`
132
133
 
134
+ > **Prop'ta parantezsiz ifade METİNDİR (PAGE-032).** Akış adımındaki `value.type: 'code'`
135
+ > ifadeyi doğrudan koşturur; prop'taki `code` ise bir şablondur ve yalnız `{{ }}` içini
136
+ > çalıştırır. `"ref": "new Date().getFullYear()"` prop'a harfi harfine o metni yazar, hata
137
+ > üretmez — `page_schema_patch` bu yüzden parantezsiz prop ifadesini reddeder.
138
+
133
139
  ## 3. Adım argümanlarında `value.type` çözümlemesi
134
140
 
135
141
  `microservice`/`setter` adımlarının `parameters[]`/`iteratees[]` değerlerinde:
@@ -140,7 +140,13 @@ koda baktığını gizlemek yerine raporlamak.
140
140
  - create/update → ilgili `*_get` ile geri oku
141
141
  - microservice → `microservice_execute`, beklenmedik sonuçta `microservice_debug`
142
142
  - workflow → `workflow_preview`; automation → `automation_trigger` + `automation_histories`
143
+ - zamanlanmış iş (`schedule-job`) → ÖNCE `workflow_preview` / `microservice_debug` (rollback'li adım
144
+ izi), SONRA `microservice_schedule_control` `trigger` + `microservice_job_history`. Geçmiş
145
+ `failed` satırında patlayan adımı ve sebebini yazar ama adım izini vermez
146
+ (`platform_guide('microservice')` §Zamanlanmış işin gerçek sonucunu görmek)
143
147
  - "API 200 döndü" tek başına bitti saymaz; politika bulgularını (`policyFindings`) oku ve gereğini yap
148
+ - Tool'un şemasında olmayan üst düzey argüman **reddedilir** ve hata okunan alanları listeler
149
+ (GW-005). Bir argüman kabul edildiyse gateway onu okuyor demektir.
144
150
 
145
151
 
146
152
  ## Yazdıktan sonra `silentlyDropped` alanına bak
@@ -12,22 +12,29 @@ kutusu layout modülünde süzülmez — tüm katalog kullanılabilir.
12
12
 
13
13
  **2. Şema alanının adı `schema` değil `views`.** (LAY-001)
14
14
 
15
- **3. Micro-op ucu yok, ama `PATCH /layouts/{app}/{id}` var.** `page_schema_patch`'in birebir
16
- karşılığı yoktur (`PATCH /layouts/.../schema` ucu yok); onun yerine platform genel bir JSON Patch
17
- ucu verir ve `layout_patch` onu kullanır: layout'u okur, JSON Patch'i ve kendi normalizasyonlarını
18
- uygular, doğrulamadan geçirir ve **farkı** `{ baseVersion, ops }` olarak yazar — tam gövde PUT'u
19
- atılmaz. Böylece tek bir başlık düzeltmesi için 12 düğümlük ağacı yeniden göndermezsin (ölçüm:
20
- 09-04 koşusu Y-25). Yol İNDEKS yerine SEÇİCİ alır:
21
- `/views/0/children[elementId=baslik]/props/content/data`.
22
-
23
- **Sürüm ve 409.** Okunan kaydın `version` alanı `baseVersion` olarak gider. Sen okuduktan sonra
24
- başka biri yazdıysa platform **409** döner ve HİÇBİR op uygulanmaz; doğru tepki "aynı op'ları
25
- tekrar göndermek" değil, `layout_schema_get` ile yeniden okuyup patch'i güncel hâle göre kurmaktır.
26
- `version` bir **string**tir (mikrosaniye cinsinden zaman damgası, JavaScript'in güvenli tam sayı
27
- sınırının üstünde) — sayıya çevirme, olduğu gibi geri gönder. `expectedUpdatedAt` verirsen gateway
28
- ayrıca istek gitmeden önce yerel bir kontrol daha yapar. Tam ağacı kendin yazacaksan `layout_update`;
29
- `views` göndermezsen mevcut ağaç korunur. Okumak için `layout_schema_get` (summary kipi hedef bulmak
30
- için yeterlidir).
15
+ **3. Ağaç değişikliği `layout_schema_patch` ile (2026-09-14).** Platform
16
+ `PATCH /layouts/{app}/{id}/schema` ucunu verir ve sayfa ile **aynı** micro-op sözlüğünü konuşur:
17
+ `add_component`, `remove_component`, `move_component`, `replace_prop`, `set_event`, `remove_event`,
18
+ `resize_component`, `set_prop_type`, `reorder` ve diğerleri `page_schema_patch`'teki gibi yazılır.
19
+ Dokunulan düğümler tam doğrulanır, geri kalan ağaç yapısal; istek atomiktir. Sayfadan farkları:
20
+
21
+ - Kök ekleme `parent: 'root'`'a gider — layout'ta `page_container` yoktur.
22
+ - `remove_event` `target: 'page'` layout düzeyi olayları hedefler.
23
+ - `baseVersion` yoktur: son yazan kazanır. Hedefleri yazmadan hemen önce `layout_schema_get` ile oku.
24
+ - Slot'u silen ya da ikinci slot ekleyen yama yazılır ama LAY-002 / LAY-006 uyarısı döner (Kural 4).
25
+ - Bağı kalmayan akışı platform kalıcı siler; gateway böyle bir yamayı `allowFlowDeletion: true`
26
+ olmadan göndermez (G-21, sayfadakiyle aynı).
27
+
28
+ Okumak için `layout_schema_get` (summary kipi hedef bulmak için yeterlidir); tam ağacı kendin
29
+ yazacaksan `layout_update` (`views` göndermezsen mevcut ağaç korunur).
30
+
31
+ **3a. `layout_patch` düz JSON Patch içindir.** Ad, `parameters`, `events` gibi ağaç dışı alanlar ya
32
+ da yol gerektiren bir değişiklik için: layout'u okur, JSON Patch'i ve kendi normalizasyonlarını
33
+ uygular ve **farkı** `PATCH /layouts/{app}/{id}`'ye `{ baseVersion, ops }` olarak yazar (09-04 koşusu
34
+ Y-25). Yol İNDEKS yerine SEÇİCİ alır: `/views/0/children[elementId=baslik]/props/content/data`.
35
+ Okunan kaydın `version`'ı `baseVersion` olarak gider; araya başka bir yazma girdiyse **409** döner
36
+ ve hiçbir op uygulanmaz — doğru tepki `layout_schema_get` ile yeniden okuyup patch'i güncel hâle
37
+ göre kurmaktır. `version` bir **string**tir (mikrosaniye zaman damgası) — sayıya çevirme.
31
38
 
32
39
  **4. TEK slot.** Sayfa şeması **her** slot'a ayrı ayrı kopyalanır — iki slot, sayfayı iki
33
40
  kez çizer ve `elementId`'leri tekrarlar. (LAY-002 / LAY-006)
@@ -92,6 +99,12 @@ container isWrapper:true heightType:'fill' layout:'flex' direction:'row' gap:
92
99
  uçludur (`y / auto`), yani sayfa uzadıkça slot uzar.
93
100
  - **Kaydırma:** `fill` + `states.isScrollable:true` verilen düğüm büyümek yerine İÇİNDE
94
101
  kaydırır — uzun içerikte kabuğu sabit tutmanın yolu budur.
102
+ - **Slot'un kenar boşluğu margin'dir, padding değil.** Slot droppable değildir; ona yazılan
103
+ `paddingType`/`paddingValue` hiçbir kutuya çizilmez (LAY-010). Her sayfanın kenardan uzak
104
+ durmasını tek yerden istiyorsan slot'a `appearance.marginType: 'custom'` + `marginValue: 24`
105
+ yaz — margin slot'un sarmalayıcısına iç boşluk olarak iner ve slot'un zemini olmadığı için
106
+ sonuç padding'le aynıdır. Studio iskeleti slot'a zaten 8px custom margin verir. Değer SAYIDIR
107
+ (`24`, `"24px"` değil — LAY-011). Her sayfaya sarmalayıcı container eklemek gerekmez.
95
108
  - **MOBİL UYARISI:** bu ağaç `flex` olduğu için telefonda YIĞILMAZ (Kural 7) — 375px'te yan
96
109
  menü ince bir şerite iner. Telefonda alt alta düşmesi gereken bir kabuk için kökü
97
110
  `layout:'grid'` kur; o zaman `fill`'in flex anlamı (`flex:1 1 auto`) devreye girmez,
@@ -135,7 +148,8 @@ bağlantı nesnesi ya da tam yol).
135
148
  ## Çeviri: header/sidebar etiketini anahtara bağlamak
136
149
 
137
150
  Layout'un `views` ağacındaki bir etiketi çeviriye bağlamak için **bütün ağacı yeniden yazma**.
138
- `layout_patch` `set_prop_type` micro-op'unu tanır ve prop'un tipini yerinde değiştirir:
151
+ `layout_schema_patch`'in `set_prop_type` op'u prop'un tipini yerinde değiştirir (`layout_patch` de
152
+ aynı op'u tanır ve JSON Patch ile karışık kabul eder):
139
153
 
140
154
  ```jsonc
141
155
  { "op": "set_prop_type", "target": "app_header_title", "prop": "content",
@@ -145,15 +159,11 @@ Layout'un `views` ağacındaki bir etiketi çeviriye bağlamak için **bütün a
145
159
  - Anahtar **`ref`'te** yaşar, `data`'da değil — runtime `data`'yı her turda çözümlenmiş değerle
146
160
  ezer. `ref` boşsa gateway isteği göndermeden reddeder.
147
161
  - Mevcut statik metin `data`'da yedek olarak KALIR, böylece Studio canvas'ında boş kutu görünmez.
148
- - `set_prop_type` ile JSON Patch aynı `ops` listesinde karışık verilebilir; micro-op'lar önce
149
- uygulanır, sonra patch yolları çözülür.
150
- - Aynı op sayfa tarafında `page_schema_patch` ile çalışır — sözleşme birebir aynıdır. Anahtarları
151
- `translation_list` ile bulun; fallback zinciri ve `t:` doğrulama mesajı sözleşmesi
152
- `platform_guide('translation')`'da.
153
-
154
- > Layout'un diğer micro-op'ları YOKTUR: `add_component`, `remove_component`, `replace_prop` ve
155
- > arkadaşları yalnız sayfa hattındadır. Layout'ta düğüm eklemek/silmek için JSON Patch ya da
156
- > `layout_update` kullanılır.
162
+ - `layout_patch`'te `set_prop_type` ile JSON Patch aynı `ops` listesinde karışık verilebilir;
163
+ micro-op'lar önce uygulanır, sonra patch yolları çözülür.
164
+ - Aynı op sayfa tarafında `page_schema_patch`, widget'ta `component_schema_patch` ile çalışır —
165
+ sözleşme birebir aynıdır. Anahtarları `translation_list` ile bulun; fallback zinciri ve `t:`
166
+ doğrulama mesajı sözleşmesi `platform_guide('translation')`'da.
157
167
 
158
168
  ## Sayfayı layout'a bağlama
159
169