ReferansYetki (Entitlement) Matrisi

Yetki (Entitlement) Matrisi

Bu sayfa, bir işletmenin neye erişebildiğini belirleyen tek mekanizmayı özetler: yetki (entitlement) anahtarları ve bu anahtarları kimin verdiği.

Plan, tier ya da paket yoktur. Çekirdek ürün süresiz ücretsizdir; ücretli yetenekler katalogdan tek tek satın alınır ve her ürün, verdiği anahtarlar (grants) üzerinden yetki setine katılır.

Kaynak gerçekler: ücretsiz taban backend/src/modules/entitlements/free-baseline.const.ts, katalog ve grant’ları backend/src/modules/marketplace/alacarte-catalog.const.ts, geçerli anahtar sözlüğü backend/src/modules/entitlements/entitlement-keys.const.ts.

Anahtar uzayı ve katlama (fold)

Yetki seti, birden çok kaynaktan gelen grant satırlarının tek bir kümeye katlanmasıyla oluşur. Katlama kuralı anahtarın önekine bağlıdır:

ÖnekTipKatlamaNot
feature.*booleanORHerhangi bir kaynak true veriyorsa özellik açıktır.
limit.*numberSUM-1 “sınırsız” sentinel’idir ve toplamı domine eder.
integration.*string[]UNIONSağlayıcı (vendor) kimliklerinin birleşimi.

Grant kaynakları üç tanedir: free:baseline (ücretsiz çekirdek), addon:<kod>:<id> (satın alınan her ürün için bir kaynak) ve override:admin (süperadmin müdahalesi; limit.* / integration.* için { __replace: … } sarmalıyla değeri değiştirebilir).

Kontörler (credit.PHOTO, credit.VIDEO, credit.MODEL3D, credit.SMS) yetki değildir. Katalog doğrulaması credit.* anahtarını grant olarak reddeder; kontör paketleri kind: "credit" + creditKind / creditUnits ile satılır ve bakiye, harcama anında canlı okunur (30 sn’lik önbellek bir para hatası olurdu).

Ücretsiz çekirdek (free:baseline)

Her tenant’a koşulsuz, süresiz ve lisans gerektirmeden projeksiyonlanır.

AnahtarDeğerAnlamı
feature.posAccesstruePOS / satış ekranı
feature.kdsIntegrationtrueMutfak ekranı (KDS)
feature.customBrandingtrueÖzel marka ve alan adı
feature.multiLocationtrueŞube hub’ı, şube seçici, geçiş arayüzü
limit.maxUsers-1Sınırsız
limit.maxTables-1Sınırsız
limit.maxProducts-1Sınırsız
limit.maxCategories-1Sınırsız
limit.maxMonthlyOrders-1Sınırsız
limit.maxBranches1İlk şube ücretsiz; tek fiyatlı kapasite

Şubedeki bölünme kasıtlıdır: çoklu şube arayüzü ücretsizdir (feature.multiLocation), ücretli olan ikinci şubenin kendisidir (limit.maxBranches). extra_branch ürünü tam olarak bu yüzden iki anahtarı birden verir.

Ücretsiz çekirdeğin geri kalanı (menü yönetimi, masa ve kat planı, QR menü, sipariş yönetimi, kasa ve nakit, temel raporlar, ekip ve rol yönetimi, müşteriler, cihaz ve şube paneli) hiçbir yetki anahtarına bağlı değildir — ilgili rotalarda @RequireEntitlement yoktur. Yetki kapıları rota bazında opt-in’dir; dekoratörü olmayan rota kimseyi reddetmez.

Katalog ürünleri ve verdikleri grant’lar

Fiyatlar TRY ve KDV dahildir; katalogda kuruş (priceCents) olarak tutulur (490000 = ₺4.900,00). annual satırlar hesabın yıl dönümüne kadar gün bazında orantılanır (bkz. Lisans & Ödeme API).

Lisans

KodFiyatGrantLisans ön koşulu
license_annual₺4.900/yılfeature.license, feature.prioritySupport, integration.fiscal += efatura

Modüller

KodFiyatGrantLisans ön koşulu
advanced_reports₺1.290/yılfeature.advancedReports
module_inventory₺3.900/yılfeature.inventoryTracking
module_reservations₺990/yılfeature.reservationSystem
module_personnel₺990/yılfeature.personnelManagement
module_personnel_card_shift₺4.000 tek seferlikfeature.cardShift
module_ai_studio₺1.990/yılfeature.aiContentGeneration
api_access₺2.490/yılfeature.apiAccess
module_external_display₺1.990/yılfeature.externalDisplay
priority_supportfeature.prioritySupportv3.6.7 arşivlendilicense_annual içine alındı

Entegrasyonlar

KodFiyatGrantLisans ön koşulu
delivery_platforms₺2.499/yılintegration.delivery += yemeksepeti, getir, trendyol_yemek, migros; feature.deliveryIntegration
fiscal_efaturaintegration.fiscal += efaturav3.6.7 arşivlendilicense_annual içine alındı
fiscal_hugin₺2.990/yılintegration.fiscal += hugin
caller_id_integration₺1.490/yılintegration.caller += generic
sms_integration₺990/yılintegration.sms += *

Teslimat artık tek ürün: delivery_platforms integration.delivery anahtarına dört vendor id’sini birden yazar. UNION katlaması hâlâ geçerlidir ama artık yalnız fiscal_* ailesinde gözlemlenir (lisansın ["efatura"]’sı ile fiscal_hugin’in ["hugin"]’i birleşir). Teslimat kapısı zaten alan-geneliydi (@RequiresIntegration("delivery"), sağlayıcı taşımaz) — tek paket satılanı gerçekte teslim edilenle hizalar.

