Paket Statü Gate'i — packet.status.update ✓ Canlı

Sipariş platformu tipi eklentiler için: packets/create ile oluşturduğunuz paketlerin statü geçişlerinde söz sahibi olun. Restoran paneli, sizin oluşturduğunuz bir paketin statüsünü değiştirmeden ÖNCE eklentinize senkron sorar; allow/deny dönersiniz. deny → geçiş engellenir, message personele gösterilir.

← Hook'lar

Genel

Hook keypacket.status.update
Scopehooks:packet.status (consent-gated güçlü yetki)
Manifesthooks: [{ event, ui, timeoutMs, failMode, statuses?, includeData }]
Hedefmanifest actionUrl (yoksa webhookUrl)
MethodPOST (senkron)
Rate limithook kovası (varsayılan 60/dk per-install)

SAHİPLİK — en önemli kural

  • POST /plugin-api/packets/create çağrınız paket üzerine sizi SAHİP olarak damgalar (pluginStatusCallback.pluginId).
  • Restoranın kendi açtığı paketlerde, başka eklentinin paketlerinde veya klasik entegrasyon (Getir/Yemeksepeti) paketlerinde hook’unuz çalışmaz — scope’unuz onaylı olsa bile.
  • Sahiplik SUNUCUDA doğrulanır (plugin.hook.notOwner); panel davranışına güvenmek zorunda değilsiniz.
Sektör analoji: Shopify fulfillment order’ı yalnız atanmış fulfillment service yönetir; Stripe kendi objelerinizin event’lerini her zaman size gönderir.

Manifest hook config

{
  "event": "packet.status.update",
  "ui": { "kind": "none" },        // gate genelde UI'sız karar; form/iframe da desteklenir
  "timeoutMs": 5000,               // cevap bütçesi [1s,10s]; aşımda failMode uygulanır
  "failMode": "open",              // VARSAYILAN: open (timeout/hata → geçişe izin ver + uyar)
  "statuses": ["OnDelivery", "Delivered"],  // OPS: yalnız bu HEDEF statülere geçişte sor; yoksa hepsi
  "includeData": true              // OPT-IN: gövdeye paketin kanonik verisi gömülür (packets/get şekli)
}

statuses filtresi

  • Yalnız listedeki HEDEF statülere geçişte hook çağrılır; liste dışı geçişler eklentiye hiç sorulmadan devam eder (yanıtta skipped:true — panel için, sizi etkilemez).
  • En çok 20 öğe, öğe başına ≤60 karakter; boşluklar trim’lenir.
  • Bilinen statü değerleri: none, Approved, OnDelivery, Delivered, Rejected. Tenant akışına göre genişleyebilir — bilmediğiniz "to" değerine allow dönmenizi öneririz.

failMode — dikkat

Varsayılan open: endpoint’iniz cevap veremezse geçiş engellenmez (degraded uyarısıyla devam). "closed" seçebilirsiniz ama ciddi sorumluluk: sunucunuz düştüğünde restoranın o paketlerdeki tüm statü geçişleri bloklanır. Yalnız geçişin gerçekten durdurulması zorunluysa kullanın.

enforce desteklenmez

enforce bu hook’ta DESTEKLENMEZ (manifest’te verseniz de yok sayılır): statü yazımının sunucu-taraflı sert doğrulayıcısı henüz yok; karar panel-işbirlikli uygulanır. Sert garanti gerektiren akışları buna kurmayın (Faz 2’de backend status ucuyla gelecek).

Restomenum → eklenti (request body)

