@appaflytech/zeyrek-ai-mcp 0.0.28 → 0.0.30

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 (201) hide show
  1. package/.env.example +15 -0
  2. package/README.md +5 -5
  3. package/dist/config.js +37 -0
  4. package/dist/index.js +2 -0
  5. package/dist/knowledge/access.js +802 -0
  6. package/dist/knowledge/backendConstraints.js +18 -1
  7. package/dist/knowledge/case.js +41 -0
  8. package/dist/knowledge/componentCatalog.js +494 -34
  9. package/dist/knowledge/componentEvents.js +132 -7
  10. package/dist/knowledge/connectDataBind.js +819 -0
  11. package/dist/knowledge/connectDataDefinition.js +341 -0
  12. package/dist/knowledge/connectDataExecute.js +93 -0
  13. package/dist/knowledge/connectDataRules.js +128 -0
  14. package/dist/knowledge/decision.js +121 -0
  15. package/dist/knowledge/expressionPrelude.js +59 -0
  16. package/dist/knowledge/layoutSummary.js +140 -2
  17. package/dist/knowledge/microserviceParameters.js +58 -0
  18. package/dist/knowledge/mining.js +94 -0
  19. package/dist/knowledge/mobileComponentCatalog.js +859 -0
  20. package/dist/knowledge/mobileComponentEvents.js +239 -0
  21. package/dist/knowledge/normalize.js +236 -67
  22. package/dist/knowledge/outlines.js +36 -0
  23. package/dist/knowledge/platform/lint.js +385 -0
  24. package/dist/knowledge/platform/mobile.js +142 -0
  25. package/dist/knowledge/platform/mobileLayoutLint.js +324 -0
  26. package/dist/knowledge/platform/mobileRules.js +231 -0
  27. package/dist/knowledge/platform/mobileSpacing.js +82 -0
  28. package/dist/knowledge/platform/mobileTabs.js +108 -0
  29. package/dist/knowledge/platform/nativeBoxModel.js +44 -0
  30. package/dist/knowledge/platform/profile.js +25 -0
  31. package/dist/knowledge/platform/resolve.js +122 -0
  32. package/dist/knowledge/platform/web.js +39 -0
  33. package/dist/knowledge/policy.js +18 -4
  34. package/dist/knowledge/process.js +510 -0
  35. package/dist/knowledge/reservedTables.js +79 -0
  36. package/dist/knowledge/rowFilter.js +43 -0
  37. package/dist/knowledge/rules.js +319 -21
  38. package/dist/knowledge/schemaGuard.js +11 -0
  39. package/dist/knowledge/styleResolve.js +50 -4
  40. package/dist/knowledge/styleResolveNative.js +527 -0
  41. package/dist/knowledge/themeResolve.js +3 -3
  42. package/dist/observability/trace.js +6 -3
  43. package/dist/platform/argumentAliases.js +128 -0
  44. package/dist/platform/bodyFile.js +103 -0
  45. package/dist/platform/capture/actions.js +333 -0
  46. package/dist/platform/capture/browser.js +1 -0
  47. package/dist/platform/{screenshot.js → capture/capture.js} +105 -519
  48. package/dist/platform/capture/console-log.js +122 -0
  49. package/dist/platform/capture/index.js +11 -0
  50. package/dist/platform/capture/readiness.js +103 -0
  51. package/dist/platform/capture/summary.js +77 -0
  52. package/dist/platform/capture/target.js +5 -0
  53. package/dist/platform/capture/targets/studio-mobile.js +15 -0
  54. package/dist/platform/capture/targets/studio-web.js +5 -0
  55. package/dist/platform/diagnostics.js +10 -4
  56. package/dist/platform/domSummary.js +1 -1
  57. package/dist/platform/errors.js +162 -10
  58. package/dist/platform/http.js +29 -8
  59. package/dist/platform/impersonation.js +45 -0
  60. package/dist/platform/jsonArray.js +24 -0
  61. package/dist/platform/responses.js +39 -5
  62. package/dist/platform/schemaReadMemory.js +60 -0
  63. package/dist/platform/secrets.js +17 -1
  64. package/dist/platform/strictArguments.js +68 -12
  65. package/dist/platform/tokenVault.js +187 -4
  66. package/dist/resources/examples/bpm-gorev-kontrol.json +294 -0
  67. package/dist/resources/examples/bpm-iso-dokuman.json +228 -0
  68. package/dist/resources/examples/bpm-satinalma.json +376 -0
  69. package/dist/resources/examples/connect-data-convert-verify.json +107 -0
  70. package/dist/resources/examples/connect-data-dropdown-roles.json +66 -0
  71. package/dist/resources/examples/connect-data-edit-m2m.json +73 -0
  72. package/dist/resources/examples/connect-data-query-params.json +50 -0
  73. package/dist/resources/examples/connect-data-table-entity.json +147 -0
  74. package/dist/resources/examples/connect-data-workflow-microservice.json +65 -0
  75. package/dist/resources/examples/mobile-app-shell-drawer.json +243 -0
  76. package/dist/resources/examples/mobile-app-shell-stack.json +157 -0
  77. package/dist/resources/examples/mobile-app-shell-tab.json +208 -0
  78. package/dist/resources/examples/mobile-form-screen.json +365 -0
  79. package/dist/resources/examples/mobile-list-detail-form.json +672 -0
  80. package/dist/resources/examples/page-detail-profile.json +2 -1
  81. package/dist/resources/examples/page-dynamic-form.json +3 -2
  82. package/dist/resources/examples/page-flex-sections.json +1 -1
  83. package/dist/resources/examples/page-html-embed.json +1 -1
  84. package/dist/resources/examples/workflow-basic.json +8 -2
  85. package/dist/resources/guides/access.md +796 -0
  86. package/dist/resources/guides/bpm.md +686 -0
  87. package/dist/resources/guides/case.md +153 -0
  88. package/dist/resources/guides/component.md +91 -4
  89. package/dist/resources/guides/decision.md +185 -0
  90. package/dist/resources/guides/entity.md +50 -8
  91. package/dist/resources/guides/expressions.md +14 -5
  92. package/dist/resources/guides/functions.md +1 -1
  93. package/dist/resources/guides/getting-started.md +38 -1
  94. package/dist/resources/guides/layout.md +11 -7
  95. package/dist/resources/guides/microservice.md +81 -2
  96. package/dist/resources/guides/middleware.md +44 -2
  97. package/dist/resources/guides/mobile-layout.md +193 -0
  98. package/dist/resources/guides/mobile.md +495 -0
  99. package/dist/resources/guides/page.md +454 -75
  100. package/dist/resources/guides/theme.md +8 -2
  101. package/dist/resources/guides/translation.md +1 -1
  102. package/dist/resources/guides/workflow.md +58 -1
  103. package/dist/resources/read.js +41 -0
  104. package/dist/resources/rules.js +11 -5
  105. package/dist/resources/schema-fingerprint.json +7 -5
  106. package/dist/resources/schemas/AccessExplanationDto.json +144 -0
  107. package/dist/resources/schemas/AccessMatrixDto.json +170 -0
  108. package/dist/resources/schemas/AccessPermissionDto.json +57 -0
  109. package/dist/resources/schemas/AccessPolicyDto.json +223 -0
  110. package/dist/resources/schemas/AccessResourceDto.json +86 -0
  111. package/dist/resources/schemas/AppSessionDto.json +53 -0
  112. package/dist/resources/schemas/ConnectDataDescribeDto.json +344 -0
  113. package/dist/resources/schemas/ConnectDataRequestModel.json +202 -0
  114. package/dist/resources/schemas/ConnectDataResultDto.json +421 -0
  115. package/dist/resources/schemas/ConnectorCredentialDto.json +70 -0
  116. package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +37 -0
  117. package/dist/resources/schemas/CreateAccessPolicyCommand.json +209 -0
  118. package/dist/resources/schemas/CreateDecisionCommand.json +221 -0
  119. package/dist/resources/schemas/CreateEntityCommand.json +118 -0
  120. package/dist/resources/schemas/CreateMicroserviceCommand.json +13 -1
  121. package/dist/resources/schemas/CreateProcessDefinitionCommand.json +1337 -0
  122. package/dist/resources/schemas/CreateQueryCommand.json +4 -0
  123. package/dist/resources/schemas/CreateWorkflowCommand.json +143 -1
  124. package/dist/resources/schemas/DataJobDto.json +6 -1
  125. package/dist/resources/schemas/DecisionDto.json +302 -0
  126. package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +28 -0
  127. package/dist/resources/schemas/ExplainAccessQuery.json +33 -0
  128. package/dist/resources/schemas/GenerateProcessDocumentCommand.json +116 -0
  129. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +21 -1
  130. package/dist/resources/schemas/MicroserviceDto.json +15 -3
  131. package/dist/resources/schemas/OrganizationProjectDto.json +335 -0
  132. package/dist/resources/schemas/OrganizationSchemaDto.json +196 -0
  133. package/dist/resources/schemas/OrganizationSchemaVersionDto.json +207 -0
  134. package/dist/resources/schemas/PatchProcessDefinitionCommand.json +76 -0
  135. package/dist/resources/schemas/PreviewMicroserviceCommand.json +10 -1
  136. package/dist/resources/schemas/PreviewWorkflowCommand.json +22 -1
  137. package/dist/resources/schemas/ProcessDefinitionDto.json +1480 -0
  138. package/dist/resources/schemas/ProcessSimulationDto.json +96 -0
  139. package/dist/resources/schemas/SaveConnectorCredentialCommand.json +90 -0
  140. package/dist/resources/schemas/SaveProcessEventSourceCommand.json +61 -0
  141. package/dist/resources/schemas/SaveProcessMailSourceCommand.json +89 -0
  142. package/dist/resources/schemas/SignProcessTaskCommand.json +73 -0
  143. package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +92 -0
  144. package/dist/resources/schemas/StepDto.json +22 -1
  145. package/dist/resources/schemas/UpdateAccessPolicyCommand.json +209 -0
  146. package/dist/resources/schemas/UpdateDecisionCommand.json +216 -0
  147. package/dist/resources/schemas/UpdateEntityCommand.json +118 -0
  148. package/dist/resources/schemas/UpdateMicroserviceCommand.json +13 -1
  149. package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +1357 -0
  150. package/dist/resources/schemas/UpdateQueryCommand.json +4 -0
  151. package/dist/resources/schemas/UpdateViewCommand.json +0 -2
  152. package/dist/resources/schemas/UpdateWorkflowCommand.json +143 -1
  153. package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +1339 -0
  154. package/dist/server.js +27 -1
  155. package/dist/tools/access.js +369 -2
  156. package/dist/tools/accessOperations.js +135 -0
  157. package/dist/tools/accessPolicies.js +170 -0
  158. package/dist/tools/accessRuntime.js +203 -0
  159. package/dist/tools/applications.js +60 -3
  160. package/dist/tools/bpm.js +343 -0
  161. package/dist/tools/bpmGovernance.js +266 -0
  162. package/dist/tools/bpmOperations.js +230 -0
  163. package/dist/tools/bpmReporting.js +154 -0
  164. package/dist/tools/bpmRouting.js +150 -0
  165. package/dist/tools/bpmRuntime.js +396 -0
  166. package/dist/tools/case.js +178 -0
  167. package/dist/tools/caseRuntime.js +89 -0
  168. package/dist/tools/common.js +7 -0
  169. package/dist/tools/components.js +118 -14
  170. package/dist/tools/connectData.js +449 -0
  171. package/dist/tools/connectors.js +193 -0
  172. package/dist/tools/datasources.js +3 -3
  173. package/dist/tools/decisions.js +206 -0
  174. package/dist/tools/dependencies.js +1 -1
  175. package/dist/tools/deployments.js +2 -2
  176. package/dist/tools/designSchemaPatch.js +34 -9
  177. package/dist/tools/dtos.js +36 -5
  178. package/dist/tools/entities.js +79 -12
  179. package/dist/tools/externalComponents.js +26 -5
  180. package/dist/tools/flows.js +122 -14
  181. package/dist/tools/folders.js +1 -1
  182. package/dist/tools/imports.js +5 -2
  183. package/dist/tools/layouts.js +50 -17
  184. package/dist/tools/merges.js +1 -1
  185. package/dist/tools/microservices.js +77 -25
  186. package/dist/tools/mobile.js +221 -0
  187. package/dist/tools/modules.js +48 -0
  188. package/dist/tools/organizationStructure.js +137 -0
  189. package/dist/tools/pages.js +465 -98
  190. package/dist/tools/platformInfo.js +27 -8
  191. package/dist/tools/profileWrite.js +92 -0
  192. package/dist/tools/projects.js +71 -9
  193. package/dist/tools/rows.js +69 -13
  194. package/dist/tools/schemaOps.js +61 -1
  195. package/dist/tools/screenWrite.js +37 -8
  196. package/dist/tools/screens.js +95 -5
  197. package/dist/tools/templates.js +26 -1
  198. package/dist/tools/translations.js +1 -1
  199. package/dist/tools/variables.js +11 -5
  200. package/dist/tools/workflows.js +10 -5
  201. package/package.json +2 -2
