Her kurulum bir ortama aittir: sandbox (test mağazaları) veya production (gerçek mağazalar). Ortam yedi yüzeyde birden gelir ve üç şeyi belirler: hangi API kökünü çağıracağın, hangi kurulumun credential'ını kullanacağın ve teslimleri nasıl ayrı tutacağın. Aynı tenant iki ortamda birden kurulu olabilir.
environment | Ne zaman | API kökü |
|---|---|---|
| sandbox | Test mağazaları — yayınlanmamış eklentini denerken | https://sandbox.plugins.restomenum.app |
| production | Gerçek mağazalar — marketplace’ten kurulum | https://plugins.restomenum.app |
Geçerli değerler yalnız bunlardır: sandboxproduction
environment’ı tahmin etme — her zaman sana verilir:
| Yüzey | Nerede |
|---|---|
| Event webhook’ları | İmzalı gövde — envelope.environment |
| Yaşam döngüsü (app.* / subscription.* / delivery.*) | İmzalı gövde |
| Gate hook’ları (type:"hook") | İmzalı gövde |
| Buton action’ları (type:"action") | İmzalı gövde |
| Capability relay (type:"capability") | İmzalı gövde |
| OAuth Connect | Query parametresi — ?environment= |
| iframe session token | JWT claim — claims.environment |
X-Restomenum-Environment header’ı imzasız kolaylık kopyasıdır: imzaya dahil değildir ve gövdeyi kuyruğa atıp sonra işleyen tasarımlarda kaybolur. Kararlarını daima imzalı gövdedeki alana (veya token claim’ine) dayandır.Aynı tenantId iki ortamda birden kurulu olabilir ve her kurulumun apiKey + webhookSecret’ı ayrıdır. Kurulumu yalnız tenantId ile saklarsan ikinci kurulum birincinin üzerine yazar; sonra imza doğrulaması yanlış secret’la yapılır ve geçerli teslimler 401’e düşer.
// Kurulum kaydının anahtarı: tenantId + environment (yalnız tenantId DEĞİL).
// Aynı tenant hem sandbox hem production'da kurulu olabilir; apiKey/webhookSecret AYRIDIR.
const key = (tenantId, environment) => `${environment}:${tenantId}`;
save({ tenantId, environment, apiKey, webhookSecret, scopes });
// Gelen her istekte ortamı GÖVDEDEN/CLAIM'den al, tahmin etme:
const install = find(envelope.tenantId, envelope.environment); // webhook / action / hook / capability
const install = find(claims.tenantId, claims.environment); // iframe session tokentenant "tnt_42" ├─ sandbox → apiKey_A · webhookSecret_A ◄── ayrı kurulum └─ production → apiKey_B · webhookSecret_B ◄── ayrı kurulum imza anahtarı = find(tenantId, environment).webhookSecret
Resmi SDK bunu destekler: getSecret(tenantId, environment) — verifyAndParseWebhook, verifyAndParseCapability ve verifySessionToken ortamı ikinci argümanla verir.
Token takası ve tüm Callback API çağrıları kurulumun ortamındaki köke gitmelidir. Tek bir köke sabitlenmiş kod, production kurulumunda yanlış kökle konuşur.
// API kökünü kurulumun ortamından çöz — tek bir köke SABİTLEME.
const BASES = {
sandbox: 'https://sandbox.plugins.restomenum.app',
production: 'https://plugins.restomenum.app',
};
// /connect?code=…&environment=production&state=…
const env = environment === 'production' ? 'production' : 'sandbox';
await fetch(`${BASES[env]}/plugin-api/oauth/token`, { /* … */ });
// Resmi SDK: ortamı geçmen yeterli (kökü kendisi çözer)
import { exchangeCode, RestomenumClient } from '@restomenum/plugin-sdk';
const cred = await exchangeCode({ code, clientId, clientSecret }, { environment: env });
const client = new RestomenumClient({ apiKey: cred.apiKey, environment: env });envelope.id) ve idempotency anahtarlarını ortamla kapsa: `${environment}:${id}`. İki ortamın teslimlerini aynı kovada tutma — sandbox’ta işlenen bir kayıt production teslimini “zaten gördüm” diye düşürmesin.requestId dedup’ını ortamla kapsa (capability relay).webhook, connect, action adreslerin ve UI sayfalarının ortak origin’i eklentinin tamamı için tanımlanır — her sürümde yeniden girmezsin. Sürüm editöründeki “Uç noktalar” kartı bu tek konfigürasyonu düzenler.
Bir sürümü kaydettiğinde o anki adres sürüme mühürlenir(snapshot). Kurulumlar mühürlenmiş adrese teslim alır:
eklenti konfigürasyonu sürüm mührü (kurulumun gördüğü)
origin https://acme.com → v1.0 https://acme.com/webhook ← yayında
webhook /webhook v1.1 https://acme.com/webhook ← taslak
origin'i https://new.com yap → v1.0 https://acme.com/webhook ← DEĞİŞMEZ
v1.1 kaydet → https://new.com/webhookBir sürümün webhookUrl, connectUrl, actionUrl ve sayfa origin’leri tek bir kayıtlı domainden türer (tek-apex kuralı). Bu yüzden test mağazandaki kurulum da varsayılan olarak canlı sunucuna teslim eder — yerelde denemek için yayınlı sürümün adresini tünele çevirmek gerekirdi ve bu canlıyı kırardı.
Bunun yerine eklenti sayfasındaki (ya da sürüm editöründeki, uç noktaların üstündeki) Sandbox origin’i alanına tünel adresini yaz (ngrok, cloudflared…). Eklenti sayfasında alanın kendi Kaydet’i vardır; sürüm editöründe sayfanın Kaydet’iyle birlikte yazılır. Yalnız sandbox teslimleri oraya gider; path’ler sürümden gelir, yalnız origin değişir:
sürüm (değişmez) sandbox origin'i: https://acme.ngrok.app https://acme.com/webhook → https://acme.ngrok.app/webhook https://acme.com/oauth/connect → https://acme.ngrok.app/oauth/connect https://acme.com/api/action → https://acme.ngrok.app/api/action pages[].customUiOrigin → https://acme.ngrok.app production kurulumları → https://acme.com/... (değişmez)
/ olmadan. Sandbox runtime bu adrese internet üzerinden ulaşır — localhost erişilemez, tünel gerekir.environment’ı oku (varsayma).tenantId + environment ile sakla.sandbox ortamındadır.