@appaflytech/zeyrek-ai-mcp 0.0.41 → 0.0.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/knowledge/componentCatalog.js +27 -97
- package/dist/knowledge/componentEvents.js +1 -18
- package/dist/knowledge/mobileComponentCatalog.js +114 -15
- package/dist/knowledge/mobileComponentEvents.js +41 -0
- package/dist/knowledge/motionResolve.js +252 -0
- package/dist/knowledge/normalize.js +87 -59
- package/dist/knowledge/pageDiscover.js +2 -2
- package/dist/knowledge/platform/batchOps.js +70 -0
- package/dist/knowledge/platform/heroTag.js +153 -0
- package/dist/knowledge/platform/lint.js +128 -6
- package/dist/knowledge/platform/mobile.js +1 -1
- package/dist/knowledge/platform/mobileLayoutLint.js +8 -1
- package/dist/knowledge/platform/mobileRules.js +18 -0
- package/dist/knowledge/platform/pageTransition.js +57 -0
- package/dist/knowledge/platform/web.js +1 -1
- package/dist/knowledge/rules.js +52 -1
- package/dist/knowledge/styleResolveNative.js +88 -4
- package/dist/platform/capture/actions.js +4 -1
- package/dist/platform/capture/capture.js +10 -13
- package/dist/platform/capture/persistent-browser.js +130 -0
- package/dist/resources/examples/flow-list-to-form.json +8 -10
- package/dist/resources/examples/flow-load-table.json +1 -1
- package/dist/resources/examples/mobile-list-detail-form.json +4 -3
- package/dist/resources/examples/mobile-scan-code.json +285 -0
- package/dist/resources/guides/component.md +3 -3
- package/dist/resources/guides/expressions.md +2 -2
- package/dist/resources/guides/merge.md +98 -18
- package/dist/resources/guides/microservice.md +2 -2
- package/dist/resources/guides/mobile-layout.md +2 -1
- package/dist/resources/guides/mobile-publish.md +1 -0
- package/dist/resources/guides/mobile-steps.md +67 -0
- package/dist/resources/guides/mobile.md +27 -55
- package/dist/resources/guides/page.md +182 -121
- package/dist/resources/guides/translation.md +26 -0
- package/dist/resources/schema-fingerprint.json +2 -2
- package/dist/resources/schemas/ResolveMergeConflictsCommand.json +30 -1
- package/dist/tools/activities.js +3 -1
- package/dist/tools/applications.js +16 -2
- package/dist/tools/components.js +12 -6
- package/dist/tools/designSchemaPatch.js +18 -13
- package/dist/tools/layouts.js +7 -2
- package/dist/tools/merges.js +29 -9
- package/dist/tools/pages.js +129 -127
- package/dist/tools/platformInfo.js +3 -2
- package/dist/tools/profileWrite.js +2 -2
- package/dist/tools/schemaOps.js +132 -34
- package/dist/tools/screenWrite.js +1 -1
- package/dist/tools/screens.js +3 -3
- package/package.json +2 -2
|
@@ -17,11 +17,12 @@ onaylıdır**. Buradaki tool'ların hiçbiri production'a yazmaz.
|
|
|
17
17
|
environment_create {projectId, name} → 202, dal "creating"
|
|
18
18
|
environment_list {projectId} → state "ready" olana kadar (30-60 sn)
|
|
19
19
|
… tenant tool'larını environment: "<dal>" ile çağır (page_schema_patch, entity_patch, …)
|
|
20
|
-
merge_plan {projectId, sourceEnvironmentId} → 202, plan "planning"
|
|
20
|
+
merge_plan {projectId, sourceEnvironmentId, title} → 202, plan "planning" (title ZORUNLU)
|
|
21
21
|
merge_get {projectId, planId} → status "planned" olana kadar
|
|
22
22
|
merge_get {projectId, planId, view:"conflicts"} → çakışanları oku
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
merge_get {projectId, planId, checks:true} → merge öncesi doğrulama (uyarılar)
|
|
24
|
+
merge_resolve{projectId, planId, resolutions[]} → source | target | both | custom
|
|
25
|
+
merge_apply {projectId, planId} → 202
|
|
25
26
|
merge_get {projectId, planId} → status "applied"
|
|
26
27
|
environment_list {projectId} → dal listede yok, şeması düştü
|
|
27
28
|
```
|
|
@@ -94,7 +95,9 @@ değişkenler, çözülen ref'ler) kareyi tamamlar: kare ne çizildiğini, bu ik
|
|
|
94
95
|
- `kind`: `add` | `update` | `delete` | `conflict`
|
|
95
96
|
- `dataRisk`: entity kaleminde veri riski var — **sebep `dataRiskReasons[]` içindedir**
|
|
96
97
|
- `derivedFromKey`: kalem OTOMATİK ÜRETİLMİŞ bir kayıtsa (varsayılan DTO) kaynağının anahtarı
|
|
97
|
-
- `elements[]`: `path`, `kind`, `base`, `source` (dal), `target` (development), `resolution
|
|
98
|
+
- `elements[]`: `path`, `kind`, `base`, `source` (dal), `target` (development), `resolution`. Açık bir elemanda
|
|
99
|
+
`resolution` hiç gelmez: gateway null alanları düşürür, yani alanın yokluğu "karar verilmedi" demektir.
|
|
100
|
+
`ownerElementId`: yolu bileşeni adlandırmayan widget prop'unun (`widgetComponentProps[id=…]`) bileşeni
|
|
98
101
|
|
|
99
102
|
`dataRisk` bir **uyarıdır, apply'ı bloklamaz**; dört sebepten biriyle doğrudur:
|
|
100
103
|
|
|
@@ -144,8 +147,83 @@ bir merge'de entity ve onun varsayılan DTO'su böylece zıt çözülemez.
|
|
|
144
147
|
{ "itemKey": "page:8f1c…", "path": "components[elementId=btn_save].props[name=label].ref", "choice": "source" }
|
|
145
148
|
```
|
|
146
149
|
|
|
147
|
-
`path` boş bırakılırsa o kaydın **tüm** çakışmaları aynı
|
|
148
|
-
|
|
150
|
+
`path` boş bırakılırsa o kaydın **tüm** çakışmaları aynı karara çözülür.
|
|
151
|
+
|
|
152
|
+
| `choice` | Ne yazılır | Ne zaman |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| `source` | dalın değeri | dal haklı |
|
|
155
|
+
| `target` | development'ın değeri | development haklı |
|
|
156
|
+
| `both` | iki tarafın birleşimi: development'ın listesi + dalın ekledikleri − dalın sildikleri. Development aynı öğeyi zaten eklediyse ikinci kez eklenmez | yalnız `combinable: true` elemanda (kimliksiz ya da gruplu liste); skalerde 400 |
|
|
157
|
+
| `custom` | `value`'daki değer | iki taraf da tam doğru değil. `value` ZORUNLU, türü `source`/`target` ile aynı olmalı. Kök yolda kaydın gövdesidir, `order-conflict`'te kimlik listesidir. Yolsuz `custom` yalnız kaydın tek çakışması varken kabul edilir |
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{ "itemKey": "page:8f1c…", "path": "components[elementId=btn_save].props[name=label].ref", "choice": "custom", "value": "Siparişi kaydet" }
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Varsayılan DTO (`derivedFromKey`) ve alanları (`derivedFromPath: fields[id=…]`) kaynağının kararını kendiliğinden
|
|
164
|
+
alır. `both` kendi listesiyle yeniden birleştirilir, `custom` yalnız üç taraf aynıysa geçer. Kaynağına zıt
|
|
165
|
+
çözmek 400 döner.
|
|
166
|
+
|
|
167
|
+
Sayfa/layout/widget'ın **dizi prop'u** (ör. dropdown `options`) planda iki kez görünür: okunur liste `….ref` ve
|
|
168
|
+
runtime'ın çizdiği satırlar `….children`. **Kararı `ref`'e verin**; `children` onu kendiliğinden izler. Bir taraf
|
|
169
|
+
seçimi aynen geçer; `both` ve `custom` satırlara listeden yeniden kurulur. `children`'a ayrı ve farklı karar vermek
|
|
170
|
+
ekranda listenin değil satırların çizilmesine yol açar.
|
|
171
|
+
|
|
172
|
+
**Nesne prop'unda** (butonun `icon`'u, `surfaceStyle`) aynı kural anahtar düzeyindedir: anahtarın değeri
|
|
173
|
+
`….ref.<anahtar>…`, runtime'ın çizdiği satırı `….children[name=<anahtar>]…`. İki taraf aynı anahtara farklı yazdıysa
|
|
174
|
+
ikisi de çakışma gelir; **kararı `ref.<anahtar>`'a verin**. Satır karar istemez ve `summary.unresolved`'a girmez:
|
|
175
|
+
merge onu değerin birleşik hâlinden kurar (`custom` dahil). Farklı anahtarlara yapılan değişiklikler kendiliğinden birleşir. Koşu 46 S-9:
|
|
176
|
+
iki ayrı karar kabul ediliyor, sayfa satırınkini çiziyordu.
|
|
177
|
+
|
|
178
|
+
Bir taraf prop'un **tipini** değiştirdiyse (`valueType`: `static` → `code`) ve öbür taraf da tipine ya da değerine
|
|
179
|
+
dokunduysa (tipler farklı kalır) eleman prop'un kendisidir: yol `…props[id=…]` (widget'ta `widgetComponentProps[id=…]`), `base`/`source`/`target` prop gövdesi,
|
|
180
|
+
`combinable: false`. Tip ile değer tek karardır; ayrı karar verilseydi düz metin kod olarak çalışabilirdi.
|
|
181
|
+
`custom`'da `value` prop gövdesidir, kimliği sunucu yoldan yazar; statik listenin satırlarını (`children`) da `ref`'ten
|
|
182
|
+
sunucu kurar, gönderilen `children` kullanılmaz:
|
|
183
|
+
|
|
184
|
+
```json
|
|
185
|
+
{ "itemKey": "page:8f1c…", "path": "components[elementId=btn_save].props[id=01a1…]", "choice": "custom",
|
|
186
|
+
"value": { "name": "text", "type": "primitive", "valueType": "code", "ref": "{{ 'Kaydet ' + Page.variables.adet }}", "children": [] } }
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Kopyada `target`, dalın kopyasından türemiş DTO alanını da düşürür. `source` ise development'ın ikizinden türemiş
|
|
190
|
+
DTO alanını siler.
|
|
191
|
+
|
|
192
|
+
### Olası kopya: `kind: "duplicate"`
|
|
193
|
+
|
|
194
|
+
İki taraf **aynı içeriği farklı kimlikle** eklediyse (iki `telefon` alanı, aynı girişi taşıyan iki bileşen) eleman
|
|
195
|
+
`duplicate` gelir; `twinPath` development'taki ikizdir. `combinable: true` olan kopya **engellemez**: çözümsüz
|
|
196
|
+
bırakılırsa ikisi de yazılır (git'in varsayılanı).
|
|
197
|
+
|
|
198
|
+
Kopyalar **`slug` taşıyorsa** (tablo alanı = kolon, sayfa = rota) ikisi birden kalamaz: eleman `combinable: false`
|
|
199
|
+
gelir, `summary.unresolved`'a sayılır ve birini seçene kadar apply edilmez; `both` 400 döner. Gerçek uçta ikisini
|
|
200
|
+
tutan apply "column already exists" ile düştü.
|
|
201
|
+
|
|
202
|
+
- `target`: development'ınki kalır, dalın eklemesi düşer.
|
|
203
|
+
- `source`: dalınki kalır, development'ın ikizi çıkar.
|
|
204
|
+
- `both`: ikisi de kalır (yalnız `combinable: true`).
|
|
205
|
+
- `custom`: tek öğe yazılır. `value` öğenin gövdesidir; kimliği development'ınkine çevrilir.
|
|
206
|
+
|
|
207
|
+
Development tabanda **zaten olan** bir alanı dalın eklediği slug'a yeniden adlandırdıysa dalın alanı da kopya gelir:
|
|
208
|
+
`twinPath` yeniden adlandırılan alandır ve **`base` doludur** (o alanın taban hâli). Bu kopyada `source` 400 döner —
|
|
209
|
+
development'ın alanı veri taşır, dalınki onun yerine geçemez; `target` (dalınki düşer) ya da `custom` seçin. Koşu 46
|
|
210
|
+
S-8: ikisi de yazılıyor, apply kolon çakışmasıyla düşüyordu.
|
|
211
|
+
|
|
212
|
+
Ayarı farklı, aynı adlı iki öğe kopya **sayılmaz**; ikisi ayrı eklenir ve doğrulamada `name-clash` uyarısı olarak
|
|
213
|
+
görünür. İki istisna: **tablo alanında slug** (kolon adı) ve **bileşen prop'unda ad** tekildir. Ayarı farklı olsa da
|
|
214
|
+
aynı slug'lı alan ya da aynı adlı prop eklemesi `combinable: false` kopyadır. Aynı adlı ama slug'ı farklı iki alan
|
|
215
|
+
yine ayrı eklenir.
|
|
216
|
+
|
|
217
|
+
### Merge öncesi doğrulama: `merge_get {checks: true}`
|
|
218
|
+
|
|
219
|
+
| Kod | Seviye | Anlamı |
|
|
220
|
+
|---|---|---|
|
|
221
|
+
| `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
|
+
| `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) |
|
|
224
|
+
| `dangling-reference` | warning | merge'ün sildiği ya da kopya kararında düşen bir kimliğe hâlâ başvuru var |
|
|
225
|
+
|
|
226
|
+
Uyarılar apply'ı engellemez; ama okunmadan `merge_apply` çağrılmaz.
|
|
149
227
|
|
|
150
228
|
`merge_resolve` **özet döner** — `{ planId, status, summary, resolved }`. Planın kendisi yanıtta
|
|
151
229
|
yoktur; kalan çakışmalar için `merge_get {planId, view:"conflicts"}` çağırın.
|
|
@@ -156,30 +234,31 @@ yoktur; kalan çakışmalar için `merge_get {planId, view:"conflicts"}` çağı
|
|
|
156
234
|
| Durum | Kod | Ne yapmalı |
|
|
157
235
|
|---|---|---|
|
|
158
236
|
| Çözülmemiş çakışma var | 409 | `merge_get view:"conflicts"` → `merge_resolve` → tekrar `merge_apply` |
|
|
159
|
-
|
|
|
237
|
+
| Dal ya da development plan alındığından beri değişti (`isStale`) | 409 | `merge_refresh`; değişmeyen elemanların kararları korunur, değişenler yeniden sorulur |
|
|
160
238
|
| Plan 24 saatten eski | 400 | yeniden planla |
|
|
161
239
|
|
|
162
240
|
Aynı `merge_apply` çağrısını tekrarlamak sonucu değiştirmez — 409 geçici bir hata değildir.
|
|
163
241
|
|
|
164
|
-
##
|
|
242
|
+
## Başlık zorunludur
|
|
165
243
|
|
|
166
|
-
|
|
167
|
-
geçmişte bu
|
|
244
|
+
İsteğin adı **plan açılırken** `merge_plan`'ın `title` alanında verilir; `merge_apply` ve `merge_revert` ayrı bir
|
|
245
|
+
mesaj almaz. Başlık plana yazılır, uygulandıktan sonra da durur ve geçmişte bu adla görünür — git'teki merge
|
|
246
|
+
request başlığının karşılığıdır.
|
|
168
247
|
|
|
169
|
-
- Boş ya da yalnız boşluktan oluşan
|
|
170
|
-
- En fazla
|
|
248
|
+
- Boş ya da yalnız boşluktan oluşan başlık **şema katmanında** reddedilir; istek platforma hiç gitmez.
|
|
249
|
+
- En fazla 100 karakter.
|
|
171
250
|
- Kalıp: `<dal> → development: <amaç>`. Ne yaptığını yaz, "merge" yazma.
|
|
172
251
|
|
|
173
|
-
Gateway senin yerine
|
|
252
|
+
Gateway senin yerine başlık **uydurmaz**: ne değiştirdiğini bilen sensin.
|
|
174
253
|
|
|
175
254
|
## Geri almak
|
|
176
255
|
|
|
177
256
|
Uygulanmış bir merge silinmez, **ters bir planla** geri alınır:
|
|
178
257
|
|
|
179
258
|
```
|
|
180
|
-
merge_revert {projectId, planId
|
|
259
|
+
merge_revert {projectId, planId} → 202, ters plan planning
|
|
181
260
|
merge_get {projectId, planId: <ters plan>} → status planned olana kadar
|
|
182
|
-
merge_apply {projectId, planId: <ters plan
|
|
261
|
+
merge_apply {projectId, planId: <ters plan>}
|
|
183
262
|
```
|
|
184
263
|
|
|
185
264
|
Bittiğinde ters plan `applied`, kaynak plan `reverted` olur; ikisi de geçmişte durur.
|
|
@@ -220,7 +299,7 @@ merge_list {projectId, environmentId:"<env>"} → o environment'ı kaynak ya d
|
|
|
220
299
|
```
|
|
221
300
|
|
|
222
301
|
`items[]` bu uçta **her zaman boştur** — bir planın değişiklik listesi için `merge_get`.
|
|
223
|
-
Satırda `
|
|
302
|
+
Satırda `title`, `description`, `createdBy` (planı alan), `appliedBy` (uygulayan), `appliedAt` ve
|
|
224
303
|
`summary` sayaçları gelir. Sayfalama `pageIndex` / `pageLength` ile.
|
|
225
304
|
|
|
226
305
|
Bir kaydın neden değiştiğini ararken sıra: `merge_list status:"applied"` → ilgili satırın
|
|
@@ -262,5 +341,6 @@ plan `applied` kalır.
|
|
|
262
341
|
- Merge sürerken dal ve development'a yazma kilitlidir; **diğer dallar etkilenmez**.
|
|
263
342
|
- Proje başına açık dal sayısı sınırlıdır (varsayılan 5) — sınır bağlantı bütçesidir, ürün kararı
|
|
264
343
|
değil.
|
|
265
|
-
- Dal adı
|
|
266
|
-
|
|
344
|
+
- Dal adı küçük harfle başlar; küçük harf/rakam/alt çizgi/tire ve `/` ile ayrılmış parçalardan oluşur
|
|
345
|
+
(ör. `feature/odeme`), 3-31 karakterdir ve şema adı olur. Adres parçası (slug) `/` yerine `-` taşır;
|
|
346
|
+
`development`, `production`, `public`, `pg_*` gibi adlar rezervedir.
|
|
@@ -534,8 +534,8 @@ hem `joins` ile getirin hem `selectFields`'a koyun; ondan sonra `filters[0][fiel
|
|
|
534
534
|
> 2026-09-06 koşusunda dokuz uç kuruldu ve dokuz patch çağrısının dokuzu da yalnız bu yolu yazdı
|
|
535
535
|
> (~3 dk). Alan create gövdesinde zaten kabul ediliyor.
|
|
536
536
|
|
|
537
|
-
> Sayfa tarafındaki karşılığı: kullanıcı ekrandan süzüyorsa (`
|
|
538
|
-
>
|
|
537
|
+
> Sayfa tarafındaki karşılığı: kullanıcı ekrandan süzüyorsa (`datatable` + `isFilterable`
|
|
538
|
+
> kolonlar) uç `enableDynamicFilters: true` olmalı; komponent seçilen
|
|
539
539
|
> koşulları kendi `filters` prop'una yazar ve akış onu uca `filters` parametresi olarak geçirir.
|
|
540
540
|
> Süzme yoksa statik query-string filtreleri yeterlidir — bkz. `platform_guide('page')` Kural 1e.
|
|
541
541
|
|
|
@@ -7,7 +7,8 @@ Bir mobil ekran kurmadan önce bunu okuyun. Buradaki kurallar zevk meselesi değ
|
|
|
7
7
|
- **Yazımda uyarı.** Yazım yanıtında sözleşme dışı durum `MOB-015…021` olarak gelir (`layoutWarnings`).
|
|
8
8
|
- **Çizimde ölçüm.** `page_screenshot({ layoutReport: true })` sonucu sayıyla ölçer (`layoutSummary.alignment`).
|
|
9
9
|
|
|
10
|
-
Temel mobil bilgi (flex-only yerleşim, tipli stil, gezinme
|
|
10
|
+
Temel mobil bilgi (flex-only yerleşim, tipli stil, gezinme) için `platform_guide('mobile')`, cihaz adımları için
|
|
11
|
+
`platform_guide('mobile-steps')`.
|
|
11
12
|
Altın örnek: `ngapps://examples/mobile-form-screen`.
|
|
12
13
|
|
|
13
14
|
## Sözleşme
|
|
@@ -71,6 +71,7 @@ metni yeni numarayla yeniden dener.
|
|
|
71
71
|
| P-11 | push (yalnız `testflight` / `internal`): `warn push_incomplete` (kimlik eksik — derleme push'suz çıkar); `push_unreadable` (kimliğin şifresi çözülemiyor), `push_profile_stale` (profil APNs anahtarından önce üretilmiş), `push_firebase_mismatch` (`google-services.json` başka Firebase projesinin), `push_package_mismatch` (dosya yüklendikten sonra Android paket adı değişmiş), `push_shell_outdated` (kabuk paketi push taşımıyor) | Studio › Yayın › Hesaplar ve kimlik bilgileri (insan yükler); `push_profile_stale`: profili yeniden üret; `push_shell_outdated`: platform ayarı (destek). Push kapalı ya da hazırsa satır `ok`'tur ve dryRun'da görünmez — hazır olduğunu `mobile_store_get { manifest: true }` → `manifest.push` söyler |
|
|
72
72
|
| P-12 | izinler: `warn permissions_shell_outdated` (yayındaki kabuk izin kümesini taşımıyor: sabit izinler bildirilir, kamera çalışmaz, kipler uygulanmaz — başka P-12 satırı çıkmaz); kabuk taşıyorsa `fail permission_off_in_use` (kip `off` ama production o izni yazılı olarak kullanıyor) ya da `warn launch_permissions_shell_outdated` (açılışta sorulan izin var, kabuk açılışta sormuyor; kabuk kümeyi de taşımıyorsa bu cümle ilk uyarının iletisine eklenir) | `mobile_store_update { settings: { permissionModes } }` ya da kullanımı kaldırıp dağıtım; açılış uyarısında daha yeni kabuk ya da izni akış adımından isteme |
|
|
73
73
|
| P-13 | reklam (yalnız `ads.enabled`): `warn ads_app_id_missing` (bu platformun AdMob App ID'si yok — derleme reklamsız çıkar), `warn ads_shell_outdated` (yayındaki kabuk reklam taşımıyor), yükleme hedefinde `manual ads_test_mode` (test kipi açık: mağazada test reklamı görünür), değilse `ok ads_ready` (yerleşim sayısıyla) | `mobile_store_update { settings: { ads } }`; test kipini yayından önce `testMode: false` |
|
|
74
|
+
| P-14 | kod tarama (yalnız production akışlarında `scan-code` adımı varsa): `warn scan_shell_outdated` (yayındaki kabuk tarayıcıyı taşımıyor — derleme çıkar, adım `error` dalıyla biter); taşıyorsa `ok scan_ready`. Kamerayı yalnız dosya alanı kullanıyorsa satır hiç gelmez | yeni kabuk paketi (destek); ajan düzeltemez |
|
|
74
75
|
|
|
75
76
|
Satırın `message` ve `fixHint`'i backend'den, istek dilinde gelir.
|
|
76
77
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Mobil akış adımları rehberi
|
|
2
|
+
|
|
3
|
+
Mobil uygulamada (`type:'mobile'`) cihaza ve barındırıcıya dokunan akış adımları: mobildeki davranış, argüman
|
|
4
|
+
sözleşmesi, `Steps.<adım>` sonucu ve tarifler. Uygulamanın kendisi (kurulum, bileşenler, gezinme, kalıcı state,
|
|
5
|
+
uzak push, sayfanın `mount` / `focus` olayları) `platform_guide('mobile')`'dedir.
|
|
6
|
+
|
|
7
|
+
## Adım sözlüğü
|
|
8
|
+
|
|
9
|
+
Motorun kendi adımları (`setter`, `condition`, `microservice`, `code`, `function`, `flow-trigger`,
|
|
10
|
+
`validation`) iki platformda aynıdır. Barındırıcıya dokunan adımlar:
|
|
11
|
+
|
|
12
|
+
| Adım | Mobilde |
|
|
13
|
+
|---|---|
|
|
14
|
+
| `redirect` | yığına iter (göreli yol) ya da dışarıda açar (tam adres) |
|
|
15
|
+
| `navigate` | eski mobil şemaların adı — `redirect`'in takma adıdır; gateway `redirect`'e çevirir |
|
|
16
|
+
| `alert` | tipli uyarı (`success`/`error`/`info`/`warning`) toast'tur ve beklemez; düz uyarı onay bekler. `message`/`description` metin şablonudur (`"{{ t('kayit.tamam') }}"`; `platform_guide('page')` §alert). Eylem düğmeli bildirim ("Silindi · Geri al") `alert`le kurulmaz: sayfaya bir `toast` bileşeni koyun (`actions: [{ text, flow }]`, gerekirse `keepOpen`), akış setter'la `isOpen: true` yazar; basış eylemin kendi akışını koşar (`actionClick { text, index }`) |
|
|
17
|
+
| `confirm` | `yes` / `no` dalları; `message`/`title`/`confirmText`/`cancelText` metin şablonudur (`{{ }}`, çeviri `t('anahtar')`) |
|
|
18
|
+
| `download` | adres cihazın açma sayfasında açılır; ikili gövde (JSON değil) önbelleğe dosya olarak yazılıp paylaşım sayfasında (`expo-sharing`) açılır, Studio mobil önizlemesi dosyayı indirir (`MOB-005`, bilgi) |
|
|
19
|
+
| `storage` | `args.name` `state.page.<key>` / `state.app.<key>` ise o state'i yazar (`platform_guide('mobile')` §Kalıcı state), değilse cihaz deposuna |
|
|
20
|
+
| `setcookie` | güvenli cihaz deposuna (SecureStore) yazar; değer sonraki her istekte `X-Flow-Cookie` başlığıyla gider ve middleware/workflow onu web'deki gibi `cookie.<ad>` olarak okur — `Cookie` başlığıyla gitmez, çünkü iOS onu yerel çerez kavanozuyla virgülle birleştirip bozuyordu (`MOB-005`, bilgi); aynı adlı sunucu çerezi varsa o kazanır. Studio paleti mobilde de sunar |
|
|
21
|
+
| `share` | RN paylaşım sayfası (metin + bağlantı; Android'de bağlantı metne eklenir, `title` iOS'ta e-posta konusu, Android'de seçici başlığı); akış `always` ile sürer — iOS'ta sayfa kapanınca, Android'de seçici açılır açılmaz (RN kapanışı bildirmez). Argümanlar `platform_guide('page')` §`share` adımı |
|
|
22
|
+
| `haptic` | dokunsal geri bildirim (`expo-haptics`, izin istemez). `args.value` stil, **düz metin**: `success` · `warning` · `error` · `light` · `medium` · `heavy` · `selection`; boş → `medium`. Değer yazmaz, hep `always`. Web'de titreşim varsa kısa titreşim, yoksa hiçbir şey (paletten yalnız mobilde sunulur) |
|
|
23
|
+
| `location` | cihaz konumu (`expo-location`; ilk kullanımda izin sorulur; derleme konumu taşımıyorsa sorulmaz, `error` dalı `status: 'unavailable'`). `args.value` doğruluk, düz metin: `low` · `balanced` · `high` (boş → `balanced`); `args.isRaw: true` → adres çözülmez. Sonuç `Steps.<adım>.data = { latitude, longitude, accuracy, address }`, `address = { country, region, subregion, city, district, street, postalCode }` ya da `null` (Türkiye'de il `region`, ilçe `subregion`, yoksa `city`). İzin reddi `Steps.<adım>.error = { status: 'denied', message }`, okunamayan konum `unavailable`: adımın `error` dalı bağlıysa o koşar (`always` koşmaz), yoksa akışın hata akışı, o da yoksa `always` (`data: null`). Web'de tarayıcı konumu, adres hep `null` |
|
|
24
|
+
| `notification-permission` | bildirim izni ister (sorulmuşsa yeniden sormaz, kalıcı red yeniden sorulmaz). Sonuç `Steps.<adım>.data.status`: `granted` · `denied` · `undetermined`; red hata değildir, hep `always` |
|
|
25
|
+
| `notification-schedule` | yerel bildirim planlar (`expo-notifications`; uzak push değil). `args.name` kimlik ve `args.title` başlık **metin şablonudur** — yalnız `{{ }}` içi çözülür (`'ilac-{{ item.id }}-0800'` kayıt başına ayrı kimlik, `"{{ t('ilac.vakti') }}"` çeviri; `{{ }}` dışındaki ifade çözülmez, FLOW-022); aynı kimlik eskisinin yerini alır. `args.message` gövde (**ifade**), `args.value` zaman (**ifade**): sonucu `'HH:mm'` → her gün, `{ weekday: 1–7, time: 'HH:mm' }` → her hafta (1 = Pazartesi), ISO tarih-saat → bir kez. `args.path` dokununca açılacak sayfanın slug'ı, düz metin — şablon çözmez (+ `args.query` ifade), boşsa uygulama açılır. İzin yoksa `error.status: 'denied'`, geçmiş ya da okunamayan zaman `invalid`: `error` dalı → hata akışı → `always`. Web'de desteklenmez (`unsupported`) — sayfa kapalıyken tarayıcı gösteremez |
|
|
26
|
+
| `notification-cancel` | `args.name` kimlikli planlı bildirimi siler (planlamadaki gibi metin şablonu: `'ilac-{{ item.id }}-0800'`), `'*'` hepsini; hep `always` |
|
|
27
|
+
| `permission` | bir cihaz iznine bakar ya da ister. `args.value` izin türü, **düz metin — ifade olamaz** (mağaza derlemesinin taşıyacağı izinler bu değerden, akış koşmadan hesaplanır; `FLOW-038`); `args.name` kip: `check` yalnız okur (sistem penceresi açılmaz), `request` verilmemiş ve hâlâ sorulabilen izni ister (boş → `request`). Sonuç `Steps.<adım>.data = { status, canAskAgain }`: `granted` · `denied` · `undetermined` · `unavailable` (derleme bu izni taşımıyor ya da web önizlemesi); `canAskAgain: false` → yalnız Ayarlar'dan değişir. `tracking` (iOS App Tracking Transparency) sonucu ayrıca `advertisingId` taşır: izin `granted` iken IDFA (iOS) / AAID (Android), değilse `null`; oynatıcı `tracking`'i hiç taşımaz (`unavailable`). Red hata değildir, hep `always`. Türler: `mobile_store_get { detail: ['permissions'] }` (`support: supported` satırlarının `key`'i) |
|
|
28
|
+
| `open-settings` | uygulamanın sistem ayar sayfasını açar; `Steps.<adım>.data.opened`. Argüman almaz |
|
|
29
|
+
| `back` | gezinme yığınında bir geri (iOS geri kaydırmasıyla aynı sonuç; kök ADR 0013). Argüman almaz (yazılan okunmaz), sonuç yazmaz, hata üretmez, hep `always`. Yığının ilk ekranında hiçbir şey yapmaz; Studio önizlemesinde runtime'ın kendi gezinmesi yoksa yine hiçbir şey, web uygulamasında tarayıcının geri'sidir. Formu kaydedip önceki ekrana dönmek için `redirect` yerine bunu kullanın: `redirect` yığına yeni ekran iter, geri kaydırması kaydedilen forma döner. 2026-10-08 öncesi runtime ve backend `back`'i tanımaz |
|
|
30
|
+
| `ad-show` | tam ekran reklam (kök ADR 0012). `args.value` mağaza ayarındaki yerleşimin **adı**, düz metin (`FLOW-039`); biçimi `interstitial` · `rewarded` · `rewardedInterstitial` olmalı. Reklam yüklenip gösterilir, kullanıcı kapatınca `Steps.<adım>.data = { shown: true, reward }` ile sürer — `reward` ödüllü reklamı sonuna kadar izleyende `{ type, amount }`, değilse `null` (ödül ayrı dal değil, `condition` ile okunur). 10 sn'de reklam yoksa, SDK hata verirse, derleme reklam taşımıyorsa ya da rıza yoksa `error.status: 'unavailable'`; tanımsız ya da banner yerleşimi `invalid`: `error` dalı → hata akışı → `always`. Oynatıcı ve web önizlemesi her zaman `unavailable` — reklamsız dalı orada sınayın. Paletten yalnız mobilde |
|
|
31
|
+
| `scan-code` | tam ekran kod tarayıcı (kök ADR 0017): tek kod okur ve kapanır. `args.value` izinli türler, **virgüllü düz metin** (`FLOW-042`): `aztec` · `codabar` · `code39` · `code93` · `code128` · `datamatrix` · `ean8` · `ean13` · `itf14` · `pdf417` · `qr` · `upc_e`; boş → hepsi. `upc_a` yok: UPC-A etiketi `ean13` ve on üç haneyle (başında `0`) döner. `args.title` ekrandaki yönerge, metin şablonu (`{{ t('anahtar') }}`). Sonuç `Steps.<adım>.data`: `{ value, type, source }` — `source` `camera` ya da `manual` (ekrandaki "elle gir"; tür bilinmiyorsa `type: null`). `error` dalı: `status` `cancelled` (kullanıcı kapattı — **vazgeçme bir hatadır, `error` dalını bağla**) · `denied` (kamera izni yok) · `unavailable` (derleme kamerayı taşımıyor ya da tarayıcı zaten açık) · `unsupported` (web uygulaması) · `invalid`. Kamera izni kendiliğinden derlemeye girer (adım production'daysa). Önizleme (`/dev`, `page_screenshot`) kamera açmaz, "kod gir" penceresi çizer: `__scan-value`'ya yaz, `__scan-confirm` ya da `__scan-cancel` (çok türde `__scan-type-<tür>`). `page_screenshot` pencereyi yalnız `captureUnready: true` ile sürer (akış pencereyi beklerken "koşuyor" sayılır; her eylem 15 sn bekler). Tam gövde: `ngapps://examples/mobile-scan-code` |
|
|
32
|
+
|
|
33
|
+
## Bildirim tarifi
|
|
34
|
+
|
|
35
|
+
Bildirim adımları paletten yalnız mobil uygulamada sunulur. Tarif — S04 "her gün hatırlat": önce
|
|
36
|
+
`notification-permission` (S03 düğmesi), sonra `timepicker`'ın değeriyle `notification-schedule`
|
|
37
|
+
(`value: "<saat>.value"`, değer `HH:mm`) ve `error` dalında kullanıcıya mesaj. Çevrimdışı bandı adım değil
|
|
38
|
+
ifadedir: `isHidden: {{ Device.isOnline }}` (`platform_guide('expressions')`).
|
|
39
|
+
|
|
40
|
+
## İzin tarifi
|
|
41
|
+
|
|
42
|
+
**İzin tarifi** (izin, ihtiyaç anında — düğmeye basılınca — istenir; sayfa açılışında değil): `permission`
|
|
43
|
+
`check` → `condition`, **bu sırayla**: `status === 'granted'` ise işe devam; `'unavailable'` ise özelliği sunma
|
|
44
|
+
(Ayarlar'da açılacak izin yoktur — `canAskAgain` burada da `false` gelir); `canAskAgain` ise `permission` `request`
|
|
45
|
+
ve sonucuna göre devam; değilse nedenini söyleyip `open-settings`. `location` adımı, `map.showUser` ve dosya alanının
|
|
46
|
+
kamera/galeri kaynağı izni kendileri de ister — `permission` adımı *ne zaman* sorulacağını seçmek ve sonucu
|
|
47
|
+
okumak içindir. `unavailable` bir hata değil, derlemenin o izni taşımadığının haberidir
|
|
48
|
+
(`platform_guide('mobile-publish')` §İzinler).
|
|
49
|
+
|
|
50
|
+
## Reklam tarifi
|
|
51
|
+
|
|
52
|
+
**Reklam tarifi** (kök ADR 0012): (1) `mobile_store_update { settings: { ads: { enabled: true, iosAppId, androidAppId,
|
|
53
|
+
testMode: true, units: [{ name, format, ios, android }] } } }` — reklam, App ID'si olan platformun derlemesine `tracking`'i de sokar (ATT metni
|
|
54
|
+
gider, kip `off` olamaz); (2) banner için sayfaya `adBanner` `unit: '<banner yerleşimi>'`; (3) geçiş/ödüllü reklam için
|
|
55
|
+
düğme akışına `ad-show` `value: '<yerleşim>'`, `error` dalında reklamsız devam; (4) ödül `condition`:
|
|
56
|
+
`Steps.<adım>.data?.reward` doluysa ödülü ver. Açılış reklamı adım değil ayardır (`ads.appOpenUnit`). Sıra cihazda:
|
|
57
|
+
rıza formu → açılış izinleri (ATT) → SDK; iOS'ta izleme izni yoksa reklam kişiselleştirilmeden istenir. Yerleşim adının
|
|
58
|
+
ayarda tanımlı olduğu sayfa/akış yazımında denetlenemez — `mobile_store_get` `settings.ads.units` ve `adsWarnings`
|
|
59
|
+
(`MOB-026`); yayın ayrıntısı `platform_guide('mobile-publish')` §Reklamlar.
|
|
60
|
+
|
|
61
|
+
## Konum ve harita
|
|
62
|
+
|
|
63
|
+
`style`, `accuracy`, `reverseGeocode` gibi anahtarlar sözleşmede yoktur ve platform onları sessizce düşürür
|
|
64
|
+
(`FLOW-029`). "Haritada aç" için adım yoktur: `map`'in `press` olayı düğüme `mapsUrl` yazar, akış
|
|
65
|
+
`redirect` `isRaw: true`, `path: '<harita>.mapsUrl'` ile açar. Tarif — L05 "mevcut konumumu kullan":
|
|
66
|
+
düğmenin `click`'i → `location` (`always` → setter `il.value = Steps.konum.data.address?.region`, `error` →
|
|
67
|
+
setter hata metni). Uzak push (sunucudan gelen bildirim) ayrı rehberde: `platform_guide('mobile')` §Uzak push.
|
|
@@ -37,7 +37,8 @@ Mobil uygulamanın bileşen kataloğu ayrıdır (backend satırları `(slug, typ
|
|
|
37
37
|
mobil farkları: düşen prop, değişen etkileşim, mobile özgü prop notları) ve `mobileNotes` (bütün
|
|
38
38
|
mobil bileşenlere geçen notlar). Web'de karşılığı olmayan bileşende (`app-bar`, `safe-area`,
|
|
39
39
|
`scroll-view`, `choice-chips`, `tooltip`, `markdown`, `calendar`, `stack`, `list-item`, `fab`, `timer`,
|
|
40
|
-
`audio`, `lottie`, `webview`, `map`, `adBanner`, `grouped-list`, `floating-container`, `skeleton`, `photo-viewer
|
|
40
|
+
`audio`, `lottie`, `webview`, `map`, `adBanner`, `grouped-list`, `floating-container`, `skeleton`, `photo-viewer`,
|
|
41
|
+
`flip-card`, `swipeable-stack`) bilgi yalnız
|
|
41
42
|
`mobileKnowledge`'tadır. Olay yükleri
|
|
42
43
|
(`events[].payload`) önce mobile özgü sözleşmeden okunur (`app-bar.clickAction`, `repeater.swipe`,
|
|
43
44
|
`choice-chips.change`…), yoksa web'inkinden.
|
|
@@ -115,6 +116,9 @@ mobil bileşenlere geçen notlar). Web'de karşılığı olmayan bileşende (`ap
|
|
|
115
116
|
listesi) ve `floating-container` (ekranın 9 noktasından birine sabit kap — §Ekrana sabit içerik)
|
|
116
117
|
mobile özgüdür. `scroll-view`'de ilk çocuk dışındaki doğrudan çocuklar `states.isSticky: true` ile
|
|
117
118
|
kaydırırken üstte kalır (Studio panelinde alanı yok; şemaya MCP yazar).
|
|
119
|
+
- **Dönen kart ve kart destesi** (2026-10-08): `flip-card` (children = [ön `view`, arka `view`]; `isFlipped`,
|
|
120
|
+
`flip`) ve `swipeable-stack` (`repeater` şekli: [kart `view`, boş `view`], `rows`, `currentIndex`;
|
|
121
|
+
`swipeLeft` / `swipeRight` / `finish` yükü `event.data`) mobile özgüdür.
|
|
118
122
|
- **Faz 10** (FlutterFlow D listesi): `datatable` web ikizidir — kolon biçimi, sıralama ve sayfa hesabı web'in
|
|
119
123
|
modülünden, akış sözleşmesi aynı (sıralama/sayfa değişince `sortField`/`sortType`/`offset` düğüme yazılır ve
|
|
120
124
|
`mount` yeniden koşar; satır eylemi `selectedRow`u yazıp eylemin akışını koşturur). Mobile özgü `variant`:
|
|
@@ -303,6 +307,18 @@ aynı katman sırası: tema taban → gruplar → serbest `style`).
|
|
|
303
307
|
(`'15deg'` yazılmaz); aralık dışı (`rotate` ±360, `scale` 10–500, kaydırma ±1000) yazılmaz ve
|
|
304
308
|
`nativeStyle.warnings`'e düşer. Katman ve kabukta (`modal`, `drawer`, `app-bar`) bu dört alan yoktur.
|
|
305
309
|
- `typographyStyle` → renk, aile (tek ad), punto, kalınlık, hizalama, satır yüksekliği.
|
|
310
|
+
- `motionStyle` (panelde Motion; kabuğun dışında çizen `modal`, `drawer`, `photo-viewer`, `toast`, `fab`,
|
|
311
|
+
`floating-container` dışında her mobil bileşende) → düğümün hareketi: `enter` / `exit` (`fade`, `fadeUp`, `fadeDown`, `slideLeft`,
|
|
312
|
+
`slideRight`, girişte `zoomIn`, çıkışta `zoomOut`), `loop` (`pulse`, `spin`, `bounce`), `transition` (`colors`,
|
|
313
|
+
`opacity`, `transform`, `all`), `press` (`scale`, `opacity`), `layout` (aç/kapa), `duration` 100–2000 ms, `delay`
|
|
314
|
+
0–5000 ms, `easing`. Yazılmayan alan yok sayılır (300 ms, `easeOut`; döngü kendi süresini kullanır) — varsayılanı
|
|
315
|
+
YAZMAYIN. Yön adı BAŞLANGIÇ tarafıdır: `fadeUp` yukarıdan, `fadeDown` aşağıdan, `slideLeft` soldan, `slideRight`
|
|
316
|
+
sağdan gelir. Tanınmayan alan ve küme/aralık dışı değer atlanır (`MOB-028`). `/dev`'de ve cihazda oynar: `enter` düğüm
|
|
317
|
+
çizilince, `exit` gizlenince (`isHidden`), `layout` bir kardeş gizlenip görününce, `transition` kabuğun stili
|
|
318
|
+
değişince; giriş biter, döngü sonra başlar; döngü ve `press` `surfaceStyle`'ın döndürme/ölçek/opaklığının üstüne
|
|
319
|
+
biner. Kanvasta donuktur (araç çubuğunda Oynat); "hareketi azalt"ta ve `page_screenshot`'ın donuk karesinde durur.
|
|
320
|
+
Koşullu hareket: alan da (`{ type: 'code', ref }`) grup da (`set_binding`) ifadeye bağlanır; alandaki düz metin
|
|
321
|
+
`{{ … }}` ifade değildir (`MOB-028`). Web şemasında yoktur.
|
|
306
322
|
- Tema token'ları (`var(--ng-*)`) sayılara çözülür; proje teması değişince mobil de değişir.
|
|
307
323
|
|
|
308
324
|
Çizilmeyen alanlar (`MOB-002`) ve yerine ne:
|
|
@@ -317,8 +333,9 @@ aynı katman sırası: tema taban → gruplar → serbest `style`).
|
|
|
317
333
|
| `surfaceStyle`'ın tanımadığı alt anahtar (ör. CSS `transform` metni, `padding`) | grubun tipli alanları; döndürme/ölçek/kaydırma `rotate`, `scale`, `translateX`/`translateY` |
|
|
318
334
|
|
|
319
335
|
Düğümün gerçek stilini görmek: `page_runtime_get({ applicationSlug, pageSlug, resolveStyles: true })`
|
|
320
|
-
→ her düğümde `nativeStyle: { shell, text, warnings }` (`shell` kutunun, `text` içine akan metnin
|
|
321
|
-
stili; RN'de tipografi miras alınmaz
|
|
336
|
+
→ her düğümde `nativeStyle: { shell, text, motion, bound, warnings }` (`shell` kutunun, `text` içine akan metnin
|
|
337
|
+
stili; RN'de tipografi miras alınmaz; `motion` yalnız hareketli düğümde, `motionStyle`'ın `/dev` ve cihazdaki
|
|
338
|
+
çözümü; `bound` ifadeye bağlı stil alanları — değerleri çalışma anında oluşur). Yanıtta `styleResolver: 'native'`. Temanın katmanı
|
|
322
339
|
(`componentStyles[tip]` ← `$preset`) TABANDIR: panel grupları üstüne biner, düğümün serbest `style`'ı son söz — rapor
|
|
323
340
|
da onu içerir. Mobilde tasarım sisteminin yolu `componentStyles`'tır (`theme_update`; tipin bütün düğümlerine iner).
|
|
324
341
|
Mobil katalogda `style` prop'u olmadığı için düğüme yeni `$preset` başvurusu yazılamaz; kayıtlı (ör. web'den taşınmış)
|
|
@@ -376,7 +393,8 @@ etiketi ailesini `typographyStyle`'dan alır, alan etiketleri platform yazı tip
|
|
|
376
393
|
Çekmece layout'un kök dizisindedir (`views: [shell_root, nav_drawer]`), kabuk kabının içinde değil.
|
|
377
394
|
- Kabuk örnekleri: `ngapps://examples/mobile-app-shell-stack` (yığın), `ngapps://examples/mobile-app-shell-tab`
|
|
378
395
|
(sekmeler), `ngapps://examples/mobile-app-shell-drawer` (çekmece); üç sayfalık liste → detay → form akışı:
|
|
379
|
-
`ngapps://examples/mobile-list-detail-form
|
|
396
|
+
`ngapps://examples/mobile-list-detail-form`; kod tarama (düğme → `scan-code` → alana yaz):
|
|
397
|
+
`ngapps://examples/mobile-scan-code`.
|
|
380
398
|
|
|
381
399
|
## Çok dil
|
|
382
400
|
|
|
@@ -405,56 +423,11 @@ Mobil uygulama web ile **aynı sözlüğü ve aynı motoru** kullanır (plans/mo
|
|
|
405
423
|
## Akış adımları
|
|
406
424
|
|
|
407
425
|
Motorun kendi adımları (`setter`, `condition`, `microservice`, `code`, `function`, `flow-trigger`,
|
|
408
|
-
`validation`) iki platformda aynıdır. Barındırıcıya dokunan adımlar:
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
| `navigate` | eski mobil şemaların adı — `redirect`'in takma adıdır; gateway `redirect`'e çevirir |
|
|
414
|
-
| `alert` | tipli uyarı (`success`/`error`/`info`/`warning`) toast'tur ve beklemez; düz uyarı onay bekler. `message`/`description` metin şablonudur (`"{{ t('kayit.tamam') }}"`; `platform_guide('page')` §alert). Eylem düğmeli bildirim ("Silindi · Geri al") `alert`le kurulmaz: sayfaya bir `toast` bileşeni koyun (`actions: [{ text, flow }]`, gerekirse `keepOpen`), akış setter'la `isOpen: true` yazar; basış eylemin kendi akışını koşar (`actionClick { text, index }`) |
|
|
415
|
-
| `confirm` | `yes` / `no` dalları; `message`/`title`/`confirmText`/`cancelText` metin şablonudur (`{{ }}`, çeviri `t('anahtar')`) |
|
|
416
|
-
| `download` | adres cihazın açma sayfasında açılır; ikili gövde (JSON değil) önbelleğe dosya olarak yazılıp paylaşım sayfasında (`expo-sharing`) açılır, Studio mobil önizlemesi dosyayı indirir (`MOB-005`, bilgi) |
|
|
417
|
-
| `storage` | `args.name` `state.page.<key>` / `state.app.<key>` ise o state'i yazar (§Kalıcı state), değilse cihaz deposuna |
|
|
418
|
-
| `setcookie` | güvenli cihaz deposuna (SecureStore) yazar; değer sonraki her istekte `X-Flow-Cookie` başlığıyla gider ve middleware/workflow onu web'deki gibi `cookie.<ad>` olarak okur — `Cookie` başlığıyla gitmez, çünkü iOS onu yerel çerez kavanozuyla virgülle birleştirip bozuyordu (`MOB-005`, bilgi); aynı adlı sunucu çerezi varsa o kazanır. Studio paleti mobilde de sunar |
|
|
419
|
-
| `share` | RN paylaşım sayfası (metin + bağlantı; Android'de bağlantı metne eklenir, `title` iOS'ta e-posta konusu, Android'de seçici başlığı); akış `always` ile sürer — iOS'ta sayfa kapanınca, Android'de seçici açılır açılmaz (RN kapanışı bildirmez). Argümanlar `platform_guide('page')` §`share` adımı |
|
|
420
|
-
| `haptic` | dokunsal geri bildirim (`expo-haptics`, izin istemez). `args.value` stil, **düz metin**: `success` · `warning` · `error` · `light` · `medium` · `heavy` · `selection`; boş → `medium`. Değer yazmaz, hep `always`. Web'de titreşim varsa kısa titreşim, yoksa hiçbir şey (paletten yalnız mobilde sunulur) |
|
|
421
|
-
| `location` | cihaz konumu (`expo-location`; ilk kullanımda izin sorulur; derleme konumu taşımıyorsa sorulmaz, `error` dalı `status: 'unavailable'`). `args.value` doğruluk, düz metin: `low` · `balanced` · `high` (boş → `balanced`); `args.isRaw: true` → adres çözülmez. Sonuç `Steps.<adım>.data = { latitude, longitude, accuracy, address }`, `address = { country, region, subregion, city, district, street, postalCode }` ya da `null` (Türkiye'de il `region`, ilçe `subregion`, yoksa `city`). İzin reddi `Steps.<adım>.error = { status: 'denied', message }`, okunamayan konum `unavailable`: adımın `error` dalı bağlıysa o koşar (`always` koşmaz), yoksa akışın hata akışı, o da yoksa `always` (`data: null`). Web'de tarayıcı konumu, adres hep `null` |
|
|
422
|
-
|
|
423
|
-
| `notification-permission` | bildirim izni ister (sorulmuşsa yeniden sormaz, kalıcı red yeniden sorulmaz). Sonuç `Steps.<adım>.data.status`: `granted` · `denied` · `undetermined`; red hata değildir, hep `always` |
|
|
424
|
-
| `notification-schedule` | yerel bildirim planlar (`expo-notifications`; uzak push değil). `args.name` kimlik ve `args.title` başlık **metin şablonudur** — yalnız `{{ }}` içi çözülür (`'ilac-{{ item.id }}-0800'` kayıt başına ayrı kimlik, `"{{ t('ilac.vakti') }}"` çeviri; `{{ }}` dışındaki ifade çözülmez, FLOW-022); aynı kimlik eskisinin yerini alır. `args.message` gövde (**ifade**), `args.value` zaman (**ifade**): sonucu `'HH:mm'` → her gün, `{ weekday: 1–7, time: 'HH:mm' }` → her hafta (1 = Pazartesi), ISO tarih-saat → bir kez. `args.path` dokununca açılacak sayfanın slug'ı, düz metin — şablon çözmez (+ `args.query` ifade), boşsa uygulama açılır. İzin yoksa `error.status: 'denied'`, geçmiş ya da okunamayan zaman `invalid`: `error` dalı → hata akışı → `always`. Web'de desteklenmez (`unsupported`) — sayfa kapalıyken tarayıcı gösteremez |
|
|
425
|
-
| `notification-cancel` | `args.name` kimlikli planlı bildirimi siler (planlamadaki gibi metin şablonu: `'ilac-{{ item.id }}-0800'`), `'*'` hepsini; hep `always` |
|
|
426
|
-
| `permission` | bir cihaz iznine bakar ya da ister. `args.value` izin türü, **düz metin — ifade olamaz** (mağaza derlemesinin taşıyacağı izinler bu değerden, akış koşmadan hesaplanır; `FLOW-038`); `args.name` kip: `check` yalnız okur (sistem penceresi açılmaz), `request` verilmemiş ve hâlâ sorulabilen izni ister (boş → `request`). Sonuç `Steps.<adım>.data = { status, canAskAgain }`: `granted` · `denied` · `undetermined` · `unavailable` (derleme bu izni taşımıyor ya da web önizlemesi); `canAskAgain: false` → yalnız Ayarlar'dan değişir. `tracking` (iOS App Tracking Transparency) sonucu ayrıca `advertisingId` taşır: izin `granted` iken IDFA (iOS) / AAID (Android), değilse `null`; oynatıcı `tracking`'i hiç taşımaz (`unavailable`). Red hata değildir, hep `always`. Türler: `mobile_store_get { detail: ['permissions'] }` (`support: supported` satırlarının `key`'i) |
|
|
427
|
-
| `open-settings` | uygulamanın sistem ayar sayfasını açar; `Steps.<adım>.data.opened`. Argüman almaz |
|
|
428
|
-
| `back` | gezinme yığınında bir geri (iOS geri kaydırmasıyla aynı sonuç; kök ADR 0013). Argüman almaz (yazılan okunmaz), sonuç yazmaz, hata üretmez, hep `always`. Yığının ilk ekranında hiçbir şey yapmaz; Studio önizlemesinde runtime'ın kendi gezinmesi yoksa yine hiçbir şey, web uygulamasında tarayıcının geri'sidir. Formu kaydedip önceki ekrana dönmek için `redirect` yerine bunu kullanın: `redirect` yığına yeni ekran iter, geri kaydırması kaydedilen forma döner. 2026-10-08 öncesi runtime ve backend `back`'i tanımaz |
|
|
429
|
-
| `ad-show` | tam ekran reklam (kök ADR 0012). `args.value` mağaza ayarındaki yerleşimin **adı**, düz metin (`FLOW-039`); biçimi `interstitial` · `rewarded` · `rewardedInterstitial` olmalı. Reklam yüklenip gösterilir, kullanıcı kapatınca `Steps.<adım>.data = { shown: true, reward }` ile sürer — `reward` ödüllü reklamı sonuna kadar izleyende `{ type, amount }`, değilse `null` (ödül ayrı dal değil, `condition` ile okunur). 10 sn'de reklam yoksa, SDK hata verirse, derleme reklam taşımıyorsa ya da rıza yoksa `error.status: 'unavailable'`; tanımsız ya da banner yerleşimi `invalid`: `error` dalı → hata akışı → `always`. Oynatıcı ve web önizlemesi her zaman `unavailable` — reklamsız dalı orada sınayın. Paletten yalnız mobilde |
|
|
430
|
-
|
|
431
|
-
Bildirim adımları paletten yalnız mobil uygulamada sunulur. Tarif — S04 "her gün hatırlat": önce
|
|
432
|
-
`notification-permission` (S03 düğmesi), sonra `timepicker`'ın değeriyle `notification-schedule`
|
|
433
|
-
(`value: "<saat>.value"`, değer `HH:mm`) ve `error` dalında kullanıcıya mesaj. Çevrimdışı bandı adım değil
|
|
434
|
-
ifadedir: `isHidden: {{ Device.isOnline }}` (`platform_guide('expressions')`).
|
|
435
|
-
|
|
436
|
-
**İzin tarifi** (izin, ihtiyaç anında — düğmeye basılınca — istenir; sayfa açılışında değil): `permission`
|
|
437
|
-
`check` → `condition`, **bu sırayla**: `status === 'granted'` ise işe devam; `'unavailable'` ise özelliği sunma
|
|
438
|
-
(Ayarlar'da açılacak izin yoktur — `canAskAgain` burada da `false` gelir); `canAskAgain` ise `permission` `request`
|
|
439
|
-
ve sonucuna göre devam; değilse nedenini söyleyip `open-settings`. `location` adımı, `map.showUser` ve dosya alanının
|
|
440
|
-
kamera/galeri kaynağı izni kendileri de ister — `permission` adımı *ne zaman* sorulacağını seçmek ve sonucu
|
|
441
|
-
okumak içindir. `unavailable` bir hata değil, derlemenin o izni taşımadığının haberidir
|
|
442
|
-
(`platform_guide('mobile-publish')` §İzinler).
|
|
443
|
-
|
|
444
|
-
**Reklam tarifi** (kök ADR 0012): (1) `mobile_store_update { settings: { ads: { enabled: true, iosAppId, androidAppId,
|
|
445
|
-
testMode: true, units: [{ name, format, ios, android }] } } }` — reklam, App ID'si olan platformun derlemesine `tracking`'i de sokar (ATT metni
|
|
446
|
-
gider, kip `off` olamaz); (2) banner için sayfaya `adBanner` `unit: '<banner yerleşimi>'`; (3) geçiş/ödüllü reklam için
|
|
447
|
-
düğme akışına `ad-show` `value: '<yerleşim>'`, `error` dalında reklamsız devam; (4) ödül `condition`:
|
|
448
|
-
`Steps.<adım>.data?.reward` doluysa ödülü ver. Açılış reklamı adım değil ayardır (`ads.appOpenUnit`). Sıra cihazda:
|
|
449
|
-
rıza formu → açılış izinleri (ATT) → SDK; iOS'ta izleme izni yoksa reklam kişiselleştirilmeden istenir. Yerleşim adının
|
|
450
|
-
ayarda tanımlı olduğu sayfa/akış yazımında denetlenemez — `mobile_store_get` `settings.ads.units` ve `adsWarnings`
|
|
451
|
-
(`MOB-026`); yayın ayrıntısı `platform_guide('mobile-publish')` §Reklamlar.
|
|
452
|
-
|
|
453
|
-
`style`, `accuracy`, `reverseGeocode` gibi anahtarlar sözleşmede yoktur ve platform onları sessizce düşürür
|
|
454
|
-
(`FLOW-029`). "Haritada aç" için adım yoktur: `map`'in `press` olayı düğüme `mapsUrl` yazar, akış
|
|
455
|
-
`redirect` `isRaw: true`, `path: '<harita>.mapsUrl'` ile açar. Tarif — L05 "mevcut konumumu kullan":
|
|
456
|
-
düğmenin `click`'i → `location` (`always` → setter `il.value = Steps.konum.data.address?.region`, `error` →
|
|
457
|
-
setter hata metni). Uzak push (sunucudan gelen bildirim) ayrı bölümde: §Uzak push.
|
|
426
|
+
`validation`) iki platformda aynıdır. Barındırıcıya dokunan adımlar ayrı rehberdedir:
|
|
427
|
+
`platform_guide('mobile-steps')` — `redirect`, `alert`, `confirm`, `download`, `storage`, `setcookie`, `share`,
|
|
428
|
+
`haptic`, `location`, `notification-permission` / `-schedule` / `-cancel`, `permission`, `open-settings`, `back`
|
|
429
|
+
ve `ad-show`'un mobildeki davranışı, argümanları, `Steps.<adım>` sonucu; bildirim, izin, reklam ve konum
|
|
430
|
+
tarifleri. Bu adımlardan birini yazmadan önce onu okuyun.
|
|
458
431
|
|
|
459
432
|
Sayfa ve layout `mount` akışları ilk çizimden sonra, `destroy` akışları sayfa kalkarken koşar. Yığındaki
|
|
460
433
|
ve sekmedeki ekran bağlı kalır: geri dönüşte `mount` KOŞMAZ. Listeyi yeniden okumak için sayfanın
|
|
@@ -463,7 +436,6 @@ değişiminde koşar. Bağ: `page_update` `events: [{ name: 'focus', value: <flo
|
|
|
463
436
|
`mount`'ta, liste okuması `focus`'ta — aynı okuma ikisine bağlanırsa ilk açılışta çift istek gider.
|
|
464
437
|
`Functions.<ad>()` uygulama ve sayfa fonksiyonlarını görür (`platform_guide('functions')`).
|
|
465
438
|
|
|
466
|
-
|
|
467
439
|
## Uzak push
|
|
468
440
|
|
|
469
441
|
Sunucudan gönderilen bildirim yerel `notification-schedule`'dan ayrıdır. Kanal ikiliye bağlıdır (NTF-004):
|