Hook'lar, bir çekirdek işlemi (örn. masa kapatma) gerçekleşmeden önce araya girer: senin formunu/onayını bekler ve verdiğin karara göre işlem devam eder veya iptal olur. Event'lerin (async bildirim) aksine senkron ve akış-durdurucudur (before-hook).
Kullanıcı bir işlemi tetikler (örn. "Masayı Kapat")
│
▼
Hook devreye girer (blocking) ──► ui.kind:
• form → manifest.forms[formId] native gösterilir
• iframe → pages[pageId] iframe açılır
• none → doğrudan webhook'una sorulur
│
▼
Senin webhook'un → { decision: "allow" | "deny", message, attach }
│
├─ allow → işlem DEVAM eder (attach çekirdeğe işlenir)
├─ deny → işlem İPTAL, message kullanıcıya gösterilir
└─ timeout/hata → failMode: closed = engelle · open = devamSen yalnız webhook'unda kararı dönersin: { decision: "allow" | "deny", message, attach }. Kullanıcıya gösterilen onay metni, consent ekranı ve işlemin gerçekten durdurulması (enforcement) Restomenum tarafındadır — bunları sen yapmazsın. Kod örneği: Action Hook referansı.
| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
| action | enum | ✓ | Yakalanan çekirdek işlem (katalog — aşağıda). |
| blocking | boolean | ✓ | Akışı durdurur (şu an tüm hook’lar blocking). |
| ui.kind | form | iframe | none | ✓ | Karar öncesi gösterilecek arayüz. |
| ui.formId | string | – | kind=form ise zorunlu — bir form id. |
| ui.pageId | string | – | kind=iframe ise zorunlu — bir sayfa id. |
| includeData | boolean | – | (opt-in) true → gate gövdesinde data (kapanış-öncesi kanonik veri; tables/get ile aynı şekil — customer→customers:read+consent, data→orders:read) gelir. Kapanıştan sonra kaynak kaybolduğu için karar-anı veriyi tek seferde almanın yolu. |
| timeoutMs | number | – | 1000–10000 (1–10 sn; varsayılan 10000). |
| enforce | boolean | – | Sert garanti (default false): backend gate-token doğrular, atlanamaz. true ise failMode closed'a kilitlenir. Yalnız zorunlu (yasal/uyumluluk) gate'ler. |
| failMode | closed | open | – | closed (varsayılan): cevap gelmeden işlem durur · open: hata olursa devam. enforce:true ile her zaman closed. |
| webhookPath | string | – | Karar sorgusu path'i (aynı origin). Boşsa ana webhook. |
"hooks": [
{
"action": "table.close", // hangi çekirdek işlemi yakalar (katalog)
"blocking": true, // işlemi durdurur (akış kontrolü)
"enforce": true, // sert garanti — backend doğrular, gate atlanamaz (→ failMode closed)
"ui": { "kind": "form", "formId": "invoiceForm" }, // form | iframe | none
"includeData": true, // (opt-in) gate gövdesinde kapanış-öncesi kanonik data gelsin mi
"timeoutMs": 10000, // 1000–10000 (1–10 sn)
"failMode": "closed" // closed (varsayılan) | open
}
]
// gerekli scope: "hooks:<action>" (örn. hooks:table.close) — otomatik eklenirKayıtlı hook'lar (her biri kendi sayfasında):
packet.status.update — Paket Statü Gatepacket.close — Paket Kapatma Gatetable.close — Masa Kapatma GateBir action başına tenant'ta yalnız bir blocking hook (çakışma → ilk aktif kurulum sahiplenir).
ui.formId bir form'a referanstır; yayınlanan registry'de portal bunu inline çözer: ui: { kind:"form", form:{ title, fields, submitLabel } } — böylece runtime formu gömülü görür (buton action.form'uyla aynı mantık). Formu sonradan düzenlersen yeni sürümde otomatik tazelenir.Normalde before-hook Tier-1'dir (host panel gate'i çalıştırır; teorik olarak atlanabilir). enforce:true ile backend, gate'in çalıştığını doğrular → atlanamaz. Eklenti açısından ekstra iş yoktur; her zamanki gibi { decision, message?, attach? } dönersin, gate-token'ı Restomenum üretir.
failMode ≠ enforce — karıştırma:
| failMode | enforce | |
|---|---|---|
| Ne | Gate çalıştı ama eklenti cevap vermedi → ne olur (closed=durdur / open=geç) | Gate hiç çalıştı mı → backend doğrular (atlanmayı engeller) |
| Bypass'ı yakalar mı? | ❌ Gate çalışmazsa timeout da olmaz | ✅ Token yoksa işlem reddedilir |
enforce:true + allow akışı:
Host → gate'ine POST { type:"hook", event, formData, … }
Sen → { decision:"allow"|"deny", message?, attach? } // token'ı Restomenum üretir
allow → Restomenum imzalı gate-token üretir → host işleme iletir
→ çekirdek işlem (masa kapatma) token'ı DOĞRULAR
→ token yoksa: plugin.hook.gateRequired ile RED (otomatik/sistem kapanışları dahil)enforce:true → eklentiniz erişilemezse, gate'lenen işlem (failMode:closed) bloklanır. Timeout/hata anında işlem geçmez — gerçek allow olmadan token üretilmez; failMode:open bile enforce'u gevşetmez. Yalnız gerçekten zorunlu (yasal/uyumluluk) gate'lerde kullanın. Kurtarma: eklentiyi pasife almak.target:{type,id} referansı + actor:{userId,role} verir. Gereken veriyi target.id ile kendi Data API ucunuzdan çekin — ya da includeData:true ile gövdede data hazır gelir (kapanıştan SONRA kaynak kaybolur → karar anında bunu tercih et). Karar = formData (kullanıcı girdisi) + data/çektiğin veri + actor.role (per-user yetki).actor:{ userId, role } — işlemi yapan kullanıcı, gövdeye imzalı gelir (güvenilir). role ∈ manager | staff. Per-user yetkiyi (örn. "yalnız manager kapatabilir")actor.role/actor.userId ile kur; ad/PII gerekiyorsa users/get (users:read + consent).hooks:<action> scope'u otomatik istenir; tenant kurulumda ek onay verir.failMode: "closed" güçlü bir garantidir — yalnız güvendiğin, yüksek erişilebilirlikteki bir servis için kullan.table.close (bu sayfa) kapatma öncesi senkron gate'tir. Kapatma sonrası bildirim almak istiyorsan table.closed event'i'ne abone ol (async webhook).