Ga naar inhoud
getnextpdf.com

Enterprise editie

Billing — Diepe referentie

Deze pagina is de diepe referentie voor het billing-oppervlak van NextPDF Enterprise. Het oppervlak kent twee lagen. Het billing-model in NextPDF\Enterprise\Billing definieert plantiers, quota, overage-beleidsregels en gededupliceerde usage-alerts. Het handhavingssubstraat in NextPDF\Enterprise\Billing\Substrate plaatst dat model op het live request-pad, fail-closed en concurrency-safe. Toegangspunten zijn PlanRegistry, QuotaManager, OverageCalculator, BillingAlertService en QuotaEnforcementGuard. Zie voor de workflow-gerichte gids de Billing-capabilitypagina.

Deze mogelijkheid wordt geleverd in NextPDF Enterprise (nextpdf/enterprise) en wordt geactiveerd met een licentie-envelop van de Enterprise-tier. Een deployment zonder dat recht laadt de classes van de mogelijkheid niet. Vergelijk edities en vraag een licentie aan.

Billing is een basismogelijkheid van Enterprise zonder aparte vlag per functie; ze is beschikbaar zodra het Enterprise-pakket naast het Core-pakket is geïnstalleerd. NextPDF Core (Apache-2.0) en NextPDF Pro hebben geen plan-, quota- of overage-model; dit oppervlak heeft geen equivalent op een lagere tier. Plan-inclusies, quota en commerciële voorwaarden worden geregeld door de licentieovereenkomst, niet door runtime-handhaving; deze referentie is geen juridisch of contractueel oordeel.

Alle symbolen bevinden zich onder NextPDF\Enterprise\Billing. Rijen gemarkeerd als substrate bevinden zich onder NextPDF\Enterprise\Billing\Substrate. TenantContext is het geauthenticeerde tenant-type uit NextPDF\Enterprise\SaaS.

