@appaflytech/zeyrek-ai-mcp 0.0.43 → 0.0.45

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/dist/knowledge/backendConstraints.js +86 -2
  2. package/dist/knowledge/componentCatalog.js +63 -26
  3. package/dist/knowledge/componentEvents.js +6 -0
  4. package/dist/knowledge/connectDataBind.js +43 -6
  5. package/dist/knowledge/connectDataDefinition.js +74 -3
  6. package/dist/knowledge/connectDataRules.js +14 -0
  7. package/dist/knowledge/mobileComponentCatalog.js +66 -7
  8. package/dist/knowledge/mobileStore.js +61 -2
  9. package/dist/knowledge/platform/mobile.js +1 -1
  10. package/dist/knowledge/platform/mobileRules.js +2 -1
  11. package/dist/knowledge/platform/mobileTabs.js +31 -2
  12. package/dist/knowledge/platform/web.js +1 -1
  13. package/dist/knowledge/rules.js +195 -4
  14. package/dist/knowledge/textHooks.js +434 -0
  15. package/dist/platform/capture/capture.js +1 -1
  16. package/dist/platform/capture/readiness.js +4 -0
  17. package/dist/platform/errors.js +22 -2
  18. package/dist/prompts/mobilePublish.js +21 -0
  19. package/dist/resources/examples/flow-biometric-confirm.json +199 -0
  20. package/dist/resources/examples/microfunction-node-dependencies.json +19 -0
  21. package/dist/resources/guides/access.md +3 -3
  22. package/dist/resources/guides/component.md +20 -4
  23. package/dist/resources/guides/deployment.md +98 -0
  24. package/dist/resources/guides/entity.md +1 -1
  25. package/dist/resources/guides/expressions.md +5 -1
  26. package/dist/resources/guides/external-component.md +6 -4
  27. package/dist/resources/guides/merge.md +81 -4
  28. package/dist/resources/guides/microfunction.md +104 -9
  29. package/dist/resources/guides/microservice.md +34 -5
  30. package/dist/resources/guides/mobile-connect-data.md +70 -0
  31. package/dist/resources/guides/mobile-flow.md +64 -0
  32. package/dist/resources/guides/mobile-publish.md +161 -16
  33. package/dist/resources/guides/mobile-steps.md +17 -0
  34. package/dist/resources/guides/mobile.md +41 -23
  35. package/dist/resources/guides/page.md +11 -5
  36. package/dist/resources/guides/translation.md +95 -0
  37. package/dist/resources/knowledge.js +3 -1
  38. package/dist/resources/prompts/mobile-publish-prepare.md +89 -0
  39. package/dist/resources/schema-fingerprint.json +4 -4
  40. package/dist/resources/schemas/ApplyMicrofunctionArchiveChangesCommand.json +76 -0
  41. package/dist/resources/schemas/ConnectDataDescribeDto.json +44 -0
  42. package/dist/resources/schemas/ConnectDataResultDto.json +10 -0
  43. package/dist/resources/schemas/CreateMicrofunctionCommand.json +8 -0
  44. package/dist/resources/schemas/InvokeMicrofunctionCommand.json +0 -4
  45. package/dist/resources/schemas/MobileStorePreflightScope.json +13 -0
  46. package/dist/resources/schemas/StartMobileBuildCommand.json +35 -1
  47. package/dist/resources/schemas/UpdateMicrofunctionCommand.json +8 -0
  48. package/dist/resources/schemas/UpsertMobileStoreSettingsCommand.json +75 -0
  49. package/dist/server.js +2 -0
  50. package/dist/tools/common.js +6 -0
  51. package/dist/tools/components.js +19 -6
  52. package/dist/tools/connectData.js +9 -4
  53. package/dist/tools/deployments.js +1 -1
  54. package/dist/tools/designSchemaPatch.js +16 -4
  55. package/dist/tools/environments.js +3 -3
  56. package/dist/tools/files.js +1 -1
  57. package/dist/tools/flows.js +29 -3
  58. package/dist/tools/layouts.js +32 -12
  59. package/dist/tools/merges.js +8 -8
  60. package/dist/tools/microfunctions.js +53 -3
  61. package/dist/tools/mobileStore.js +83 -21
  62. package/dist/tools/pages.js +59 -24
  63. package/dist/tools/platformInfo.js +4 -2
  64. package/dist/tools/textHookGuard.js +116 -0
  65. package/package.json +2 -2
