@appaflytech/zeyrek-ai-mcp 0.0.43 → 0.0.46

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 (75) 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 +67 -8
  8. package/dist/knowledge/mobileStore.js +61 -2
  9. package/dist/knowledge/platform/lint.js +23 -0
  10. package/dist/knowledge/platform/mobile.js +1 -1
  11. package/dist/knowledge/platform/mobileOffline.js +45 -0
  12. package/dist/knowledge/platform/mobileRules.js +8 -1
  13. package/dist/knowledge/platform/mobileTabs.js +31 -2
  14. package/dist/knowledge/platform/web.js +1 -1
  15. package/dist/knowledge/rules.js +220 -7
  16. package/dist/knowledge/textHooks.js +434 -0
  17. package/dist/platform/capture/capture.js +1 -1
  18. package/dist/platform/capture/readiness.js +4 -0
  19. package/dist/platform/errors.js +22 -2
  20. package/dist/prompts/mobilePublish.js +21 -0
  21. package/dist/resources/examples/flow-biometric-confirm.json +199 -0
  22. package/dist/resources/examples/microfunction-node-dependencies.json +19 -0
  23. package/dist/resources/examples/mobile-offline-list.json +357 -0
  24. package/dist/resources/examples/mobile-offline-queue.json +82 -0
  25. package/dist/resources/examples/mobile-offline-seamless.json +1520 -0
  26. package/dist/resources/guides/access.md +4 -4
  27. package/dist/resources/guides/component.md +20 -4
  28. package/dist/resources/guides/deployment.md +98 -0
  29. package/dist/resources/guides/entity.md +1 -1
  30. package/dist/resources/guides/expressions.md +5 -1
  31. package/dist/resources/guides/external-component.md +6 -4
  32. package/dist/resources/guides/merge.md +81 -4
  33. package/dist/resources/guides/microfunction.md +104 -9
  34. package/dist/resources/guides/microservice.md +34 -5
  35. package/dist/resources/guides/mobile-connect-data.md +70 -0
  36. package/dist/resources/guides/mobile-flow.md +64 -0
  37. package/dist/resources/guides/mobile-publish.md +161 -16
  38. package/dist/resources/guides/mobile-steps.md +21 -1
  39. package/dist/resources/guides/mobile.md +45 -23
  40. package/dist/resources/guides/page.md +122 -5
  41. package/dist/resources/guides/translation.md +97 -2
  42. package/dist/resources/knowledge.js +3 -1
  43. package/dist/resources/prompts/mobile-publish-prepare.md +89 -0
  44. package/dist/resources/schema-fingerprint.json +4 -4
  45. package/dist/resources/schemas/ApplyMicrofunctionArchiveChangesCommand.json +76 -0
  46. package/dist/resources/schemas/ConnectDataDescribeDto.json +44 -0
  47. package/dist/resources/schemas/ConnectDataResultDto.json +10 -0
  48. package/dist/resources/schemas/CreateMicrofunctionCommand.json +8 -0
  49. package/dist/resources/schemas/CreateMicroserviceCommand.json +3 -0
  50. package/dist/resources/schemas/InvokeMicrofunctionCommand.json +0 -4
  51. package/dist/resources/schemas/MicroserviceDto.json +3 -0
  52. package/dist/resources/schemas/MobileStorePreflightScope.json +13 -0
  53. package/dist/resources/schemas/StartMobileBuildCommand.json +35 -1
  54. package/dist/resources/schemas/UpdateMicrofunctionCommand.json +8 -0
  55. package/dist/resources/schemas/UpdateMicroserviceCommand.json +3 -0
  56. package/dist/resources/schemas/UpsertMobileStoreSettingsCommand.json +75 -0
  57. package/dist/server.js +2 -0
  58. package/dist/tools/accessRuntime.js +1 -1
  59. package/dist/tools/applications.js +16 -2
  60. package/dist/tools/common.js +6 -0
  61. package/dist/tools/components.js +19 -6
  62. package/dist/tools/connectData.js +9 -4
  63. package/dist/tools/deployments.js +1 -1
  64. package/dist/tools/designSchemaPatch.js +16 -4
  65. package/dist/tools/environments.js +3 -3
  66. package/dist/tools/files.js +1 -1
  67. package/dist/tools/flows.js +118 -7
  68. package/dist/tools/layouts.js +32 -12
  69. package/dist/tools/merges.js +8 -8
  70. package/dist/tools/microfunctions.js +53 -3
  71. package/dist/tools/mobileStore.js +83 -21
  72. package/dist/tools/pages.js +59 -24
  73. package/dist/tools/platformInfo.js +4 -2
  74. package/dist/tools/textHookGuard.js +116 -0
  75. package/package.json +2 -2