@@ -0,0 +1,153 @@
1
+ # Vaka Rehberi — CMMN 1.1 vaka yönetimi
2
+
3
+ Adımları önceden bilinmeyen işler içindir: müşteri şikâyeti, soruşturma, hasar dosyası, uygunsuzluk incelemesi. Süreç tanımı
4
+ (`process_definition_*`) sırayı çizer; **vaka** ise aşamaları, isteğe bağlı görevleri ve "şu olunca şu açılır" koşullarını
5
+ (sentry) tanımlar, sırayı olaylar ve kişiler belirler. İnsan görevleri süreç görevleriyle **aynı kutuya** düşer
6
+ (`kind: case-task`) ve `process_task_update` ile tamamlanır. Süreçten vaka `case` düğümüyle başlatılır (§Süreçten vaka).
7
+
8
+ Modüller: `case` (tanım: `case_definition_*`, `case_cmmn_*`) ve `caseRuntime` (`case_execute`, `case_instance_*`).
9
+
10
+ ## Başlangıç
11
+
12
+ 1. **Modeli yazın** — `case_definition_create { case }`. Taslak sürüm oluşur. Gateway yazmadan önce CASE-001'i denetler
13
+ (§Lint); `case_definition_preview { case }` aynı denetimi istek göndermeden yapar.
14
+ 2. **Yayınlayın** — `case_definition_publish { id }`. Çalışan vakalar başladıkları sürümde kalır; production'a yayın yok (BPM-001).
15
+ 3. **Başlatın** — `case_execute { slug, subjectRowId, caseFile, asUser }`. Yanıt `planItems[]` ve `availableActions[]` taşır.
16
+ 4. **Yürütün** — `case_instance_get` → `availableActions` → `case_instance_update { operation, planItemId }`; insan görevleri
17
+ `process_task_list` / `process_task_update`.
18
+
19
+ Düzeltmede tam modeli yeniden göndermeyin: `case_definition_get` → `case_definition_patch` (`/planItems[id=<öğe>]/…`).
20
+ Başka modelleyiciden gelen CMMN için `case_cmmn_update { filePath }`; dışa aktarma `case_cmmn_get { outPath }`.
21
+
22
+ ## Model
23
+
24
+ ```jsonc
25
+ {
26
+ "slug": "musteri-sikayeti", "name": { "tr": "Müşteri şikâyeti" }, "description": { "tr": "Şikâyeti inceler ve kapatır." },
27
+ "caseFile": [{ "id": "musteriCevabi" }, { "id": "oncelik", "default": "normal" }],
28
+ "planItems": [
29
+ { "id": "inceleme", "type": "stage", "required": true, "autoComplete": true },
30
+ { "id": "sikayeti-incele", "type": "human-task", "parent": "inceleme", "required": true, "assignee": { "rule": "user", "arg": "<kullanıcı id>" } },
31
+ { "id": "hukuk-gorusu", "type": "human-task", "parent": "inceleme", "discretionary": true, "assignee": { "rule": "role", "arg": "hukuk" } },
32
+ { "id": "yanit-alindi", "type": "milestone", "entry": ["musteri-cevapladi"] },
33
+ { "id": "kapanis", "type": "stage", "required": true, "manualActivation": true, "autoComplete": true, "entry": ["musteri-cevapladi"] }
34
+ ],
35
+ "sentries": [
36
+ { "id": "musteri-cevapladi",
37
+ "onParts": [{ "source": "inceleme", "event": "complete" }, { "source": "musteriCevabi", "event": "update" }],
38
+ "ifPart": "caseFile.musteriCevabi != 'yok'" }
39
+ ]
40
+ }
41
+ ```
42
+
43
+ | Alan | Kural (backend `CaseValidator`, hata 422 `CaseInvalid` + bulgu yolu `/planItems[id=x]/alan`) |
44
+ |---|---|
45
+ | `slug`, plan öğesi ve sentry `id` | kebab-case, benzersiz; ilk yayından sonra slug değişmez (400) |
46
+ | `caseFile[].id` | harf, rakam, alt çizgi; `default` herhangi bir JSON |
47
+ | `planItems[].type` | `stage` · `human-task` · `milestone` |
48
+ | `parent` | yalnız bir `stage`; döngü yasak. `parent` yoksa öğe vaka planının köküdür |
49
+ | `required` | aşama tamamlanmadan önce bitmesi gereken öğe; `disable` edilemez |
50
+ | `repeatable` | tamamlanınca yeni `occurrence` açılır; giriş sentry'si ister, kilometre taşında olmaz |
51
+ | `manualActivation` | koşul sağlanınca `enabled` olur, biri `start` edene kadar bekler |
52
+ | `discretionary` | tanımda durur, kişi `add-discretionary` ile ekleyene kadar oluşmaz |
53
+ | `autoComplete` | yalnız `stage`: etkin çocuk kalmayınca ve zorunlular bitince kendiliğinden kapanır |
54
+ | `assignee` | `human-task` için zorunlu: `user` (`arg` kullanıcı id), `role` (`arg` rol slug'ı, aday kaydı), `initiator` |
55
+ | `entry` / `exit` | sentry kimlikleri; girişlerden biri yeter, çıkış öğeyi ve alt ağacını `terminated` yapar |
56
+ | `onParts[].event` | kaynak kilometre taşıysa yalnız `occur`; başka plan öğesiyse `complete` · `start` · `terminate`; vaka dosyası öğesiyse `update` |
57
+ | `ifPart` | Jint; `caseFile.x` (ya da `vars.x`) vaka dosyasını, `initiator` başlatanı okur |
58
+
59
+ Süreç tanımındaki `assignee` sözlüğü (`unit-manager of …`, `position:`) vakada **yoktur**; yalnız üç kural.
60
+
61
+ ## Yaşam döngüsü
62
+
63
+ Plan öğesi: `available → enabled → active → completed | terminated | disabled`. Vaka: `active → completed | terminated`.
64
+
65
+ Her değişiklikten sonra platform yerleşimi sabitlenene kadar yeniden çalıştırır: çıkış sentry'si sağlanan öğe `terminated`;
66
+ ebeveyni etkin ve giriş koşulu sağlanan öğe `manualActivation` ise `enabled`, değilse etkin olur (insan görevi görev açar,
67
+ kilometre taşı doğrudan `completed`); kökteki her şey bitince vaka `completed`.
68
+
69
+ Aşama kapanışı **turun sonunda ve yalnız o turda başka hiçbir öğe hareket etmediyse** denenir — bir çocuk daha açılabiliyorken
70
+ aşama kapatılmaz. `autoComplete` aşama etkin çocuğu yokken ve zorunlu çocukları bitmişken kapanır, bekleyen çocuklarını
71
+ `terminated` eder. `autoComplete` **olmayan** aşama da kendiliğinden kapanır ama **bütün** çocukları terminal olmalıdır;
72
+ bekleyen çocuğu varken bekler ve onları terminale çekmez. Çocuğu olmayan aşama yalnız `autoComplete` ise kendiliğinden kapanır,
73
+ değilse elle `complete` bekler (elle `complete` her zaman gevşek koşulu kullanır: etkin çocuk yok + zorunlular bitmiş).
74
+
75
+ Sentry **durum tabanlıdır**: `onPart` kaynağın şu anki durumuna bakar (`complete`/`occur` → tamamlanmış, `start` → etkin ya da
76
+ tamamlanmış, `update` → vaka dosyası öğesi dolu) ve `ifPart` her turda yeniden çalışır. Bu yüzden vaka dosyasını değiştirmek
77
+ (`update-case-file`) bekleyen öğeyi açabilir.
78
+
79
+ ## Eylemler
80
+
81
+ `case_instance_get` yanıtındaki `availableActions[] { action, itemId, planItemId }` o an yapılabilecekleri listeler:
82
+
83
+ | `case_instance_update { operation }` | Ne yapar | Hata |
84
+ |---|---|---|
85
+ | `start` (`planItemId`) | `enabled` öğeyi başlatır | yanlış durum 409 `InstanceStateTransitionNotAllowed` |
86
+ | `complete` (`planItemId`) | etkin aşamayı kapatır (etkin çocuk yok, zorunlular bitmiş); insan görevi görev ucundan kapanır | 409 |
87
+ | `disable` (`planItemId`) | zorunlu olmayan `enabled` öğeyi devre dışı bırakır | 409 |
88
+ | `enable` (`planItemId`) | `available` öğeyi elle açar; giriş sentry'si **varsa** biri sağlanmalı (sentry'si olmayan öğe koşulsuz açılır) | sentry sağlanmıyorsa **422 `CaseSentryNotSatisfied`**, `available` değilse 409 |
89
+ | `add-discretionary` (`itemDefinitionId`) | isteğe bağlı öğeyi ebeveyn aşaması etkinken ekler | aynı öğenin bitmemiş örneği varsa 409 |
90
+ | `update-case-file` (`itemId`, `value`) | vaka dosyasına yazar, yerleşimi yeniden çalıştırır | tanımsız öğe 400 |
91
+
92
+ `enable` `availableActions`'ta **listelenmez**: yerleşim, giriş sentry'si sağlanan ya da hiç sentry'si olmayan öğeyi zaten açar,
93
+ dolayısıyla listede kalan `available` öğe sentry'sini bekliyordur ve ona `enable` 422 döner. Bu bir lint değil çalışma zamanı
94
+ kuralıdır — koşulu sağlamak için vaka dosyasını güncelleyin ya da kaynak öğeyi bitirin. Kapanmış vakada her değişiklik 409.
95
+
96
+ ## Görevler
97
+
98
+ `human-task` etkinleşince `ProcessTask` açılır: `kind: case-task`, `instanceId` = vaka kimliği, `nodeId` = plan öğesi `id`,
99
+ `definitionSlug` = vaka slug'ı. `user` ve `initiator` doğrudan atanır; `role` aday kaydı açar ve görev `claim` ister. Tamamlama
100
+ `process_task_update { action: complete, payload, asUser }` — plan öğesi `completed` olur, yük vaka defterine yazılır. Vaka
101
+ görevi süreç defterine yazmaz; görev yardımcısı (`process_task_get { view: 'assistant' }`) çalışır ama `ai-suggestion` satırı
102
+ yalnız öneri tablosuna düşer.
103
+
104
+ Görünürlük: vakayı başlatan, görevi atanan ya da tamamlayan kişi `case_instance_get` ile okur; liste (`case_instance_list`)
105
+ ve başkalarının vakaları `process.view-all` ister. Başlatma `process.start`, tanım yazımı `process.manage` ister.
106
+
107
+ ## Süreçten vaka
108
+
109
+ Süreç tanımında `case` düğümü yayındaki vakayı başlatır ve **beklemez** (akış devam eder):
110
+
111
+ ```jsonc
112
+ { "id": "sikayet-ac", "type": "case", "description": "Şikâyet vakasını açar.", "caseSlug": "musteri-sikayeti",
113
+ "input": { "musteriCevabi": "'yok'" }, "output": "vars.sikayetVakasi" }
114
+ ```
115
+
116
+ Başlatan süreç örneğinin başlatanı, iş satırı süreç konusudur; `output` yoluna vaka kimliği yazılır, süreç defterine
117
+ `case-started`. Bilinmeyen ya da yayınlanmamış slug tanım doğrulamasında `CaseUnknown`, çalışma anında düğüm hatası.
118
+
119
+ ## CMMN XML
120
+
121
+ `case_cmmn_get` CMMN 1.1 XML üretir (`zeyrek:` uzantısı atamayı, çok dilli ad/açıklamayı, varsayılanı ve sırayı taşır);
122
+ `case_cmmn_update { xml | filePath }` içe aktarır: aynı slug varsa taslağına yazar, yoksa yeni tanım açar. `stage`, `humanTask`,
123
+ `milestone` dışındaki öğeler (`processTask`, `caseTask`, olay dinleyicileri) ve DTD içeren XML 400'dür. Başka araçta
124
+ çizilmiş vakanın atamaları uzantı taşımıyorsa içe aktarma sonrası `case_definition_patch` ile ekleyin.
125
+
126
+ ## Lint
127
+
128
+ | Kural | Ne zaman | Önem |
129
+ |---|---|---|
130
+ | CASE-001 | `onParts[].source` bir plan öğesi ya da vaka dosyası öğesi değil; `entry`/`exit` tanımsız sentry'ye bakıyor | block |
131
+
132
+ Denetim `case_definition_create`, `case_definition_update`, `case_definition_patch`, `case_definition_publish` öncesinde ve
133
+ `case_definition_preview`'da çalışır. Diğer model kuralları backend'dedir (422 `CaseInvalid` bulgu listesi).
134
+
135
+ ## Hata sözlüğü
136
+
137
+ | Kod | Anlamı | Ne yapılır |
138
+ |---|---|---|
139
+ | `CaseInvalid` (422) | Model kuralı ihlali; `errors[]` yol ve mesaj taşır | yolu `case_definition_patch` ile düzeltin |
140
+ | `CaseSentryNotSatisfied` (422) | `enable` edilen öğenin giriş koşulu sağlanmıyor | kaynak öğeyi bitirin ya da `update-case-file` |
141
+ | `InstanceStateTransitionNotAllowed` (409) | öğe ya da vaka bu eyleme uygun durumda değil | `case_instance_get` ile `availableActions`'a bakın |
142
+ | `CaseUnknown` (422) | süreçteki `case` düğümü yayında olmayan vakaya bakıyor | vakayı yayınlayın |
143
+ | `ReferencedByProcess` (422) | silinen vaka tanımına bir süreç `case` düğümüyle başvuruyor | önce süreci güncelleyin |
144
+ | `InvalidOperation` (400) | vakası olan tanım silinemez | tanımı yerinde bırakın |
145
+
146
+ ## Sık tuzaklar
147
+
148
+ - **Sırayı vaka ile çizmek.** Adımlar belliyse süreç tanımı kullanın; vaka bekleme ve dallanmayı sentry'ye çevirir, okunması zorlaşır.
149
+ - **`enable`'ı düzeltme sanmak.** 422 aldıysanız koşul sağlanmamıştır; tekrar denemek değil koşulu sağlamak gerekir.
150
+ - **`repeatable` öğeyi giriş sentry'siz yazmak.** Model reddedilir; tekrar tetikleyicisiz sonsuz döngü olurdu.
151
+ - **Vaka görevini `case_instance_update { complete }` ile kapatmaya çalışmak.** `complete` yalnız aşama içindir; görev
152
+ `process_task_update` ile kapanır.
153
+ - **`caseFile` öğesini tanımlamadan `ifPart`'ta kullanmak.** Tanımsız değer `undefined` okunur; öğeyi `caseFile[]`'a ekleyin.
@@ -3,6 +3,11 @@
3
3
  Sayfaya konan her şeyin ortak kuralları. Kuruluş sırası ve şema gövdesi için