@@ -0,0 +1,199 @@
1
+ {
2
+ "_meta": {
3
+ "synthetic": true,
4
+ "note": "Ödeme gibi bir eylemden önce kullanıcıyı Face ID / parmak izi ile doğrulayan düğme akışı (kök docs/adr/0021-biyometrik-dogrulama-adimi-ve-uygulama-kilidi.md): başarı always dalında işi yapar, vazgeçme ve doğrulanamama error dalında kullanıcıya söylenir. 'Bu cihazda biyometri yok' metni Device.biometric.available'a bağlıdır.",
5
+ "harvestedFrom": "canlı doğrulama 2026-10-15: lokal test projesi mobile-app, /dev önizlemesinde 'Doğrulandı say' → Doğrulandı: {\"verified\":true}, vazgeç → Hata: cancelled; aynı akış page_screenshot ile (click → awaiting-user → preview-biometric__verify) sürüldü"
6
+ },
7
+ "_rules": {
8
+ "args": "args.title sistem penceresindeki gerekçe, args.cancelText vazgeç düğmesi (metin şablonu; boşsa uygulama dilindeki varsayılan). args.value yedek, DÜZ METİN: 'device' (biyometri olmazsa cihaz parolası; boş = bu) ya da 'none'. Küme dışı 422; fallback/reason/cancelLabel anahtarı sessizce düşer — FLOW-042.",
9
+ "branches": "Dallar 'always' ve 'error'. Vazgeçme bir HATADIR: error dalı → akışın hata adımları → ikisi de yoksa akış bu adımda BİTER ve always'e bağlı iş koşmaz (FLOW-042 uyarır).",
10
+ "output": "Başarı Steps.<adım ADI>.data = { verified: true }; hata Steps.<ad>.error.status: cancelled · not-enrolled · lockout · failed · unavailable · unsupported · invalid.",
11
+ "where": "Studio önizlemesi, canlı kip, /dev ve /branch sormaz: 'Doğrulandı say' / vazgeç penceresi açar. Production /view ve web uygulaması unsupported döner. Oynatıcıda (Expo Go) yedeği none olan adım hep unavailable.",
12
+ "security": "Yerel bir kapıdır, sunucu için kanıt değildir: sunucu tarafı yetkiyi ayrıca denetleyin.",
13
+ "binding": "Akışı olaya bağlamak ayrı adımdır: page_schema_patch set_event { target: 'btn_ode', event: 'click', eventValue: '<flow id>' }."
14
+ },
15
+ "pageOps": [
16
+ {
17
+ "op": "add_component",
18
+ "parent": "page_container",
19
+ "component": {
20
+ "elementId": "tx_biyometri_yok",
21
+ "name": "tx_biyometri_yok",
22
+ "type": "text",
23
+ "props": {
24
+ "content": "Bu cihazda biyometri ya da cihaz parolası kurulu değil",
25
+ "isHidden": {
26
+ "type": "code",
27
+ "ref": "{{ Device.biometric.available }}"
28
+ }
29
+ },
30
+ "blocks": [
31
+ {
32
+ "breakpoint": 1024,
33
+ "size": {
34
+ "w": 12,
35
+ "h": 1
36
+ },
37
+ "position": {
38
+ "x": 0,
39
+ "y": 1
40
+ }
41
+ }
42
+ ]
43
+ }
44
+ },
45
+ {
46
+ "op": "add_component",
47
+ "parent": "page_container",
48
+ "component": {
49
+ "elementId": "btn_ode",
50
+ "name": "btn_ode",
51
+ "type": "button",
52
+ "props": {
53
+ "text": "Ödemeyi onayla"
54
+ },
55
+ "blocks": [
56
+ {
57
+ "breakpoint": 1024,
58
+ "size": {
59
+ "w": 12,
60
+ "h": 1
61
+ },
62
+ "position": {
63
+ "x": 0,
64
+ "y": 2
65
+ }
66
+ }
67
+ ]
68
+ }
69
+ },
70
+ {
71
+ "op": "add_component",
72
+ "parent": "page_container",
73
+ "component": {
74
+ "elementId": "tx_sonuc",
75
+ "name": "tx_sonuc",
76
+ "type": "text",
77
+ "props": {
78
+ "content": ""
79
+ },
80
+ "blocks": [
81
+ {
82
+ "breakpoint": 1024,
83
+ "size": {
84
+ "w": 12,
85
+ "h": 1
86
+ },
87
+ "position": {
88
+ "x": 0,
89
+ "y": 3
90
+ }
91
+ }
92
+ ]
93
+ }
94
+ }
95
+ ],
96
+ "flowCreateArgs": {
97
+ "host": "page",
98
+ "hostId": "<page id>",
99
+ "name": "btn_ode - click",
100
+ "slug": "btn-ode-click",
101
+ "steps": [
102
+ {
103
+ "stepId": "start",
104
+ "name": "start",
105
+ "type": "start",
106
+ "kind": "normal",
107
+ "args": {},
108
+ "branches": [
109
+ {
110
+ "name": "always",
111
+ "nextStepId": "dogrula"
112
+ }
113
+ ]
114
+ },
115
+ {
116
+ "stepId": "dogrula",
117
+ "name": "dogrula",
118
+ "type": "biometric-auth",
119
+ "kind": "normal",
120
+ "args": {
121
+ "title": "Ödemeyi onaylayın",
122
+ "cancelText": "Vazgeç",
123
+ "value": "device"
124
+ },
125
+ "branches": [
126
+ {
127
+ "name": "always",
128
+ "nextStepId": "onaylandi"
129
+ },
130
+ {
131
+ "name": "error",
132
+ "nextStepId": "olmadi"
133
+ }
134
+ ]
135
+ },
136
+ {
137
+ "stepId": "onaylandi",
138
+ "name": "onaylandi",
139
+ "type": "setter",
140
+ "kind": "normal",
141
+ "args": {
142
+ "iteratees": [
143
+ {
144
+ "element": "tx_sonuc",
145
+ "property": "content",
146
+ "source": "component",
147
+ "mapping": {
148
+ "source": "",
149
+ "mappings": {}
150
+ },
151
+ "type": "change",
152
+ "value": {
153
+ "type": "code",
154
+ "ref": "'Onaylandı'"
155
+ }
156
+ }
157
+ ]
158
+ },
159
+ "branches": [
160
+ {
161
+ "name": "always",
162
+ "nextStepId": null
163
+ }
164
+ ]
165
+ },
166
+ {
167
+ "stepId": "olmadi",
168
+ "name": "olmadi",
169
+ "type": "setter",
170
+ "kind": "normal",
171
+ "args": {
172
+ "iteratees": [
173
+ {
174
+ "element": "tx_sonuc",
175
+ "property": "content",
176
+ "source": "component",
177
+ "mapping": {
178
+ "source": "",
179
+ "mappings": {}
180
+ },
181
+ "type": "change",
182
+ "value": {
183
+ "type": "code",
184
+ "ref": "Steps.dogrula.error.status === 'cancelled' ? 'Vazgeçildi' : 'Doğrulanamadı: ' + Steps.dogrula.error.status"
185
+ }
186
+ }
187
+ ]
188
+ },
189
+ "branches": [
190
+ {
191
+ "name": "always",
192
+ "nextStepId": null
193
+ }
194
+ ]
195
+ }
196
+ ],
197
+ "errorSteps": []
198
+ }
199
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "_meta": {
3
+ "synthetic": false,
4
+ "note": "microfunction-faz-2/development ortamında gerçek uçta doğrulandı (2026-09-29): publish:true ile kayıt 'publishing' döndü, Fission builder dayjs ve ms paketlerini kurdu (build günlüğü 'added 2 packages'), ~4-6 sn sonra 'published' oldu; microfunction_invoke {} → ok:true output {year:2026, twoDays:172800000}. Kurallar: dependencies SATIR BAŞINA BİR PAKET, node'da 'ad@aralık' (aralıksız satır latest olur); inline kaynakta entrypoint GÖNDERİLMEZ; paketler yalnız Built-In'de kurulur (aws-lambda'da MF-007 uyarısı); kurulum düşerse publish-failed ve publishError build günlüğünün son 4 KB'ını taşır."
5
+ },
6
+ "microfunction": {
7
+ "name": "tarih-araci",
8
+ "description": "dayjs ve ms paketleriyle yılı ve iki günün milisaniye karşılığını döner.",
9
+ "language": "node",
10
+ "provider": "built-in",
11
+ "sourceKind": "inline",
12
+ "code": "const dayjs = require('dayjs')\nconst ms = require('ms')\nexports.handler = async () => ({ year: dayjs('2026-09-29').year(), twoDays: ms('2d') })\n",
13
+ "dependencies": "dayjs@^1.11\nms@^2.1",
14
+ "timeoutSeconds": 30,
15
+ "memoryMb": 256,
16
+ "environmentVariables": {},
17
+ "publish": true
18
+ }
19
+ }
@@ -691,9 +691,9 @@ Ağacın bugünkü kuralları — hepsi 2026-09-20'de ölçüldü (S2-17 · S2-1
691
691
  ## Toplu işlem