@@ -0,0 +1,70 @@
1
+ # Mobil veri bağlama rehberi
2
+
3
+ Mobil uygulamada (`type:'mobile'`) bileşeni veriye bağlamak web'deki connect-data sözleşmesinin aynısıdır
4
+ (`platform_guide('page')` Kural 1c-3: `connect_data_describe` → `connect_data_bind` → `connect_data_get`).
5
+ Bu rehber yalnız telefonun farkını anlatır: tanıma eklenen telefon alanları, mobil projede yazılan varsayılanlar,
6
+ gruplu liste ve kurallar. Ekranın kendisi `platform_guide('mobile')`'dadır.
7
+
8
+ ## Telefonda
9
+
10
+ Telefon kararları tanımda durur, bileşen prop'unda değil; web aynı tanımı okur ve bu alanları yok sayar.
11
+
12
+ - **Seçim alanı:** alana dokunmak **alt sayfa** açar (hızlı liste, son seçilenler, arama); alanın yanındaki ↗
13
+ **tam ekran** seçimi açar (arama, filtre ve sıralama çipleri). Varsayılan yüzeyi `lookup.mobileMode` seçer:
14
+ `sheet` (varsayılan) | `fullscreen`. Satır `lookup.mobileRow { title, subtitle?, trailing? }`: başlık, alt satır
15
+ ve sağda mono değer.
16
+ - **Liste ve tablo:** **sonsuz kaydırma** varsayılandır (`behavior.mobile.infiniteScroll`); sayfalar birleşir,
17
+ düşen sayfa "Yeniden dene" gösterir. Kapalıysa listenin sonunda "Daha fazla yükle".
18
+ - **Mobil projede `connect_data_bind` varsayılanları yazar:** kök lookup'a `mobileMode: 'sheet'` ve
19
+ `mobileRow.title` ← label alanı; liste/seçim bağlantısına `behavior.mobile: { infiniteScroll: true }`.
20
+ Yeniden bağlamada kayıtlı telefon ayarı korunur; `null` kaldırır.
21
+ - Studio sihirbazındaki "Telefonda" kutusu aynı alanları yazar; web'de çekmece Uygula bunları silmez.
22
+
23
+ ## Seçim bileşenleri
24
+
25
+ `dropdown` ve `multi-select` kök lookup'ı (entity kaynağı) telefonda böyle açar. `behavior.mobile` seçim
26
+ bileşeninde: `search` (alt sayfada arama kutusu), `infiniteScroll`, `pullToRefresh`, `recentSelections`.
27
+ `mobileRow` parçaları lookup `fields` içinden seçilir (dışındaysa CD-004); `fields: []` (türetilen lookup)
28
+ yalnız başlığın dolu olmasını ister. Tek seçim alt sayfada dokununca kapanır; çoklu seçim onay kutusu +
29
+ "Seçililer (n)" + Temizle/Uygula ile yazar, `change` yalnız Uygula'da gider; `max-length` doğrulaması dolunca
30
+ öbür satırlar pasifleşir.
31
+
32
+ `autocomplete` lookup taşımaz (seçim listesi gerekiyorsa `dropdown`): bağlı `options` `value` + `label` ister,
33
+ `caption`/`icon` isteğe bağlıdır. Bağlantı arama alanı seçmişse (`behavior.searchable`) yazılan metin
34
+ `search { searchText }` ile düğüme yazılır ve bağlantı yeniden okunur — sunucu arar, akış gerekmez.
35
+
36
+ ## Tablo ve liste
37
+
38
+ - **`datatable`:** `behavior.mobile` → `filterChips` (web `filterable` kolonlarından çip şeridi), `swipeDelete`
39
+ (onaylı kaydırarak sil), `infiniteScroll`, `pullToRefresh`. Kart görünümü `behavior.mobileCard
40
+ { title, fields?, trailing? }` seçili yollardan (dışındaysa CD-004); yoksa ilk metin alan başlıktır.
41
+ Satıra dokunmak düzenleme alt sayfasını açar (bağlantının `edit` ayarıyla).
42
+ - **`repeater`:** bağlı satırlar sayfa sayfa birleşir; öğe şablonundaki metne alan bağlamak
43
+ `page_schema_patch` ile `set_binding { prop, expression: '{{ item.<alan> }}' }` (Studio'nun "Şablonda" seçimi
44
+ aynı op'u yazar).
45
+
46
+ ## Gruplu liste
47
+
48
+ `grouped-list` `rows`u bağlanabilir; bağlarken `grouping` **zorunludur** (kök ADR 0019):
49
+
50
+ ```json
51
+ { "grouping": { "by": "dueDate", "sectionOrder": "asc", "dateBucket": "day", "otherSectionTitle": "Tarihsiz", "stickyHeaders": true, "showCounts": true } }
52
+ ```
53
+
54
+ - `by` seçili ve sıralanabilir bir alan (`asis` hariç); `sectionOrder` `asc` · `desc` · `asis`.
55
+ - `dateBucket` (`day` · `week` · `month`) yalnız `date`/`datetime` alanda (describe `dateBuckets`). Sunucu
56
+ sırayı gruplama alanıyla başlatır (azalanda boşlar sonda); `date` alanında kovayı satıra `__section` yazar,
57
+ `datetime` cihazın yerel gününe kovalanır.
58
+ - Bağlıyken bölümleme tanımdan okunur; `groupBy`/`sectionOrder`/`otherSectionTitle`/`stickySectionHeaders`/
59
+ `showCounts` prop'ları yok sayılır. Bağsız (`rows` ifadeyle) gruplu liste: `platform_guide('mobile')`
60
+ §Güne göre görev listesi.
61
+
62
+ ## Kurallar
63
+
64
+ | Kod | Ne zaman | Ne yapılır |
65
+ |---|---|---|
66
+ | CD-004 | `mobileRow` parçası lookup alanı değil; `mobileCard` parçası seçili yol değil | alanı seçime ekleyin ya da parçayı değiştirin |
67
+ | CD-019 | gruplu liste `grouping`siz; tarih dışı alanda `dateBucket` | `grouping { by, sectionOrder }` verin |
68
+ | CD-020 | `grouping` gruplama adımı bildirmeyen bileşende | `grouping`i kaldırın |
69
+ | PAGE-035 | `mobileMode` `sheet`/`fullscreen` dışında | iki değerden birini yazın |
70
+ | CD-013 | `grouping` entity dışı kaynakta | entity kaynağı kullanın |
@@ -0,0 +1,64 @@
1
+ # Mobil akış adımları rehberi
2
+
3
+ Mobil uygulamada (`type:'mobile'`) akış motoru web'deki motorun aynısıdır (`platform_guide('page')`, `flow_create`).
4
+ Bu rehber yalnız barındırıcıya — cihaza — dokunan adımların telefondaki sözleşmesini ve tariflerini anlatır.
5
+ Ekranın kendisi, sayfa olayları (`mount` · `focus` · `destroy`) ve uzak push `platform_guide('mobile')`'dadır.
6
+
7
+ ## Adımlar
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
+
32
+ ## Bildirim ve izin
33
+
34
+ Bildirim adımları paletten yalnız mobil uygulamada sunulur. Tarif — S04 "her gün hatırlat": önce
35
+ `notification-permission` (S03 düğmesi), sonra `timepicker`'ın değeriyle `notification-schedule`
36
+ (`value: "<saat>.value"`, değer `HH:mm`) ve `error` dalında kullanıcıya mesaj. Çevrimdışı bandı adım değil
37
+ ifadedir: `isHidden: {{ Device.isOnline }}` (`platform_guide('expressions')`).
38
+
39
+ **İzin tarifi** (izin, ihtiyaç anında — düğmeye basılınca — istenir; sayfa açılışında değil): `permission`
40
+ `check` → `condition`, **bu sırayla**: `status === 'granted'` ise işe devam; `'unavailable'` ise özelliği sunma
41
+ (Ayarlar'da açılacak izin yoktur — `canAskAgain` burada da `false` gelir); `canAskAgain` ise `permission` `request`
42
+ ve sonucuna göre devam; değilse nedenini söyleyip `open-settings`. `location` adımı, `map.showUser` ve dosya alanının
43
+ kamera/galeri kaynağı izni kendileri de ister — `permission` adımı *ne zaman* sorulacağını seçmek ve sonucu
44
+ okumak içindir. `unavailable` bir hata değil, derlemenin o izni taşımadığının haberidir
45
+ (`platform_guide('mobile-publish')` §İzinler).
46
+
47
+ ## Reklam
48
+
49
+ **Reklam tarifi** (kök ADR 0012): (1) `mobile_store_update { settings: { ads: { enabled: true, iosAppId, androidAppId,
50
+ testMode: true, units: [{ name, format, ios, android }] } } }` — reklam, App ID'si olan platformun derlemesine `tracking`'i de sokar (ATT metni
51
+ gider, kip `off` olamaz); (2) banner için sayfaya `adBanner` `unit: '<banner yerleşimi>'`; (3) geçiş/ödüllü reklam için
52
+ düğme akışına `ad-show` `value: '<yerleşim>'`, `error` dalında reklamsız devam; (4) ödül `condition`:
53
+ `Steps.<adım>.data?.reward` doluysa ödülü ver. Açılış reklamı adım değil ayardır (`ads.appOpenUnit`). Sıra cihazda:
54
+ rıza formu → açılış izinleri (ATT) → SDK; iOS'ta izleme izni yoksa reklam kişiselleştirilmeden istenir. Yerleşim adının
55
+ ayarda tanımlı olduğu sayfa/akış yazımında denetlenemez — `mobile_store_get` `settings.ads.units` ve `adsWarnings`
56
+ (`MOB-026`); yayın ayrıntısı `platform_guide('mobile-publish')` §Reklamlar.
57
+
58
+ ## Konum ve harita
59
+
60
+ `style`, `accuracy`, `reverseGeocode` gibi anahtarlar sözleşmede yoktur ve platform onları sessizce düşürür
61
+ (`FLOW-029`). "Haritada aç" için adım yoktur: `map`'in `press` olayı düğüme `mapsUrl` yazar, akış
62
+ `redirect` `isRaw: true`, `path: '<harita>.mapsUrl'` ile açar. Tarif — L05 "mevcut konumumu kullan":
63
+ düğmenin `click`'i → `location` (`always` → setter `il.value = Steps.konum.data.address?.region`, `error` →
64
+ setter hata metni). Uzak push (sunucudan gelen bildirim): `platform_guide('mobile')` §Uzak push.
@@ -5,23 +5,96 @@ hata kodları. Uygulamanın kendisi (ekranlar, akışlar, uzak push gönderimi)
5
5
 
6
6
  ## Genel
7
7
 
8
- Mağaza derlemesi bir Mac runner'da koşar; uygulama **production ortamını** okur (yükleme için açılış sayfası
9
- production'a dağıtılmış olmalı; yalın `build` onsuz da derlenir, uygulama "yayımlanmamış" ekranını gösterir). Mağaza bilgisi ortam değil uygulama düzeyindedir (Core DB), dağıtımla kopyalanmaz.
8
+ Mağaza derlemesi bir Mac runner'da koşar; uygulama işin **ortamını** okur — boşsa production (yükleme için
9
+ açılış sayfası o ortamda olmalı, production'da dağıtılmış olmalı; yalın `build` onsuz da derlenir, uygulama
10
+ "yayımlanmamış" ekranını gösterir). Mağazaya yalnız production işinin derlemesi gider (§Test derlemesi). Mağaza
11
+ bilgisi ortam değil uygulama düzeyindedir (Core DB), dağıtımla kopyalanmaz.
12
+
13
+ ## Yolculuk
14
+
15
+ Studio › Yayınla sekiz adımdır; 1–5 ortak (3'ün test derlemesi platform başına), 6–8 iOS ve Android için ayrı
16
+ sekmede yürür (biri de tek başına yayınlanabilir):
17
+
18
+ 1. **Production'dan çıkar** — uygulama production ortamını okur; hangi mağazaya gidileceği
19
+ (`settings.releaseTargets`) burada seçilir.
20
+ 2. **Telefonunda dene** — Zeyrek Mobile ile (`platform_guide('mobile')` §Cihazda dene).
21
+ 3. **Test sürümü** — üç bölüm: kimlik ve sürüm · Apple hesabı · Google Play hesabı; ardından isteğe bağlı test
22
+ derlemesi (TestFlight / Play iç test, istenen ortamdan — §Test derlemesi) ve test kullanıcıları.
23
+ 4. **Yayına hazırla** — yedi bölüm: mağaza metinleri · görseller · yaş derecelendirmesi · gizlilik · beyanlar ·
24
+ sürüm, fiyat, yayın · konsolda kalanlar. Ajanın `mobile_store_update` / `mobile_asset_*` yolu; 3 ve 4'ün iş
25
+ tarifi MCP prompt'u `mobile_publish_prepare`'dir.
26
+ 5. **Canlıya al** — iki tür güncelleme (aşağıda).
27
+ 6. **Son kontrol** — mağaza ön kontrolü (`scope: 'store'`); aynı düğme derlemeyi başlatır (`mobile_build_start`:
28
+ iOS `testflight`, Android `internal`; Android'de paket türü).
29
+ 7. **Derle** — işin ilerlemesi ve sonucu (`mobile_build_status`).
30
+ 8. **Mağazada yayınla** — incelemeye gönder, yayınla, kanala taşı: insan onayıyla Studio'da.
31
+
32
+ **Doldurmadan ilerlenmez.** Studio sonraki adımı kilitler: 3'te kimlik ya da bu sürümün gittiği mağazanın hesap
33
+ bölümü eksikken 4'e (test derlemesi kapı değildir), 4'te eksik bölüm varken 5'e (konsol bölümü elle yapılır,
34
+ kilide girmez), 5'te production'a gitmemiş değişiklik varken (`detail: ['changes']` → `live` dolu) 6'ya, 6'da
35
+ bu platformun mağaza işi yokken 7'ye, 7'de başarıyla biten iş yokken 8'e geçilmez. 3'teki test işi 6–8'i açmaz.
36
+ Ajan kullanıcıyı "sonraki adıma geç" diye yönlendirmeden önce o adımın koşulunu karşılar.
37
+
38
+ ## Test derlemesi
39
+
40
+ Yayınla 3 · Test sürümü, mağaza hazırlığından ve canlıya almadan **önce** TestFlight'a / Play iç test kanalına bir
41
+ derleme gönderir. İsteğe bağlıdır; her başlatma derleme numarası ayırır ve kimliği kilitler.
42
+
43
+ - **Ortam:** `mobile_build_start { platform, target, environment, dryRun: true }` — `environment` ortamın adı ya da
44
+ slug'ı: `development`, `production` ya da `Ready` durumdaki bir dal; boş = production. Yalnız `build`,
45
+ `testflight`, `internal` alır; yükseltme hedefinde gateway istek gitmeden reddeder. Etkin olmayan
46
+ ortam ya da hazır olmayan dal backend'de 422 `environment`. Yanıt ve `mobile_build_status` işin `environment`'ını
47
+ taşır.
48
+ - **Ön kontrol `scope: 'test'`** (environment verilince kendiliğinden; `'store'` ile birlikte reddedilir, yükseltme
49
+ hedefinde verilmez). Yalnız test yüklemesinin istediğini sorar:
50
+
51
+ | Satır | `scope: 'test'` |
52
+ |---|---|
53
+ | P-01 | yalnız kimlik: `displayName`, `bundleIdentifier`, `androidPackage`, `scheme`, `version`, sayaçlar (metin ve Play sürüm notu sınırı yok) |
54
+ | P-03, P-04, P-05, P-07, P-08, P-09 | aynı (hesap ve imza, konsolda uygulama kaydı, https, etkin iş, runner) |
55
+ | P-06 | seçilen ortamda: production dışında `ok environment_ready` / `fail environment_page_missing` |
56
+ | P-11 | aynı kurallar, `fail` → `warn` (push eksikliği testi durdurmaz) |
57
+ | P-12, P-14 | seçilen ortamın kullanımı ve akışları |
58
+ | P-13 | `manual ads_test_mode` yok (test kipi testte beklenir) |
59
+ | P-02, P-10, P-15…P-21 | sorulmaz — metin, görsel, beyan ve App Review kuralları mağazaya giden işte |
60
+
61
+ - **Yayın kaynağı yalnız production işidir.** Production'dan alınan ve testte beğenilen derleme sonradan yeniden
62
+ derlenmeden incelemeye (`app-store-review`) ya da kanala (`play-promote`) gider. Development ya da dal derlemesi
63
+ **asla** mağazaya yükseltilemez ve daha yeni olsa da production işini gölgelemez. Dal merge'ten sonra silinir; o
64
+ dalın test derlemesi açılamaz olur.
65
+ - Development ya da dal derlemesi test edene o ortamın verisini açar; ortamın erişim kipi `off` ise korumalı alanlar
66
+ uygulanmaz — ortamı seçerken kullanıcıya söyleyin.
67
+ - **Play taslak uygulama:** Play'de hiç yayınlanmamış uygulamada API yalnız `draft` sürüm açabilir; ilk iç test
68
+ yayını Play Console'dan elle başlatılır (`play.releaseStatus` ayarı korunur).
69
+ - TestFlight **dış** test grubu (Test bilgisi, Beta App Review) bu yolun dışındadır; test kullanıcıları iç test
70
+ ekibine Studio'dan davet edilir.
71
+
72
+ ## İki tür güncelleme
73
+
74
+ `mobile_store_get { detail: ['changes'] }` son production dağıtımından beri değişenleri iki kovada döner:
75
+ `live` (sayfa, akış, uç — production'a dağıtılınca telefonlara dakikalar içinde gider, mağaza gerekmez;
76
+ dağıtım insan onaylıdır) ve `store` (izin, kimlik, görsel, kabuğun taşıdığı ayar — yeni mağaza sürümü ve
77
+ 1–3 gün inceleme ister → adım 6). Kova boşsa o tür güncelleme gerekmez.
10
78
 
11
79
  ## Kim ne yapar
12
80
 
13
81
  **Ajanın yaptığı:** `mobile_store_get` (ayar, kilitli alanlar, görsel sayısı, beyanlar; `manifest: true`;
14
- `detail: ['assets','signing','runners','audit']` id'li görseller, maskeli kimlik bilgisi/hesap, runner, denetim) ·
82
+ `detail: ['assets','signing','runners','audit','status','changes']` id'li görseller, maskeli kimlik bilgisi/hesap,
83
+ runner, denetim, mağaza durumu, iki kova) ·
15
84
  `mobile_store_update` (`settings` yaması · `declarations` · `registerAppleBundleId`) · `mobile_asset_create` /
16
- `_update` (sıra) / `_delete` · `mobile_build_start` (`dryRun`, `runnerScope`) · `mobile_build_status` ·
17
- `mobile_build_log` · `mobile_build_cancel`.
85
+ `_update` (sıra) / `_delete` · `mobile_build_start` (`dryRun`, `environment`, `scope`, `runnerScope`, `runnerId`, `packageType`) ·
86
+ `mobile_build_status` · `mobile_build_log` · `mobile_build_cancel`.
18
87
 
19
88
  **Beyan kullanıcınındır:** `declarations` (App Privacy, Data safety, içerik derecelendirme, hedef kitle,
20
89
  uygulama erişimi) yalnız kullanıcı formu mağazada doldurduğunu onaylayınca `true` yazılır.
21
90
 
22
91
  **İnsanın Studio › Yayın › Hesaplar'da yaptığı (MCP'de araç yok):** Apple/Google hesabı, sertifika, profil,