4
4
  `platform_guide('page')`; HTML kaçış kapısının derin sözleşmesi için `platform_guide('html')`.
5
5
 
6
+ > **Mobil uygulamada** katalog ayrıdır: `component_list`/`component_get` mobil satırları okur,
7
+ > `component_get` `mobileKnowledge` (bileşenin mobil farkları) ve `mobileNotes` ekler; katalogda
8
+ > olmayan tip `MOB-003` alır. Stil CSS değil React Native'dir — `page_runtime_get(resolveStyles)`
9
+ > `nativeStyle` döner (`platform_guide('mobile')`).
10
+
6
11
  ## Keşif: iki tool, üç bilgi katmanı
7
12
 
8
13
  ```
@@ -23,7 +28,9 @@ component_get → tek tipin TAM sözleşmesi, üç katman birleşik:
23
28
  - **`isHidden`** her komponenti gizler; setter ile yazmak katalogda listelenmeyen tiplerde de
24
29
  çalışır. Gizli komponent `mount` olayını görünür olana dek TETİKLEMEZ.
25
30
  - **`mount`** olayını komponentin kendisi değil ortak katman yayar: komponent ilk kez
26
- görünür olduğunda bir kez. Sayfa açılış akışı `page_container.mount`'a bağlanır.
31
+ görünür olduğunda bir kez. Sayfa açılış akışı `page_container.mount`'a DEĞİL, sayfanın kendi
32
+ `mount` olayına bağlanır (`page_update { events }`, `platform_guide('page')` Kural 1d-2) —
33
+ `page_container` Studio'nun Layers ağacında görünmez.
27
34
  - **`name` = `elementId`** kuralı: runtime her komponent için `const <name> = Components[...]`
28
35
  üretir; bozuk ad sayfadaki BÜTÜN ifadeleri öldürür (`platform_guide('page')` Kural 1c-2).
29
36
  - **Boyut:** `blocks[].size` katalogdaki `maxSize`'ı aşamaz; yükseklikte
@@ -74,6 +81,51 @@ Doğrulama mesajını çeviriye bağlamak ayrı bir sözleşmedir (`t:` öneki,
74
81
  İstisna: `html` komponentinin
75
82
  aksiyonları kendi `flow` prop'uyla bağlanır (`platform_guide('html')`).
76
83
 
84
+ ## Korumalı değer ve arayüz yetkisi (kompleks proje)
85
+
86
+ Kompleks projede ortamın zorlama modu `enforce` iken runtime iki şey taşır; ikisi de **yalnız
87
+ arayüzdür**, yetkiyi backend her istekte yeniden denetler.
88
+
89
+ - **Satır metası.** Table-source uçtan dönen satırda korumalı alan varsa
90
+ `__protected: { <alanSlug>: 'masked' | 'plain' }` bulunur; `hidden` alan satırda hiç yoktur.
91
+ `table` · `datatable` · `detailview` · `text` (`record` + `recordField` ile) `masked` alanı
92
+ kilitli maske olarak çizer; "Göster" → gerekçe → değer 30 sn görünür, sonra yeniden maskelenir.
93
+ "Göster" yalnız erişim özeti yüklüyken çıkar: `off`'ta (basit proje hep `off`) hiç çıkmaz —
94
+ backend her reveal'i reddeder; `shadow`'da çıkar — backend reveal'i yine denetler, yetkisiz
95
+ kullanıcı ret mesajını görür; `enforce`'ta yalnız entity'nin `actions`'ında `reveal` varsa.
96
+ Değeri boş maskeli hücrede "Göster" çıkmaz. Tasarımcı kanvasında (**View as user**) düğme seçilen
97
+ kullanıcıya sunulacağı yerde etkisiz çizilir (kullanıcı seçili değilken tasarımcının
98
+ `project.data.reveal` izni karar verir); gerçek açma önizlemededir.
99
+ Açılan değer prop'a, akışa, olaya yazılmaz. Entity `revealEntity` prop'undan (slug ya da id) ya
100
+ da boşsa erişim özetinden çözülür (`component_get` → `knowledge.propNotes.revealEntity`).
101
+ - **Maske forma bağlanmaz.** Güncelleme formunda korumalı alanın `textinput`'u her zamanki gibi
102
+ `value` ile kaydın alanına bağlanır, yanına `isMasked` eklenir:
103
+ `{{ Steps.<adım>.data.__protected?.tckn === 'masked' }}`. `isMasked` açıkken bağlı değer maske
104
+ metni sayılır ve gösterilmez: alan boş başlar, "Değiştirmek için yeni değer girin" yer tutucusunu
105
+ gösterir, mount sonrası düğüm değerini `null`'a çeker ve `required`'a takılmaz. Kullanıcı yazınca
106
+ sıradan girdidir; değer girdinin yazmadığı bir değere dönerse (forma başka satır seçildi, akış
107
+ alanı sıfırladı) yeni kaydın maskesi yine gizlenir ve temizlenir.
108
+ - **Izgarada kör üzerine yazma (ADR 0007).** Bağlı `datatable`'da `capability.canWrite` politikadan gelir;
109
+ maskeli okumak yazmayı kapatmaz. Maskeli hücre düzenlemeye **boş** açılır, yazılan değer gider, boş bırakılan
110
+ maske gitmez; hücre seçimine girmez, toplu düzenleme maskeli kolonu sunmaz. Korumalı alanı güncellemek için
111
+ form kurmak zorunlu değildir. Eski değeri görerek düzeltmek gerekiyorsa önce "Göster" (30 sn, editöre ön
112
+ doldurulmaz). Bağlı olmayan tabloda ve `table` bileşeninde maskeli hücre düzenlenmez.
113
+ - **Boş değerin gönderilmemesi isteğin kuruluşuna bağlıdır.** Microservice çağrısının parametre
114
+ bağı boş (`null`/`''`) değeri gövdeye koymaz → saklı değer korunur. Gövdeyi akış kodunda ya da
115
+ setter göreviyle elle kuruyorsan (`{ tckn: TextInput1.value }`) `null` gider: `canWrite` yoksa
116
+ 403 `AccessFieldWriteDeniedException`, varsa saklı değer **silinir**. Boş maskeli alanı böyle bir
117
+ gövdeye koyma.
118
+ - **`Page.can(permission, resourceKey)`** her ifadede (görünürlük bağı, akış kodu) kullanılır:
119
+ `Page.can('reveal', 'entity:musteriler')` · `Page.can('entity.update', 'entity:<id>')` ·
120
+ `Page.can('view', 'page:musteri/detay')` · `Page.can('execute', 'microservice:musteri-listesi')`.
121
+ İzin kısa eylem adı ya da katalog slug'ıdır; anahtar `entity:<slug|id>` · `page:<slug>` ·
122
+ `microservice:<slug>`. `enforce` dışında (ya da özet yüklenmemişken) HER ZAMAN `true`; okunamayan
123
+ anahtar ya da başka kaynak tipinin izni `enforce`'ta `false`.
124
+ - **Oturum.** `/view` runtime isteklerinde oturum çerezi gider, durum değiştiren isteğe `X-ZY-CSRF`
125
+ eklenir; oturum 401'i bir kez yenilenir (`auth/refresh`) ve istek tekrarlanır. Yenilenemezse
126
+ uygulamanın giriş sayfasına gidilir — sayfa yükü bugün giriş sayfasını taşımadığı için yönlendirme
127
+ backend bunu gönderene dek olmaz (teknik borç). Özetin listelemediği sayfa ana sayfaya döner.
128
+
77
129
  ## Stil
78
130
 
79
131
  Her komponentin `style` prop'u vardır ve iç parçalara iner (`textinput.style`: `&__label` ·
@@ -88,7 +140,10 @@ Widget, kendi komponent ağacını taşıyan yeniden kullanılabilir pakettir (`
88
140
 
