Hook'lar (Akış Kontrolü)

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).

Uçtan uca uygulama rehberi (istek/yanıt CANLI örnek, veri çekme, imza, tam kod): Action Hook (before-hook sözleşmesi).

Nasıl çalışır

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 = devam

Senin sorumluluğun (net sınır)

Sen 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ı.

Manifest şeması — hooks[]

AlanTipZorunluAçıklama
actionenumYakalanan çekirdek işlem (katalog — aşağıda).
blockingbooleanAkışı durdurur (şu an tüm hook’lar blocking).
ui.kindform | iframe | noneKarar öncesi gösterilecek arayüz.
ui.formIdstringkind=form ise zorunlu — bir form id.
ui.pageIdstringkind=iframe ise zorunlu — bir sayfa id.
includeDataboolean(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.
timeoutMsnumber1000–10000 (1–10 sn; varsayılan 10000).
enforcebooleanSert garanti (default false): backend gate-token doğrular, atlanamaz. true ise failMode closed'a kilitlenir. Yalnız zorunlu (yasal/uyumluluk) gate'ler.
failModeclosed | openclosed (varsayılan): cevap gelmeden işlem durur · open: hata olursa devam. enforce:true ile her zaman closed.
webhookPathstringKarar 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 eklenir

Kayıtlı hook'lar (her biri kendi sayfasında):

Bir action başına tenant'ta yalnız bir blocking hook (çakışma → ilk aktif kurulum sahiplenir).

Manifestte 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.

Sert Garanti (enforce) — gate atlanamaz

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:

failModeenforce
NeGate ç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.
İstek varsayılan olarak değer-torbası taşımaz; yalnız 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).

Adımlar

  1. (form göstereceksen) bir form ekle; (iframe ise) bir sayfa.
  2. Editörde “Hook'lar” → action seç, ui.kind ve form/sayfa bağla, timeout + failMode ayarla.
  3. hooks:<action> scope'u otomatik istenir; tenant kurulumda ek onay verir.
  4. Webhook'unda kararı dön: Action Hook referansı.
Blocking hook tenant'a kurulumda ek onay olarak çıkar (“bu eklenti masa kapatmayı durdurabilir; hata durumunda kapatılamayabilir”). failMode: "closed" güçlü bir garantidir — yalnız güvendiğin, yüksek erişilebilirlikteki bir servis için kullan.
Akışı durdurmadan, kullanıcının bir butona basmasıyla tetiklenen bir aksiyon mu istiyorsun? Aksiyon Butonları (ui:button) — NON-BLOCKING alternatif.
Karıştırma: table.close (bu sayfa) kapatma öncesi senkron gate'tir. Kapatma sonrası bildirim almak istiyorsan table.closed event'i'ne abone ol (async webhook).