692
692
 
693
693
  Kapsam ve koşul her satırda ayrı ayrı uygulanır; dolayısıyla "hepsini birden onayla" bir POLİTİKA
694
- sorusu değil bir UÇ sorusudur ve table-source `update` bunu **filtreyle yapamaz** — tam olarak bir
695
- tekil alan filtresi ister (`InvalidFilterCountException` · `FilterFieldMustUniqueException`,
696
- ölçüldü 2026-09-20, S2-22). Doğru kurulum: anahtarlar elindeyse `bulk-update` ucu (tek çağrı, tek
694
+ sorusu değil bir UÇ sorusudur ve table-source `update` bunu **filtreyle yapamaz** — hedefi her
695
+ zaman tek satırdır: tek kök filtre, benzersiz alan + `eq`, ek koşullar yalnız AND grubunda
696
+ (MS-019; `platform_guide('microservice')` §"Güncelle/sil filtresi"). Doğru kurulum: anahtarlar elindeyse `bulk-update` ucu (tek çağrı, tek
697
697
  transaction), satır başına sonuç ve satır başına yetki kararı gerekiyorsa **iş akışı + döngü**
698
698
  (liste → her satır için `microservice` adımı → özet). Akış içinden yazmak yetki YÜKSELTMEZ: her
699
699
  satır çağıranın kimliğiyle denetlenir ve reddedilen satır ötekileri geri almaz. Reçete:
@@ -51,8 +51,21 @@ Komponentlerin KENDİ arayüz metni (tablo sayfalaması, filtre operatörleri, b
51
51
  düğmeleri) ve sayı/tarih biçimleri uygulamanın aktif dilinden gelir — prop vermene gerek yok.
52
52
  İki ayrı kural işliyor ve karıştırılmamalı:
53
53
 
54
- - **Metin İngilizceye düşer.** Kütüphanenin sözlüğü tr/en taşır; projede `de` seçiliyse o metinler
55
- İngilizce çıkar. Yeni dil eklemek sözlüğe satır eklemektir, komponent değişikliği değil.
54
+ - **Metin önce uygulama sözlüğünden gelir; Metin İngilizceye düşer** (bileşen kelimeleri, frontend ADR 0023 / 0024;
55
+ 2026-10-15).
56
+ Kelime listesi olan bileşen (tablo, sürüm karşılaştırma, qm'in kullandığı form ve gösterim bileşenleri) her kelimesini
57
+ önce uygulama sözlüğünde arar: kendi kelimesi `compProp.<bileşen>.<kelime>`, birçok bileşende geçen kelime ("Yükleniyor…",
58
+ "Kapat", "Ara") tek satır `compProp.common.<kelime>`. Satır yoksa kütüphanenin tr/en/ar tohumu, o da yoksa İngilizce.
59
+ Yeni dil eklemek sözlüğe satır eklemektir. Ayrıntı ve yazım yolları: `platform_guide('translation')` §Bileşenin kendi
60
+ kelimeleri.
61
+ - **`texts` ayarı:** kelimesi olan web bileşeninin gizli `texts` ayarı yalnız o düğümde değiştirilen kelimeleri taşır
62
+ (`{ rowsPerPage: { type: 'translation', ref: 'page.x.y' } }` ya da düz metin). Bütün bileşenlerin kelimesini değiştirmek
63
+ için `texts`'e değil sözlüğe yaz. Mobil bileşenlerde `texts` yoktur.
64
+ - **Kelime gibi çalışan ayar boş bırakılır.** Açılır kutu ve çoklu seçim `placeholder`'ı, etiket kutusu `placeholder` /
65
+ `createNewLabel`'ı, ağaç görünümü `searchPlaceholder` / `emptyText` / `actionsTitle`'ı, tarih-saat `placeholder` /
66
+ `timePlaceholder`'ı, tarih-saat aralığının saat yer tutucuları, seçicinin `trueLabel` / `falseLabel`'ı boşken ortak kelimeyi
67
+ gösterir ("Bir seçenek seçin", "Ara", "Açık / Kapalı" …). Web kataloğunda bunların varsayılanı yoktur; yalnız sayfaya özel
68
+ metin yaz. Ayarı hiç yazmamak kelimeyi gösterir; bilerek boş metin (`''`) yazmak yer tutucuyu / etiketi kaldırır.
56
69
  - **Biçim düşmez.** Sayı ayraçları ve tarih adları seçilen dilin kendi kuralını kullanır
57
70
  (`de` → `1.234,5`). Dili olmayan bir biçim yoktur; dil verilmediğinde taban İngilizcedir.
58
71
 
@@ -60,7 +73,9 @@ Bazı komponentlerin `locale` prop'u geriye uyum için durur ve **doluysa kazan
60
73
  sabitleme içindir. Boş bırakmak doğru varsayılandır.
61
74
 
62
75
  Doğrulama mesajını çeviriye bağlamak ayrı bir sözleşmedir (`t:` öneki, `platform_guide('page')`
63
- §validasyon); prop'ları bağlamak için `set_prop_type` (`platform_guide('translation')`).
76
+ §validasyon); prop'ları bağlamak için `set_prop_type` (`platform_guide('translation')`). **Kuralın mesajı boşsa** ekran
77
+ kuralın varsayılan kelimesini gösterir (`compProp.common.validationRequired`, `…MinLength` "En az {value} karakter girin" …;
78
+ sayı kuralın `value`'sundan) — varsayılan mesaj için kurala İngilizce cümle yazma, `message`'ı boş bırak.
64
79
 
65
80
  ## Olay modeli
66
81
 
@@ -93,7 +108,8 @@ arayüzdür**, yetkiyi backend her istekte yeniden denetler.
93
108
  "Göster" yalnız erişim özeti yüklüyken çıkar: `off`'ta (basit proje hep `off`) hiç çıkmaz —
94
109
  backend her reveal'i reddeder; `shadow`'da çıkar — backend reveal'i yine denetler, yetkisiz
95
110
  kullanıcı ret mesajını görür; `enforce`'ta yalnız entity'nin `actions`'ında `reveal` varsa.
96
- Değeri boş maskeli hücrede "Göster" çıkmaz. Tasarımcı kanvasında (**View as user**) düğme seçilen
111
+ Değeri boş maskeli hücrede "Göster" çıkmaz. Web tasarımcı kanvasında (**Kullanıcı gözüyle** / View as user; mobil
112
+ ekran tasarımcısındaki karşılığı **Kim olarak** çipidir; mobil `datatable` `revealEntity`'yi düşürür) düğme seçilen
97
113
  kullanıcıya sunulacağı yerde etkisiz çizilir (kullanıcı seçili değilken tasarımcının
98
114
  `project.data.reveal` izni karar verir); gerçek açma önizlemededir.
99
115
  Açılan değer prop'a, akışa, olaya yazılmaz. Entity `revealEntity` prop'undan (slug ya da id) ya
@@ -0,0 +1,98 @@
1
+ # Deployment Rehberi (development → production)
2
+
3
+ `deployment_start` projeyi `development`'tan `production`'a taşır; production'a giden **tek** yol
4
+ budur ve **insan onaylıdır**. Bu rehber deploy'un neyi taşıdığını, neyi taşımadığını ve production'da
5
+ eksik çıkan satırın ya da dosyanın neden eksik olduğunu anlatır. Dal açma ve merge için
6
+ `platform_guide('merge')`.
7
+
8
+ ## Varsayılan: yalnız tanım taşınır
9
+
10
+ Deploy bir **tanım** aktarımıdır. Ayar açılmadıkça tablo satırları ve dosyalar production'a gitmez —
11
+ development'ta doldurulan bir tablo production'da boş, development'a yüklenen bir görsel production'da
12
+ 404 çıkar. Bu tasarım gereğidir, hata değildir: development verisini production'a kopyalamak bir veri
13
+ kazasıdır, bu yüzden her tablo ve her dosya ayrıca seçilir.
14
+
15
+ | Ne | Taşınır mı | Kural |
16
+ |---|---|---|
17
+ | Entity, alan, index, sayfa, layout, workflow, DTO, query, microservice, fonksiyon, çeviri, tema | evet | her deploy'da |
18
+ | Süreç tanımı ve iş takvimi | evet | yalnız aktif model; yayınlanmamış taslak taşınmaz (`deployment_start` yanıtı `unpublishedDrafts`) |
19
+ | Microfunction | evet | yalnız YAYINLANMIŞ kod; hedefte yayınlanır (DEP-006) |
20
+ | Tablo satırları | **yalnız tabloda kayıt taşıma açıksa** | §Tablo satırları |
21
+ | Dosyalar | **yalnız id referansıyla** | §Dosyalar |
22
+ | Kullanıcı, rol ataması, süreç örneği, görev, defter | hayır | ortama özgüdür |
23
+
24
+ Kaynak yalnız `development`'tır (DEP-003); deploy başlamadan production verisi ön denetimden geçer
25
+ (DEP-004). İkisinin ayrıntısı `deployment_start` açıklamasında.
26
+
27
+ ## Tablo satırları (recordTransferMode)
28
+
29
+ Satırlar **tablo başına** açılan kayıt taşıma ayarıyla gider. Ayar entity tanımındadır:
30
+
31
+ | `recordTransferMode` | Ne taşınır |
32
+ |---|---|
33
+ | yok (`null`, varsayılan) | hiçbir satır |
34
+ | `'all'` | tablonun bütün satırları |
35
+ | `'specific'` + `transferRowIds: ['<id>', …]` | yalnız seçilen satırlar ve bu satırların FK ile gösterdiği satırlar |
36
+
37
+ - **Yazmak:** `entity_patch` ile `{op:'replace', path:'/recordTransferMode', value:'all'}` (seçili
38
+ satırlar için ayrıca `/transferRowIds`), ya da `entity_update` tam gövdesi. `'specific'` iken
39
+ `transferRowIds` dolu, tekil ve boşsuz olmalıdır (ENT-018).
40
+ - **Studio karşılığı:** Tablo paneli → **"Sistem kayıtlarını dağıtımlar/şablonlar üzerinden aktar"**.
41
+ Aynı ayar şablon kurulumunda da geçerlidir.
42
+ - **Birlikte giden:** çok dilli tablonun `*_localization` çeviri tablosu ve junction (çoka-çok)
43
+ satırları ana tabloyla **otomatik** gider; onlara ayrıca ayar açılmaz. Junction satırı yalnız iki
44
+ tarafı da taşınıyorsa gider (dosya tarafı her zaman geçer).
45
+ - **Kimlikler 1:1 korunur:** satır production'a aynı birincil anahtarla yazılır, identity sayacı
46
+ taşınan id'lerin ötesine ilerletilir. Production'da aynı id'li satır varsa üzerine yazılır.
47
+ - **`'all'` = ayna (DEP-005, backend ADR 0011):** promote'ta production o tabloda development'ın
48
+ aynasıdır. Kaynakta olmayan satır, çevirisi ve junction satırı production'da **silinir** —
49
+ production'a doğrudan girilmiş satırlar dahil. Kaynak tablo boşsa hedef tablo boşalır. Platformun
50
+ kendi tabloları (`users`, `roles`, `permissions`) taşımaya açılabilir ama aynalanmaz.
51
+ - **`'specific'` silmez:** yalnız upsert yapar. Seçili satırın FK ile gösterdiği satırlar zincirleme
52
+ gelir (bir satır seçmek birkaçını taşıyabilir); seçilmemiş bir satıra giden çoka-çok bağı düşer.
53
+ - **İlişki sırası:** `'all'` açılan tablonun ilişki hedefinde de taşıma açık olmalıdır, yoksa kayıt
54
+ `RelationTransferNotEnabledException` ile reddedilir — önce hedef (ebeveyn) tabloyu açın. `'all'`
55
+ bir tablonun gösterdiği tabloda taşımayı kapatmak da reddedilir. `'specific'` bu denetimden muaftır:
56
+ seçili satırın ilişki sütunu taşınmayan bir satırı gösterirse hata production'da FK ihlali olarak
57
+ çıkar.
58
+
59
+ Kayıt taşıma deploy'un kuralıdır. Dal açarken `includeRecords: true` bu ayara bakmadan bütün veri
60
+ tablolarını kopyalar; merge satır taşımaz (`platform_guide('merge')` §Dalda çalışmak).
61
+
62
+ ## Dosyalar
63
+
64
+ `files` tablosu ortama aittir ve **toptan taşınmaz**. Bir dosya production'a yalnız iki yoldan biriyle,
65
+ **id'siyle başvurulduğu için** gider:
66
+
67
+ 1. **Dosya tipli prop:** sayfa ya da komponent prop'unda `{ type:'file', ref:'<fileId>' }` —
68
+ Studio panelinin dosya seçicisinin yazdığı şekil budur. Tasarım bu dosyayı id'siyle tutar.
69
+ 2. **Taşınan bir satırın dosya sütunu:** kayıt taşıması açık tabloda tekil dosya alanının ya da dosya
70
+ çoka-çok alanının taşıdığı dosya id'leri. Satır gitmiyorsa dosyası da gitmez.
71
+
72
+ Dosya production'a **aynı id'yle** yazılır. Production'da o id zaten varsa yalnız adı güncellenir;
73
+ içerik yeniden yüklenmez ve kaynakta değişen içerik production'a geçmez.
74
+
75
+ **Sabit URL tuzağı.** Sayfaya metin olarak yazılmış bir dosya adresi (görselin `src`'sine düz URL,
76
+ html içeriği, stil) deploy'da **yeniden yazılır** — development serve öneki `…/files/serve/d/…`
77
+ production'da `…/files/serve/p/…` olur (dal öneki de aynı biçimde çevrilir). Ama bu yalnız metin
78
+ değişimidir: adresin gösterdiği **dosya kopyalanmaz**, production'da adres **404** döner. Görseli
79
+ production'a taşımak için onu dosya tipli prop'a (`ref`) ya da taşınan bir satırın dosya sütununa
80
+ bağlayın.
81
+
82
+ ## Production'a doğrudan yazılmaz
83
+
84
+ Eksik satır ya da dosya production'da elle tamamlanamaz. Production ortamında `file_upload`,
85
+ `row_create`, `row_update`, `row_delete` ve `import_*` araçları backend'de yazma korumasına
86
+ (`ProductionWriteGuardBehavior`) takılır ve **400 `CantWriteInProductionException`** döner. Yol her
87
+ zaman aynıdır: düzeltmeyi development'ta yapın (ayarı açın, prop'u bağlayın), sonra insan onaylı
88
+ yeni bir deploy.
89
+
90
+ ## Production'da eksik veri teşhisi
91
+
92
+ | Belirti | Bak | Düzeltme (development'ta) |
93
+ |---|---|---|
94
+ | Tablo production'da boş ya da eksik | `entity_get` → `recordTransferMode` | `'all'` ya da `'specific'` + `transferRowIds`; ilişki hedeflerini önce açın |
95
+ | Çeviriler eksik, satırlar var | ana tablonun ayarı | çeviri tablosu ana tabloyla gider; ana tabloda ayar açık olmalı |
96
+ | Görsel production'da 404 | `page_schema_get` → prop düz URL mi, `{ type:'file', ref }` mi | prop'u `ref` ile bağlayın ya da dosyayı taşınan satırın dosya sütunundan okuyun |
97
+ | Satırın dosyası 404, satır var | satır taşınıyor mu (`recordTransferMode`) | dosya yalnız taşınan satırla gider |
98
+ | Production'da silinmiş satırlar | tablo `'all'` mı | ayna kuralı (DEP-005); production'a girilen veri bu tabloda tutulmaz |
@@ -624,7 +624,7 @@ karakter, primaryKey yok). Tam katalog, kaynak referanslı JSON: `ngapps://rules
624
624
  | `folderId` | yalnız `commonType: 'file'` alanında | ENT-017 |
625
625
  | `properties.generationType` | yalnız `commonType` `guid` ya da `number` | ENT-017 |
626
626
  | `commonType` / `defaultValueType` / `relationType` | sözlükten; bilinmeyen değer 400 `InvalidEnumTokenException` (`multiFile` diye bir tip YOK) | ENT-017 |
627
- | `recordTransferMode: 'specific'` | `transferRowIds` dolu, tekil, boşsuz | ENT-018 |
627
+ | `recordTransferMode: 'specific'` | `transferRowIds` dolu, tekil, boşsuz; ayar yoksa deploy satır taşımaz — `platform_guide('deployment')` §Tablo satırları | ENT-018 |
628
628
  | `indexes[]` | ad önek hariç en fazla 32, `fieldIds` dolu ve tekil, adlar tekil | ENT-013 |
629
629
 
630
630
  **Birincil anahtar kalıbı** (bu rehberde yoktu; 2026-09-08 koşusunda iki hatalı çağrı + bir
@@ -10,6 +10,10 @@
10
10
 
11
11
  Uydurma fonksiyon adı runtime'da `X is not defined` 500'üdür — yalnız buradakileri kullan.
12
12
 
13
+ **Hiçbir ifade görünen metinle karşılaştırılmaz** (`durum === 'Onaylandı'`, `title !== 'Aksiyonlar'`,
14
+ `/Klasörler/.test(...)`): kod değerine, state'e, değişkene, `Page.queryParams`'a, elementId / sınıfa bağlanır. UI flow
15
+ yazımında gateway yeni kancayı TR-005 ile durdurur — `platform_guide('translation')` §Mantık görünen metne bağlanmaz.
16
+
13
17
  ## 1. Backend ifadeleri — kullanılabilir bağlam
14
18
 
15
19
  **Değişkenler:** step çıktıları (`<stepAdı>.data`), middleware değişkenleri (`user`,
@@ -107,7 +111,7 @@ dalından devam eder.
107
111
  | `setComponentProperty(name, key, value)` / `getComponentProperty(name, key)` | fonksiyon alternatifi |
108
112
  | `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** |
109
113
  | `LocalStorage` · `Widget` · `params` | yerel veri · widget bağlamı · olay parametreleri. `LocalStorage` barındırıcının deposudur, salt okunur ve değerler METİNdir: web'de uygulamanın kökenindeki `localStorage` (Studio önizlemesinde Studio'nun kendi anahtarları da görünür), cihazda akışın `storage` deposu. `storage` adımı düz bir anahtara yazınca `LocalStorage.<anahtar>` aynı akışta yeni değeri verir ve sayfanın bağları yeniden değerlendirilir (`isSelected: {{ LocalStorage['zeyrek:theme-mode'] === 'dark' }}`). `state.page\|app.<key>`'e yazan adım `LocalStorage`'a girmez (ARC-147, 2026-09-29) |
110
- | `Device` | Salt okunur cihaz durumu, barındırıcı günceller: `Device.isOnline` — ağ bağlantısı var mı (bilinmiyorsa `true`). Değişince sayfanın bütün bağları yeniden değerlendirilir; çevrimdışı bandı: `isHidden: {{ Device.isOnline }}`. Cihazda `expo-network`, web'de tarayıcının `online`/`offline` olayları. `Device` adında komponent ifade bağlamından süzülür (ayrılmış ad) |
114
+ | `Device` | Salt okunur cihaz durumu, barındırıcı günceller: `Device.isOnline` — ağ bağlantısı var mı (bilinmiyorsa `true`). Değişince sayfanın bütün bağları yeniden değerlendirilir; çevrimdışı bandı: `isHidden: {{ Device.isOnline }}`. Cihazda `expo-network`, web'de tarayıcının `online`/`offline` olayları. `Device.biometric = { available, enrolled, kinds }` (kök ADR 0021): `available` cihaz kullanıcıyı şu an doğrulayabilir (biyometri **ya da** cihaz parolası kurulu), `enrolled` biyometri kayıtlı, `kinds` ⊆ `face · fingerprint · iris`; barındırıcı vermezse (web, derleme taşımıyor) `{ available: false, enrolled: false, kinds: [] }`, Studio önizlemesi ve kanvas senaryosu `{ true, true, ['face'] }`. Uygulama ön plana dönünce yeniden okunur. `Device` adında komponent ifade bağlamından süzülür (ayrılmış ad) |
111
115
  | **Ayrılmış adlar** | Bu tablodaki globallerle (ve önsözün iç adlarıyla: `payload`, `error`, `repeaterId`, `_` ile başlayanlar…) aynı `name`'i taşıyan komponent (runtime yalnız İLK `-`'yi siler: `ite-m` da `item` sayılır) ifadede kendi adıyla GÖRÜNMEZ — süzülür, uyarı loglanır (liste: `@ng-apps/flow` `EXPRESSION_PRELUDE_NAMES`). Eskiden aynı ad sayfanın BÜTÜN ifadelerini `SyntaxError`'la düşürürdü (ARC-143). Gateway artık bu adların HEPSİNİ **PAGE-009** ile sayfa/layout yazma yollarında ve `page_schema_validate`'te istek gitmeden reddeder — komponente `t`, `state`, `event`, `item`, `self`, `Page`, `Row` gibi ad verme |