89
141
  1. **Kayıt:** `component_create` — `kind:'widget'`, `widgetType`, `schema` (widget'ın kendi
90
142
  ağacı; `name = elementId` kuralı burada da geçerli — layout gibi widget adları da kullanan
91
- sayfaya sızar).
143
+ sayfaya sızar). Ağacın KÖKÜ tiplidir: `container` → `widget-area`, `modal`/`drawer` → kendi
144
+ tipi (+ düğümde `widgetType`). Runtime widget'ı yalnız bu kökten çizer; düz `container` kökle
145
+ kayıt 200 döner ama boş çizilir. Kök vermezsen gateway düğümlerini Studio'nun kurduğu köke
146
+ sarar ve `gatewayNormalized`'da CMP-002 ile bildirir (`component_update` şemada da aynı).
92
147
  2. **Sayfaya koyma:** `add_component` düğümünde `kind:'widget'` ve **`type` = widget KAYDININ
93
148
  ID'si** — slug DEĞİL (runtime widget'ı `widget.id === node.type` ile çözer; slug yazarsan
94
149
  kayıt 200 döner, render sessizce boş kalır — gateway **PAGE-012/LAY-005** ile reddeder).
@@ -102,15 +157,30 @@ Widget, kendi komponent ağacını taşıyan yeniden kullanılabilir pakettir (`
102
157
  micro-op'ları `PATCH /components/{app}/{id}/schema`'ya yazar; `component_update` ise slug alan
103
158
  tam gövde PUT'tur. Widget'ın düzey olayı yoktur, `remove_event` yalnız komponent hedefler.
104
159
 
160
+ ## Satır başına çizilen çocuklar ve `item`
161
+
162
+ İki komponent çocuklarını VERİ SATIRI başına çizer; çocukların kod bağlamalarında o satır `item`'dır
163
+ (`{{ item.title }}`):
164
+
165
+ | Host | Hangi çocuklar | `item` |
166
+ |---|---|---|
167
+ | `repeater` | Bütün çocukları, `rows`'un her satırında | Satır; `item.x = …` satıra geri YAZAR |
168
+ | `datatable` | Yalnız `datatable-cell` çocukları: her biri `column` prop'undaki kolonun hücresine, her satırda | Satır; SALT OKUNUR |
169
+
170
+ `datatable`'ın kendisi `isDroppable` DEĞİLDİR: çocuğu yalnız `datatable-cell` olabilir
171
+ (`props.column = <columns[].name>`), asıl içerik onun içine konur. Şablonu olan kolonda kolonun
172
+ `type`/format ayarı çizilmez; sıralama, filtre ve dışa aktarma ham değerle çalışır. Hangi türün host
173
+ olduğu tek kayıttadır: `zeyrek-frontend/packages/ng-apps-ui/src/shared/render/row-scope.ts`.
174
+
105
175
  ## `states` ve `appearance` sözlükleri
106
176
 
107
177
  Her şema düğümünde iki sözlük vardır; ikisi de ortak render katmanında çözülür:
108
178
 
109
179
  | `states` | Anlamı |
110
180
  |---|---|
111
- | `isDroppable` | İçine komponent alır (container/form/repeater true) |
181
+ | `isDroppable` | İçine komponent alır (container/form/repeater true). **Değer kataloğun kararıdır** (`component_list` `droppable` sütunu): Studio kanvası bırakma hedefini bu alandan çözer, bu yüzden gateway yazdığı düğümlerde alanı katalogdan doldurur ve `gatewayNormalized` ile bildirir (PAGE-040). `false` yazılmış bir kabın içine kanvasta bırakma yapılamaz — bilerek kapatmak için `resize_component`/`set_states` |
112
182
  | `isScrollable` | İçeriği kendi alanında kaydırır (sabit yükseklikte `overflow-y: auto`) |
113
- | `isWrapper` | Sayfanın/layout'un/widget'ın ANA kabı — salt düzen elemanı: `height:100%` + **`min-height:80vh`**, kap başlığı ÇİZİLMEZ. **Yalnız sayfa boyu kaplaması gereken tek kap için kullan:** iç içe kutuya verirsen 720px'lik pencerede o kutu 36px içerikle bile 576px çizilir (ölçüldü, `platform_guide('page')` Kural 1f). Çerçeve/başlık gizlemek için wrapper değil `style` (`border:'none'`) kullan. Kurulmuş bir düğümün bayrağını `resize_component` micro-op'unun `states` alanı değiştirir — düğümü yeniden kurmak gerekmez |
183
+ | `isWrapper` | Sayfanın/layout'un/widget'ın ANA kabı — salt düzen elemanı: `height:100%` + **`min-height:80vh`**, kap başlığı ÇİZİLMEZ. **Yalnız sayfa boyu kaplaması gereken tek kap için kullan:** iç içe kutuya verirsen 720px'lik pencerede o kutu 36px içerikle bile 576px çizilir (ölçüldü, `platform_guide('page')` Kural 1f). Çerçeve/başlık gizlemek için wrapper kullanma: çerçevesiz kutu `box`'tır; `container`'da çerçeve `surfaceStyle`'ın dört `border*` yönüne `'none'` yazılarak kapatılır (`platform_guide('page')` §Kap seçimi). Kurulmuş bir düğümün bayrağını `resize_component` micro-op'unun `states` alanı değiştirir — düğümü yeniden kurmak gerekmez |
114
184
  | `isSticky` | Kaydırmada yerinde kalır (header/sidebar; z-index'i otomatik) |
115
185
  | `isFloating` | Düğümü akıştan çıkarıp yüzdürür (katman davranışı; nadir) |
116
186
  | `isQuickStack` | Studio'nun Quick Stack iskelet hücresi işareti — editörde kesikli çerçeve çizer, **runtime'da hiçbir etkisi yoktur**. MCP'den iskelet kurarken yazmak serbesttir ama gerekmez |
@@ -189,6 +259,23 @@ ve `layout` grubundaki adlar giremez. **MCP tarafında karşılığı yoktur:**
189
259
  bir prop'tur, `set_prop` ile aynı şekilde yazılır. Bu bilgi yalnız "studio'da neden o
190
260
  düğmeler var" sorusuna cevaptır.
191
261
 
262
+ ## Bağlanabilir prop'lar (`connectData`)
263
+
264
+ `component_get` yanıtındaki `connectData` bileşenin hangi prop'unun veri kaynağına bağlanabileceğini
265
+ söyler; alan yoksa bileşen bağlanamaz (`connectDataNote`). Kaynak platform kataloğudur.
266
+
267
+ | Alan | Anlamı |
268
+ |---|---|
269
+ | `primary` | Birincil bağlanabilir prop (`rows`, `options`); Studio "Veriye bağla" düğmesi bunu açar |
270
+ | `trigger` | "Veriye bağla" düğmesinin yeri: `toolbar` (bileşen araç çubuğu) · `canvas` (kanvastaki bileşenin üstü) |
271
+ | `props.<yol>.roles` | Rol → tür (`any` · `string` · `number` · `boolean` · `date` · `parent`); dropdown `{ label, value }`, grafik `{ category, value }` |
272
+ | `props.<yol>.required` | Doldurulmadan bağlanamayan roller |
273
+ | `props.<yol>.fields` | Rol → bileşenin alan ADI prop'u (grafik `category → categoryField`, kanban `title → titleField`); bağlama o prop'lara seçilen alanın slug'ını yazar. Kaydında `fields` olmayan bileşen (dropdown) satırı rol adlarıyla okur |
274
+ | `props.<yol>.fieldsFrom` | Satırların alanlarını tanımlayan liste prop'u (`datatable.rows → columns`); rol yerine kolon listesi üretilir |
275
+
276
+ Yol joker olabilir: `series[].data` kaydı `series.1.data` prop'unu kapsar. Bağlamanın kendisi, tanım
277
+ şekli ve kurallar: `platform_guide('page')` §Kural 1c-3.
278
+
192
279
  ## Komponent seçimi
193
280
 
194
281
  "Hangi işe hangi komponent" tablosu ve `table` / `datatable` karşılaştırması:
@@ -0,0 +1,185 @@
1
+ # Karar Rehberi — DMN karar tabloları
2
+
3
+ Eşik, seviye, oran, uygunluk gibi **kuralları süreç tanımından ayırır**: iş birimi tabloyu değiştirir, süreç
4
+ yeniden yayınlanmaz. Karar bir DMN 1.3 karar tablosu (`kind: table`) ya da tek bir FEEL ifadesidir
5
+ (`kind: literal`). Süreçte `decision` düğümüyle çağrılır; tek başına `decision_preview` ile değerlendirilir.
6
+ Karar **workflow değildir** (yan etkisi yoktur, veri okumaz — girdileri çağıran verir) ve **süreç değildir**
7
+ (beklemez).
8
+
9
+ ## Başlangıç
10
+
11
+ 1. **Tabloyu yazın** — `decision_create { decision }`. Taslak sürüm oluşur. Gateway yazmadan önce DMN-001 ve
12
+ DMN-002 denetimini çalıştırır (§Lint).
13
+ 2. **Deneyin** — `decision_preview { id, inputs }`. Her sınır değerini ayrı deneyin (§Deneme).
14
+ 3. **Yayınlayın** — `decision_publish { id }`. Motor yalnız aktif sürümü kullanır; production'a yayın yoktur
15
+ (BPM-001).
16
+ 4. **Süreçte kullanın** — `decision` düğümü (§Süreçte kullanım); tanımı `process_definition_preview` ile doğrulayın
17
+ (bilinmeyen `decisionSlug` → `DecisionUnknown`).
18
+
19
+ Düzeltmede tam modeli yeniden göndermeyin: `decision_get` → `decision_patch` (`/rules[id=<kural>]/…`).
20
+ Başka modelleyiciden (Camunda Modeler, Trisotech) gelen tablo için `decision_dmn_update { filePath }`.
21
+
22
+ ## Karar modeli
23
+
24
+ ```jsonc
25
+ {
26
+ "slug": "siparis-onay-limitleri", // tekil; yayından sonra değişmez
27
+ "name": { "tr": "Sipariş onay limitleri" },
28
+ "variable": "siparisOnayLimitleri", // üst kararların gördüğü ad; yoksa slug'daki '-' → '_'
29
+ "kind": "table", // table | literal
30
+ "hitPolicy": "unique", // §İsabet politikaları
31
+ "aggregation": null, // collect + tek çıktı: sum | min | max | count
32
+ "requires": [], // DRD: önce değerlendirilecek alt kararlar (slug)
33
+ "inputData": [], // { name, typeRef, source: "authority-limits", category }
34
+ "inputs": [
35
+ { "id": "tutar", "label": "Tutar", "expression": "tutar", "typeRef": "number" },
36
+ { "id": "kategori", "label": "Kategori", "expression": "kategori", "typeRef": "string", "allowedValues": "\"makine\", \"sarf\"" }
37
+ ],
38
+ "outputs": [
39
+ { "id": "seviye", "name": "seviye", "typeRef": "number", "allowedValues": "3, 2, 1", "defaultOutputEntry": "1" }
40
+ ],
41
+ "rules": [
42
+ { "id": "kucuk", "description": "10 binin altı", "inputEntries": ["< 10000", "-"], "outputEntries": ["1"] },
43
+ { "id": "orta", "inputEntries": ["[10000..100000)", "-"], "outputEntries": ["2"] },
44
+ { "id": "buyuk", "inputEntries": [">= 100000", "-"], "outputEntries": ["3"] }
45
+ ]
46
+ }
47
+ ```
48
+
49
+ - `inputEntries[i]` `inputs[i]`'nin **tekli testidir**, `outputEntries[j]` `outputs[j]`'nin **FEEL ifadesidir**.
50
+ Sütun sayısı eşleşmezse 422 `DecisionInvalid` (yol `/rules/{i}/inputEntries`).
51
+ - `inputs[].expression` girdinin bağlamdaki adıdır ya da ifadesidir (`siparis.tutar`, `tutar * 1.2`).
52
+ - Metin değerler FEEL'de **çift tırnaklıdır**: `"makine"`. Tırnaksız `makine` bir değişken adıdır ve `null` olur.
53
+ - `typeRef`: `number`, `string`, `boolean`, `date`, `time`, `dateTime`, `dayTimeDuration`,
54
+ `yearMonthDuration`, `list`, `context`. Dönüştürme yalnız metin girdiye uygulanır (`"2026-09-17"` → tarih).
55
+ - Literal karar: `{ "kind": "literal", "literalExpression": "tutar * oran", "typeRef": "number" }`.
56
+
57
+ ## İsabet politikaları
58
+
59
+ | Politika | Ne döner | Ne zaman |
60
+ |---|---|---|
61
+ | `unique` | En çok bir kural; ikisi eşleşirse 422 `DecisionHitPolicyViolated` | Kurallar kesin ayrık (varsayılan) |
62
+ | `any` | Eşleşenlerin çıktıları aynı olmalı, yoksa 422 | Aynı sonucu farklı yollardan veren kurallar |
63
+ | `first` | Kural sırasındaki ilk eşleşme | "Özel durum önce, genel en sonda" |
64
+ | `priority` | Çıktının `allowedValues` sırasına göre en yüksek (ilk yazılan) | Birden çok eşleşmede en katısı kazanır |
65
+ | `collect` | Eşleşenlerin listesi; `aggregation` ile tek sayı | Puanlama, kontrol listesi |
66
+ | `rule-order` | Eşleşenler kural sırasıyla | Sıralı öneriler |
67
+ | `output-order` | Eşleşenler `priority` sırasıyla | Önceliğe göre sıralı liste |
68
+
69
+ Tek çıktılı tabloda karar değeri çıktının kendisidir; çok çıktılıda `{ çıktıAdı: değer }`. Çok isabetli
70
+ politikada değer listedir. Hiç kural eşleşmezse `defaultOutputEntry` olan çıktılar varsayılanı alır, yoksa `null`
71
+ — `null` sonucu süreçte gateway koşulunu sessizce yanlış dala gönderebilir; ya varsayılan verin ya da son kurala
72
+ joker (`-`) koyup `first` kullanın.
73
+
74
+ ## FEEL
75
+
76
+ **Tekli testler** (`inputEntries`):
77
+
78
+ | Yazım | Anlamı |
79
+ |---|---|
80
+ | `-` ya da boş | her şey |
81
+ | `< 100` · `>= 5` | karşılaştırma |
82
+ | `[10..20)` · `]1..5]` | aralık; `[` `]` dahil, `(` `)` ya da ters köşe hariç |
83
+ | `"makine"` · `3` · `null` · `esik` | eşitlik (değer ya da bağlamdaki ad) |
84
+ | `"makine", "sarf"` | virgül = VEYA |
85
+ | `not("makine", "sarf")` | hiçbiri |
86
+ | `? > esik * 2` | `?` girdinin kendisi; ifade mantıksal döner |
87
+
88
+ **İfadeler** (`outputEntries`, `expression`, `literalExpression`): `+ - * / **`; `= != < <= > >=`;
89
+ `and`/`or` üç değerli (`true and null` → `null`); `x between 1 and 5`; `x in [1..5]`;
90
+ `if … then … else …`; `for x in liste return x * 2`; `some x in liste satisfies x > 3`; liste filtresi
91
+ `kalemler[tutar > 100]`, indeks `liste[1]` (1'den başlar), `liste[-1]` (son); yol `siparis.musteri.ad`; bağlam
92
+ `{ ad: "x", tutar: 5 }`; zamansal değişmez `@"2026-09-17"`, `@"P3D"`.
93
+
94
+ **Yerleşik işlevler** (tam liste; başkası DMN-002):
95
+ `date`, `time`, `date and time`, `duration`, `years and months duration`, `string length`, `substring`,
96
+ `substring before`, `substring after`, `upper case`, `lower case`, `contains`, `starts with`, `ends with`,
97
+ `matches`, `replace`, `string`, `number`, `not`, `list contains`, `count`, `sum`, `product`, `min`, `max`, `mean`,
98
+ `all`, `any`, `append`, `concatenate`, `flatten`, `reverse`, `distinct values`, `index of`, `get value`, `abs`,
99
+ `floor`, `ceiling`, `decimal` (yarıdan çifte yuvarlar), `modulo`, `sqrt`, `odd`, `even`.
100
+
101
+ Özellikler: tarihte `year month day weekday`, zamanda `hour minute second`, sürede `days hours minutes seconds`
102
+ ve `years months`, aralıkta `start end`.
103
+
104
+ **Yok:** `round up/down/half`, `sort`, `now()`/`today()` (bugünü girdi olarak verin), işlev tanımı, adlı
105
+ argüman, `instance of`, BKM çağrısı, saat dilimli zaman. Sözdizimi hatası 422 `ExpressionInvalid`; tür uyuşmazlığı,
106
+ sıfıra bölme ve tanımsız ad hata değil `null`'dır.
107
+
108
+ ## DRD ve girdi verisi
109
+
110
+ `requires: ["risk-skoru"]` alt kararı önce değerlendirir ve sonucunu `variable` adıyla (yoksa `risk_skoru`)
111
+ bağlama ekler; üst tablonun sütunu `{ "expression": "risk_skoru" }` olur. Döngü yayında 422 `DecisionInvalid`;
112
+ alt kararın aktif sürümü yoksa 422 `DecisionUnknown`. Silme: süreç başvuruyorsa 422 `ReferencedByProcess`,
113
+ başka karar `requires` ile başvuruyorsa 422 `DecisionInvalid`.
114
+
115
+ **Yetki limitleri:** `inputData: [{ "name": "limitler", "typeRef": "list", "source": "authority-limits",
116
+ "category": "makine" }]` — girdi verilmezse `process_authority_limit_list` satırları
117
+ `[{ subjectKind, subjectId, category, limit, currency }]` listesi olarak yüklenir. Tabloda
118
+ `count(limitler[limit >= tutar])` gibi kullanılır.
119
+
120
+ ## Süreçte kullanım
121
+
122
+ ```jsonc
123
+ { "id": "limit", "type": "decision", "description": "Onay seviyesini belirler",
124
+ "decisionSlug": "siparis-onay-limitleri",
125
+ "binding": "latest", // latest | deployed | "v:2" (sabit sürüm)
126
+ "input": { "tutar": "vars.tutar", "kategori": "row.kategori" }, // Jint; yoksa vars + row
127
+ "output": "vars.onay" } // yoksa her çıktı vars'a kendi adıyla
128
+ ```
129
+
130
+ Sonraki gateway'de `vars.onay.seviye >= 2` (çok çıktılı) ya da `vars.onay >= 2` (tek çıktılı). Değerlendirme
131
+ hatası örneği `faulted` yapar; `process_instance_get { view: 'timeline' }` → `decision-evaluated`
132
+ `{ decisionSlug, version, inputs, matchedRules, outputs }`. Tanım yayını karar yayınını beklemez ama motor
133
+ aktif sürüm ister: önce kararı yayınlayın.
134
+
135
+ ## Deneme
136
+
137
+ `decision_preview { id, inputs, version? }` yan etkisizdir; `version` yoksa taslak (yoksa aktif), alt kararlar da
138
+ taslak/son modelle çalışır. Yanıt `{ value, outputs, matchedRules, decisions[] }` — `decisions[]` DRD'deki her
139
+ kararın girdisini ve eşleşen kuralını gösterir.
140
+
141
+ Her kuralı en az bir kez tetikleyin ve **sınırları** ayrı deneyin: `[10000..100000)` için 9999, 10000, 99999,
142
+ 100000. Aralık uçlarındaki `[`/`)` hatası en sık kusurdur; DMN-001 bunu yakalamaz (§Lint).
143
+
144
+ ## DMN XML
145
+
146
+ - `decision_dmn_get { id, outPath? }` kararı ve alt kararlarını DMN 1.3 XML'e yazar; çok dilli ad, `kind`,
147
+ `variable`, `inputData` kaynağı `zeyrek:` uzantısıyla (`https://zeyrek.dev/dmn`) gidiş-dönüş kayıpsızdır.
148
+ - `decision_dmn_update { xml | filePath }` DMN 1.3/1.2/1.1 içe aktarır: `decision id` → slug (küçük harf),
149
+ var olan slug yeni taslak alır, yoksa oluşturulur; bir karar geçersizse hiçbiri yazılmaz. Kutulu bağlam/ilişki,
150
+ BKM ve DMNDI desteklenmez. İçe aktardıktan sonra `decision_preview` — başka motorun FEEL işlevleri (ör.
151
+ Camunda `round up`) içe aktarmada 422 ile reddedilir.
152
+ - Ortamlar arası taşıma: kararlar deployment/merge zincirinde **yoktur**; dışa aktarıp hedef dalda içe aktarın.
153
+
154
+ ## Lint
155
+
156
+ | Kural | Ne | Şiddet |
157
+ |---|---|---|
158
+ | DMN-001 | `unique` tabloda iki kural her girdi sütununda aynı testi ya da `-` taşıyor → aynı girdi ikisini eşler | block (istek gitmez) |
159
+ | DMN-002 | FEEL alt kümesinde olmayan işlev çağrısı | warn (istek gider; backend yazımı 422 ile reddeder) |
160
+
161
+ DMN-001 temkinlidir: yalnız **kesin** çakışmayı yakalar. `< 20` ile `< 10` ya da `[1..5]` ile `[5..9]` kesişir ama
162
+ yakalanmaz — `decision_preview` ile sınır değeri deneyin. Bilinçli istisna `policyOverride: true`.
163
+
164
+ ## Hata sözlüğü
165
+
166
+ | Kod | Anlamı | Ne yapılır |
167
+ |---|---|---|
168
+ | 422 `DecisionHitPolicyViolated` | unique/any tabloda çakışan kurallar (yanıtta kural kimlikleri) | Kuralları ayırın ya da politikayı değiştirin |
169
+ | 422 `ExpressionInvalid` | FEEL sözdizimi ya da bilinmeyen işlev (yol `/rules/{i}/…`) | §FEEL listesine bakın |
170
+ | 422 `DecisionInvalid` | Model hatası (sütun sayısı, politika, döngü) | Yoldaki alanı düzeltin |
171
+ | 422 `DecisionUnknown` | `requires` ya da süreç `decisionSlug`'ı aktif kararı bulamadı | Alt kararı yayınlayın |
172
+ | 422 `ReferencedByProcess` | Silinmek istenen karara süreç başvuruyor | Önce süreci değiştirin |
173
+
174
+ ## Sık tuzaklar
175
+
176
+ - **Tırnaksız metin:** `inputEntries: ["makine"]` değil `["\"makine\""]`. Tırnaksız ad bağlamda aranır, `null` olur ve
177
+ kural hiç eşleşmez.
178
+ - **Sayı metin geliyor:** satırdaki `"180000"` metni `number` sütunda karşılaştırılamaz; `typeRef: "number"` verin ya da
179
+ düğüm girdisinde `Number(row.tutar)`.
180
+ - **Boşluk bırakan aralıklar:** `< 10000` ve `(10000..100000)` → tam 10000 hiçbir kurala düşmez.
181
+ - **`null` sonuç:** eşleşme yoksa varsayılan yoksa `null` döner; süreçte koşul `vars.onay.seviye >= 2` `false`
182
+ olur, hata vermez.
183
+ - **Bugünün tarihi:** FEEL'de `today()` yok; süreç düğümü girdisinde `{ "bugun": "new Date().toISOString().slice(0, 10)" }`.
184
+ - **Taslakla çalıştığını sanmak:** `decision_preview` taslağı, süreç motoru aktif sürümü kullanır — yayınlamayı unutmak
185
+ "önizlemede doğruydu, süreçte eski sonuç" demektir.
@@ -15,7 +15,9 @@ uzayındadır. Çakışan slug `Migration failed … relation "X" already exists
15
15
  kaydı hiç oluşmaz**. Rezerve adlardan bilinenler: `branches`, `applications`, `caches`,
16
16
  `components`, `datasources`, `entities`, `fields`, `files`, `flows`, `folders`, `layouts`,
17
17
  `microservices`, `pages`, `permissions`, `projects`, `queries`, `queued_events`, `roles`,
18
- `steps`, `users`, `variables`, `views`, `workflows`. Alan adı bunlardan biriyse eş anlamlısını
18
+ `steps`, `users`, `variables`, `views`, `workflows` — ve rol yönetim şemasının tabloları:
19
+ `organization_units`, `organization_positions`, `user_positions`, `access_policies`, `access_grants`
20
+ (tam liste gateway'in rezerve ad kontrolündedir). Alan adı bunlardan biriyse eş anlamlısını
19
21
  seç (ör. şube/branş için `branches` değil `specialties`).
20
22
 
21
23
  > **Ama `users`/`roles`/`files`/`folders` bir istisna:** bunlar "dolu olduğu için kaçınılacak"
@@ -24,7 +26,7 @@ seç (ör. şube/branş için `branches` değil `specialties`).
24
26
 
25
27
  ## Hazır entity'ler — kimlik tablosu ZATEN VAR
26
28
 
27
- Her projeye seed sırasında 9 entity açılır ve **id'leri her kurulumda aynı sabitlerdir**
29
+ Her projeye seed sırasında hazır entity'ler açılır ve **id'leri her kurulumda aynı sabitlerdir**
28
30
  (`Defaults` sınıfı) — aramana gerek yok, doğrudan `entity_get` ile çekebilirsin:
29
31
 
30
32
  | slug | id | Ne için |
@@ -35,12 +37,33 @@ Her projeye seed sırasında 9 entity açılır ve **id'leri her kurulumda aynı
35
37
  | `permissions` · `role_permissions` | `01917ede-a457-…` · `01917ede-d450-…` | yetki matrisi |
36
38
  | `files` · `folders` | `0191dbf2-39c4-…` · `0191df94-f635-…` | Drive; `FILE` alanları buraya bağlanır (`entity_list`'te GİZLİ) |
37
39
  | `audit_trails` · `audit_trail_values` | `01961f53-25c3-…` · `01961f53-3552-…` | denetim izi |
40
+ | `organization_units` · `organization_unit_closure` | `01a0a05e-1c9a-7022-a0c7-6b8320756a4c` · `01a0a05e-1ca3-7b6a-9f1b-7f1633f7f05a` | **Organizasyon ağacı** (yalnız okunur, aşağıda): birimler — `parent_id` · `unit_type` (holding/company/branch/region/department/team/other) · `function_code` · `name` · `code` · `manager_position_id` · `origin` · `is_active` — ve ata/torun kapanışı |
41
+ | `organization_positions` · `organization_position_closure` | `01a0a05e-1ca3-700f-95c6-18fe1e30079c` · `01a0a05e-1ca4-7b73-b90e-4aa7d8eeeeef` | birimdeki koltuklar — `unit_id` · `parent_position_id` (idari hat) · `functional_parent_position_id` (işlevsel hat) · `role_id` · `name` · `code`; kapanışta `line_type` |
42
+ | `user_positions` | `01a0a05e-1ca4-7841-b6b3-45c5892d5501` | kullanıcı ↔ pozisyon — `user_id` · `position_id` · `is_primary` · `assignment_type` · `starts_at` · `ends_at` |
38
43
 
39
44
  **`users` gerçek bir entity'dir**, sahte bir sistem tablosu değil: `entity_get` alanlarını verir,
40
45
  `RELATION` alanı hedef alabilir, table step / microservice okur, `row_create` yazar, kendi default
41
46
  DTO'su vardır. Auth middleware tarifi zaten bunu okur — `ngapps://examples/middleware-authenticate`