{
  "type": "hook",
  "event": "packet.status.update",
  "stage": "before",
  "tenantId": "<tenantId>",
  "target": { "type": "packet", "id": "<packetId>" },
  "transition": { "from": "Approved", "to": "OnDelivery" },
  "data": {
    "packetId": "<packetId>", "docNo": 12,
    "customer": { "id": "c1", "name": "...", "phone": "..." },
    "orders": [ { "id": "...", "title": "...", "quantity": 1, "options": [], "lineTotal": 130 } ],
    "entegrasyon": "packet", "total": 130, "paid": 0, "totalDiscount": 0
  },
  "formData": { "<sizin-field-keyiniz>": "<personel-degeri>" },   // DİNAMİK: formunuzdaki key'ler; yalnız ui.kind form/iframe ise
  "actor": { "userId": "<uid>", "role": "staff" },
  "timeoutMs": 5000,
  "occurredAt": 1718000000000,
  "hookId": "hk_<uuid>"
}
AlanAçıklama
transitionOnaylanan geçiş: to her zaman var (hedef statü); from eski paketlerde olmayabilir.
target.idPaket id’si. Veriyi packets/get?packetId= ile de çekebilirsiniz.
dataYalnız includeData:true ise. packets/get ile birebir kanonik şekil; customer yalnız customers:read + PII consent ile, data yalnız orders:read ile.
formDataYalnız ui.kind form/iframe ise gelir. İçeriği DİNAMİKTİR: anahtarlar SİZİN formunuzda tanımladığınız field key’ler, değerler personelin girdiği değerlerdir (her eklentiye özel; sabit şema yok). ui.kind none ise hiç gelmez.
actorGeçişi yapan kullanıcı {userId, role} (manager/staff) — imzalı gövdede, güvenilir.
hookIdBu çağrının id’si (loglama/dedup).

Eklenti → Restomenum (response)

allow — geçiş devam
{ "decision": "allow", "message": "Kurye atandı, yola çıkabilir." }
deny — engelle (message personele gösterilir)
{ "decision": "deny", "message": "Kurye henüz atanmadı — yola çıkarılamaz." }
  • decision: allow (geçiş devam) / deny (engelle; message personele gösterilir).
  • Geçersiz/boş cevap veya timeout → failMode uygulanır.
  • attach desteklenir (allowlist: invoiceNo / reference / note).
  • { decision:"pending" } → geçişi askıya al (senkron pencereye sığmayan kararlar), sonra gate-resolve ucuyla allow/deny ver. Bkz. /docs/gate-pending.

Hata mesajları (hook çağrısı)

messageAnlam
plugin.hook.notOwnerPaket sizin değil (sahiplik damgası eşleşmedi).
plugin.hook.targetNotFoundPaket bulunamadı.
plugin.hook.missingTransitionGeçiş bağlamı eksik/geçersiz (panel hatası).
plugin.hook.notRegisteredManifest’inizde bu hook yok.
plugin.scope.deniedhooks:packet.status onaylı değil.
plugin.hook.inactiveKurulum pasif (kill-switch / billing / connect).

Güvenlik

  • İmza: X-Restomenum-Signature: t=<sec>,v1=<HMAC_SHA256(webhookSecret,"<t>.<rawBody>")> (±5dk) — webhook/action ile aynı şema; type:"hook" ile ayırt edin.
  • transition/data/actor server-türevli (panel iddiası değil; panel yalnız geçişi başlatır).
  • Karar uygulaması Faz 1’de panel-işbirlikli: deny UX sözleşmesidir, kriptografik garanti değildir (enforce notuna bkz).

Tipik akış

1. Sipariş geldi  → POST /plugin-api/packets/create  (callbackUrl + idempotencyKey ile)
2. Restoran "Yola Çıkar"a bastı
   → Restomenum → sizin actionUrl: { type:"hook", event:"packet.status.update",
                                     transition:{from:"Approved", to:"OnDelivery"}, ... }
   → siz: kurye atandı mı? → { decision:"allow" }  /  { decision:"deny", message:"..." }
3. (yakında) Statü değişti → packet.status_changed event'i callbackUrl'inize düşer
4. Kurye teslim etti → packets:status callback'leriyle Delivered'ı SİZ setlersiniz