SymboolParametersStandaardgedragRetourneertWerpt of faalt metOpmerkingen
SaaSPlan (enum)String-backed plantiers: standard, advanced, high_controlWerpt nietlabel() retourneert de weergavenaam
PlanDefinition::__constructSaaSPlan $plan, float $includedCuQuota, list<CapabilityCode> $capabilities, non-empty-string $priceTier, bool $intelligencePackIncluded, bool $privacyPackIncludedImmutable plan-value-object; slaat inputs op zoals aangeleverdNieuwe instanceWerpt nietfinal readonly; gepromote public properties
PlanDefinition::includesCapabilityCapabilityCode $capabilityStrikte identity-membershipcheckboolWerpt niet
PlanRegistry::__constructlist<PlanDefinition> $definitionsIndexeert definities per tier; de laatste definitie per tier wintNieuw registerWerpt nietVoor tests en white-label-plansets
PlanRegistry::getSaaSPlan $planCanonieke plan-lookupPlanDefinitionInvalidArgumentException wanneer het plan niet is geregistreerd
PlanRegistry::hasSaaSPlan $planRegistratieprobeboolWerpt niet
PlanRegistry::defaultRegistry (static)Productie-standaarden: Standard 1,000 CU; Advanced 5,000 CU plus Intelligence Pack; High Control 20,000 CU plus Intelligence- en Privacy PackPlanRegistryWerpt nietGebruik dit tenzij contractuele voorwaarden maatwerkdefinities vereisen
OveragePolicy (enum)hard_stop, soft_stop, budget_alertWerpt niethttpStatusCode() mapt 402 / 429 / 200; isBlocking() is alleen true voor hard en soft stop
QuotaManager::__constructPlanRegistry $planRegistry, OveragePolicy $overagePolicyBindt het register aan één beleidNieuwe instanceWerpt niet
QuotaManager::checkQuotaTenantContext $tenant, SaaSPlan $plan, float $currentCuRetourneert stil op of onder quotum, of onder een niet-blokkerend beleidvoidQuotaExceededException bij strikte overage onder een blokkerend beleid; InvalidArgumentException uit het register bij een niet-geregistreerd planresetsAt = eerste dag van volgende maand, middernacht UTC
QuotaManager::remainingQuotaSaaSPlan $plan, float $currentCuPure read; blokkeert nooitfloatRegister-InvalidArgumentExceptionNegatief bij overage
QuotaManager::usagePercentageSaaSPlan $plan, float $currentCuPure read; blokkeert nooitfloatRegister-InvalidArgumentException0.0 wanneer het inbegrepen quotum niet-positief is; boven 1.0 bij overage
OverageCalculator::calculatePlanDefinition $plan, float $currentCuBerekent een immutable overage-snapshotOverageResultWerpt nietfinal readonly, stateless
OverageResultincludedCu, usedCu, overageCu, usageRatio, isOverageImmutable berekeningsresultaatWerpt nietoverageCu = max(0, used - included); isOverage vereist strikte overage
BillingAlertType (enum)quota_warning_80, quota_warning_100, budget_exceeded, monthly_cap_reachedWerpt nietthreshold() 0.8 / 1.0 / 1.0 / 1.0; severity() warning / critical / critical / critical
BillingAlertService::__constructAlertStateRepositoryInterface $alertStateBindt de deduplicatiestoreNieuwe instanceWerpt niet
BillingAlertService::evaluateTenantContext $tenant, SaaSPlan $plan, PlanDefinition $planDef, float $currentCuVuurt nog-niet-afgevuurde alerts af in oplopende drempelvolgorde en legt ze vastlist<BillingAlertType>InvalidArgumentException bij plan/definitie-mismatchDedup-sleutel: tenant, type, UTC-YYYY-MM-periode
BillingAlertService::clearAlertsTenantContext $tenantWist de fired-state van de tenant voor de huidige UTC-periodevoidDoor de repository gedefinieerde fouten propagerenHerbewapent alerts binnen dezelfde periode
AlertStateRepositoryInterfacehasAlertFired(), markAlertFired(), clearForPeriod()Duurzaam persistentiecontract voor alert-deduplicatiePer methodeImplementatie-gedefinieerdOperator is eigenaar van duurzaamheid over replica’s heen
InMemoryAlertStateRepositoryArray-backed fired-statePer interfaceWerpt nietAlleen single-request-lifecycles en tests
QuotaExceededExceptionReadonly currentCu, limitCu, resetsAt, tenantId, isSaaSDeployment-mode-bewuste quota-weigeringIs de throwablehttpStatusCode() 402 SaaS / 403 on-prem; specCode() SPEC-BILLING-003 / SPEC-LIC-001; toErrorEnvelope() levert een gestructureerd error-body op
DeploymentMode (enum)saas, self_hosted_oss, local_developmentWerpt nietSubstrate. enforcesQuota() is alleen true voor Saas; opt-out is altijd expliciet
QuotaEnforcementGuard::__constructDeploymentMode, PlanResolverInterface, QuotaManager, UsageCounterStoreInterfaceStelt de live quota-gate samenNieuwe instanceWerpt nietSubstrate. final readonly
QuotaEnforcementGuard::enforce?TenantContext $tenant, non-empty-string $featureKey, float $amount = 1.0Fail-closed quota-gate met atomaire reserveringQuotaDecision (alleen toegestane uitkomsten)Zie de weigeringstaxonomie hieronderSubstrate. Monteer na tenant-authenticatie, vóór de billable handler
PlanResolverInterface::resolveTenantContext $tenantResolvet een tenant naar zijn plan en beleidsregels per functieResolvedPlanNoPlanForTenantExceptionSubstrate. Een default-plan-terugval voor onbekende tenants is een defect
RegistryPlanResolverarray<non-empty-string, ResolvedPlan> $plansByTenantMap-backed resolverResolvedPlanNoPlanForTenantException voor niet-gemapte tenantsSubstrate. Fail-closed by construction
ResolvedPlan::policyFornon-empty-string $featureKeyBeleids-lookup op het geresolvede plan?QuotaPolicyWerpt nietSubstrate. null betekent onbekende feature; de guard weigert die
QuotaPolicynon-empty-string $featureKey, float $limit, OveragePolicy $overagePolicyLimiet per functie en breach-beleidWerpt nietSubstrate. UNLIMITED = -1.0; een limiet van 0.0 is nul-toelage, niet unlimited; isUnlimited(), isBlocking()
QuotaDecisionStatics bypassed(), unlimited(), consumed()Value-object voor toegestane uitkomstQuotaDecisionWerpt nietSubstrate. isAllowed() is altijd true; elke weigering werpt in plaats daarvan
UsageCounterRij-snapshot: tenant, feature, periodegrenzen, used, limit, updatedAtImmutable usage-rijWerpt nietSubstrate. remaining() kan negatief zijn; wouldExceed() is strikt
UsageCounterStoreInterface::getTenant, feature, periodegrenzen, float $limitLeest de usage-rij en maakt die aan met used = 0 wanneer afwezigUsageCounterUsageStoreUnavailableExceptionSubstrate. Retourneert nooit een falsy waarde bij backend-fout
UsageCounterStoreInterface::tryConsumeTenant, feature, periodegrenzen, float $amount, float $limitAtomaire compare-and-set-reservering binnen de limiet?UsageCounter (null wanneer de reservering de limiet zou overschrijden)UsageStoreUnavailableExceptionSubstrate. Moet één enkele atomaire operatie tegen de backing store zijn
InMemoryUsageCounterStoreIn-process referentie-implementatie van het store-contractPer interfacePer interfaceSubstrate. Alleen single-process; documenteert de atomiciteitsinvariant
QuotaEnforcementException (abstract)Basistype van elke substrate-weigeringIs de throwable-familieSubstrate. Elk subtype declareert httpStatusCode()
public function checkQuota(TenantContext $tenant, SaaSPlan $plan, float $currentCu): void
public function evaluate(
TenantContext $tenant,
SaaSPlan $plan,
PlanDefinition $planDef,
float $currentCu,
): array
public function enforce(?TenantContext $tenant, string $featureKey, float $amount = 1.0): QuotaDecision
public function tryConsume(
string $tenantId,
string $featureKey,
DateTimeImmutable $periodStart,
DateTimeImmutable $periodEnd,
float $amount,
float $limit,
): ?UsageCounter;