42
47
  `entityId` olarak `users`'ı kullanır.
43
48
 
49
+ ### Organizasyon ağacı tabloları — okunur, genel yolla YAZILMAZ (ORG-001 · ORG-002)
50
+
51
+ Beş organizasyon tablosu **her projede vardır**; basit projede boştur, kompleks projede
52
+ (`project_create` `accessModel: 'complex'`) organizasyonun rol yönetim şemasının kopyasını taşır.
53
+
54
+ - **Yazma kapalı (ORG-001, block).** `row_create` / `row_update` / `row_delete`, table kaynaklı uç
55
+ ve table step bu tablolara platformda `400 SystemEntityWriteNotAllowed` alır; gateway isteği hiç
56
+ göndermez. Ağaç organizasyon şemasından **senkronla** gelir (yönetim konsolunda yayın → abone
57
+ projenin her ortamı); projeye özel birim/pozisyon ve kullanıcı ataması Studio › Organizasyon
58
+ ekranındadır — MCP'de bu yazma yolu bilinçli olarak yoktur: projede yapı değişikliği aboneliği
59
+ kapatır (`receiveUpdates = false`) ve dal ortamında 409 döner.
60
+ - **Kompleks proje yayınlı son şemayla doğar (ORG-002).** Organizasyonda yayın yoksa tablolar boş
61
+ kalır; önce `organization_schema_get` ile `publishedVersion`'a bak. Abonelik ve özelleştirme
62
+ durumu `project_get` → `organizationSchema`.
63
+ - **Okuma serbest:** `row_list('organization_units')`, pozisyonlar için `row_list('organization_positions')`.
64
+ Alt ağaç sorusu (bir birimin bütün torunları) kapanış tablosundan `ancestor_id` filtresiyle
65
+ okunur; `depth` 0 düğümün kendisidir.
66
+
44
67
  ### Neden gözden kaçıyor
