@appaflytech/zeyrek-ai-mcp 0.0.35 → 0.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +15 -0
- package/README.md +5 -5
- package/dist/config.js +37 -0
- package/dist/index.js +2 -0
- package/dist/knowledge/access.js +802 -0
- package/dist/knowledge/backendConstraints.js +18 -1
- package/dist/knowledge/case.js +41 -0
- package/dist/knowledge/componentCatalog.js +655 -424
- package/dist/knowledge/componentEvents.js +140 -23
- package/dist/knowledge/connectDataBind.js +843 -0
- package/dist/knowledge/connectDataDefinition.js +344 -0
- package/dist/knowledge/connectDataExecute.js +93 -0
- package/dist/knowledge/connectDataRules.js +128 -0
- package/dist/knowledge/decision.js +121 -0
- package/dist/knowledge/expressionPrelude.js +59 -0
- package/dist/knowledge/layoutSummary.js +140 -2
- package/dist/knowledge/microserviceParameters.js +58 -0
- package/dist/knowledge/mining.js +94 -0
- package/dist/knowledge/mobileComponentCatalog.js +864 -0
- package/dist/knowledge/mobileComponentEvents.js +239 -0
- package/dist/knowledge/mobileStore.js +321 -0
- package/dist/knowledge/normalize.js +235 -84
- package/dist/knowledge/outlines.js +36 -0
- package/dist/knowledge/platform/lint.js +385 -0
- package/dist/knowledge/platform/mobile.js +142 -0
- package/dist/knowledge/platform/mobileLayoutLint.js +324 -0
- package/dist/knowledge/platform/mobileRules.js +231 -0
- package/dist/knowledge/platform/mobileSpacing.js +82 -0
- package/dist/knowledge/platform/mobileTabs.js +108 -0
- package/dist/knowledge/platform/nativeBoxModel.js +44 -0
- package/dist/knowledge/platform/profile.js +25 -0
- package/dist/knowledge/platform/resolve.js +122 -0
- package/dist/knowledge/platform/web.js +39 -0
- package/dist/knowledge/policy.js +18 -4
- package/dist/knowledge/process.js +510 -0
- package/dist/knowledge/reservedTables.js +79 -0
- package/dist/knowledge/rowFilter.js +43 -0
- package/dist/knowledge/rules.js +423 -37
- package/dist/knowledge/schemaGuard.js +11 -0
- package/dist/knowledge/styleResolve.js +53 -19
- package/dist/knowledge/styleResolveNative.js +527 -0
- package/dist/knowledge/themeResolve.js +4 -4
- package/dist/knowledge/themeSchema.js +1 -2
- package/dist/observability/trace.js +6 -3
- package/dist/platform/argumentAliases.js +128 -0
- package/dist/platform/bodyFile.js +103 -0
- package/dist/platform/capture/actions.js +398 -0
- package/dist/platform/capture/browser.js +1 -0
- package/dist/platform/capture/capture.js +683 -0
- package/dist/platform/capture/console-log.js +122 -0
- package/dist/platform/capture/index.js +11 -0
- package/dist/platform/capture/readiness.js +103 -0
- package/dist/platform/capture/summary.js +77 -0
- package/dist/platform/capture/target.js +5 -0
- package/dist/platform/capture/targets/studio-mobile.js +15 -0
- package/dist/platform/capture/targets/studio-web.js +5 -0
- package/dist/platform/diagnostics.js +10 -4
- package/dist/platform/domSummary.js +1 -1
- package/dist/platform/errors.js +163 -10
- package/dist/platform/http.js +29 -8
- package/dist/platform/impersonation.js +45 -0
- package/dist/platform/jsonArray.js +24 -0
- package/dist/platform/responses.js +39 -5
- package/dist/platform/schemaReadMemory.js +60 -0
- package/dist/platform/secrets.js +19 -1
- package/dist/platform/strictArguments.js +68 -12
- package/dist/platform/tokenVault.js +187 -4
- package/dist/resources/examples/bpm-gorev-kontrol.json +294 -0
- package/dist/resources/examples/bpm-iso-dokuman.json +228 -0
- package/dist/resources/examples/bpm-satinalma.json +376 -0
- package/dist/resources/examples/connect-data-convert-verify.json +107 -0
- package/dist/resources/examples/connect-data-dropdown-roles.json +66 -0
- package/dist/resources/examples/connect-data-edit-m2m.json +73 -0
- package/dist/resources/examples/connect-data-query-params.json +50 -0
- package/dist/resources/examples/connect-data-table-entity.json +147 -0
- package/dist/resources/examples/connect-data-workflow-microservice.json +65 -0
- package/dist/resources/examples/middleware-authenticate.json +1 -1
- package/dist/resources/examples/mobile-app-shell-drawer.json +244 -0
- package/dist/resources/examples/mobile-app-shell-stack.json +157 -0
- package/dist/resources/examples/mobile-app-shell-tab.json +208 -0
- package/dist/resources/examples/mobile-form-screen.json +365 -0
- package/dist/resources/examples/mobile-list-detail-form.json +703 -0
- package/dist/resources/examples/page-detail-profile.json +2 -1
- package/dist/resources/examples/page-dynamic-form.json +3 -2
- package/dist/resources/examples/page-flex-sections.json +1 -1
- package/dist/resources/examples/page-html-embed.json +1 -1
- package/dist/resources/examples/workflow-basic.json +8 -2
- package/dist/resources/guides/access.md +810 -0
- package/dist/resources/guides/bpm.md +691 -0
- package/dist/resources/guides/case.md +153 -0
- package/dist/resources/guides/component.md +93 -6
- package/dist/resources/guides/decision.md +185 -0
- package/dist/resources/guides/entity.md +50 -8
- package/dist/resources/guides/expressions.md +14 -5
- package/dist/resources/guides/functions.md +1 -1
- package/dist/resources/guides/getting-started.md +38 -1
- package/dist/resources/guides/layout.md +11 -7
- package/dist/resources/guides/merge.md +37 -3
- package/dist/resources/guides/microservice.md +87 -2
- package/dist/resources/guides/middleware.md +68 -4
- package/dist/resources/guides/mobile-layout.md +193 -0
- package/dist/resources/guides/mobile-publish.md +124 -0
- package/dist/resources/guides/mobile.md +549 -0
- package/dist/resources/guides/page.md +463 -83
- package/dist/resources/guides/theme.md +8 -3
- package/dist/resources/guides/translation.md +1 -1
- package/dist/resources/guides/workflow.md +58 -1
- package/dist/resources/read.js +41 -0
- package/dist/resources/rules.js +11 -5
- package/dist/resources/schema-fingerprint.json +7 -5
- package/dist/resources/schemas/AccessExplanationDto.json +144 -0
- package/dist/resources/schemas/AccessMatrixDto.json +170 -0
- package/dist/resources/schemas/AccessPermissionDto.json +57 -0
- package/dist/resources/schemas/AccessPolicyDto.json +223 -0
- package/dist/resources/schemas/AccessResourceDto.json +86 -0
- package/dist/resources/schemas/AppSessionDto.json +53 -0
- package/dist/resources/schemas/ConnectDataDescribeDto.json +344 -0
- package/dist/resources/schemas/ConnectDataRequestModel.json +202 -0
- package/dist/resources/schemas/ConnectDataResultDto.json +421 -0
- package/dist/resources/schemas/ConnectorCredentialDto.json +70 -0
- package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +37 -0
- package/dist/resources/schemas/CreateAccessPolicyCommand.json +209 -0
- package/dist/resources/schemas/CreateDecisionCommand.json +221 -0
- package/dist/resources/schemas/CreateEntityCommand.json +118 -0
- package/dist/resources/schemas/CreateMicroserviceCommand.json +13 -1
- package/dist/resources/schemas/CreateProcessDefinitionCommand.json +1337 -0
- package/dist/resources/schemas/CreateQueryCommand.json +4 -0
- package/dist/resources/schemas/CreateWorkflowCommand.json +146 -1
- package/dist/resources/schemas/DataJobDto.json +6 -1
- package/dist/resources/schemas/DecisionDto.json +302 -0
- package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +28 -0
- package/dist/resources/schemas/ExplainAccessQuery.json +33 -0
- package/dist/resources/schemas/GenerateProcessDocumentCommand.json +116 -0
- package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +25 -1
- package/dist/resources/schemas/MicroserviceDto.json +15 -3
- package/dist/resources/schemas/OrganizationProjectDto.json +335 -0
- package/dist/resources/schemas/OrganizationSchemaDto.json +196 -0
- package/dist/resources/schemas/OrganizationSchemaVersionDto.json +207 -0
- package/dist/resources/schemas/PatchProcessDefinitionCommand.json +76 -0
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +10 -1
- package/dist/resources/schemas/PreviewWorkflowCommand.json +25 -1
- package/dist/resources/schemas/ProcessDefinitionDto.json +1480 -0
- package/dist/resources/schemas/ProcessSimulationDto.json +96 -0
- package/dist/resources/schemas/SaveConnectorCredentialCommand.json +90 -0
- package/dist/resources/schemas/SaveProcessEventSourceCommand.json +61 -0
- package/dist/resources/schemas/SaveProcessMailSourceCommand.json +89 -0
- package/dist/resources/schemas/SignProcessTaskCommand.json +73 -0
- package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +92 -0
- package/dist/resources/schemas/StartMobileBuildCommand.json +54 -0
- package/dist/resources/schemas/StepDto.json +25 -1
- package/dist/resources/schemas/UpdateAccessPolicyCommand.json +209 -0
- package/dist/resources/schemas/UpdateDecisionCommand.json +216 -0
- package/dist/resources/schemas/UpdateEntityCommand.json +118 -0
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +13 -1
- package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +1357 -0
- package/dist/resources/schemas/UpdateQueryCommand.json +4 -0
- package/dist/resources/schemas/UpdateViewCommand.json +0 -2
- package/dist/resources/schemas/UpdateWorkflowCommand.json +146 -1
- package/dist/resources/schemas/UpsertMobileStoreSettingsCommand.json +274 -0
- package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +1339 -0
- package/dist/server.js +31 -1
- package/dist/tools/access.js +369 -2
- package/dist/tools/accessOperations.js +135 -0
- package/dist/tools/accessPolicies.js +170 -0
- package/dist/tools/accessRuntime.js +203 -0
- package/dist/tools/applications.js +60 -3
- package/dist/tools/bpm.js +343 -0
- package/dist/tools/bpmGovernance.js +266 -0
- package/dist/tools/bpmOperations.js +230 -0
- package/dist/tools/bpmReporting.js +154 -0
- package/dist/tools/bpmRouting.js +150 -0
- package/dist/tools/bpmRuntime.js +396 -0
- package/dist/tools/case.js +178 -0
- package/dist/tools/caseRuntime.js +89 -0
- package/dist/tools/common.js +10 -1
- package/dist/tools/components.js +118 -14
- package/dist/tools/connectData.js +450 -0
- package/dist/tools/connectors.js +193 -0
- package/dist/tools/datasources.js +3 -3
- package/dist/tools/decisions.js +206 -0
- package/dist/tools/dependencies.js +1 -1
- package/dist/tools/deployments.js +38 -3
- package/dist/tools/designSchemaPatch.js +34 -9
- package/dist/tools/dtos.js +36 -5
- package/dist/tools/entities.js +79 -12
- package/dist/tools/externalComponents.js +26 -5
- package/dist/tools/flows.js +119 -17
- package/dist/tools/folders.js +1 -1
- package/dist/tools/imports.js +5 -2
- package/dist/tools/layouts.js +50 -17
- package/dist/tools/merges.js +2 -2
- package/dist/tools/microservices.js +77 -25
- package/dist/tools/mobile.js +280 -0
- package/dist/tools/mobileStore.js +556 -0
- package/dist/tools/modules.js +48 -0
- package/dist/tools/organizationStructure.js +137 -0
- package/dist/tools/pages.js +465 -98
- package/dist/tools/platformInfo.js +28 -8
- package/dist/tools/profileWrite.js +92 -0
- package/dist/tools/projects.js +71 -9
- package/dist/tools/rows.js +69 -13
- package/dist/tools/schemaOps.js +61 -1
- package/dist/tools/screenWrite.js +36 -7
- package/dist/tools/screens.js +95 -5
- package/dist/tools/templates.js +26 -1
- package/dist/tools/translations.js +1 -1
- package/dist/tools/variables.js +11 -5
- package/dist/tools/workflows.js +10 -5
- package/package.json +2 -2
- package/dist/platform/screenshot.js +0 -1162
|
@@ -0,0 +1,691 @@
|
|
|
1
|
+
# Süreç Rehberi — Hibrit BPM
|
|
2
|
+
|
|
3
|
+
İnsanı bekleyen, durumlu iş süreçleri: tanım, yürütme, görev kutusu, bölge olayları. Süreç
|
|
4
|
+
**workflow değildir**: workflow tek istekte biten sunucu akışıdır (`platform_guide('workflow')`);
|
|
5
|
+
süreç günlerce insan görevlerinde, zamanlayıcılarda ve dış olaylarda bekler, her adımı hash zincirli
|
|
6
|
+
bir defterde tutar. Bir süreç düğümü gerektiğinde workflow'u `service` düğümüyle çağırır.
|
|
7
|
+
|
|
8
|
+
## Başlangıç
|
|
9
|
+
|
|
10
|
+
Sıra her zaman aynıdır:
|
|
11
|
+
|
|
12
|
+
1. **İş nesnesi** — sürecin konusu olan entity (`gorevler`, `satinalma_talepleri`). Süreç o satırın
|
|
13
|
+
üstünde koşar: ifadelerde `row`, `writeBack` ile satıra yazar.
|
|
14
|
+
2. **Tanım** — `process_definition_create`. Önce altın örneği okuyun:
|
|
15
|
+
`ngapps://examples/bpm-gorev-kontrol` (satır olayı → görev → onay → iade),
|
|
16
|
+
`ngapps://examples/bpm-satinalma` (seviye servisi → sıralı yönetici zinciri → paralel kontrol),
|
|
17
|
+
`ngapps://examples/bpm-iso-dokuman` (onay birimi → okuma turu → düzenleme isteği bölge olayı).
|
|
18
|
+
3. **Önizleme** — `process_definition_preview` ile önce `definition` gövdesiyle doğrulama, kayıttan
|
|
19
|
+
sonra `id` + `subjectRowId` ile kuru koşu: her insan adımında kimin görev alacağını görürsünüz.
|
|
20
|
+
4. **Yayın** — `process_definition_publish`. Taslak aktif olur; production'a yayın yoktur (BPM-001).
|
|
21
|
+
5. **Yürütme** — `process_execute(slug, subjectRowId, vars, asUser)`; görevler `process_task_list(tab,
|
|
22
|
+
asUser)` kutusunda, eylemler `process_task_update(id, action, version, asUser)`, defter
|
|
23
|
+
`process_instance_get(id, view: 'timeline')`.
|
|
24
|
+
|
|
25
|
+
Tanımı düzeltirken tam gövdeyi yeniden göndermeyin: `process_definition_get` (outline) →
|
|
26
|
+
`process_definition_patch` (`/nodes[id=<düğüm>]/…` seçicileriyle).
|
|
27
|
+
|
|
28
|
+
## Tanım modeli
|
|
29
|
+
|
|
30
|
+
```jsonc
|
|
31
|
+
{
|
|
32
|
+
"slug": "gorev-kontrol", // kebab-case, uygulamada benzersiz; yayından sonra değişmez
|
|
33
|
+
"name": "Görev kontrol", // tek dil düz metin; çok dilli nesne gelirse gateway düz metne çevirir
|
|
34
|
+
"description": "…", // ZORUNLU (BPM-002), tek dil düz metin
|
|
35
|
+
"analysis": { "purpose": { "en": "…", "tr": "…" }, "summary": { "en": "…", "tr": "…" } }, // ZORUNLU (BPM-023) — § Analiz dokümanı
|
|
36
|
+
"subject": { "entity": "gorevler" }, // entity slug ya da id
|
|
37
|
+
"singleton": "per-subject", // aynı satırda açık örnek varsa yeni başlatma mevcut örneği döner
|
|
38
|
+
"withdrawPolicy": "before-first-decision", // never | before-first-decision | anytime
|
|
39
|
+
"history": "full", // full | audit | minimal — defter ayrıntısı
|
|
40
|
+
"sod": ["not-initiator"], // başlatan kendi onayını veremez
|
|
41
|
+
"params": { "esikTutar": { "default": 50000, "type": "number", "editable": "params" } },
|
|
42
|
+
"emailActions": false, // true: onay e-postasına tek kullanımlık onay/ret bağlantısı
|
|
43
|
+
"nodes": [ … ],
|
|
44
|
+
"edges": [ ["baslangic", "bildir"], { "from": "karar", "to": "red", "condition": "!vars.uygun" } ],
|
|
45
|
+
"on": [ … ] // süreç düzeyi olay işleyicileri
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Kurallar:
|
|
50
|
+
|
|
51
|
+
- **Her düğüm ve tanımın kendisi `description` taşır** (BPM-002, block). Kutuda ve tasarımcıda
|
|
52
|
+
görevin ne istediğini anlatır; mekanizmayı değil niyeti yazın. Gerçek bir tuzak varsa `caution`.
|
|
53
|
+
- **Tanım ve her düğüm iki dilli `analysis` taşır** (BPM-023, block): Studio'nun Analiz dokümanı
|
|
54
|
+
sekmesi onu gösterir. Biçim ve yazım kuralı § Analiz dokümanı.
|
|
55
|
+
- Düğüm `id`'leri kebab-case ve tanım içinde benzersizdir; kenarlar ve `back-to:` bu id'lerle bağlanır.
|
|
56
|
+
- **Adımın okunabilir adı (`resultKey`) snake_case'dir, kebab-case DEĞİL.** `id` kenarların anahtarıdır,
|
|
57
|
+
ifadede okunmaz; ifade sonucu adıyla ve noktayla okur: `vars.tasks.ik_kaydi.action`,
|
|
58
|
+
`vars.approvals.yonetici_onayi.outcome`. Her `user-task` ve `approval` düğümüne id'nin snake_case'ini
|
|
59
|
+
`resultKey` olarak yazın (`"id": "ik-kaydi"` → `"resultKey": "ik_kaydi"`). Köşeli parantezle kebab
|
|
60
|
+
anahtar okumayın — `vars.tasks?.['ik-kaydi']?.action` yazmayın; Studio kartı ve ifade tamamlaması
|
|
61
|
+
adı snake_case gösterir, kebab anahtar yalnız eski ifadeler bozulmasın diye yazılır.
|
|
62
|
+
- Tam bir `start` üst düzeydedir; bölgenin içinde `start` yoktur.
|
|
63
|
+
- İfadeler Jint'tir: `vars` (süreç değişkenleri), `row` (iş satırı), `previousRow` (satır olayında),
|
|
64
|
+
`initiator` (başlatan kullanıcı id). `{{…}}` yer tutucu yalnız şablon metinlerinde ve `chain` argümanında.
|
|
65
|
+
- Kısa biçimler gateway'de tam biçime çevrilir ve yanıtta `gatewayNormalized` ile bildirilir:
|
|
66
|
+
`"sla": "P2D"` → `[{ "duration": "P2D" }]`, `"assignee": "unit-manager of initiator"` → nesne,
|
|
67
|
+
`[from, to]` → `{ from, to }`.
|
|
68
|
+
- Parametre (`params`) varsayılanları başlatmada `vars`'a yazılır; başlatma girdisi üstüne biner.
|
|
69
|
+
- `history` defterin ayrıntısıdır: `full` her olayı, `audit` kararları, görev yaşam döngüsünü (açılma,
|
|
70
|
+
üstlenme, bilgi isteme), SLA ihlallerini ve yorumları, `minimal` yalnız başlangıç/bitiş, kararlar,
|
|
71
|
+
tamamlanan görevler ve satıra yazmaları tutar — `minimal`de raporun ret döngüsü ve SLA ihlali boş kalır.
|
|
72
|
+
|
|
73
|
+
## Analiz dokümanı
|
|
74
|
+
|
|
75
|
+
Studio'da süreç tasarımcısının alt bilgi çubuğundaki **Analysis document** paneli, süreci hiç görmemiş bir iş
|
|
76
|
+
kullanıcısına her adımda ne olduğunu anlatır. Kullanıcının çizdiği süreçte metin şablonla üretilir;
|
|
77
|
+
**AI'ın yazdığı süreçte metni siz yazarsınız** ve gateway zorunlu tutar (BPM-023, block —
|
|
78
|
+
create, update ve patch'in sonucu denetlenir).
|
|
79
|
+
|
|
80
|
+
```jsonc
|
|
81
|
+
"analysis": { // tanım düzeyi
|
|
82
|
+
"purpose": { "en": "…", "tr": "…" }, // bu süreç neden var, hangi ihtiyacı karşılıyor
|
|
83
|
+
"summary": { "en": "…", "tr": "…" } // baştan sona ne oluyor, 2-3 cümle
|
|
84
|
+
}
|
|
85
|
+
"analysis": { // her düğüm, bölge içindekiler dahil
|
|
86
|
+
"what": { "en": "…", "tr": "…" }, // bu adımda ne yapılıyor, kim yapıyor
|
|
87
|
+
"data": { "en": "…", "tr": "…" }, // hangi değerleri kullanıyor, nereden geliyor, ne yazıyor
|
|
88
|
+
"why": { "en": "…", "tr": "…" }, // bu adım neden gerekli; olmasa ne ters gider
|
|
89
|
+
"example": { "en": "…", "tr": "…" } // gerçek hayattan küçük bir örnek: bu adım bir vakada ne yapar
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Yazım kuralı — sekmeyi okuyan kişi teknik değildir:
|
|
94
|
+
|
|
95
|
+
- **İş diliyle, 1-3 kısa cümle.** Alan ve id yerine etiketini yazın: "talebin tutarı", `row.tutar`
|
|
96
|
+
değil; "birim yöneticisi", `unit-manager of initiator` değil. İfade ya da JSON yazmayın.
|
|
97
|
+
- **`what` eylemi ve eylemi yapanı söyler**, mekanizmayı değil: "Finans ekibinden biri bütçeyi kontrol
|
|
98
|
+
eder ve onaylar ya da reddeder."
|
|
99
|
+
- **`data` somut değerleri sayar**: okunan alanlar, dal koşulunun baktığı değer, yazılan sonuç. Değer
|
|
100
|
+
kullanmayan adımda bunu söyleyin: "Değer kullanmaz; yalnız süreci bitirir."
|
|
101
|
+
- **`why` gerekçeyi verir**: kural, risk, denetim ihtiyacı — `description`'ın tekrarı değil.
|
|
102
|
+
- **`example` bu adımı somut bir vakayla gösterir**: adı, tutarı olan bir kişi ve talep ("Ayşe'nin
|
|
103
|
+
yöneticisi Mehmet, 25.000 TL'lik dizüstü talebini kutusunda görür ve onaylar"). Bütün adımlarda aynı
|
|
104
|
+
vakayı sürdürün ki okuyan akışı tek hikâye gibi izlesin; dal ya da ret yolundaki adımda vakanın o
|
|
105
|
+
yola nasıl düştüğünü söyleyin ("tutar 60.000 TL olsaydı talep CFO onayına giderdi").
|
|
106
|
+
- **İki dil aynı şeyi söyler**; biri diğerinin çevirisidir, `en` kısaltılmış değildir.
|
|
107
|
+
- Var olan bir sürecin analizi yoksa her yazma BPM-023'e takılır: aynı çağrıda eksikleri ekleyin
|
|
108
|
+
(`process_definition_patch` ile `add /nodes[id=x]/analysis`).
|
|
109
|
+
|
|
110
|
+
Örnek — satın alma onayındaki bir `approval` düğümü:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
"analysis": {
|
|
114
|
+
"what": { "en": "The requester's unit manager reviews the request and approves or rejects it.", "tr": "Talep sahibinin birim yöneticisi talebi inceler; onaylar ya da reddeder." },
|
|
115
|
+
"data": { "en": "Reads the title, category and amount of the request. A rejection ends the process.", "tr": "Talebin başlığını, kategorisini ve tutarını okur. Ret süreci bitirir." },
|
|
116
|
+
"why": { "en": "No money is spent without the manager knowing about it.", "tr": "Yöneticinin haberi olmadan harcama yapılmasın diye." },
|
|
117
|
+
"example": { "en": "Ayşe's manager Mehmet sees her 25,000 TL laptop request in his inbox and approves it the same day.", "tr": "Ayşe'nin yöneticisi Mehmet, 25.000 TL'lik dizüstü talebini kutusunda görür ve aynı gün onaylar." }
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Düğümler
|
|
122
|
+
|
|
123
|
+
Her türün alanları ve örneği: `process_step_schema(type)`. Özet:
|
|
124
|
+
|
|
125
|
+
**start** — `trigger: row-event | manual | api | schedule | sub-process | message | signal`, `entity`, `operation`,
|
|
126
|
+
`condition`. `row-event` bağlıdır (ölçüldü 2026-09-18): aktif sürümün konu entity'sine
|
|
127
|
+
(`subject.entity`; start düğümündeki `entity` eşleşmeye BAKILMAZ) ilk start düğümünün `operation`'ı
|
|
128
|
+
(boşsa `create`; `delete` hiç başlatmaz) yazılıp `condition` sağlanınca örnek kendiliğinden açılır —
|
|
129
|
+
yetki denetimi bastırılır, başlatan satırı yazan kullanıcıdır. Yayından önce yazılmış satırlar
|
|
130
|
+
başlatmaz. Aynı olaya workflow `process` adımıyla ikinci başlatma eklemeyin — iki örnek açılır.
|
|
131
|
+
Kendiliğinden başlatan yalnız `row-event` ve `message`tır; `manual`, `api`, `schedule`, `sub-process` ve
|
|
132
|
+
`signal` belgeleyicidir — örnek açık bir başlatmayla açılır (`process_execute`, uygulamanın Süreçler sayfası,
|
|
133
|
+
`Page.bpm.start`, üst sürecin `sub-process` düğümü, bitiş düğümünün `schedule`'ı). Sinyal bugün yalnız bekleyen
|
|
134
|
+
örneği ilerletir, yeni örnek açmaz.
|
|
135
|
+
|
|
136
|
+
**user-task** — insan görevi. `assignee` zorunlu. `mode: claim` (varsayılan) adaylardan birinin
|
|
137
|
+
üstlenmesini bekler; `mode: individual` her kişiye ayrı görev açar ve `join: all | any | force-complete`
|
|
138
|
+
ile birleşir. `actions[]` özel eylemler: `completes: true` görevi bitirir (`evidence: read-proof`
|
|
139
|
+
defterde okuma kanıtı bırakır), `completes: false` görevi açık bırakıp `emits: signal:<ad>` yayar.
|
|
140
|
+
`completeOn { trigger: row-event, operation: update, condition }` görevi satır değişince bitirir.
|
|
141
|
+
`requestInfo: true` başlatandan bilgi isteme; `allowReassign`, `external: true` (dış kullanıcı görevi,
|
|
142
|
+
yalnız atanan görür), `revisionBound: true` (bölge yeniden başlarsa eski görev `superseded`),
|
|
143
|
+
`undoWindow: "PT5M"` (karar geri alma). Tamamlanan görevin sonucu
|
|
144
|
+
`vars.tasks.<resultKey>` altına `{ outcome, action, completedBy, payload }` olarak yazılır.
|
|
145
|
+
`resultKey` yoksa anahtar id'nin snake_case hâlidir (`teslimat-kontrol` → `vars.tasks.teslimat_kontrol`);
|
|
146
|
+
eski ifadeler bozulmasın diye sonuç kebab-case id altına da yazılır, ama ifadeyi hep snake_case
|
|
147
|
+
ve noktayla yazın — slug değil, `vars.tasks?.['teslimat-kontrol']` gibi köşeli parantezli kebab değil. **Süreç kurarken her `user-task` ve `approval` düğümüne snake_case bir
|
|
148
|
+
`resultKey` verin** — id kebab-case kalır: `{ "id": "teslimat-kontrol", "resultKey": "teslimat_kontrol" }`
|
|
149
|
+
ve geçitte `vars.tasks.teslimat_kontrol.action === 'sorunlu'`. Ad harf, rakam ve `_`'dır; tire yok,
|
|
150
|
+
aynı tipte benzersiz (başka adımın id'si ve snake_case'i de dolu sayılır). Yazılmamış bir adı okumak
|
|
151
|
+
(`vars.tasks.teslimatKontrol` — camelCase, ne ad ne id) `undefined` verir ve geçit hiç o dala gitmez.
|
|
152
|
+
|
|
153
|
+
**approval** — onay görevi + politika:
|
|
154
|
+
`policy: sequential | all | any | quorum(n) | majority | weighted(0.6)`,
|
|
155
|
+
`rejectPolicy: any-reject | quorum(n) | majority`, `onReject: end | back-to:<düğüm> | restart`,
|
|
156
|
+
`commentRequired: true | "outcome === 'rejected'"`, `selfApproval: escalate | skip | allow`,
|
|
157
|
+
`weights: { "position:P-SATIS": 2, "role:yk-baskani": 3 }`, `veto: ["user:…"]`, `abstain: true`,
|
|
158
|
+
`countAs: "vars.onaySayisi"`. `sequential` sonraki halkayı **karar anında** çözer (geç bağlama).
|
|
159
|
+
`rejectPolicy` yazılmazsa: sequential/all ilk retle, any herkes reddedince, quorum/majority eşiğe
|
|
160
|
+
ulaşılamaz olunca reddeder. Karar `vars.approvals.<resultKey>` altına yazılır; `resultKey` yoksa
|
|
161
|
+
anahtar id'nin snake_case hâlidir (`grup-onayi` → `vars.approvals.grup_onayi`; kebab-case id altına
|
|
162
|
+
da yazılır) — yine de açık bir snake_case ad verin (`"resultKey": "grup_onayi"`).
|
|
163
|
+
**`back-to:` bir SIÇRAMADIR ve düğümün `writeBack`'ini ÇALIŞTIRMAZ** (yalnız onaylanan dal ve bitiş
|
|
164
|
+
düğümü geri yazar). "Ret satıra durum yazsın" isteyen tasarım, ret hedefini geri yazmayı yapan bir
|
|
165
|
+
`script` düğümü yapar ve oradan asıl hedefe bir kenar çeker (ölçüldü 2026-09-21, S-6 CAPA).
|
|
166
|
+
|
|
167
|
+
**service** — workflow çağrısı: `workflowId` (zorunlu; yalnız `workflowSlug` yazılan düğüm önizlemede ve yayında
|
|
168
|
+
`DefinitionInvalid` alır — slug değişebilir, bağ kimlikle tutulur; yanıt ikisini birlikte döner), `input: { ad: "<Jint>" }`, `output: "vars.x"`,
|
|
169
|
+
`retry: { count }`. Başarısızlık `retry.count` (varsayılan 3) sonra örneği `faulted` yapar.
|
|
170
|
+
`runAs: system` gerekçesi `caution`'da durur (BPM-005). `input` anahtarları workflow'un **parametre DTO
|
|
171
|
+
alanlarının `slug`'larıdır** (`dto_get` → `children[].slug`); platform onları alan kimliğine bağlar. DTO'da
|
|
172
|
+
olmayan anahtar kayıtta, önizlemede ve yayında `ServiceInputUnknown` verir (mesaj geçerli parametreleri sayar).
|
|
173
|
+
DTO alanı yeniden adlandırılınca tanım yeni adı gösterir, yayındaki sürüm de doğru anahtarla çağırır. Süreçte
|
|
174
|
+
kullanılan alan `dto_update` ile silinemez (422 `ReferencedByProcess`). Parametre DTO'su olmayan workflow'un
|
|
175
|
+
girdisi denetlenmez. Workflow gövdesindeki `input.x` adları elle güncellenir.
|
|
176
|
+
|
|
177
|
+
**notify** — `to` (atama sözlüğü), `channels: ["inbox", "email"]`, `template { subject, body }`
|
|
178
|
+
(`{{row.baslik}}`), `ackRequired`. Kutu bildirimi satırı aynı transaction'da yazılır.
|
|
179
|
+
|
|
180
|
+
**gateway** — `kind: exclusive` (ilk doğru kenar, yoksa `default`), `parallel` (çatallanır;
|
|
181
|
+
birleşmede gelen kenar sayısı kadar varış bekler), `inclusive` (koşulu tutan **her** kenar, hiçbiri
|
|
182
|
+
tutmazsa `default`; birleşmede o gateway'e hâlâ ulaşabilecek token kalmayınca devam eder) ya da
|
|
183
|
+
`event-based` (yalnız `wait`/`timer` düğümlerine gider; ilk gelen olay kazanır, diğer bekleyişler
|
|
184
|
+
iptal edilir, defterde `event-gateway-resolved`).
|
|
185
|
+
|
|
186
|
+
**timer** — `duration` (ISO) ya da `until` (Jint). `duration` **düz metindir, ifade
|
|
187
|
+
değerlendirilmez**; beklemeyi bir parametreye bağlamanın tek yolu `until`'dır
|
|
188
|
+
(`until: "new Date(Date.now() + vars.beklemeGunu * 86400000).toISOString()"`). **wait** — `message { name, correlationKey }` +
|
|
189
|
+
`output: "vars.x"` (mesaj gövdesi), `signal: "<ad>"` (`process_trigger kind signal` ile gelir) ya da
|
|
190
|
+
`link: "<ad>"` (yakalama noktası; gelen kenarı olmaz).
|
|
191
|
+
|
|
192
|
+
**send** — `message { name, correlationKey: "<Jint>" }` + `input` (gövde) mesajı kuyruktan atar;
|
|
193
|
+
alıcı yoksa `timeout: "PT10M"` (en çok `P1D`) boyunca tamponda bekler ve sonra açılan `wait` hemen
|
|
194
|
+
tüketir. `link: "<ad>"` verilirse aynı kapsamdaki `wait { link }` düğümüne sıçrar. BPMN karşılığı
|
|
195
|
+
*intermediate throw event*'tir (message ya da link) — bildirim değildir ve **e-posta göndermez**; mesaj kuyruktan
|
|
196
|
+
aynı adla bekleyen `wait`'e ya da mesajla başlayan sürece gider, e-posta `notify { channels: ["email"] }` işidir.
|
|
197
|
+
Studio adımı kipine göre adlandırır: `message` → **Mesaj gönder** (sinyal anteni), `link` → **Bağlantıya atla** (ok); yakalayan
|
|
198
|
+
`wait { link }` → **Bağlantı noktası** (ok); palette kutucuğu **Mesaj**. Kullanıcıya bu adlarla anlat.
|
|
199
|
+
**manual** — sistem dışı iş; görev satırı açmaz, `process_instance_update { operation: skip }` ile geçilir.
|
|
200
|
+
Süre dolunca: `sla[]` ya da `deadline` (Jint tarih) ile `skipOnDeadline: true` adımı geçer, `onTimeout: "end:<sonuç>"`
|
|
201
|
+
örneği o sonuçla bitirir; ikisi de yoksa adım yöneticiyi bekler.
|
|
202
|
+
**script** — `code` Jint (2 sn, dosya/HTTP/CLR yok); `vars.x = …` yazar, son ifade `output` yoluna. Globaller
|
|
203
|
+
`vars`, `row`, `previousRow`, `initiator`.
|
|
204
|
+
**case** — `caseSlug` (aktif sürümü olan vaka tanımı; yayında denetlenir, yoksa `CaseUnknown`),
|
|
205
|
+
`input { vakaDosyasıÖğesi: "<Jint>" }` (tanımsız öğe düşer), `output: "vars.x"` (vaka kimliği). Vakayı iş satırı
|
|
206
|
+
üzerinde, örneği başlatan adına açar ve **beklemez**; defterde `case-started`.
|
|
207
|
+
**document** — şablondan belge üretir ve beklemez; alanları § Bağlayıcı ve belge'de. `output` → `{ fileId, name }`.
|
|
208
|
+
|
|
209
|
+
**sub-process** — ayrı örnek başlatır ve bekler: `processSlug`, `subject { rowId: "<Jint>" }` (farklı iş
|
|
210
|
+
nesnesi), `input`, `output`, `binding: latest (varsayılan) | deployed | v:<n>` (`latest` ve `deployed` bugün ikisi de
|
|
211
|
+
aktif sürümü okur; sabitlemek için `v:<n>`), `forEach { entity, where: "item.aktif === true",
|
|
212
|
+
batch }` (partili başlatma, hepsi bitince devam). Alt örnek kuyruktan başlar; üst örnek
|
|
213
|
+
`sub-process-completed` ile ilerler.
|
|
214
|
+
`v:<n>` yayında **o sürümün kimliğine** bağlanır; numara ortamın yerel sayacıdır ve merge/promote
|
|
215
|
+
ara sürümleri taşımaz. Aktarım bağı hedefte **aynı içerikli** sürüme yeniden yazar (numara değişebilir,
|
|
216
|
+
ör. development `v:3` → production `v:2`); hedefte o içerik yoksa promote 422
|
|
217
|
+
`SubProcessBindingNotCarried` ile durur — önce çağrılan sürümü taşıyın ya da bağı değiştirin.
|
|
218
|
+
|
|
219
|
+
**region** — uyarlanabilir blok ve olay kapsamı: `nodes`, `edges`, `limits { maxSteps, nodeTypes,
|
|
220
|
+
assigneeRules }`, `on[]`. Girişler iç kenarlarda hedef olmayan düğümlerdir; iç tokenlar bitince dış
|
|
221
|
+
kenardan devam eder.
|
|
222
|
+
|
|
223
|
+
**end** — `outcome`, `writeBack`, `reopenWindow: "P30D"`. Bölge içindeki `end` yalnız o kolu kapatır.
|
|
224
|
+
`kind: terminate` bütün dalları iptal eder, `onCancel` workflow'unu koşar ve `terminated` sonucuyla
|
|
225
|
+
biter (bölge içinde yalnız o bölgeyi kapatır). `kind: error` + `code` en yakın bölgenin
|
|
226
|
+
`on: [{ event: "error:<code>", afterHandlers: "exit-region:<hedef>" }]` işleyicisine sıçrar; yoksa süreç
|
|
227
|
+
`error:<code>` sonucuyla biter ve üst sürecin `sub-process` düğümündeki aynı biçimli `on[]` yakalar
|
|
228
|
+
(yakalamazsa üst örnek `faulted`).
|
|
229
|
+
|
|
230
|
+
`writeBack { alan: "<Jint>" }` her düğümde düğüm çıkışında iş satırına yazar; satır otomasyonları bu
|
|
231
|
+
yazmada tetiklenmez (sonsuz döngü koruması).
|
|
232
|
+
|
|
233
|
+
## Atama sözlüğü
|
|
234
|
+
|
|
235
|
+
`assignee` nesnesi `{ rule, arg, of, unit, fallback, selfApproval, dedupe, sod, expand, items }` ya da
|
|
236
|
+
kısa biçim `"rule:arg of <referans>@unit:<kod>"`. Referans (`of`): `initiator` (varsayılan),
|
|
237
|
+
`subject-field:<alan>`, `user:<id>`, `vars.<yol>`.
|
|
238
|
+
|
|
239
|
+
| Kural | Çözüm |
|
|
240
|
+
|---|---|
|
|
241
|
+
| `initiator` | başlatan |
|
|
242
|
+
| `subject-field:<alan>` | iş satırındaki kullanıcı id'si |
|
|
243
|
+
| `user:<id>` | sabit kişi |
|
|
244
|
+
| `unit-manager` | referansın birincil pozisyonunun birimi → `manager_position_id` → aktif sahip (vekil `acting` önce). Referans birimin yöneticisiyse bir üst birimin yöneticisi. Pozisyon boşsa üst birime tırmanır (`source: escalation`) |
|
|
245
|
+
| `parent-unit-manager` | birincil birimin üst biriminin yöneticisi |
|
|
246
|
+
| `ancestor-manager:<tip>` | en yakın ata birim; `unit_type`, `function_code` ya da `code` eşleşir (`mudurluk`) |
|
|
247
|
+
| `chain:<n>` · `chain:{{vars.seviye}}` | referanstan yukarı n yönetici, sıralı; `dedupe: true` aynı kişiyi atlar |
|
|
248
|
+
| `role:<slug>` | rol adayı + rolün pozisyon sahipleri ve kullanıcıları; `mode: claim` ile grup görevi |
|
|
249
|
+
| `unit-members:<kod>` | birimin (`includeDescendants`) pozisyon sahipleri; aday grup |
|
|
250
|
+
| `position:<kod>` | pozisyonun aktif sahibi; boşsa üst pozisyon (`strategy: functional` işlevsel hat) |
|
|
251
|
+
| `list` | `items[]` ya da `of` — **`of` burada REFERANS DEĞİL Jint İFADESİDİR** (`vars.liste`, `row.birimler.split(",")`); `subject-field:x` yazmak motoru 500 JavaScriptException ile düşürür. Değerler `["user:…", "unit:satis", "position:P-X", "role:…"]`, `expand: members` |
|
|
252
|
+
| `expression` | Jint → id ya da id dizisi (sıra korunur) |
|
|
253
|
+
| `previous-approver-manager` | Görev sayacının ihlalinde (`onBreach`) atanmış görevin asıl sahibinin yöneticisi — zincirde bir üst halka, kökte `admin-queue`; düğüm/süreç sayacında, grup görevinde ve ihlal dışında son onaylayanın yöneticisi |
|
|
254
|
+
| `chain-until-authority` | `{ rule: 'chain', arg: 'until-authority', category, amount: 'vars.tutar' }` — yukarı yönetici zinciri, limiti (`process_authority_limit_*`; pozisyon limiti kişiyi ezer) tutarı karşılayan ilk halkada durur; hiçbiri yetmezse tüm zincir + uyarı |
|
|
255
|
+
| `partner:<kod>` | kabul edilmiş partner ilişkisinin (Organization.API `organizations/{id}/partners`) karşı kurumu aday olur (`candidates: partner`); ilişki etkin değilse ya da süreç izinli listede yoksa çözülmez (fallback). Doğrulama `PartnerUnknown`; partner kullanıcısının görevi açması henüz yok |
|
|
256
|
+
| `pool:<kod>` | havuz (`process_pool_*`) stratejisi: `round-robin` · `least-loaded` (açık görev / haftalık kapasite — saat, yalnız ağırlık: 20 saatlik kişi 40 saatlik kişinin yarısı kadar iş alır) · `skill-match` (`skills: ["vars.dil"]` + havuz becerileri) · `manual` (havuzda bekler). İş yükü kaydında `maxOpenTasks` doluysa açık görevi o sayıya ulaşan kişi manual dışı stratejilerde seçilmez; boşsa tavan yoktur. Havuzu kullanan süreçler `process_pool_list` çıktısında `usedBy`; kullanılan havuz silinemez (`process_pool_update { id, remove: true }` → 422 `ReferencedByProcess`) |
|
|
257
|
+
|
|
258
|
+
Çözüm sırası: strateji → SoD (`not-initiator`) → `selfApproval` → pasif kullanıcı süzgeci (kullanıcı
|
|
259
|
+
tablosunda olmayan kişi seçilmez; bitişi geçmiş pozisyon ataması sayılmaz) → **vekalet** (aktif
|
|
260
|
+
vekaleti olan kişinin yerine vekil; görevde `principalUserId` asıl, zincir izlenmez, SoD vekile de uygulanır) → `dedupe`
|
|
261
|
+
(vekil ikameden SONRA: vekil zincirde zaten varsa tek adım alır — asıl kişinin seviyesi vekilin kararıyla kapanır ve
|
|
262
|
+
zincir bir halka kısalır; `chain:2`'de Murat→Selin vekaletiyle tek karar yeter) → `fallback`
|
|
263
|
+
(`escalate` referansın yöneticisi, `role:<slug>`, varsayılan `admin-queue` havuzu). Kimse çıkmazsa görev
|
|
264
|
+
`admin-queue` havuzuna düşer; süreç yöneticisi görür. Kim çıkacağını yayından önce
|
|
265
|
+
`process_definition_preview(id, subjectRowId)` gösterir.
|
|
266
|
+
|
|
267
|
+
## Yaşam döngüsü ve işletim
|
|
268
|
+
|
|
269
|
+
**SLA ve takvim.** `sla: "PT8H"` ya da `[{ name, duration, calendar, stopOn: state-change, reminders: [0.5], onBreach: [{ notify | escalate | reassign+ | priority }] }]`;
|
|
270
|
+
süreler iş takvimiyle (`process_calendar_*`; kod → birim → `default` → Pzt–Cum 08–18) hesaplanır. Tatil `{ date, name, workEnd }`: `workEnd` yoksa gün tam tatil, varsa yarım gündür ve süre o saate kadar sayılır (arife `workEnd: '13:00'`); `P1D` yarım güne düşer ve saat `workEnd`'i geçerse vade o günün `workEnd`'idir. Kullanılan takvim silinemez (`process_calendar_update { id, remove: true }` → 422); `default` ya da birim takvimi silinince zincirin sonraki halkası kullanılır — yani **`P5D` beş İŞ GÜNÜDÜR**, takvimde 7+ gün eder; senaryoda sayacı ihlal etmek için saati ona göre ilerletin (`{ clock: 'P10D' }`). **Sayaç yalnız `duration` ile kurulur:** `deadline` alanı platformun SLA şemasında YOKTUR (sessizce düşer) ve `duration`suz sayaç 422 `DefinitionInvalid` verir — vadeyi iş satırındaki bir tarihe bağlamanın yolu bugün yok (ölçüldü 2026-09-22, S-9 ECN). Görev `dueAt` ilk sayaçtır; kutu `priority DESC, dueAt ASC` sıralar, görevde `slaRatio`. Son sayaç ihlalinde
|
|
271
|
+
`onTimeout: approve | reject | end:<sonuç>`, `join: force-complete`, alt süreçte `skipOnDeadline`. `reassign+` görevi asıl
|
|
272
|
+
sahibinde bırakıp çözülen kişiyi aday ekler; doğrudan atanmış görevde ilk karar veren kapatır. Devralma yalnız
|
|
273
|
+
`reassign+`'ın eklediği kişiye açıktır — kural adayı, gruptan üstlenilmiş ya da yeniden atanmış görevi devralamaz. Süreç düzeyi `sla`
|
|
274
|
+
ihlali örneği `critical` yapar; `priorityRule` başlangıç önceliği. Askıya alma ve bilgi isteme sayacı durdurur.
|
|
275
|
+
Timer'lar 15 sn'de bir taranır (Tenant.API job'u).
|
|
276
|
+
|
|
277
|
+
**Servis hatası.** Servis düğümü başarısız olursa `retry { count, backoff: fixed | exponential, delay }` timer'la yeniden
|
|
278
|
+
dener; son denemede örnek `faulted`. Müdahale `process_instance_update`: `retry` (yalnız faulted), `skip` / `jump`
|
|
279
|
+
(`reason` zorunlu, defterde kırmızı satır, atlanan görevler iptal). Tanım düzeyi `onCancel` (servis düğümü biçimi:
|
|
280
|
+
`workflowId`/`connector`/`ai`/`externalEngine` ve/veya `writeBack`; yalnız `workflowSlug` canlıda çözülmez) iptalde, geri çekmede ve `terminate` bitişinde telafi koşar; `writeBack` ifadesi
|
|
281
|
+
`cancel.cause`'u (`cancelled` · `withdrawn` · `terminated`) okur — geri çekilen talebin durumunu iş satırına böyle
|
|
282
|
+
yazın: `"onCancel": { "writeBack": { "durum": "cancel.cause === 'withdrawn' ? 'geri-cekildi' : 'iptal'" } }`.
|
|
283
|
+
Terminate bitişinde bu `writeBack` önce, bitiş düğümününki sonra koşar. Telafi başarısızsa örnek kapanmaz, `faulted` kalır.
|
|
284
|
+
|
|
285
|
+
**Vekalet ve devir.** `process_delegation_create { toUserId, startsAt, endsAt, processSlugs, onBehalfOf }` —
|
|
286
|
+
başkası adına açmak birim/üst birim yöneticiliği ya da `process.manage` ister; vekilin kesişen tarih ve süreçte bitmemiş
|
|
287
|
+
vekaleti varsa BPM-008.
|
|
288
|
+
Ayrılan kullanıcı: önce `process_handover_preview(userId)`, sonra `process_handover_create { decisions[], force }`
|
|
289
|
+
(`force`: kararsız assigned-tasks yöneticiye ya da admin-queue'ya, candidate-tasks gruba);
|
|
290
|
+
açık görevi olan birim kapatılamaz (`OpenTasksExist` 422). Yönetici değişince `rebindOnManagerChange: true`
|
|
291
|
+
tanımlarında üstlenilmemiş yönetici görevleri yeni yöneticiye taşınır; üyelik değişince aday görevler yeniden hesaplanır.
|
|
292
|
+
Servis adımı yerine workflow `process` adımı `processOperation: delegate` ile izin süreci vekalet yazar.
|
|
293
|
+
|
|
294
|
+
**Toplu işlem.** `process_batch_execute`: `start` (100.000 satır, arka planda) · `reassign` · `extend-due` · `cancel`
|
|
295
|
+
(en çok 500 görev) → `process_batch_get`; `process_batch_update { operation: undo }` yalnız reassign/extend-due.
|
|
296
|
+
|
|
297
|
+
**Bildirim.** Bildirimler outbox'tan (15 sn) kanallara gider: `inbox` (hub `/hubs/process-notifications`),
|
|
298
|
+
`socket` (`task-changed`), `email`; kanal hatasında 1/5/25/125 dk sonra yeniden, 5 denemede bırakılır. Aynı
|
|
299
|
+
`dedupeKey` ile okunmamış bildirim tazelenir. Tercih `process_preference_update` (`immediate | digest | sla-only`,
|
|
300
|
+
sessiz saat, özet saati). `process_instance_update { operation: watch }` karar/kapanış bildirimlerini izletir;
|
|
301
|
+
görev yorumunda `@<kullanıcı-id>` bahsetme bildirimi üretir.
|
|
302
|
+
|
|
303
|
+
**Tetikleyiciler.** `process_trigger { kind: message, name, correlationKey }` bekleyen `wait` düğümünü ilerletir ya da
|
|
304
|
+
mesaj başlangıçlı tanımı başlatır; anahtarsız mesaj yalnız anahtarsız bekleyen örneklere gider ve `broadcast: true` ister.
|
|
305
|
+
Dış sistemden gelen webhook `POST bpm/webhooks/{slug}`: `X-Zeyrek-Signature: sha256=HMAC(sır, "{timestamp}.{slug}.{gövde}")`,
|
|
306
|
+
`X-Zeyrek-Timestamp` (±300 sn) ve `X-Zeyrek-Delivery` zorunlu; sır proje + ortam + slug başına türetilir ve
|
|
307
|
+
`GET bpm/webhooks/{slug}/secret` (`process.manage`) ile alınır. Giden olaylar için `process_webhook_subscription_create` (HMAC imzalı CloudEvents).
|
|
308
|
+
|
|
309
|
+
## Bölge olayları
|
|
310
|
+
|
|
311
|
+
```jsonc
|
|
312
|
+
"on": [ { "event": "signal:duzenleme-istegi", // signal:<ad> | membership-added | subject-changed
|
|
313
|
+
"interrupt": false, // true: bölge tokenları ve görevleri askıya alınır
|
|
314
|
+
"handler": { "type": "sub-process", "processSlug": "dokuman-duzenleme", "input": { "istek": "event.form" } },
|
|
315
|
+
"afterHandlers": "restart-region", // continue | restart-region | exit-region:<düğüm> | append
|
|
316
|
+
"restartWhen": "no-open-handlers", // | each
|
|
317
|
+
"restartIf": "handler.outcome === 'approved'",
|
|
318
|
+
"restartScope": "all", // | pending-only
|
|
319
|
+
"cancelStale": "superseded" } ] // | cancelled
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
- Olay en içteki açık bölgenin `on[]` listesinde aranır, yoksa `process.on[]`'da.
|
|
323
|
+
- `handler.type`: `sub-process` (kuyruktan başlar, sayaç artar), `notify` (hemen), `append-task`
|
|
324
|
+
(bölgenin bekleyen bireysel görevine olaydaki kişi için tek görev ekler — `membership-added` ile).
|
|
325
|
+
- `restart-region`: revizyon artar, açık görevler `cancelStale` ile kapanır, liste yeniden açılır;
|
|
326
|
+
tamamlanmış görevler ve `read-proof` satırları kanıt olarak kalır. Üç düzenleme isteği gelse de
|
|
327
|
+
`no-open-handlers` ile tek yeniden başlatma olur; reddedilen istek (`restartIf` yanlış) başlatmaz.
|
|
328
|
+
- Olay tetiklemek: görevin `completes: false` eylemi (`emits`) ya da `POST bpm/signals
|
|
329
|
+
{ instanceId, name, payload }`. `withdraw` ve `reopen` adları yerleşiktir.
|
|
330
|
+
|
|
331
|
+
## Uyarlama
|
|
332
|
+
|
|
333
|
+
`editable` dereceleri: `locked` (varsayılan), `params` (`editableParams` listesindeki alanlar),
|
|
334
|
+
`open` (yalnız `region` — BPM-003). `open` bölgede eklenen düğümün atama kuralı
|
|
335
|
+
`limits.assigneeRules` içinden seçilir (BPM-004, platform 422 `RuleNotAllowed`), düğüm türü
|
|
336
|
+
`limits.nodeTypes`, adım sayısı `limits.maxSteps` ile sınırlıdır. Tanım yazarken dereceyi bilinçli
|
|
337
|
+
seçin — dışarıdan değişmesi riskli adımı `locked` bırakın.
|
|
338
|
+
|
|
339
|
+
**Uyarlama katmanı.** Uygulama yöneticisi aktif sürümün üstüne ortam başına bir JSON Patch yazar
|
|
340
|
+
(tenant iş verisi; deployment ile taşınmaz). Okuma `process_override_get` (`editableScopes` hangi
|
|
341
|
+
düğümün hangi derecede açık olduğunu, `outline` etkin tanımı gösterir; `view: 'studio'` salt okunur).
|
|
342
|
+
Uygulama ekranı aynısını `process.override.*` sistem işlemleriyle yapar; `process.manage` ister, modül kurulumu vermez.
|
|
343
|
+
Yazma `process_override_update` — yönetici adına (BPM-013; Studio jetonu 403): development'ta parolasız `asUserId` (users satır id'si) ya da `asUser` (uygulama jetonu):
|
|
344
|
+
|
|
345
|
+
| Yol | İzin |
|
|
346
|
+
|---|---|
|
|
347
|
+
| `/params/<ad>/default` | parametre `editable: params` ya da `open` ise |
|
|
348
|
+
| `/nodes[id=<düğüm>]/<alan>` (üst düzey) · `/nodes[id=<bölge>]/nodes[id=<adım>]/<alan>` (bölge çocuğu — seçici yalnız doğrudan çocukları bulur) | düğüm `params` ise yalnız `editableParams`; açık bölgenin derecesiz çocuğunda her alan. `id/type/editable/editableParams/limits`, `nodes` ve `edges` `editableParams`'ta yazsa da kilitli |
|
|
349
|
+
| `/nodes[id=<bölge>]/nodes/-` (add) | bölge `open`; eklenen adım `editable`, `editableParams`, `limits`, `nodes` taşımaz, `region` değildir |
|
|
350
|
+
| `/nodes[id=<bölge>]/nodes[id=<adım>]` | bölge `open` ve adımın kendi derecesi yok: `remove` ya da aynı `id`/`type` ile düz adım `replace` |
|
|
351
|
+
| `/nodes[id=<bölge>]/edges…` | bölge `open` |
|
|
352
|
+
| `move` · `copy`, bölgenin bütün `nodes` dizisi, diğer her yol | kilitli (BPM-010, 422 `RegionLocked` / `ParamNotEditable`) |
|
|
353
|
+
|
|
354
|
+
Gateway yazmadan önce patch'i temel modele uygular ve istek gitmeden durdurur: kilitli yol BPM-010,
|
|
355
|
+
bölgenin izin vermediği atama kuralı BPM-011 (liste atamasında kalemlerin kuralı), adım sayısı ya da düğüm türü sınırı BPM-012; bilinçli istisnada `policyOverride: true`. Platform ayrıca etkin tanımın referanslarını denetler (`RoleUnknown`, `WorkflowUnknown`).
|
|
356
|
+
`mode: 'append'` (varsayılan) mevcut uyarlamanın sonuna ekler; iyimser kilit aktif sürüm +
|
|
357
|
+
`overrideRevision`'dır (409 → `process_override_get`).
|
|
358
|
+
|
|
359
|
+
**Yeni örnek, açık örnek.** Kayıttan sonra başlayan örnek uyarlamayla koşar; açık örnek eski
|
|
360
|
+
zincirle biter. `operation: 'migrate-open'` açık örnekleri güncel uyarlamaya bağlar — açık düğümü
|
|
361
|
+
(ya da açık bölgesi) etkin tanımda olmayan örnek atlanır ve `skipped` listesinde döner.
|
|
362
|
+
`operation: 'reset'` varsayılana döner (yeni örnekler için).
|
|
363
|
+
|
|
364
|
+
**Yeni sürüm yayını (üç yönlü birleştirme).** Geliştirici yeni sürüm yayınlayınca uyarlama yeni modele
|
|
365
|
+
yeniden uygulanır: tüm yollar hâlâ izinliyse yeni revizyon açılır; bölge kaldırıldıysa ya da
|
|
366
|
+
kilitlendiyse uyarlama `conflictState: conflicted` olur, `conflictDetail` hangi yolun neden
|
|
367
|
+
düştüğünü söyler, tanım sahibine ve uyarlamayı yazana gelen kutusu bildirimi gider ve yeni örnekler
|
|
368
|
+
varsayılanla başlar — sessiz ezme yoktur. Çözüm: `process_override_get` → patch'i yeni sürüme göre
|
|
369
|
+
kurup `mode: 'replace'` ile yazın. `process_definition_preview(id)` kuru koşusu kayıtlı uyarlamayı içerir.
|
|
370
|
+
|
|
371
|
+
## Yürütme ve kutu
|
|
372
|
+
|
|
373
|
+
- Süreç sayfaları hazır gelir: projede ilk tanım (create, BPMN içe aktarma, klon) `bpm-management`
|
|
374
|
+
sistem şablonunu tanımın uygulamasına öneksiz kurar (sayfa slug'ı doluysa kurmaz) — `gorevlerim`, `gorev-detayi` (`?task=` /
|
|
375
|
+
`?instance=`), `surecler`, `surec-izleme`, `vekaletler`, `bildirimler`. Kompleks projede sayfalar
|
|
376
|
+
**Yetki kabuğuna** bağlanır ve `MENÜ` / `YÖNETİM` grupları Yetki kabuğu menüsüne eklenir (ikinci layout
|
|
377
|
+
doğmaz); Yetki kabuğu olmayan uygulamada kendi `Süreç kabuğu` layout'uyla gelir.
|
|
378
|
+
Proje başına bir kez kurulur, production'a dağıtılmaz. Sayfalar süreçten bağımsızdır (ad, form alanı,
|
|
379
|
+
özel eylem sunucudan gelir): yeni süreç ya da sürüm için sayfa YAZMAYIN, önce `page_list`.
|
|
380
|
+
- Başlatma: `process_execute { slug, subjectRowId, vars, asUser }` (REST `POST bpm/processes/{slug}/start`)
|
|
381
|
+
→ yeni örnek; tekil (`singleton`) tanımda aynı satırda açık örnek varsa mevcut örnek döner. Yetki
|
|
382
|
+
`process.start` (`process:<tanımId>`). production'a yürütme yok (BPM-001).
|
|
383
|
+
- Örnek: `process_instance_get { id, view: 'timeline' }` (defter, güncel ve sonraki düğümler,
|
|
384
|
+
`isLedgerValid`); `process_instance_list`; müdahale `process_instance_update { operation: cancel |
|
|
385
|
+
suspend (reason zorunlu) | resume | withdraw (withdrawPolicy) | reopen (reopenWindow içinde) }`.
|
|
386
|
+
- Olay: `process_trigger { instanceId, name, payload, eventId }` — bölge işleyicisi, `completeOn`,
|
|
387
|
+
`membership-added`.
|
|
388
|
+
- Kutu: `process_task_list { tab: mine | group | delegated | started | done | all, asUser }`.
|
|
389
|
+
Görünürlük: atanan, aday (rol/birim/pozisyon/kişi), başlatan; `all` sekmesi `process.view-all` ya da
|
|
390
|
+
`process.manage` ister. `process_task_get` eylem listesini ve `version`'ı verir.
|
|
391
|
+
- Görev eylemleri tek kapıdan: `process_task_update { action, actionId, payload, comment, version,
|
|
392
|
+
asUser }` — `claim` (sürüm denetimli; ikinci üstlenme 409 `TaskAlreadyClaimed`, bayat `version` 409 `AggregateVersionConflictException` — ikisinde de görevi yeniden okuyun),
|
|
393
|
+
`unclaim`, `complete` (özel eylem `actionId`), `approve`, `reject`, `request-info { question }` →
|
|
394
|
+
başlatana `provide-info` görevi, `provide-info { answer }`, `reassign { targetUserId, reason }`, `undo`.
|
|
395
|
+
kimlik zorunludur (BPM-006): development'ta parolasız `asUserId` — `/bpm/*` uçları platform şemasıyla `[Authorize]` edildiği için uygulama jetonu orada 401 alır — ya da `asUser`; yetki `task.complete` (`task:<tanımId>`); Studio jetonu görev eylemi
|
|
396
|
+
yapamaz.
|
|
397
|
+
- Görev durumları: `open`, `claimed`, `waiting-info`, `suspended`, `unassigned`, `completed`,
|
|
398
|
+
`superseded`, `cancelled`, `expired`.
|
|
399
|
+
- E-postadan karar: `emailActions: true` süreçte atanan kişiye onay/ret bağlantısı üretilir; bağlantı
|
|
400
|
+
tek kullanımlıktır, 72 saat geçerlidir, ikinci kullanım 410 döner.
|
|
401
|
+
- Sayfadan: süreç çalışma zamanına **sistem mikroservisiyle** gidilir (BPM-022, warn).
|
|
402
|
+
`microservice_system_operation_list` `process.*` işlemlerini verir — kutu `process.task.list`, görev
|
|
403
|
+
`process.task.get/claim/unclaim/complete/request-info/provide-info/reassign/sign/assessment.start`, örnek
|
|
404
|
+
`process.instance.*`, `process.batch.*`, `process.delegation.*`, `process.handover.*`,
|
|
405
|
+
`process.notification(-preference).*`, `process.report.get`, uyarlama `process.override.*`, seçici listeleri
|
|
406
|
+
`process.definition.list/user.list/directory.get`. `microservice_create { source: 'system', systemOperation }`
|
|
407
|
+
ucu kurar; akışta `microservice` adımı çağırır, sonraki `code` adımı `Steps.<adım>.data`'yı okur, hatada
|
|
408
|
+
`Steps.<adım>.error` doludur (`Conflict`, gövde `.data`'da). Hata dalı kurmayın: ilk hatada akışı keser;
|
|
409
|
+
kayıt başına çağrı `condition` → `microservice` → `code` çevrimiyle yazılır. Yanıt REST `bpm/*` ile aynı alan
|
|
410
|
+
adlarındadır, listeler düz dizidir (`meta` yok). İzin boş işlemde kararı servis verir, `process.override.*`
|
|
411
|
+
`process.manage` ister. Hazır süreç sayfaları (`bpm-management` 1.1.0) bu desenle kuruludur; yeni ekran onların
|
|
412
|
+
akışını örnek alır.
|
|
413
|
+
- Sistem işlemi olmayan işler eski yolda kalır ve BPM-022 onlarda uyarmaz: başlatma **Süreç** adımıyla
|
|
414
|
+
(`type: 'bpm'`; argüman `value` sütununda JSON METNİ — `args: { value: '{"operation":"start","processSlug":"satin-alma","subjectRowId":"Page.queryParams.id"}' }`,
|
|
415
|
+
düz `args.operation` DÜŞER; hata `fail` dalına) ya da `Page.bpm.start(slug, { subjectRowId, vars })`; vaka
|
|
416
|
+
`Page.bpm.cases.*`, belge `documents.print/generate`, `analytics`, `exportLog`, çevrimdışı kuyruk `offline.*`.
|
|
417
|
+
`start` slug tek uygulamadaysa tanımı bulur, iki uygulamada varsa `applicationId` ister. Sinyal adı
|
|
418
|
+
`signal:<ad>`; `completeOn` bekleyen görev yalnız `completeOn.trigger` adındaki sinyalle kapanır.
|
|
419
|
+
|
|
420
|
+
## Simülasyon ve test
|
|
421
|
+
|
|
422
|
+
`process_definition_preview` **yan etkisizdir**: transaction açmaz, satır/görev/bildirim yazmaz.
|
|
423
|
+
|
|
424
|
+
- `definition` ile: platform doğrulayıcısı — bulgular `{ code, path, message }` (`path`:
|
|
425
|
+
`/nodes[id=onay]/assignee`).
|
|
426
|
+
- `id` ile: doğrulama + kuru koşu. Kuru koşu başlangıçtan yürür; exclusive gateway `vars` ile karar
|
|
427
|
+
verir, paralel dallar ve bölge girişleri açılır, her `user-task`/`approval`/`notify` için atanan
|
|
428
|
+
kişiler (ad soyad) ve adaylar döner. `vars` servis çıktılarını taklit eder (`{ "seviye": 3 }`);
|
|
429
|
+
servis düğümü çalıştırılmaz. `send { link }` motor gibi yakalayan `wait { link }`'e sıçrar (not
|
|
430
|
+
`→ <id>`). Kuru koşu her adımı bir kez yürür: geri dönen bir döngü (düzeltme → yeniden kontrol) tekrar
|
|
431
|
+
yürünmez, dönülen adım rotanın sonunda `walked before; the dry run does not repeat it` notuyla yer alır.
|
|
432
|
+
|
|
433
|
+
Yayından önce: `findings` boş, `steps` beklenen kişileri gösteriyor, her `back-to:` hedefi mevcut.
|
|
434
|
+
|
|
435
|
+
### Senaryo test paketi
|
|
436
|
+
|
|
437
|
+
Kuru koşu "kim yapar"ı söyler; **senaryo** bütün yolu gerçek motorla oynatır ve beklenenle karşılaştırır.
|
|
438
|
+
|
|
439
|
+
- `process_scenario_create { fromInstanceId, name }` gerçek örneğin defterinden kaydeder: insan kararları,
|
|
440
|
+
zaman atlamaları, sinyal/mesaj/alt süreç sonuçları adım; servis çıktıları `stubs`; girilen düğümler,
|
|
441
|
+
atananlar, sonuç beklenen olur. Elle: `{ definitionId, name, given, stubs, steps, expect }`.
|
|
442
|
+
- Adım başına **tek eylem**: `{ task: 'onay', as: 'user:<id>', action: 'approve' | 'reject' | 'complete', form }`
|
|
443
|
+
(görev verisi `form`'dadır, `payload` görev adımında okunmaz) · `action: 'sign'` — `signature` taşıyan düğümde
|
|
444
|
+
**zorunludur**: `approve`/`complete` adımı canlı uçtaki gibi 422 `SignatureRequired` alır ve senaryo kırmızı düşer
|
|
445
|
+
(ret ve çekimser imzasız geçer). Senaryo parola istemez ve `SignatureRecord` yazmaz; defterine düğümün
|
|
446
|
+
`meaning`/`level`'ıyla bir `TaskSigned` satırı düşer (ölçüldü 2026-09-22, S-7 sözleşme) ·
|
|
447
|
+
`action: 'request-info'` (`comment` soru; görev
|
|
448
|
+
`waiting-info`, SLA durur) ve başlatanın `action: 'provide-info'` (`comment` yanıt; aynı görev yeniden açılır) ·
|
|
449
|
+
`{ clock: 'P3D' }` (vadesi gelen zamanlayıcılar sırayla ateşlenir, sonrakiler senaryo saatinden kurulur) ·
|
|
450
|
+
`{ signal }` (`{ signal: 'withdraw', as: 'user:<başlatan>' }` `withdrawPolicy`'ye göre geri çeker) ·
|
|
451
|
+
`{ message, correlationKey }` · `{ subProcess: '<düğüm>', outcome }` (çocuk örnek açılmaz).
|
|
452
|
+
- `expect`: `path` (girilen düğüm dizisi birebir), `assignees` (düğüm → kullanıcılar, alt küme), `outcome`,
|
|
453
|
+
`state`, `vars` (nokta yolu), `writeBack`. Yazılmayan alan denetlenmez.
|
|
454
|
+
- `process_scenario_execute { definitionId | id, version? }` yan etkisizdir: writeBack satıra yazılmaz,
|
|
455
|
+
bildirim/webhook/e-posta jetonu gitmez, `service` düğümü workflow çağırmaz (stub anahtarı
|
|
456
|
+
`workflowSlug → workflowId → düğüm id`; `workflowSlug` yalnız düğümde yazılıysa eşleşir — `workflowId`'li
|
|
457
|
+
düğümde düğüm id'sini kullanın; stub yoksa örnek `faulted`). Yalnız son koşu sonucu kaydedilir.
|
|
458
|
+
`version` yoksa taslak — v3 senaryolarını v4 taslağında koşmak sürüm regresyonudur.
|
|
459
|
+
- Sonuç: ilk sapma `divergence { kind: step | error | path | assignee | outcome | state | vars | write-back,
|
|
460
|
+
nodeId, stepIndex, expected, actual, message }` ve `coverage`; `process_scenario_list { view: 'coverage' }`
|
|
461
|
+
`untestedEdgeKeys` ('from->to') hiç test edilmeyen dalları listeler.
|
|
462
|
+
- Senaryo düzenlenince son koşu silinir. Senaryolar ortam verisidir; deployment/merge taşımaz.
|
|
463
|
+
|
|
464
|
+
## Yayın ve taşıma
|
|
465
|
+
|
|
466
|
+
- `process_definition_publish`: taslak → `active`; önceki aktif `retiring` olur, açık örnekler kendi
|
|
467
|
+
sürümünde biter. Yayın doğrulamadan geçmezse 422 `DefinitionInvalid` döner, liste `errors[]`'dadır.
|
|
468
|
+
- Yayınlanmış tanımda slug değişmez; değişiklik yeni taslak sürümdür (`process_definition_update`
|
|
469
|
+
ya da `patch` taslağı yazar).
|
|
470
|
+
- production'a yayın ve yürütme gateway'de durur (BPM-001); production'a taşıma insan onaylı
|
|
471
|
+
deployment işidir.
|
|
472
|
+
- **Diff:** `process_definition_diff { id, from?, to? }` anlamsal satırlar (`node-added`, `assignee-changed`,
|
|
473
|
+
`editable-changed`, `param-type-changed` …); `isOverrideRisk` yöneticinin uyarlamasını bozabilecek değişikliktir. Yayından önce okuyun.
|
|
474
|
+
- **Dört göz:** aktif sürüm ya da taslak `publishPolicy: four-eyes` ve ortamda `process-publish` (bpm-management modülü)
|
|
475
|
+
kuruluysa `process_definition_publish` gerekçesiz 403 `PublishApprovalRequired` alır — taslakta politikayı `direct` yapmak
|
|
476
|
+
kapıyı açmaz. `{ reason }` ile istek açılır: `isPublished: false`, `request.instanceId`; onay görevi tanım sahibine düşer.
|
|
477
|
+
Yalnız isteyenden farklı bir kullanıcının onay kararı yayınlar; yönetici atlaması onay sayılmaz. Onay gerekmiyorsa aynı
|
|
478
|
+
çağrı doğrudan yayınlar.
|
|
479
|
+
- **Yayın kapısı:** aktif sürüm ya da taslakta `requireGreenScenarios: true` iken her senaryo taslak sağlamasında yeşil
|
|
480
|
+
koşmuş olmalı, yoksa 422 `ScenarioFailed` — doğrudan yayında da `{ reason }` ile istek açarken de (istek açılmaz).
|
|
481
|
+
Onaydan sonra kapıya takılan istek `rejected` olur. Gateway kapı kapalıyken de uyarır (BPM-015): önce `process_scenario_execute`.
|
|
482
|
+
- **SOP ve yorum:** `process_documentation_get` HTML (kulvar, RACI, SLA, diyagram); tasarım notları
|
|
483
|
+
`process_comment_list/create/update { resolved }`.
|
|
484
|
+
- **Sahiplik ve portföy:** tanımın sahibi (kullanıcı kimliği) dört göz onay görevini alır; RACI rolleri
|
|
485
|
+
(`responsible`, `accountable`, `consulted`, `informed`) atama kurallarıdır ve SOP'ta görünür
|
|
486
|
+
(`PUT bpm/definitions/{id}/governance`, bugün yalnız Studio'da). Studio'daki süreç portföyü
|
|
487
|
+
(`GET bpm/definitions/portfolio`) uygulamanın tanımlarını sahip, RACI, aktif/taslak sürüm, açık/kapalı
|
|
488
|
+
örnek, SLA ve son yayınla listeler; yayın onayı bekleyenler üstte.
|
|
489
|
+
- **Taşınan / taşınmayan (K-26):** deployment, dal açma, merge ve şablon tanımı ve iş takvimini taşır;
|
|
490
|
+
uyarlama, örnek, görev, timer, defter, bildirim, yorum, vekalet, havuz ve yetki limiti taşınmaz.
|
|
491
|
+
- **Hedefte ne olur:** tanım `(slug, applicationId)` ile eşleşir. Yeni tanım gelen kimlik ve sürümlerle
|
|
492
|
+
kurulur. Var olan tanımda aktif modelin sağlaması farklıysa hedefte **yeni sürüm olarak yayınlanır**
|
|
493
|
+
(production'da gelişte aktif) ve hedefin uyarlaması korunur ya da çatışma bildirimi gelir. Taslak
|
|
494
|
+
yalnız dal açma ve merge'de taşınır. Hedefte workflow/entity/rol eksikse taşıma `DefinitionInvalid` ile
|
|
495
|
+
düşer. Kaynakta olmayan tanım silinir; açık örneği varsa emekliye ayrılır.
|
|
496
|
+
- **Şablon:** `template_items(module: 'process-definition')` yalnız aktif sürümü taşır; kurulum yeni
|
|
497
|
+
kimlik verir, uygulama/workflow/sayfa/DTO kimliklerini yeniden eşler.
|
|
498
|
+
- **Merge planı:** tanım farkı `versions[…].model.nodes[<düğüm id>]…` yolunda görünür.
|
|
499
|
+
- **Silme kapısı:** kullanan tanım varken entity ve workflow silinmez (422 `ReferencedByProcess`,
|
|
500
|
+
mesajda tanım slug'ları); kimin kullandığını `dependency_graph(module: 'process-definition' | 'entity' | 'workflow')` gösterir.
|
|
501
|
+
- **Modül paketleri:** `module_list` katalog + kurulum; `module_update { operation: install | upgrade | detach, module, applicationId }`.
|
|
502
|
+
Katalogdaki tek süreç modülü `bpm-management`'tır (süreç sayfaları ve tr-mesai takvimi); `requires`
|
|
503
|
+
taşıyan bir modül, gerektirdiği modül aynı application'a kurulmadan 409 `ModuleRequiresModule` döner.
|
|
504
|
+
Kurulum tabloları (yoksa), takvimi ve süreçleri getirir; güncelleme değişen
|
|
505
|
+
süreci yeni sürümle yayınlar, uyarlamayı ve tablo verisini korur; ayırma içeriği bırakır. production'a kurulum
|
|
506
|
+
gateway'de durur (BPM-014).
|
|
507
|
+
|
|
508
|
+
## BPMN 2.0
|
|
509
|
+
|
|
510
|
+
- **Dışa:** `process_bpmn_get { id, version?, outPath? }` — düğüm ve süreç alanları `zeyrek:` uzantısında,
|
|
511
|
+
saklı diyagram korunur. 256 KB üstü için `outPath`.
|
|
512
|
+
- **İçe:** yeni tanım `process_definition_create { bpmn }`; var olan tanımın taslağı
|
|
513
|
+
`process_bpmn_update { id, xml | filePath }` (≤ 5 MB). `zeyrek:` uzantılı XML kayıpsız döner.
|
|
514
|
+
- **Başka modelleyiciden (uzantısız):** düğüm öğe türünden türetilir (`userTask` → `user-task`,
|
|
515
|
+
`exclusiveGateway` → `gateway`, `callActivity` → `sub-process`, `subProcess` → `region` …), kimlikler
|
|
516
|
+
kebab-case olur, **derece `locked`**, insan adımı ve bildirimin ataması **yer tutucu `initiator`**, SLA/politika boş
|
|
517
|
+
(BPM-016 uyarısı). İçe aktardıktan sonra `process_definition_get { view: 'outline' }` → atamaları
|
|
518
|
+
`process_definition_patch` ile düzelt → `process_definition_preview`. Bağlama isteyen öğe (`serviceTask` workflow'suz,
|
|
519
|
+
`callActivity` süreçsiz) için yer tutucu yoktur: içe aktarım 422 `DefinitionInvalid` döner.
|
|
520
|
+
- Şerit, havuz, not, veri nesnesi gibi yürütülmeyen öğeler kaybolmaz (alt süreç içindekiler dahil); içlerindeki kimlik
|
|
521
|
+
başvuruları normalize kimliklere çevrilir ve dışa aktarımda yerine yazılır. DTD/dış varlık içeren XML 400.
|
|
522
|
+
|
|
523
|
+
## Bağlayıcı ve belge
|
|
524
|
+
|
|
525
|
+
**Karar düğümü** `decision { decisionSlug, binding, input, output }` eşik ve seviye kurallarını DMN tablosundan
|
|
526
|
+
okur — tablo yazımı, FEEL ve DRD `platform_guide('decision')`.
|
|
527
|
+
|
|
528
|
+
**Bağlayıcı:** `connector_list` kataloğu (salesforce, sap-odata, microsoft-graph, google-workspace, jira, uipath, imap,
|
|
529
|
+
netgsm, twilio, teams-webhook, slack, camunda8, camunda7, flowable) her satırda `category` (ai · process-engine ·
|
|
530
|
+
productivity · messaging · business-app · rpa) taşır ve `category` ile süzülür; `connector_get { name }` işlem girdi şemaları.
|
|
531
|
+
Kimlik önce kasaya: `connector_credential_create { name, connectorName, kind, … sırlar }` →
|
|
532
|
+
`connector_credential_update { id, operation: 'test' }`. Sırlar şifreli saklanır, hiçbir yanıtta dönmez (BPM-017).
|
|
533
|
+
Düğümde:
|
|
534
|
+
|
|
535
|
+
```jsonc
|
|
536
|
+
{ "id": "lead", "type": "service", "description": "Satış fırsatı açar", "output": "vars.lead",
|
|
537
|
+
"connector": { "name": "salesforce", "operation": "create", "credentialRef": "sf-sandbox",
|
|
538
|
+
"input": { "sobject": "'Lead'", "fields": "({ LastName: vars.soyad, Company: row.firma })" } } }
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
`input` değerleri Jint ifadesidir (metin sabiti tek tırnakla). Hata `502 ConnectorFailed` ve `retry` politikası workflow
|
|
542
|
+
servis düğümüyle aynıdır.
|
|
543
|
+
|
|
544
|
+
**Dış motor:** Camunda/Flowable'da koşan süreci başlatıp sonucunu bekleyin:
|
|
545
|
+
|
|
546
|
+
```jsonc
|
|
547
|
+
{ "id": "camunda", "type": "service", "description": "Dış siparişi başlatır", "output": "vars.dis",
|
|
548
|
+
"externalEngine": { "engine": "camunda8", "processKey": "siparis", "credentialRef": "c8", "input": { "tutar": "vars.tutar" } } },
|
|
549
|
+
{ "id": "dis-bitti", "type": "wait", "description": "Dış süreç biter",
|
|
550
|
+
"message": { "name": "external-engine.done", "correlationKey": "vars.dis.zeyrekInstanceId" } }
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
Dış süreç değişkeninde `zeyrekInstanceId` gelir; bitişte `POST bpm/messages { name: "external-engine.done",
|
|
554
|
+
correlationKey: <zeyrekInstanceId>, payload }` çağırması gerekir (MCP'den deneme: `process_trigger { kind: 'message' }`).
|
|
555
|
+
|
|
556
|
+
**Olay ve e-posta kaynağı:** `process_event_source_create { name, kind: 'http', messageName, correlationKey:
|
|
557
|
+
'payload.siparisNo' }` dış olayı mesaja çevirir, olay `process_trigger { kind: 'event-source', name, eventId, payload }`.
|
|
558
|
+
`process_mail_source_create { kind: imap | graph, credentialRef, rules[{ subjectPattern, messageName, correlationKey }] }`
|
|
559
|
+
e-postayı mesaja çevirir (ekler files'a); yoklama `process_trigger { kind: 'mail-source', sourceId }`. `credentialRef` kasadaki
|
|
560
|
+
kaydın adıdır: olmayan ad kayıtta 404 döner, kasa kaydı yeniden adlandırılırsa kaynak yeni adı gösterir, kaynağın kullandığı
|
|
561
|
+
kasa kaydı silinemez. Mesajı bekleyen
|
|
562
|
+
`wait` düğümü ya da message start'lı tanım yoksa olay kaybolur — `bufferSeconds` verin.
|
|
563
|
+
|
|
564
|
+
**Belge:** süreçte `type: 'document'` düğümü `document { templateFileId, format: docx | pdf | html, fileName, folderId,
|
|
565
|
+
data: { alan: '<Jint>' }, stamp { revision, state, watermark, note } }` ve `output`; tek başına
|
|
566
|
+
`process_document_execute { operation: generate | stamp | print }`. Şablon DOCX ya da HTML, yer tutucu `{{alan}}`: DOCX
|
|
567
|
+
şablon `docx | pdf`, HTML şablon `html | pdf` üretir, başka biçim hata verir. `fileName` şablon metnidir, uzantısı biçime
|
|
568
|
+
uyar; `folderId` boşsa şablonun klasörü. Damga HTML çıktıya basılmaz.
|
|
569
|
+
|
|
570
|
+
**İmza:** `user-task`/`approval` düğümünde `signature { meaning, level: SES }` varsa görev imzasız tamamlanamaz
|
|
571
|
+
(422 `SignatureRequired`); `process_task_update { action: 'sign', password, meaning?, email?, fileId?, version, asUser }`.
|
|
572
|
+
Parola zorunlu (BPM-018; yalnız `signature.reauth: false` düğümde değil), gateway günlüğüne maskeli yazılır. `meaning` verilmezse düğümünki. İmzalanan dosya kilitlenir (409 `FileLocked`).
|
|
573
|
+
|
|
574
|
+
**Kanallar:** `notify` `channels` `inbox | email | socket | sms | teams | slack`. `sms` kullanıcının tercihindeki numaraya
|
|
575
|
+
(`process_preference_update { phone }`) `notification-sms` kasa kimliğiyle (bağlayıcı netgsm ya da twilio); `teams` ve
|
|
576
|
+
`slack` kullanıcının e-postasıyla `notification-teams` / `notification-slack` kimlikleriyle gider. Kimlik yoksa kanal sessizce
|
|
577
|
+
atlanır. `push` henüz yok.
|
|
578
|
+
|
|
579
|
+
## Doküman kontrolü ve AI
|
|
580
|
+
|
|
581
|
+
**Değerlendirme (okuma sınavı):** `user-task`'ta `assessment { questionBank { entity, where, questionField, optionsField,
|
|
582
|
+
answerField }, count, passScore, attempts, random, completeAction }`. Akış: `process_task_update { action: 'start-assessment' }`
|
|
583
|
+
(sorular cevapsız döner) → `{ action: 'submit-assessment', answers: { soruId: cevap } }`. **Submit'te `version` gönderme:**
|
|
584
|
+
sınavı açmak görevi üstlenir ve sürümünü ilerletir, elindeki sürüm bayattır (409). Başlatma yanıtı `{ id, taskId, number,
|
|
585
|
+
passScore, questions, startedAt, attempts, lastScore, isPassed }`: `attempts` adımın izin verdiği hak, `lastScore`/`isPassed`
|
|
586
|
+
**bu kullanıcının** son gönderilmiş denemesinin sonucudur (ilk denemede null). Denemeler **kullanıcı başına** sayılır (defterdeki
|
|
587
|
+
`number` örnek genelinde artar) ve sınavı yalnız görevin atandığı kişi açıp gönderebilir — başkası 403 `TaskComplete`.
|
|
588
|
+
Görev ayrıntısı (`process_task_get`) sınav isteyen adımda `assessment { count, passScore, attempts }` kuralını taşır; deneme
|
|
589
|
+
açılmadan önce paneli o kural açar. Soru bankası ve konu satırı okuyucunun alan izinlerine bakılmadan okunur; `passScore`
|
|
590
|
+
gerçekten sorulan soru sayısına kırpılır (banka `count`'tan az soru döndürürse geçme notu o sayıya iner). Cevap anahtarı boş
|
|
591
|
+
ya da yalnız boşluk olan soru **hiçbir cevapla doğru sayılmaz**. Geçen deneme görevi `completeAction` (yoksa düğümün okuma
|
|
592
|
+
kanıtı eylemi, o da yoksa `complete`) ile kapatır; kalan deneme hak varsa görevi açık bırakır, hak bitince sonuç
|
|
593
|
+
`assessment-failed` (geçide yönlendirin). Sınavsız okuma kanıtı 422. `passScore` 1..`count` (BPM-020).
|
|
594
|
+
|
|
595
|
+
**Yürürlük tarihi:** `end` düğümünde `effectiveAt: "<Jint tarih>"` + `revision { stateField, groupField, effectiveValue,
|
|
596
|
+
supersededValue, numberField }`; tarihte satır `effective`, aynı gruptaki önceki `superseded` olur. Grup satırları alan
|
|
597
|
+
filtresiyle okunur (10.000 satır sınırı yok). `numberField` verilirse sıra **numaraya** göre kurulur: yürürlüğe giren revizyon
|
|
598
|
+
numarası yürürlükteki bir satırdan küçükse **gelen satır** `superseded` olur, yürürlükteki yerinde kalır — geç işlenen eski bir
|
|
599
|
+
revizyon yeniyi düşürmez. `numberField` yoksa gelen satır her zaman yürürlüğe girer. **Check-out:** dosya
|
|
600
|
+
`POST files/{id}/checkout { taskId }` ile kilitlenir, başkası yazarsa 409 `FileCheckedOut`; görev **hangi yolla kapanırsa
|
|
601
|
+
kapansın** (eylem, imza, e-posta jetonu, zaman aşımı) kilit bırakılır. Kilitli ya da check-out'lu dosya barındıran klasör
|
|
602
|
+
silinemez.
|
|
603
|
+
|
|
604
|
+
**B2B:** `process_partner_create` ilişki önerir, karşı organizasyon `process_partner_update { operation: 'accept' }` ile
|
|
605
|
+
açar; tanımda `assignee: "partner:<kod>"` yalnız `active` ve süreci izinli ilişkiyle yayınlanır (`PartnerUnknown`).
|
|
606
|
+
|
|
607
|
+
**AI önerisi (service düğümü):**
|
|
608
|
+
|
|
609
|
+
```jsonc
|
|
610
|
+
{ "id": "oneri", "type": "service", "description": "Karar önerir", "output": "vars.oneri",
|
|
611
|
+
"ai": { "operation": "suggest-decision", "labels": ["approve", "reject"], "input": { "talep": "vars.talep" } } }
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
`operation`: `summarize` → `{ summary }` · `classify` (`labels`) → `{ label }` · `extract` (`schema.properties`,
|
|
615
|
+
`files` PDF/görsel) → `{ fields }` · `suggest-assignee` (`input.candidates`) → `{ userId }` · `suggest-decision`
|
|
616
|
+
(`labels`) → `{ outcome }`; liste/şema dışı değer `null`. AI **karar vermez**: çıktı yalnız `output` yoluna yazılır,
|
|
617
|
+
sonraki onay görevi açık kalır; geçitte kullanacaksanız kişi onaylasın. Korumalı alanlar modele `***` gider. Her öneri
|
|
618
|
+
defterde `ai-suggestion { promptHash }`. `autonomy: act-in-adhoc` yalnız `adHoc` süreçte (BPM-019) ve bugün öneriyle aynı.
|
|
619
|
+
Model ve kasa kimliği ortam ayarıdır (`Bpm:AiModel`, `Bpm:AiCredentialRef`); yoksa 400.
|
|
620
|
+
|
|
621
|
+
**Görev yardımcısı:** `process_task_get { view: 'assistant' }` özet ve önerilen eylem, `question` ile soru-cevap döner
|
|
622
|
+
(`aiSuggestion` rozetiyle; `outcome` yoktur). `process_task_list { q: 'bu ay geciken satınalmalar' }` süzgeci
|
|
623
|
+
`appliedFilter` ile döner. Kullanıcı başına dakikalık sınır 429 `AiRateLimited`.
|
|
624
|
+
|
|
625
|
+
## Operasyon
|
|
626
|
+
|
|
627
|
+
- **Rapor:** `process_report_get { slug, from, to }` — defterden türer, arşivlenmiş örneği saymaz. Çevrim
|
|
628
|
+
`instance-started` → `instance-completed`; SLA içinde % son termine (uzatma dahil) göre; `rejectLoops` ardından yeni
|
|
629
|
+
görev açılan retler; `units[]` başlatanın birincil birimi. Pencere en çok 366 gün; `isTruncated` 5000 örneği aştığını
|
|
630
|
+
söyler — pencereyi daraltın. Yetki `process.view-all`.
|
|
631
|
+
- **Madencilik:** `process_export_get { format: xes | ocel, definition, from, to, outPath }` IEEE XES (iz = örnek, olay =
|
|
632
|
+
defter satırı, `org:resource` eylemci, vekalette `zeyrek:principal`) ya da OCEL 2.0 JSON (örnek, görev, konu, belge
|
|
633
|
+
nesneleri, dosya `.json`) indirir; gateway dosyayı yapısal denetler (`validated`, `problems`) — resmî XSD değil;
|
|
634
|
+
`isTruncated: true` 5000 örnek tavanıdır, pencereyi bölün. ProM/Celonis için
|
|
635
|
+
`outPath`. `process_analytics_get { definition, view: variants | heatmap | conformance | prediction, from, to }`: yol
|
|
636
|
+
varyantları (pay % yolu olan örneklere göre), insan görevi düğümü başına süre, tanım dışı geçişler (sıçrama, atlama, göç), açık örnekte kalan süre
|
|
637
|
+
medyanı. Pencere ve 5000 örnek tavanı rapor ile aynı; `history: minimal` tanımda yol eksik kalır.
|
|
638
|
+
- **Defter:** `process_instance_get { view: 'events' }` CSV (en çok 256 KB satır içi), `view: 'verify'`
|
|
639
|
+
`{ isValid, brokenAtSequence }`. `isValid: false` defterin sonradan değiştirildiğini gösterir; kırık satırı
|
|
640
|
+
zaman çizelgesinde bulun, örneği düzeltmeye çalışmayın — denetim kaydıdır.
|
|
641
|
+
- **Saklama ve yasal bekletme:** tanımda `retention` (ör. `P5Y`) doluysa kapanmış örnek saatlik işte arşive taşınır,
|
|
642
|
+
30 gün sonra silinir. `process_legal_hold_create { scope: process | instance | user, scopeKey, reason }` taşımayı ve
|
|
643
|
+
silmeyi durdurur; `process_legal_hold_delete` kaldırır (kayıt kalır). İkisi de production'a gitmez (BPM-001).
|
|
644
|
+
- **Sağlık:** `process_health_get` — `timerLagSeconds` 60 sn'yi aşarsa `degraded`, 600 sn'yi aşarsa `unhealthy`
|
|
645
|
+
(timer işi durmuş ya da geride); `notificationLagSeconds` 300 sn üstü ve 10'dan çok `faulted` örnek de `degraded`.
|
|
646
|
+
`faulted` örnek için `process_instance_list { state: 'faulted' }` → `process_instance_update { operation: 'retry' }`.
|
|
647
|
+
- **Yarı yolda örnek:** `process_execute { slug, subjectRowId, vars, importAt: { nodeId, assigneeUserId, startedAt } }`
|
|
648
|
+
kâğıttan ya da eski sistemden gelen işi o düğümde açar; defterin ilk satırı `instance-imported`, rapordaki çevrim
|
|
649
|
+
`startedAt`'tan sayılır. Düğüm başlangıç, bitiş ya da bölge içi olamaz; yetki `process.manage`.
|
|
650
|
+
- **Tanım yedeği:** `process_definition_list { view: 'export' }` bütün tanımları (sürümler, taslak, RACI) ve takvimleri
|
|
651
|
+
verir; `process_definition_create { restore: <export data> }` geri yükler (takvim üzerine yazılır, değişen aktif sürüm
|
|
652
|
+
yayınlanır, yedekte olmayan tanım silinmez). Ortamlar arası taşıma için yedek değil deployment kullanılır.
|
|
653
|
+
|
|
654
|
+
## Hata sözlüğü
|
|
655
|
+
|
|
656
|
+
| Kod | HTTP | Anlam ve çözüm |
|
|
657
|
+
|---|---|---|
|
|
658
|
+
| `DefinitionInvalid` | 422 | Yapı: tek start, ulaşılamayan düğüm, tanımsız kenar, açıklama. `errors[]` satırlarını düzeltin |
|
|
659
|
+
| `RuleNotAllowed` · `RegionLocked` · `ParamNotEditable` · `MaxStepsExceeded` · `NodeTypeNotAllowed` | 422 | Bölge ya da uyarlama sınırı ihlali — §Uyarlama yol tablosu |
|
|
660
|
+
| `ExpressionInvalid` | 422 | Jint ifadesi derlenmiyor |
|
|
661
|
+
| `SubjectEntityUnknown` · `WorkflowUnknown` · `RoleUnknown` | 422 | Referans çözülmedi |
|
|
662
|
+
| `ServiceInputUnknown` | 422 | Servis düğümünün `input` anahtarı workflow'un parametre DTO'sunda yok — `dto_get` ile alan slug'larını okuyun |
|
|
663
|
+
| `TaskAlreadyClaimed` | 409 | Görev başkasında — görevi yeniden okuyun |
|
|
664
|
+
| `AggregateVersionConflictException` | 409 | `version` bayat (görev ya da tanım siz okuduktan sonra değişti) — `process_task_get` / `process_definition_get` ile yeniden okuyun |
|
|
665
|
+
| `TaskStateTransitionNotAllowed` | 422 | Görev bu durumda bu eylemi almaz (ör. `waiting-info` iken onay) |
|
|
666
|
+
| `TaskCommentRequired` | 422 | `commentRequired` koşulu yorum ister |
|
|
667
|
+
| `InstanceStateTransitionNotAllowed` | 409 | Örnek bu durumda değişmez (tamamlanmış örneği askıya alma) |
|
|
668
|
+
| `WithdrawNotAllowed` | 422 | `withdrawPolicy` geri çekmeye izin vermiyor |
|
|
669
|
+
| `UndoWindowClosed` | 409 | Geri alma penceresi geçti ya da sonraki insan görevi açıldı |
|
|
670
|
+
| `TaskActionTokenInvalid` | 410 | E-posta bağlantısı kullanılmış ya da süresi dolmuş |
|
|
671
|
+
| `OpenTasksExist` | 422 | Kullanıcının ya da birimin açık görevi var — önce `process_handover_preview` / `process_handover_create` |
|
|
672
|
+
| `HandoverIncomplete` | 422 | Kararı olmayan görev grubu var — karar verin ya da `force: true` |
|
|
673
|
+
| `DelegationOverlap` | 409 | Asıl kişinin kesişen vekaleti var |
|
|
674
|
+
| `DelegationChainNotAllowed` | 422 | Vekil aynı aralıkta kendi görevlerini devretmiş |
|
|
675
|
+
| `BatchOperationNotUndoable` | 422 | Yalnız tamamlanmış reassign / extend-due bir kez geri alınır |
|
|
676
|
+
| `PublishApprovalRequired` | 403 | Dört göz tanımı — `process_definition_publish { reason }` ile yayın isteği açın |
|
|
677
|
+
| `ScenarioFailed` | 422 | `requireGreenScenarios` ve senaryo bu taslakta yeşil değil — `process_scenario_execute` |
|
|
678
|
+
|
|
679
|
+
## Sık tuzaklar
|
|
680
|
+
|
|
681
|
+
- **Süreç ≠ workflow.** Tek istekte biten iş için workflow yazın; bekleme, insan kararı, SLA varsa süreç.
|
|
682
|
+
- **`description` eksik düğüm** gateway'de durur (BPM-002); her düğüme niyet cümlesi yazın.
|
|
683
|
+
- **İki dilli `analysis` eksik tanım ya da düğüm** gateway'de durur (BPM-023); § Analiz dokümanı.
|
|
684
|
+
- **`editable: open` bölge dışında** geçersizdir (BPM-003).
|
|
685
|
+
- **Sıralı zincirin uzunluğu `vars`'tan geliyorsa** önceki `service` düğümü `output: vars.seviye` yazmalı;
|
|
686
|
+
kuru koşuda aynı değeri `vars` ile verin.
|
|
687
|
+
- **`back-to:` bölge dışına** dönebilir; bölge koşusu `exited` olur ve içindeki açık görevler iptal edilir.
|
|
688
|
+
- **Paralel birleşme** gelen kenar sayısını bekler; birleşmeye koşullu olarak gelmeyen bir kol süreci
|
|
689
|
+
asılı bırakır — koşullu dalları önce exclusive gateway'de toplayın.
|
|
690
|
+
- **Görev eylemi app kullanıcısı adına yapılır**; Studio jetonuyla `complete` 403 alır.
|
|
691
|
+
- **production** hedefine yayın/yürütme gönderilmez (BPM-001).
|