23
92
  keystore, harita anahtarı, demo parolası, push kimlikleri — APNs anahtarı, Firebase hesabı,
24
- `google-services.json` (gizli bilgi) ve runner kaydı. `review.demoPassword` şemada reddedilir.
93
+ `google-services.json` (gizli bilgi) ve runner kaydı. `review.demoPassword` şemada reddedilir: App Review demo
94
+ hesabı (P-15) Studio'da girilir. **Test kullanıcıları** (TestFlight davetleri, Play test grubu ve katılım
95
+ bağlantısı) Studio › Yayınla'dan davet edilir — kişisel e-posta taşıdığı için MCP'de araç yok. **Mağazaya
96
+ gönderim** (adım 8: `app-store-review`, `app-store-release`, `play-promote`) geri dönüşsüz ya da insan onaylıdır;
97
+ ajan yalnız `dryRun` ile ön kontrolünü okur ve kullanıcıyı Studio'ya yönlendirir.
25
98
 
26
99
  **Ekran görüntüsü:** `page_screenshot { environment: 'production', device, format: 'jpeg', quality: 92,
27
100
  language, colorScheme: 'light', outPath }` → `mobile_asset_create { path, kind: 'screenshot', deviceClass, locale }`.
@@ -44,36 +117,90 @@ ikon/splash/öne çıkan görsel tekli yuvadır: yeni yükleme eskisinin yerine
44
117
  ## Hedefler