45
68
 
46
69
  `entity_list`'i **`applicationId` ile** çağırdığında hazır entity'ler listede **görünmez**: seed
@@ -94,6 +117,12 @@ yapıyorsan devam et).
94
117
  uygulamanın rol açması/düzenlemesi gerekiyorsa yol her domain tablosuyla aynıdır: entity + kendi
95
118
  microservice ucun + sayfa. `role_list` yalnız okur.
96
119
 
120
+ > **Kompleks projede roller organizasyon şemasından gelir** (`roles.origin = 'organization'`;
121
+ > `role_list` bu alanı döndürmez, `row_list('roles')` okur). Şemadan gelen rol MCP'den yazılmaz,
122
+ > yönetim konsolunda düzenlenir; yetki `page.roleIds` ile değil erişim politikasıyla verilir.
123
+ > Aşağıdaki reçete basit proje içindir — kompleks projede kendi rolünü açan uç yine uyarı alır
124
+ > (ROL-002 warn), dikey çözümün açtığı rol projeye özgü kalır.
125
+
97
126
  `roles` entity'sinin açtığı alanlar — fiziksel tabloda ayrıca `template_*` kolonları var, hepsi
98
127
  nullable, gateway'den görünmez:
99
128
 
@@ -134,6 +163,15 @@ Rol açma reçetesi:
134
163
  `permissions` / `role_permissions` **Studio'nun yetki matrisidir**, uygulama sayfasının yetkisi