Weigeringstaxonomie van QuotaEnforcementGuard::enforce

ExceptieHTTP-statusGeworpen wanneer
MissingTenantContextException401SaaS-modus zonder geauthenticeerde tenant-context
NoPlanForTenantException402De resolver vindt geen plan toegewezen aan de tenant
UnknownFeatureException402Het geresolvede plan definieert geen beleid voor de feature-key
UsageStoreUnavailableException503De usage store kan niet worden gelezen of atomair bijgewerkt; ook geworpen bij een niet-positieve $amount
QuotaExceededException402 (SaaS) / 403 (on-prem)Het quotum van een blokkerend beleid wordt overschreden, of een gelijktijdige reservering heeft de laatste ruimte verbruikt
  • Het standaardregister levert drie tiers (Standard / Advanced / High Control) met toenemende CU-quota en capabilitysets. Een aanvraag voor een niet-geregistreerd plan faalt met een expliciete InvalidArgumentException.
  • QuotaManager::checkQuota() werpt alleen wanneer beide condities gelden: het beleid is blokkerend en het huidige gebruik ligt strikt boven het inbegrepen quotum. Een budget-alert-beleid werpt nooit; overage wordt via alerts gesignaleerd.
  • remainingQuota() en usagePercentage() zijn pure reads en blokkeren nooit. Het resterende quotum gaat negatief bij overage; het gebruikspercentage overschrijdt 1.0 bij overage.
  • Alerts evalueren in oplopende drempelvolgorde: 80% warning, 100% warning (critical), daarna budget-exceeded (critical). Budget-exceeded is gegate op strikte overage; gebruik op precies 100% vuurt de 100% warning af, niet budget-exceeded.
  • Elk alerttype vuurt hoogstens één keer per tenant per billing-periode af. De fired-state wordt vastgelegd via AlertStateRepositoryInterface, dus deduplicatie is zo duurzaam als de gekozen implementatie.
  • De deduplicatiesleutel bevat de UTC-YYYY-MM-periode. Een nieuwe kalendermaand herbewapent daarom automatisch elk alerttype; er is geen clear-aanroep nodig voor het herbewapenen bij rollover. clearAlerts() wist de huidige periode, wat alerts midden in de periode herbewapent, bijvoorbeeld na een plan-upgrade.
  • Een plan-mismatch-guard in evaluate() wijst een aanroep af waarbij het aangeleverde plan en de plandefinitie niet overeenkomen, ter bescherming tegen een definitie van een andere tier dan het plan van de tenant.
  • Alle periode-rekenkunde is verankerd aan UTC. Het quota-exceeded-reset-moment is de eerste dag van de volgende kalendermaand om middernacht UTC; een soft-stop-respons zou dit als retry-horizon moeten adverteren.
  • QuotaEnforcementGuard is fail-closed in SaaS-modus. Ontbrekende tenant, ontbrekend plan, onbekende feature, store-uitval en quota-breach weigeren allemaal; niets valt door naar een impliciete allow. Non-SaaS-deployments doen alleen opt-out door de guard te construeren met een non-SaaS-DeploymentMode.
  • Blokkerende beleidsregels reserveren gebruik via UsageCounterStoreInterface::tryConsume, een atomaire compare-and-set. Gelijktijdige requests kunnen het gebruik niet gezamenlijk voorbij de limiet duwen; de verliezer van de race ontvangt QuotaExceededException ook al slaagde de pre-check.
  • Onder een budget-alert-beleid legt de guard verbruik best-effort vast en weigert nooit; een reservering voorbij het zachte plafond legt de rij nog steeds vast op de limiet.
  • QuotaExceededException is deployment-mode-bewust: SaaS-weigeringen mappen naar HTTP 402 met spec-code SPEC-BILLING-003 en worden als retryable gemarkeerd; on-prem-weigeringen mappen naar HTTP 403 met SPEC-LIC-001.
  • De library zendt zelf geen HTTP-responses uit. De gedeclareerde statuscodes zijn het contract voor de edge-laag, die een geworpen weigering naar een respons mapt en de billable handler niet mag aanroepen.
  • Niet-positief inbegrepen quotum. usagePercentage(), evaluate() en OverageCalculator::calculate() leveren allemaal een 0.0-gebruiksratio op in plaats van te delen door nul. Drempelalerts vuren dan nooit af op basis van de ratio alleen.
  • Budget-alert plus grote overage. De manager en de guard retourneren beide toegestane uitkomsten. Behandel de afwezigheid van een exceptie niet als bewijs dat je binnen het quotum zit; raadpleeg OverageResult of de alert-stream.
  • Precies op de limiet. checkQuota() bij currentCu == includedCuQuota slaagt. BudgetExceeded vereist strikte overage. UsageCounter::wouldExceed() is eveneens strikt.
  • MonthlyCapReached. De enum declareert dit vierde alerttype, maar BillingAlertService::evaluate() zendt het nooit uit; de kandidatenlijst dekt alleen de drie drempelalerts. Het is gereserveerd voor cap-tracking-emitters buiten deze module.
  • Dubbele tierdefinities. PlanRegistry indexeert op tierwaarde; de laatste definitie voor een tier vervangt eerdere stilzwijgend. Construeer registers vanuit een gededupliceerde lijst.
  • Nul-toelage versus unlimited. Een QuotaPolicy-limiet van 0.0 betekent dat elk verbruik in de periode overage is. Alleen de negatieve UNLIMITED-sentinel schakelt metering uit; isUnlimited() blokkeert nooit.
  • Niet-positieve reserveringshoeveelheid. enforce() weigert een niet-positieve $amount fail-closed met UsageStoreUnavailableException (503). Dit is een aanroeperdefect, geen store-uitval.
  • Store-uitval. Elke lees- of reserveringsfout verschijnt als UsageStoreUnavailableException en weigert. De guard staat nooit ongemeten werk toe terwijl de meter uit staat.
  • In-memory-implementaties. InMemoryAlertStateRepository en InMemoryUsageCounterStore zijn alleen correct binnen één PHP-proces. Multi-replica-deployments moeten implementaties leveren die worden ondersteund door een datastore met echte atomiciteit; een read-then-write-store is een defect dat over-quotum onder belasting toelaat.
  • FIPS-modus. Billing voert geen eigen cryptografische bewerkingen uit en heeft geen FIPS-specifiek gedrag. De tenant-identiteit die het consumeert, moet afkomstig zijn uit een geauthenticeerde context wiens FIPS-positie is gedocumenteerd bij het SaaS-oppervlak.