45
118
 
46
119
  `build` (iki platform, yalnız derler) · `testflight` (yalnız iOS) · `internal` (yalnız Android, Play
47
- iç test). TestFlight'ta runner yükledikten sonra iş `running` + `store_processing` kalır (`awaitingStore`),
120
+ iç test). Android paketi `packageType`: `aab` (varsayılan, mağaza) · `apk` (yalnız `build`; telefona doğrudan
121
+ kurulur, mağazaya **gitmez** — indirme bağlantısı Studio'da). Runner verilmezse backend seçer: kurumun kendi
122
+ Mac'i çevrimiçiyse o, değilse Zeyrek'in runner'ı; yanıtta `runnerKind` (`own` · `zeyrek`). TestFlight'ta runner yükledikten sonra iş `running` + `store_processing` kalır (`awaitingStore`),
48
123
  Apple işleyince `completed` (en çok 60 dk); bu durumda iptal 409. İptal 409'unun mesajı nedeni söyler (iş zaten
49
124
  tamamlandı / başarısız / iptal edildi, mağaza yüklemeyi işliyor).
50
- TestFlight'ta derleme yüklenip mağaza metni/ekran görüntüleri reddedilirse iş yine tamamlanır;
51
- `storeResult.listingError` (hata kodu, ör. `store_rejected`) + `listingMessage` (ne yapılacağı) gelir. Derleme
52
- TestFlight'tadır, numara harcanmıştır: metni düzeltip yeni sürüm yüklemek gerekir, işi yeniden başlatmak aynı
53
- metni yeni numarayla yeniden dener.
125
+ `testflight` ve `internal` yalnız ikiliyi yükler; mağaza metni, ekran görüntüleri ve inceleme bilgisi yükseltme
126
+ işinde gider (iOS `app-store-review`, Android `play-promote` `production` kanalına). Eski TestFlight işlerinde
127
+ görülen `storeResult.listingError` + `listingMessage` o işin metin yüklemesinin reddidir; derleme yine TestFlight'tadır.
128
+
129
+ ## Mağaza yayını
130
+
131
+ Yayın hedefleri önceki adımın derlemesini taşır (yeni derleme yapmaz): `app-store-review` son TestFlight
132
+ derlemesini incelemeye gönderir, `app-store-release` onaylanan sürümü yayınlar, `play-promote` son iç test
133
+ derlemesini `releaseTrack` kanalına (`closed` | `production`) taşır. Kaynak yalnız **production işinin** derlemesidir
134
+ (development / dal test derlemesi sayılmaz); yoksa P-22 `fail`. Yükseltme hedefi `environment` ve `scope: 'test'` almaz.
135
+ **MCP'den yalnız `dryRun`**: gerçek çağrı `release_target_studio_only` ile durur, hiçbir iş açılmaz. App Review'a ek
136
+ görsel: `mobile_asset_create { kind: 'reviewAttachment' }` (dilsiz; yalnız `app-store-review` gönderimine girer).
137
+
138
+ `mobile_store_get { detail: ['status'] }` → `status.apple` (`appStoreState`, sürüm, kademeli durum),
139
+ `status.play.tracks[]` (kanal, durum, `versionCodes`, `rolloutPercent`) ve `status.actions[]`: Studio'daki
140
+ yayın düğmeleri, her biri `irreversible` + `consequence` (ne olacağı, istek dilinde). `irreversible: true`
141
+ geri alınamaz (App Store'da yayın, Play üretim kanalı; `releaseType` `manual` değilse incelemeye göndermek de) —
142
+ kullanıcıya `consequence`'ı aynen söyleyin.
143
+
144
+ Yayın ayarı (`mobile_store_update { settings }`, MOB-022 aynası): `apple.releaseType` `manual` (varsayılan) ·
145
+ `automatic` · `scheduled` (+ ileri `scheduledAt`), `apple.phasedRelease` (7 güne yayılan otomatik
146
+ güncelleme), `apple.pricing` `free` | `tier-1…tier-87`, `apple.territories` `['all']` ya da ISO alfa-3 kodları
147
+ (gönderim yalnız EKLER; satıştan kaldırma App Store Connect'te), `play.contactPhone` (E.164),
148
+ `play.contactWebsite` (https), `play.promoVideoUrl` (YouTube), `play.rolloutPercent` 1–100 (üretim kanalı;
149
+ boş = 100).
150
+
151
+ ## Yaş derecelendirmesi
152
+
153
+ `settings.apple.advisory` Apple'ın yaş anketidir: soru anahtarı → cevap (metin). Ön kontrol (P-21) tek cevabı
154
+ yeterli sayar, ama App Store Connect beyanı **her soru cevaplı** değilse reddeder ve Studio'nun bölümü de
155
+ ancak hepsi cevaplıyken tamamdır. Bütün soruları yazın (yama `advisory`'yi anahtar anahtar birleştirir;
156
+ yazılmayan soru boş kalır).
157
+
158
+ - Sıklık soruları — `NONE` · `INFREQUENT_OR_MILD` · `FREQUENT_OR_INTENSE`:
159
+ `alcoholTobaccoOrDrugUseOrReferences`, `contests`, `gamblingSimulated`, `gunsOrOtherWeapons`,
160
+ `horrorOrFearThemes`, `matureOrSuggestiveThemes`, `medicalOrTreatmentInformation`, `profanityOrCrudeHumor`,
161
+ `sexualContentGraphicAndNudity`, `sexualContentOrNudity`, `violenceCartoonOrFantasy`, `violenceRealistic`,
162
+ `violenceRealisticProlongedGraphicOrSadistic`.
163
+ - Evet/hayır soruları — `'true'` · `'false'` (metin):
164
+ `advertising`, `ageAssurance`, `gambling`, `healthOrWellnessTopics`, `lootBox`, `messagingAndChat`,
165
+ `parentalControls`, `socialMedia`, `socialMediaAgeRestricted`, `unrestrictedWebAccess`, `userGeneratedContent`.
166
+ - `kidsAgeBand` (isteğe bağlı): boş = Çocuklar kategorisinde değil; `FIVE_AND_UNDER` · `SIX_TO_EIGHT` ·
167
+ `NINE_TO_ELEVEN`.
168
+
169
+ Cevap uygulamanın içeriğinden çıkar (sayfalar, akışlar, reklam ayarı: `settings.ads.enabled` → `advertising`);
170
+ emin olunmayan soru kullanıcıya sorulur. Google Play'in IARC anketi konsoldadır (insan).
54
171
 
55
172
  ## Ön kontrol
56
173
 
57
- `mobile_build_start { dryRun: true }` yalnız `ok` OLMAYAN satırları döner (`okCount` gerisini sayar).
174
+ `mobile_build_start { dryRun: true }` yalnız `ok` OLMAYAN satırları döner (`okCount` gerisini sayar). Tablo
175
+ `scope: 'store'` (varsayılan) içindir; `scope: 'test'` farkı §Test derlemesi'nde.
58
176
 
59
177
  | id | Kod (`fail`) | Nerede düzelir |
60
178
  |---|---|---|
61
- | P-01 | `settings_incomplete`; Android `internal`'da `release_notes_too_long` (bir dilde `releaseNotes` > 500 — Play sınırı; ayar 4000'e izin verir çünkü App Store'a da gider; ikisi birlikteyse tek satırda iki cümle) | `mobile_store_update` |
179
+ | P-01 | `settings_incomplete`; Android `internal`'da `release_notes_too_long` (bir dilde `releaseNotes` > 500 — Play sınırı; ayar 4000'e izin verir çünkü App Store'a da gider; ikisi birlikteyse tek satırda iki cümle). Mesaj alanları istek dilinde adlandırır ("başlık (English)", "gizlilik politikası adresi"), ayar yolunu değil — yol `mobile_store_get`'ten | `mobile_store_update` |
62
180
  | P-02 | `assets_missing` | `mobile_asset_create` |
63
181
  | P-03 | `secrets_missing`, `secrets_unreadable`, `signing_expired` (`warn signing_expiring`) | Studio › Yayın › Hesaplar |
64
182
  | P-04 | `apple_account_missing`, `asc_bundle_id_missing`, `asc_app_missing`, `asc_unauthorized`, `asc_forbidden`, `asc_unreachable` | `asc_bundle_id_missing`: `mobile_store_update { registerAppleBundleId: true }`. `asc_app_missing`: App Store Connect'te uygulama kaydı (API açamaz, insan açar). Diğerleri: Studio hesabı |
65
183
  | P-05 | `google_account_missing`, `play_app_missing`, `play_unauthorized`, `play_forbidden`, `play_unreachable` | Play Console'da uygulama + servis hesabı yetkisi |
66
- | P-06 | `production_missing`, `production_page_missing` (yalın `build`'de `warn`, başlatmayı engellemez) | production ortamı ve dağıtım — insan onaylı, ajan yapmaz |
184
+ | P-06 | `production_missing`, `production_page_missing` (yalın `build`'de `warn`, başlatmayı engellemez); production dışı `environment` ile `fail environment_page_missing` | production ortamı ve dağıtım — insan onaylı, ajan yapmaz; başka ortamda açılış sayfası o ortamda |
67
185
  | P-07 | `https_required` | platform ayarı (destek) |
68
186
  | P-08 | `build_active` | etkin işi bekle ya da `mobile_build_cancel` |
69
187
  | P-09 | `runner_offline` | runner Mac'te `zeyrek-mobile-runner run` |
70
188
  | P-10 | `manual declarations_pending` | kullanıcı onayıyla `mobile_store_update { declarations }` (engellemez) |
71
189
  | 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
- | 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 |
190
+ | 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), `warn permission_shell_outdated` (derlemenin taşıdığı izin yayındaki kabuktan yeni — katalog satırının `minShellVersion`'ı, ör. `biometric` 0.6.0; manifest o izni yazmaz, açılış uyarısı varsa iletisine eklenir) , `warn launch_permissions_shell_outdated` (açılışta sorulan izin var, kabuk açılışta sormuyor) ya da `warn app_lock_shell_outdated` (uygulama kilidi açık, kabuk 0.6.0'dan eski: mağaza sürümü kilitsiz açılır); kabuk uyarıları tek satırda birleşir — kod ilk uyarınındır, ileti hepsini söyler, kabuk kümeyi de taşımıyorsa açılış ve kilit cümleleri `permissions_shell_outdated`'ı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
191
  | 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
192
  | 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 |
193
+ | P-15 | App Review satırları P-15…P-21 yalnız iOS yükleme hedeflerinde (`testflight`, `app-store-*`); sinyal okunamazsa `manual review_signals_unreadable`. P-15 demo hesabı: giriş varsa ve demo hesabı yoksa `review_demo_missing` | Studio › Yayın › Hesaplar (demo hesabı gizli bilgidir) |
194
+ | P-16 | `manual screenshot_source_unverified` (ekran görüntüsü uygulamanın gerçek ekranı mı — 2.3.3); hiç iOS ekran görüntüsü yoksa satır yok (eksikliği P-02 söyler) | kullanıcı doğrular |
195
+ | P-17 | `app_name_missing`, `app_name_too_long` (> 30); `warn`: adda yasak terim, anahtar kelime adı tekrarlıyor | `mobile_store_update { settings: { listing } }` |
196
+ | P-18 | giriş varsa `manual third_party_sign_in_unverified` (üçüncü taraf girişte Apple ile giriş — 4.8) | kullanıcı doğrular |
197
+ | P-19 | `privacy_policy_missing` | `settings.urls.privacyPolicy` |
198
+ | P-20 | kendi kaydı olan uygulamada hesap silme yolu görülmezse `manual account_deletion_unverified` (5.1.1(v)) | ekran + kullanıcı doğrular |
199
+ | P-21 | `age_rating_missing` (yaş derecelendirmesi yanıtsız) | `settings.apple.advisory` |
200
+ | P-22 | yayın hedefinde `release_source_missing`: kaynak derleme yok (`testflight` → `app-store-review` → `app-store-release`, `internal` → `play-promote`) | önce kaynak hedefi derle |
75
201
 
76
- Satırın `message` ve `fixHint`'i backend'den, istek dilinde gelir.
202
+ `manual` satır başlatmayı engellemez ama kullanıcıya söylenir; `fail` engeller. Satırın `message` ve `fixHint`'i
203
+ backend'den, istek dilinde gelir.
77
204
 
78
205
  ## İzinler
79
206
 
@@ -126,6 +253,24 @@ yerleşim o platformda yoktur. Biçim hatası `MOB-022` ile yazılmadan durur.
126
253
  - `mobile_store_get` reklam açıkken `adsWarnings` döner (`MOB-026`): test kipi, App ID'si olan platformda birimi olmayan
127
254
  yerleşim, konsol beyanları (App Privacy, Data safety, AdMob rıza mesajı — insanın işi).
128
255
 
256
+ ## Uygulama kilidi
257
+
258
+ Mağaza sürümünün Face ID / parmak izi / cihaz parolasıyla kilitlenmesi (kök ADR 0021 madde 8–11) bir mağaza ayarıdır:
259
+ `settings.appLock = { enabled, timeoutSeconds }`, süre `0` (her dönüşte) · `60` · `300` · `900` saniye. Yama alan alan
260
+ birleşir (`{ appLock: { timeoutSeconds: 300 } }` açık/kapalıyı korur).
261
+
262
+ - Açık kilit `biometric` için bir kullanımdır (`usage` içinde `source: lock`): izin `auto` kipte derlemeye girer.
263
+ `permissionModes.biometric` `off` iken kilit açılamaz, açık kilitle kip `off` yapılamaz (422 `appLock.enabled`;
264
+ gateway birleşik kayıtta istek gitmeden durdurur, `MOB-022`).
265
+ - Bir sonraki mağaza derlemesiyle etkili olur. Kilit kabuğun ayrı bir yeteneğidir (kabuk paketi ≥ 0.6.0): görünümde
266
+ `shell.carriesAppLock: false` ise ayar saklanır ama manifest `appLock` yazmaz, uygulama kilitsiz açılır
267
+ (`permissionWarnings` `MOB-031`; ön kontrol P-12 uyarır — kabuk 0.5.x'te kod `app_lock_shell_outdated`, daha eski kabukta
268
+ cümle o kabuğun ilk P-12 uyarısına eklenir, aynı satırda `fail permission_off_in_use` varsa kilit cümlesi görünmez).
269
+ - Davranış: soğuk açılışta ve arka planda süre dolup dönüşte kilit ekranı, ardından sistem penceresi; içerik kilit
270
+ açılmadan çizilmez, oturum kapanmaz. Cihazda biyometri de parola da yoksa kilit atlanır. iOS'ta uygulama değiştirici
271
+ görüntüsü örtülür, Android'de örtülmez. **Oynatıcıda (Expo Go) ve Studio önizlemesinde kilit yoktur** — tek bir
272
+ ekranı kapı arkasına almak için `biometric-auth` adımı (platform_guide('mobile-steps')).
273
+
129
274
  ## Hata kodları
130
275
 
131
276
  `mobile_build_status` → `error.code`.
@@ -28,6 +28,7 @@ Motorun kendi adımları (`setter`, `condition`, `microservice`, `code`, `functi
28
28
  | `open-settings` | uygulamanın sistem ayar sayfasını açar; `Steps.<adım>.data.opened`. Argüman almaz |
29
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
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
+ | `biometric-auth` | kullanıcıyı Face ID / parmak izi (yedekle cihaz parolası) ile doğrular (kök ADR 0021). `args.title` sistem penceresindeki gerekçe, `args.cancelText` vazgeç düğmesi — ikisi metin şablonu, boşsa uygulama dilindeki varsayılan; `args.value` yedek, düz metin: `device` (biyometri olmazsa cihaz parolası; boşsa bu) ya da `none` (`FLOW-042`; `fallback` / `reason` / `cancelLabel` anahtarı sessizce düşer). Başarı: `Steps.<adım>.data = { verified: true }` → `always`. **Vazgeçmek hatadır**: `error.status` `cancelled` · `not-enrolled` · `lockout` · `failed` · `unavailable` (donanım yok ya da derleme taşımıyor) · `unsupported` (web uygulaması, production `/view`) · `invalid`; `error` dalı → hata akışı → **o da yoksa akış bu adımda biter**, `always`'e bağlı adım koşmaz. Yerel bir kapıdır, sunucu için kanıt değildir. Paletten yalnız mobilde |
31
32
  | `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
 
33
34
  ## Bildirim tarifi
@@ -35,7 +36,10 @@ Motorun kendi adımları (`setter`, `condition`, `microservice`, `code`, `functi
35
36
  Bildirim adımları paletten yalnız mobil uygulamada sunulur. Tarif — S04 "her gün hatırlat": önce
36
37
  `notification-permission` (S03 düğmesi), sonra `timepicker`'ın değeriyle `notification-schedule`
37
38
  (`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
+ ifadedir: `isHidden: {{ Device.isOnline }}` (`platform_guide('expressions')`) — ağı CANLI izler, ekran açıkken bağlantı
40
+ gidince çıkar. Kabuğun kendi bandı ayrıdır: yalnız sayfa isteği (açılış ya da yenileme) düşünce çıkar — ağ yoksa
41
+ "Çevrimdışı · son güncelleme …", sunucu 5xx dönerse "Yenilenemedi". İkisi aynı anda görünebilir; sayfa bandını
42
+ ekranın tepesine değil, anlattığı verinin yanına koyun (`platform_guide('page')` §Kural 1g-4).
39
43
 
40
44
  ## İzin tarifi
41
45
 
@@ -58,6 +62,22 @@ rıza formu → açılış izinleri (ATT) → SDK; iOS'ta izleme izni yoksa rekl
58
62
  ayarda tanımlı olduğu sayfa/akış yazımında denetlenemez — `mobile_store_get` `settings.ads.units` ve `adsWarnings`
59
63
  (`MOB-026`); yayın ayrıntısı `platform_guide('mobile-publish')` §Reklamlar.
60
64
 
65
+ ## Biyometri tarifi
66
+
67
+ **Biyometri tarifi** (kök ADR 0021): (1) onaylanacak düğmenin akışına `biometric-auth` `args: { title: 'Ödemeyi
68
+ onaylayın' }`, işi `always` dalına, kullanıcıya söylenecek olanı `error` dalına (`Steps.<adım>.error.status`) bağlayın —
69
+ hata yolu yoksa vazgeçen kullanıcıda akış biter; (2) "bu cihazda biyometri yok" metni `isHidden: {{ Device.biometric.available }}`
70
+ (`Device.biometric = { available, enrolled, kinds }`, `platform_guide('expressions')`). Nerede ne olur: Studio önizlemesi,
71
+ canlı kip, `/dev` ve `/branch` sormaz — "Doğrulandı say" / vazgeç penceresi açar (`Device.biometric` orada açık, kayıtlı,
72
+ yüz); production `/view` ve web uygulaması `unsupported` döner. Oynatıcıda (Expo Go) yedeği `device` olan adım çalışır,
73
+ `none` olan her zaman `unavailable`. Mağaza derlemesi biyometriyi yalnız production'da kullanılıyorsa ya da uygulama kilidi açıksa taşır (izin satırı
74
+ `biometric`, Face ID metni `mobile_store_update { settings: { permissions: { biometric } } }`, kabuk 0.6.0+). `biometric`
75
+ **sorulamayan izindir**: `permission` adımının türü olamaz, açılışta sorulamaz (422). Uygulamanın tamamını açılışta
76
+ kilitlemek adım değil mağaza ayarıdır (`settings.appLock`, `platform_guide('mobile-publish')` §Uygulama kilidi). `page_screenshot` pencereyi
77
+ sürer: adımı tetikleyen tıklamanın raporu `pageState: 'awaiting-user'` der, sonraki eylem `{ action: 'click', target:
78
+ 'preview-biometric__verify' }` (Doğrulandı say) ya da `'preview-biometric__cancel'`. Tam gövde:
79
+ `ngapps://examples/flow-biometric-confirm`.
80
+
61
81
  ## Konum ve harita
62
82
 
63
83
  `style`, `accuracy`, `reverseGeocode` gibi anahtarlar sözleşmede yoktur ve platform onları sessizce düşürür
@@ -20,8 +20,10 @@ anlamları ayrı.
20
20
  `page_update({ layoutId })` × N → `application_update({ homepageId, properties.mobile.tabs })`.
21
21
  Sekme ayarı sayfa **id**'si ister; bu yüzden sayfalardan SONRA yazılır.
22
22
  2. **Veri.** Entity, microservice ve workflow web'dekiyle aynıdır (`platform_guide('microservice')`).
23
- Sayfa akışı `microservice` adımıyla aynı uçları çağırır.
24
- 3. **Ekranlar.** `page_schema_patch` ile bileşen ekle, akış bağla (`flow_create` → `set_event`).
23
+ Sayfa akışı `microservice` adımıyla aynı uçları çağırır. Veri bağlamanın telefon
24
+ kararları: `platform_guide('mobile-connect-data')`.
25
+ 3. **Ekranlar.** `page_schema_patch` ile bileşen ekle, akış bağla (`flow_create` → `set_event`). Cihaza
26
+ dokunan adımlar (izin, konum, bildirim, reklam, geri, kod tarama): `platform_guide('mobile-steps')`.
25
27
  4. **Doğrulama.** `page_screenshot` (mobilde varsayılan `device: 'phone'`, 390x844 @2) ve
26
28
  `page_runtime_get({ resolveStyles: true })` (düğümün React Native stili). Ayrıntı §Doğrulama.
27
29
 
@@ -119,12 +121,9 @@ mobil bileşenlere geçen notlar). Web'de karşılığı olmayan bileşende (`ap
119
121
  - **Dönen kart ve kart destesi** (2026-10-08): `flip-card` (children = [ön `view`, arka `view`]; `isFlipped`,
120
122
  `flip`) ve `swipeable-stack` (`repeater` şekli: [kart `view`, boş `view`], `rows`, `currentIndex`;
121
123
  `swipeLeft` / `swipeRight` / `finish` yükü `event.data`) mobile özgüdür.
122
- - **Faz 10** (FlutterFlow D listesi): `datatable` web ikizidir — kolon biçimi, sıralama ve sayfa hesabı web'in
123
- modülünden, akış sözleşmesi aynı (sıralama/sayfa değişince `sortField`/`sortType`/`offset` düğüme yazılır ve
124
- `mount` yeniden koşar; satır eylemi `selectedRow`u yazıp eylemin akışını koşturur). Mobile özgü `variant`:
125
- `table` (varsayılan, yatay kaydırılan tablo; başlığa dokunuş `__sort-<kolon>`) ya da `cards` (satır başına
126
- kart). Eylemler `__action-<satır>-<sıra>`, `dropdown` kipinde `__more-<satır>` → alttan eylem sayfası;
127
- sayfa çubuğu `__page-prev`/`__page-next`. Filtre düzenleyicisi, özet satırı ve sabit eylem sütunu yok.
124
+ - **Faz 10:** `datatable` web ikizidir (kolon, sıralama, sayfa ve akış sözleşmesi web'in). Telefon farkları
125
+ (`variant: table | cards`, filtre çipleri, düzenleme alt sayfası, sonsuz kaydırma) `component_get`
126
+ `mobileKnowledge`'ta; bağlı tablonun telefon ayarı `platform_guide('mobile-connect-data')`'da.
128
127
  - Web'e özgü bileşenlerin mobil karşılığı:
129
128
 
130
129
  | Web | Mobilde |
@@ -136,6 +135,7 @@ mobil bileşenlere geçen notlar). Web'de karşılığı olmayan bileşende (`ap
136
135
  | `iframe` | `webview` (`src` ya da `html`) |
137
136
  | `theme-toggle` | cihaz teması |
138
137
  | `fileUpload` | `fileInput` (alan) ya da `filebutton` (düğme) — sürükle-bırak yok |
138
+ | `attachments` | `filebutton` (`isMultiple`) — önizlemeli kart ızgarası, popup ve sürükle-bırak yok |
139
139
 
140
140
  **Harici bileşen mobilde yoktur** (`MOB-006`): protokol v1 tarayıcı `.mjs` paketidir;
141
141
  `external_component_*` araçları mobil uygulamada platforma gitmez. **Geçici yol `html`** (2026-09-28):
@@ -365,7 +365,7 @@ etiketi ailesini `typographyStyle`'dan alır, alan etiketleri platform yazı tip
365
365
  ## Gezinme
366
366
 
367
367
  - **Yığın varsayılandır; ayar yoktur.** `redirect` adımı hedef sayfayı yığına iter, geri hareketi
368
- (cihaz geri tuşu, app-bar geri düğmesi, tarayıcı geri) önceki ekrana döner. Göreli yol uygulama
368
+ (cihaz, app-bar ya da tarayıcı geri) önceki ekrana döner. Göreli yol uygulama
369
369
  köküne eklenir; tam adres (`https://…`) dışarıda açılır.
370
370
  - **Sekmeler uygulama ayarıdır, layout'ta değil.** `application_update({ properties: { mobile: { tabs } } })`:
371
371
 
@@ -377,7 +377,7 @@ etiketi ailesini `typographyStyle`'dan alır, alan etiketleri platform yazı tip
377
377
  "style": "default",
378
378
  "items": [
379
379
  { "page": "<page_list id>", "label": "Görevler", "icon": "list" },
380
- { "page": "<page_list id>", "label": "Profil", "icon": "user" }
380
+ { "page": "<id>", "label": "Sepet", "badge": { "source": "state", "ref": "sepet.adet" }, "reselect": "keep" }
381
381
  ],
382
382
  "showLabels": true
383
383
  }
@@ -385,14 +385,19 @@ etiketi ailesini `typographyStyle`'dan alır, alan etiketleri platform yazı tip
385
385
  }
386
386
  ```
387
387
 
388
- `items` 1–5 sayfa **id**'si (slug değil), tekrar yok; `style: 'floating'` köşe `pill` + gölge `md`
389
- çizer. Çubuğun rengi ayarda YOKTUR: zemin `surface`, seçili `accent-primary`, seçilmemiş
390
- `text-secondary` — değiştirmek için `theme_update`; eski `appearance` alanı okunmaz; `style: 'custom'` + `customWidgetId` çubuğu kendi widget'ınla çizer. Tutarsız ayar ve
388
+ `items` 1–5 sayfa **id**'si (slug değil), tekrarsız; `floating` köşe `pill` + gölge `md`. Renk ayarda YOK: zemin `surface`, seçili `accent-primary`, seçilmemiş
389
+ `text-secondary` (`theme_update`); `style: 'custom'` + `customWidgetId` çubuğu o widget'la çizer. Tutarsız ayar ve
391
390
  layout/sayfada eski `tab-bar` / `drawer-menu` düğümü `MOB-007` alır. Sekme dışı sayfalar yığına açılır.
391
+ `badge.ref` **saklı** state yolu; `keep`: ikinci dokunuşta yığın durur.
392
+ Çubuk düzeyinde iki davranış anahtarı vardır ve **yalnız varsayılandan ayrılınca yazılır**: `"keepStackOnSwitch": false`
393
+ (sekme değişince hedef sekme köke döner; alan yoksa yığın korunur) ve `"hideOnKeyboard": true` (klavye açılınca çubuk
394
+ gizlenir; alan yoksa görünür). `true`/`false`'tan başka değer (ör. metin `"false"`) yok sayılır ve `MOB-007` uyarır.
395
+ İkinci dokunuş (`reselect`) ile sekme değişimi (`keepStackOnSwitch`) ayrı ayardır; eski runtime anahtarları bilmez ve
396
+ varsayılan davranışta kalır.
392
397
  - **Çekmece bir bileşendir.** `drawer` widget'ı + `app-bar`'ın `menuTarget` prop'u çekmeceyi açar.
393
398
  Çekmece layout'un kök dizisindedir (`views: [shell_root, nav_drawer]`), kabuk kabının içinde değil.
394
399
  - Kabuk örnekleri: `ngapps://examples/mobile-app-shell-stack` (yığın), `ngapps://examples/mobile-app-shell-tab`
395
- (sekmeler), `ngapps://examples/mobile-app-shell-drawer` (çekmece); üç sayfalık liste → detay → form akışı:
400
+ (sekmeler), `ngapps://examples/mobile-app-shell-drawer` (çekmece); liste → detay → form:
396
401
  `ngapps://examples/mobile-list-detail-form`; kod tarama (düğme → `scan-code` → alana yaz):
397
402
  `ngapps://examples/mobile-scan-code`.
398
403
 
@@ -425,9 +430,9 @@ Mobil uygulama web ile **aynı sözlüğü ve aynı motoru** kullanır (plans/mo
425
430
  Motorun kendi adımları (`setter`, `condition`, `microservice`, `code`, `function`, `flow-trigger`,
426
431
  `validation`) iki platformda aynıdır. Barındırıcıya dokunan adımlar ayrı rehberdedir:
427
432
  `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.
433
+ `haptic`, `location`, `notification-permission` / `-schedule` / `-cancel`, `permission`, `open-settings`, `back`,
434
+ `ad-show` ve `scan-code`'un mobildeki davranışı, argümanları, `Steps.<adım>` sonucu; bildirim, izin, reklam ve
435
+ konum tarifleri. Bu adımlardan birini yazmadan önce onu okuyun.
431
436
 
432
437
  Sayfa ve layout `mount` akışları ilk çizimden sonra, `destroy` akışları sayfa kalkarken koşar. Yığındaki
433
438
  ve sekmedeki ekran bağlı kalır: geri dönüşte `mount` KOŞMAZ. Listeyi yeniden okumak için sayfanın
@@ -519,17 +524,30 @@ variable_create({ applicationId, pageId, variables: [
519
524
  kabuğun yükleme göstergesi) durur, aynı sayfanın iki karesi aynı çıkar. Hareketin kendisini görmek için
520
525
  `motion: 'play'` (kare çekildiği ana bağlıdır; yanıt `motionNote` taşır).
521
526
 
522
- ## Cihazda önizleme
527
+ ## Studio'da ne görünür
523
528
 
524
- Expo uygulaması (`apps/mobile-runtime`) aynı sayfayı native çizer. Derin bağlantı
525
- `zeyrek://open/{proje}/{uygulama}/{sayfa}?env=<ortam>` **token taşımaz**: cihazdaki uygulama zaten giriş
526
- yapmış olmalıdır. Canlı önizleme sayfa şeması değişikliğini (`/hubs/page-schema`) dinler; yazdığın
527
- yama cihazda yenilenir.
529
+ Mobil ekran tasarımcısındaki telefon ekranın **runtime çizimidir**: kayıtlı sayfa gerçek veri, kabuk ve akışlarla
530
+ çizilir, kaydedilmemiş değişiklik anında üstüne yansır. Ayrı bir "canlı" kip yoktur; "Canlı" yalnız
531
+ production ortamının adıdır. **Düzenle** kipinde dokunuş seçer (production'da akış koşmaz), **Dene** kipinde
532
+ uygulamadaki gibi çalışır ve development'ta gerçek veriye yazar. **Ekran durumu** çipi (Gerçek veri · Örnek veri ·
533
+ Yükleniyor · Boş · Hata · Erişim yok) hâli yalnız telefonda zorlar, şemaya yazmaz. **Kim olarak** çipi telefonu bir
534
+ uygulama kullanıcısı, rol ya da Studio kullanıcısı olarak çizer; o kimliğin göremediği bileşen taralıdır. Yeni
535
+ bağlanan liste kayda kadar örnek satırla çizilir. `page_screenshot` aynı runtime'ı kayıtlı hâliyle çeker (taslak,
536
+ örnek rozeti ve tarama karede yok). Tasarımcı şema yayınına abone değildir: MCP'nin yazdığı değişikliği açık
537
+ tasarımcı kendiliğinden göstermez, kullanıcı ekranı yeniden açar.
538
+
539
+ ## Cihazda dene
540
+
541
+ Studio'daki **Cihazda dene** penceresinin iki yolu var; tarayıcıda deneme yolu yoktur. **Telefonunda:** Zeyrek
542
+ Mobile App Store'dan ya da Google Play'den yüklenir (pencere mağaza bağlantısını verir; davet yoktur), pencerede
543
+ çıkan kod okutulur (120 sn geçerli). **Senin Mac'inde:** kullanıcı kendi Mac'ini bir kez ekler, simülatör o Mac'te
544
+ açılır; Mac'i olmayan için Zeyrek'in Mac'inde açma henüz yoktur. **Kaydettiğinde güncellenir:** yazdığın yama
545
+ telefonda ve simülatörde yenilenir. Ajan kod üretmez, önizleme başlatmaz; kullanıcıyı bu pencereye yönlendirir.
528
546
 
529
547
  ## Yayın
530
548
 
531
549
  Mağaza yayını ayrı rehberdedir: `platform_guide('mobile-publish')` — `mobile_store_*` / `mobile_asset_*` /
532
- `mobile_build_*` akışı, ekran görüntüsü, ön kontrol (P-01…P-11), derleme hata kodları ve insanın Studio › Yayın'da
550
+ `mobile_build_*` akışı, ekran görüntüsü, ön kontrol (P-01…P-22), derleme hata kodları ve insanın Studio › Yayın'da
533
551
  yaptıkları. Derlenen uygulama
534
552
  **production ortamını** okur; ilk derleme kimlik alanlarını (`bundleIdentifier`, `androidPackage`, `scheme`) kilitler.
535
553
 
@@ -544,3 +562,7 @@ yaptıkları. Derlenen uygulama
544
562
  Web'in `theme-toggle`'ı mobilde yoktur. Seçili düğme saklanan seçimi `LocalStorage`'dan okur:
545
563
  `{{ LocalStorage['zeyrek:theme-mode'] || 'light' }}` (ARC-147).
546
564
  - Dar ekran kırılımı (`hideOn: 'mobile'`) mobil uygulamada anlamsızdır: ekran zaten tek boydur.
565
+ - Ağ yokken ekranlar ve (açıksa) son okunan veri cihazdaki kopyadan gelir: `properties.mobile.offline`
566
+ (MOB-033), `Steps.<ad>.cache.at`, `error.network` — `platform_guide('page')` §Kural 1g-4. Önizleme önbellek kullanmaz.
567
+ "Uygulama ağsızken de çalışsın" isteğinin tarifi (okuma GET, yazma kuyruğu, liste birleştirme, düğme kilidi, korumasız
568
+ açılış, bant kapalı): §Kural 1g-4 "Ağsızken fark göstermeyen uygulama", örnek `ngapps://examples/mobile-offline-seamless`.