135
164
  değil; uygulama tarafında yetkiyi `page.roleIds` ve middleware ifadesi kurar.
136
165
 
166
+ ## Veri koruma — maskeli, şifreli ve türetilmiş alan
167
+
168
+ TCKN, telefon gibi alanlar `fields[].protection` ile maskeli ve/veya şifreli saklanır; telefonun
169
+ operatör kodu gibi sorgulanabilir parça `derivedFromFieldId` + `derivationRule` ile türetilmiş alan
170
+ olur. Koruma yalnız düz metin alana konur (display, birincil anahtar, ilişki, çok dilli değil —
171
+ PROT-003), korumalı alanda metin araması ve sıralama yoktur (PROT-001, PROT-002). Modlar, maske
172
+ türleri, dolu kolonda geçiş ve hatalar: `platform_guide('access')` §'Alan koruması'. Satırları bir
173
+ bileşene bağlamak (liste, dropdown, grafik) akış değil `connect_data_bind`: `platform_guide('page')` §Kural 1c-3.
174
+
137
175
  ## Alan tipleri (dbType + commonType İKİSİ birden verilir)
138
176
 
139
177
  | dbType (BÜYÜK HARF zorunlu) | commonType |
@@ -159,6 +197,9 @@ değil; uygulama tarafında yetkiyi `page.roleIds` ve middleware ifadesi kurar.
159
197
  `description`'a yaz: para → `INT8` kuruş (`*_minor`), süre → `INT4` dakika, yüzde →