ClaimStandaardClausule
De 402-statuscode is gereserveerd voor toekomstig gebruik; ze draagt zelf geen normatieve request-semantiek.RFC 9110§15.5.3
429 geeft aan dat de client te veel requests binnen een gegeven tijdspanne heeft verzonden (“rate limiting”).RFC 6585§4
Retry-After geeft aan hoe lang de user agent zou moeten wachten voordat hij een vervolgrequest doet.RFC 9110§10.2.3

Alle clausules zijn geparafraseerd; NextPDF reproduceert geen normatieve tekst. NextPDF doet geen enkele HTTP-protocol-conformiteits- of certificeringsclaim voor dit oppervlak. De 402 / 429 / 200-mapping die OveragePolicy::httpStatusCode() declareert en de 401 / 402 / 503-weigeringscodes van de guard zijn een productconventie die is afgestemd op de clausules hierboven: RFC 9110 reserveert 402, dus het gebruik ervan voor betalingsweigering hier is de gangbare industrieconventie, geen door de IETF gedefinieerde semantiek. De soft-stop-retry-horizon (resetsAt) is de waarde die een edge-laag als Retry-After-begeleiding zou moeten tonen. Het uitzenden van daadwerkelijke HTTP-responses, headers en cachegedrag is de verantwoordelijkheid van de hostende applicatie.

  • Stel het model samen uit PlanRegistry::defaultRegistry(), één OveragePolicy en een QuotaManager; voeg BillingAlertService toe met een duurzame AlertStateRepositoryInterface-implementatie voor alerting.
  • Monteer QuotaEnforcementGuard in de request-pipeline na tenant-authenticatie en vóór de billable handler. Vang QuotaEnforcementException en de billing-QuotaExceededException af aan de edge en map httpStatusCode() naar de respons.
  • Plandefinities in deze module zijn de enige bron van waarheid voor billing; onderhoud nergens anders in je deployment een parallelle billing-definitie.
  • De in-memory-implementaties maken het hele oppervlak unit-testbaar zonder I/O. Aanbevolen grenswaardetests: gebruik precies op het quotum, één eenheid erboven, ratiodrempels op 0.8 en 1.0, de plan-mismatch-guard, de CAS-race (twee reserveringen tegen de laatste eenheid ruimte) en store-uitval-weigering.
  • De core-modelclasses dragen @since 2.2.0; het substraat draagt @since 2.3.0. De huidige pakketlijn is 3.1.0.
  • De operator is eigenaar van de alert-state-repository- en usage-store-implementaties, hun duurzaamheid over replica’s heen, en elk herbewapenen van alerts midden in de periode via clearAlerts().

Deze pagina documenteert alleen extern waarneembaar gedrag en het ondersteunde publieke API-oppervlak. Interne namespace-paden, helper-classes, mechanismetabellen, runbook-bestandsnamen en ticketprefixen vallen buiten de scope.