112
116
  | `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')` |
113
117
  | `log(...)` | console (proxy'leri temizler) |
@@ -109,10 +109,12 @@ platform yeniden başlamaz, açık oturumlar bozulmaz.
109
109
 
110
110
  ## Editor modu
111
111
 
112
- `zxContext.editorMode` true olduğunda element Studio kanvasında statik bir
113
- önizleme olarak duruyor: zamanlayıcı kurmayın, ağ çağrısı yapmayın, tıklamayı
114
- işlemeyin. Kanvasta etkileşim host tarafından zaten engellenir, ama gereksiz iş
115
- yapmamak kanvası hızlı tutar.
112
+ `zxContext.editorMode` yalnız web sayfa tasarımcısının kanvasında true'dur;
113
+ önizlemede ve runtime'da false. True iken element statik bir önizleme olarak
114
+ duruyor: zamanlayıcı kurmayın, ağ çağrısı yapmayın, tıklamayı işlemeyin.
115
+ Kanvasta etkileşim host tarafından zaten engellenir, ama gereksiz iş yapmamak
116
+ kanvası hızlı tutar. Mobil uygulamada dış bileşen çizilmez; mobil ekran
117
+ tasarımcısının Düzenle / Dene kipi bu bayrağı taşımaz.
116
118
 
117
119
  ## Geliştirici kiti
118
120
 
@@ -10,6 +10,10 @@ onaylıdır**. Buradaki tool'ların hiçbiri production'a yazmaz.
10
10
  - **Production'a merge eden tool yoktur.** Production'a giden tek yol insan onaylı deployment'tır.
11
11
  - Sabit environment'lar (`development`, `production`) silinemez; `environment_delete` bunu HTTP'ye
12
12
  gitmeden reddeder.
13
+ - **Şablondan kurulup güncellemeleri alan projede dal açılamaz, var olan dal değiştirilemez** (`project_get` →
14
+ `templateMetadata.installedTemplateReceiveUpdates: true`): dal açma/silme ve merge planının her adımı
15
+ 400 döner (MRG-018). Değişiklik şablonun kaynak projesinde yapılır, `template_create` ile yayımlanır,
16
+ abone projede `template_check_updates` → `template_receive_updates` ile alınır.
13
17
 
14
18
  ## Akış
15
19
 
@@ -36,9 +40,9 @@ yazmaya çalışmak 400 döner — `environment_list` ile durumu doğrula.
36
40
  Dal açılırken **yalnız tanımlar** kopyalanır. `includeRecords: true` verirsen projenin kendi
37
41
  veritabanındaki **bütün** veri tablolarının satırları da gelir — entity'de kayıt taşıması ayarı
38
42
  açık olmasa bile (çok dilli companion tablolar ve junction'lar dahil; `files`/`folders` ve audit
39
- trail tabloları hariç, dış datasource'lara dokunulmaz). Kayıt taşıması ayarı deployment'ın
40
- (`promote`) kuralıdır ve orada aynen geçerlidir. **Satırlar merge'de geri taşınmaz** — merge yalnız
41
- tanım işidir.
43
+ trail tabloları hariç, dış datasource'lara dokunulmaz). Merge'de geri gelen satırlar yalnız **kayıt
44
+ taşıması ayarı açık** tablolarınkidir; promote (`platform_guide('deployment')`) ve şablonla aynı
45
+ ayar, ama kural üç yollu: aşağıda "Tablo kayıtları".
42
46
 
43
47
  Tanım sayılan ve merge'in taşıdığı üç şey 2026-09-25'ten beri listede: **çeviriler**
44
48
  (translation kalemi, adı çeviri anahtarı), **microfunction'lar** (kod ve arşiv; hedefte **taslak**
@@ -169,6 +173,16 @@ runtime'ın çizdiği satırlar `….children`. **Kararı `ref`'e verin**; `chil
169
173
  seçimi aynen geçer; `both` ve `custom` satırlara listeden yeniden kurulur. `children`'a ayrı ve farklı karar vermek
170
174
  ekranda listenin değil satırların çizilmesine yol açar.
171
175
 
176
+ **Widget prop'unda da yollar aynıdır** (2026-10-15'ten beri). Widget prop'larını düz satırda tutar ama merge onları
177
+ sayfa gibi ağaç olarak karşılaştırır: dizi prop'unun satırları `widgetComponentProps[id=<prop>].children` yolunda gelir,
178
+ kararı `widgetComponentProps[id=<prop>].ref`'e verin. Öncesinde satırlar ayrı ayrı `add` geliyordu. İki taraf aynı
179
+ widget'ı kaydedince satırlar çoğalıyor, `ref` kararı satırlara geçmiyordu (MRG-017). O tarihten önce açılmış plan
180
+ eski yollarla da doğru uygulanır; ağaç görünümü için `merge_refresh` yeter.
181
+
182
+ **Sınır (sayfa ve widget):** iki taraf listenin öğe sayısını değiştirmeden aynı öğeyi farklı değiştirdiyse liste
183
+ konumsal karşılaştırılır. `ref`'in alt yollarında (`….ref[1].label.data`) ve satırlarda (`….children[2].ref`) ayrı
184
+ çakışmalar gelir; `ref` kararı satırlara geçmez. Hepsine **aynı tarafı** seçin, yoksa liste ile satırlar ayrışır (P-19).
185
+
172
186
  **Nesne prop'unda** (butonun `icon`'u, `surfaceStyle`) aynı kural anahtar düzeyindedir: anahtarın değeri
173
187
  `….ref.<anahtar>…`, runtime'ın çizdiği satırı `….children[name=<anahtar>]…`. İki taraf aynı anahtara farklı yazdıysa
174
188
  ikisi de çakışma gelir; **kararı `ref.<anahtar>`'a verin**. Satır karar istemez ve `summary.unresolved`'a girmez:
@@ -220,7 +234,7 @@ yine ayrı eklenir.
220
234
  |---|---|---|
221
235
  | `unresolved` | error | çözülmemiş çakışma ya da `slug` taşıyan çözümsüz kopya; apply 409 döner. Dizi prop'unun `children`'ı `ref` açıkken, nesne prop'unun satırı (`children[name=…]`) değeri çakışırken, türetilmiş DTO elemanı kaynağı açıkken ayrı satır almaz ve `summary.unresolved`'a girmez: kaynağı çözünce kendiliğinden çözülür |
222
236
  | `duplicate-open` | warning | çözümsüz kopya (`combinable: true`), ikisi de yazılacak |
223
- | `name-clash` | warning | birleşik gövdede aynı adla iki kardeş (örneğin iki `telefon` sütunu) |
237
+ | `name-clash` | warning | birleşik gövdede aynı adla iki kardeş (örneğin iki `telefon` sütunu). Widget prop'unda kardeş, aynı öğenin aynı üst prop ve satırdaki prop'udur; iki ayrı öğenin aynı adlı prop'u uyarı vermez |
224
238
  | `dangling-reference` | warning | merge'ün sildiği ya da kopya kararında düşen bir kimliğe hâlâ başvuru var |
225
239
 
226
240
  Uyarılar apply'ı engellemez; ama okunmadan `merge_apply` çağrılmaz.
@@ -229,6 +243,51 @@ Uyarılar apply'ı engellemez; ama okunmadan `merge_apply` çağrılmaz.
229
243
  yoktur; kalan çakışmalar için `merge_get {planId, view:"conflicts"}` çağırın.
230
244
  `summary.unresolved` 0 olduğunda `merge_apply` yolu açıktır.
231
245
 
246
+ ## Tablo kayıtları
247
+
248
+ 2026-10-17'den beri merge, **kayıt taşıması ayarı açık** tabloların satırlarını da taşır ("Transfer system records
249
+ through deployments/templates"; `specific`'te yalnız seçili satırlar). Ayarın kapsamı toplayıcınındır: tablonun
250
+ çeviri tablosu ve iki ucu ayarlı bağlantı tablosu da gelir. Kullanıcılar ve kullanıcı ↔ grup üyelikleri hiçbir ayarla
251
+ taşınmaz; roller için aşağıdaki **Roller** maddesi.
252
+
253
+ - **Kalem tablodur:** `module: "row"`, `recordId` = entity kimliği, `name` = tablo adı. Satır farkı `rows.<anahtar>`,
254
+ hücre farkı `rows.<anahtar>.<sütun>` yolundadır; etiket anahtar + satırın okunur alanıdır (`571 · dm-documents-compare`).
255
+ - **Yalnız dalın değişiklikleri kalem üretir.** Taban dal açılışındaki satırlardır. Development'ın kendi eklediği ya da
256
+ değiştirdiği satır plana girmez ve apply ona dokunmaz. Denetim sütunları (`sys_created_at`, `sys_updated_at`,
257
+ `sys_created_user_id`, `sys_updated_user_id`) sayılmaz.
258
+ - **Silme** yalnız dalda `all` olan tabloda çıkar: dalın sildiği, development'ın dokunmadığı satır `delete` gelir.
259
+ `specific` ve çeviri tablolarında dalın silmesi taşınmaz. **Ek alansız bağlantı tablosu** (junction, iki bağ alanı)
260
+ satırını `(sol, sağ)` çiftiyle tanır: anahtar `rows.<sol>|<sağ>`'dir, aynı bağ iki tarafta farklı kimlikle tek bağdır;
261
+ sahibi (sol taraf) dalda `all` ise dalın kaldırdığı bağ development'tan da kalkar (ADR 0031).
262
+ - **Kimlik çakışması:** iki taraf tabanda olmayan aynı anahtarla farklı satır açtıysa `rows.<anahtar>` yolunda tek
263
+ `conflict` gelir, `base` boştur. `source` dalın satırını yazar, development'ınki ezilir. `target` dalın satırını düşürür.
264
+ `custom` `value`'daki satırı yazar. `both` ikisini de tutar: development'ın satırı yerinde kalır, dalın satırı
265
+ **yeni anahtarla** eklenir. Sayı anahtarda en büyüğün bir fazlası, `uuid`'de yeni kimlik verilir. Dalın o satıra bakan
266
+ satırları yeni anahtara çevrilir. `both` yalnız `combinable: true`'da geçer; metin anahtarda 400 döner.
267
+ - **Development tabloyu taşımıyorsa** (entity var, ayarı kapalı) development'ın satırları bilinmez: tablo kökünde tek
268
+ çakışma gelir. `source` dalın satırlarını yazar (silmeden), `target` atlar. Tablo development'ta hiç yoksa satırlar
269
+ `add`'dir.
270
+ - **Veri olmadan açılmış dal**da taban yoktur: yalnız dalda olan satır `add`, iki tarafta farklı olan satır kimlik
271
+ çakışması gelir.
272
+ - **Roller `[SY] Roles`'un kendi ayarıyla gelir** (2026-10-18). Rol kalemi `module: "role"`dur, satır kalemi değil;
273
+ gövdesi uygulamanın `roles`'a eklediği alanları (`code` …) da taşır. Dalda `roles` `all` ya da `specific` ise ayarın
274
+ kapsadığı roller `add` / `update` gelir (`delete` yalnız `all`'da), rolün kendi bağları (rol ↔ izin) satır kalemidir.
275
+ **Ayar kapalıysa** yalnız dalın bir sayfası, ucu, klasörü, erişim politikası ataması ya da taşınan bir satırı
276
+ kimliğiyle, bir süreç tanımı slug'ıyla gösterdiği **yeni** rol `add` gelir; rol ↔ izin bağları gelmez, development'taki
277
+ rol değişmez. Dalın yeni rolleri ve bağları gidecekse `merge_plan`'dan önce dalda `entity_patch roles` ile
278
+ `recordTransferMode`'u `all` ya da `specific` (+ `transferRowIds`) yapın. Başka tablonun role bağı (grup ↔ rol) o
279
+ tablonun ayarıyla gelir, gösterdiği rol development'ta yoksa kurulur. İki tarafın da eklediği aynı bağ (ek alansız
280
+ bağlantı tablosu) tek bağ sayılır, `23505` vermez. Development'ta ayar kapalıyken dalda ilk açılışta rolün bağ tablosu
281
+ kökte tek çakışma gelir → `source` (o ilk merge'te silme çıkmaz, development'ın bağları bilinmiyordur). Ayar iki
282
+ tarafta da açıkken dalda kaldırılan izin ve silinen rolün bağları development'tan da kalkar, rol de silinir.
283
+ - **Apply ayna yapmaz.** Yalnız planın değiştirdiği satırlar yazılır, silinecek anahtarlar önce silinir.
284
+ Development'ta ayarlı bir tablo plandan sonra değişirse plan bayatlar (`isStale`) ve `merge_refresh` ister.
285
+ `merge_revert` satırları da ters çevirir: merge'ün eklediği satır `delete` gelir.
286
+
287
+ ```json
288
+ { "itemKey": "row:01a0…", "path": "rows.571", "choice": "both" }
289
+ ```
290
+
232
291
  ## Apply'ın reddettiği üç durum
233
292
 
234
293
  | Durum | Kod | Ne yapmalı |
@@ -239,6 +298,17 @@ yoktur; kalan çakışmalar için `merge_get {planId, view:"conflicts"}` çağı
239
298
 
240
299
  Aynı `merge_apply` çağrısını tekrarlamak sonucu değiştirmez — 409 geçici bir hata değildir.
241
300
 
301
+ Bir kararın yazılacağı yer development'ın gövdesinde yoksa `merge_get { checks: true }` hata düzeyinde bir
302
+ `not-applicable` kontrolü döner (yol `path`'tedir). O hâlde apply etme: planı yenile (`merge_refresh`), o yoldaki kararı
303
+ yeniden ver ve kontrolleri tekrar oku. Kontrol sürerse `platform_gap_report` ile bildir; bu, motorun eşleyemediği bir
304
+ dizi demektir.
305
+
306
+ Kontrol okunmadan apply edilirse süreç `MergeResolutionNotApplicableException` ile hataya düşer. Plan `failed` olur ve
307
+ yenilenemez; yeni plan gerekir.
308
+
309
+ 2026-10-18 öncesinde bu kararlar sessizce düşüyordu. Workflow dalları artık adla eşlenir (`branches[name=…]`); adı
310
+ değişen dal kayıt kimliğiyle tanınır, kimliği Studio'da yenilenmiş dal da kaybolmaz.
311
+
242
312
  ## Başlık zorunludur
243
313
 
244
314
  İsteğin adı **plan açılırken** `merge_plan`'ın `title` alanında verilir; `merge_apply` ve `merge_revert` ayrı bir
@@ -332,6 +402,13 @@ plan `applied` kalır.
332
402
  - `applied` → dal `merged` olur ve **şeması düşer**; `environment_list` artık göstermez.
333
403
  - `applied-with-drift` → dal ve şeması **durur**. `verification.driftTables` dal ile development
334
404
  arasında hâlâ farklı olan tabloları listeler; incelenmeden dal silinmez.
405
+ - **Bilinen yanlış alarm — platform tabloları (geçici çözüm, 2026-10-15).** `driftTables` yalnız `users`,
406
+ `roles`, `files`, `folders` ve `permissions`'tan oluşuyorsa fark gerçek değildir. Bu tabloların zorunlu
407
+ sütunları, platformun 2026-10-06 öncesi koduyla dokunulmuş bir development'ta `NOT NULL`, yeni açılan dalda
408
+ `NULL`'dır; doğrulama bu farkı görür. Merge'ün içeriği development'a tam geçmiştir. Dal ise `merged` ve aktif
409
+ kalır: proje başına 5 dal sınırından yer tutar, taban görüntüsü temizlenmez. Bu tablolara dokunan her merge'de
410
+ tekrar eder. Yapılacak: dalı elle silin — `environment_delete {projectId, environmentId}` (`merged` dal
411
+ silinir, şeması düşer). `driftTables`'ta bunların dışında bir tablo varsa dalı silmeden önce o farkı inceleyin.
335
412
  - `failed` → plan `failed`, dal `ready`'ye döner. Dal ve içindeki iş kaybolmaz; yeniden planlanır.
336
413
 
337
414
  ## Sınırlar