160
198
  `INT4` ×100, puan → `INT4` ×10.
161
199
  - `commonType`'sız `UUID`/`BOOL` "isn't a supported database type" hatasıyla reddedilir.
200
+ - Birincil anahtar `properties.generationType` taşımak ZORUNDADIR: `properties` hiç verilmezse create
201
+ `Please select a valid generation type for 'id'` ile düşer (38/U-14). `0` (Always) ve `1` (ByDefault) ikisi de
202
+ geçerlidir — `UUID` anahtarda ikisiyle de satır id'si üretildi (ölçüldü 2026-09-21, 39/05 D-15).
162
203
  - **Katalogu okumak gerekiyorsa** (bu datasource'ta hangi `dbType` var, hangisi varsayılan, tip
163
204
  hangi seçenekleri kabul ediyor, hangi tipe dönüştürülebilir) `datasource_configuration_options`
164
205
  çağır: varsayılan yanıt ~5 KB'lık **özettir**; 816 kayıtlık collation DEĞER listesi yalnız
@@ -680,12 +721,13 @@ orada `undefined` alır.
680
721
  > `Sequence contains no **elements**` (satır yok — genelde preview rollback'i) **farklı**
681
722
  > sorunlardır; karıştırmak teşhisi saptırır.
682
723
 
683
- - **Audit izi ne zaman gerçekten yazılır?** `CreateAuditTrailCommandHandler` şu üç durumda
684
- **hiç kayıt açmaz**: `IsAuditTrailActive == false`, `AuditTrailType == null`, ya da
685
- `AuditTrailType == simple`. Yani iz tutulması için `isAuditTrailActive: true` **ve**
686
- `auditTrailType: "basic" | "detailed"` birlikte gerekir. Enum yalnız üç değer tanır —
687
- `simple` · `basic` · `detailed` (`AuditTrailType.cs`); `advanced` diye bir değer **yoktur**,
688
- gönderirsen bağlama hatası alırsın.
724
+ - **Audit izi ne zaman gerçekten yazılır?** Tek koşul `isAuditTrailActive: true`. Bayrak açık ve
725
+ `auditTrailType` boş gelirse **`simple`** yazılır (TB-101, 2026-09-20 — eskiden bayrak tek başına
726
+ hiçbir şey yazmıyordu, sessiz tuzaktı); okuma yolunda da tipsiz ama açık entity `simple` sayılır.
727
+ Üç tip, aynı satır başlığını yazar, farkları okumada: `simple` yalnız "kim oluşturdu / kim
728
+ güncelledi" meta'sını besler (geçmiş listesi dönmez) · `basic` geçmiş listesini döndürür, değişen
729
+ alanları döndürmez · `detailed` değişen alanları da yazar. Enum yalnız bu üç değeri tanır
730
+ (`AuditTrailType.cs`); `advanced` diye bir değer **yoktur**, gönderirsen bağlama hatası alırsın.
689
731
  - **Audit izi IP adresi tutar.** `audit_trails.IpAddress`, isteğin
690
732
  `HttpContext.Connection.RemoteIpAddress` değerinden doldurulur (`UserContext.cs`) ve satır
691
733
  olaylarıyla (`Row.Created/Updated/Deleted` → `UserIpAddress`) audit consumer'a taşınır; kullanıcı