Kapasite

KodFiyatGrantLisans ön koşulu
extra_branch₺3.990/yıl/adetlimit.maxBranches +1, feature.multiLocation

maxQuantity: 100. Adet olarak alınır; projektör limit.* değerini satırın quantity’siyle çarpar, motor da bunu ücretsiz tabandaki 1 ile toplar.

Kontörler (tek seferlik, süresiz)

KodFiyatBakiyeBağımlılık
credit_ai_photo_100₺690100 PHOTOmodule_ai_studio
credit_ai_video_20₺89020 VIDEOmodule_ai_studio
credit_ai_3d_10₺79010 MODEL3Dmodule_ai_studio
credit_sms_500₺490500 SMSsms_integration

Kontör paketleri hiçbir yetki vermez (grants: {}); bakiye açar ve tükenene kadar geçerlidir. Bağımlılık, satın alma anında sahip olunan aktif bir ürünle ya da aynı sepetteki bir kardeş satırla karşılanabilir.

Hizmet

KodFiyatGrantLisans ön koşulu
onsite_install_full₺7.500 (tek seferlik)— (grants: {})
⚠️

onsite_install_full bir hizmet kalemidir: ödenir ve faturalanır ama hiçbir entitlement vermez. Tek seferliktir ve dönem sonu penceresi almaz (currentPeriodEnd: null).

Lisans karartması (suppression)

requiresLicense: true olan her ürünün grant’ları, lisans canlı değilken verilmez. Projektör sahiplik satırını yine yazar (sahip olunanlar listesi eksilmez) ama grant dizisi boştur.

  • Hiçbir iş verisi silinmez: stok, rezervasyon, personel, üretilmiş AI medyası ve chargedCents yerinde kalır. Lisans yeniden ödendiğinde bir sonraki projeksiyonda her şey aynen geri yanar.
  • Sepet seviyesindeki LICENSE_REQUIRED kontrolü satışı durdurur; asıl erişim kapısı budur — bir işletme yıl dönümü faturasının bazı satırlarını ödeyip lisansı ödemezse fark burada ortaya çıkar.
  • Ödeme süresi geçmiş (past_due) satırlar 7 gün boyunca grant vermeye devam eder (ADDON_GRACE_DAYS); süpürücü satırı expired’a çevirince hak düşer. active satırlar da aynı 7 günlük ufku alır, böylece yıl dönümü gecesi motorun 5 dakikalık taraması ile günlük süpürücü arasındaki saatlerde kimse kilitlenmez.

Yetkileri okuma

YöntemYolDöndürdüğü
GET/api/v1/entitlements/meKatlanmış set: features, limits, integrations, computedAt
GET/api/v1/me/licensingLisans durumu, sahip olunan ürünler, kontör bakiyeleri, yenileme, teklifler ve satın alınabilirlik
GET/api/v1/catalog/pricingPublic fiyat listesi (yayınlanmış katalog)

/v1/entitlements/me ve /v1/me/licensing tenant seviyesindedir ve X-Branch-Id beklemez.

⚠️

Eski GET /api/subscriptions/effective-features ucu hâlâ yönlendirmede duruyor ama plan raylarına bağlıdır: Tenant.currentPlan yoksa 404 atar. v3.3.0 migrasyonu currentPlanId’yi her tenant için NULL’ladı ve kayıt akışı artık plan damgalamıyor — yani normal bir işletme için bu uç 404 döner. Yeni entegrasyonlar /v1/entitlements/me (veya tek çağrıda her şeyi veren /v1/me/licensing) kullanmalıdır.

Yetki reddi (403)

Kapılı bir rota, eksik yetkiyi ve onu açan ürünü taşıyan bir 403 döner:

{
  "statusCode": 403,
  "message": "Bu özellik hesabınızda etkin değil.",
  "error": "Entitlement Required",
  "errorCode": "ENTITLEMENT_REQUIRED",
  "timestamp": "2026-08-13T08:14:05.123Z",
  "path": "/api/reports/advanced",
  "requestId": "1786…-a1b2c3d4e",
  "actionable": {
    "requirement": { "type": "feature", "key": "feature.advancedReports" },
    "offer": {
      "code": "advanced_reports",
      "name": "Gelişmiş Rapor & Analitik",
      "kind": "module",
      "annualPriceCents": 129000,
      "proratedCents": 74123,
      "currency": "TRY",
      "periodEnd": "2027-03-10T00:00:00.000Z"
    },
    "licenseRequired": false,
    "reason": "not_owned"
  }
}

Remediation yükü, global hata filtresinin allowlist’inden geçerek actionable altında taşınır (yalnızca requirement, offer, licenseRequired, reason alanları):

  • requirement.type: feature | limit | integration. limit reddinde ayrıca usage ve cap gelir.
  • offer: anahtarı açan en ucuz ürün, bu tenant için bugün fiyatlanmış hâliyle. Gösterilen fiyat ile checkout’ta tahsil edilecek fiyat aynı katalog okumasından gelir.
  • licenseRequired: true ise asıl engel ürünün kendisi değil, eksik lisanstır; teklif de lisansa döner.
  • reason: not_owned (hiç alınmamış) veya lapsed (süresi dolmuş) — istemcinin “Satın al” ile “Yenile” arasında seçim yapmasını sağlar.

İlgili