콘텐츠로 이동
getnextpdf.com

Enterprise 에디션

Billing — 심층 참조

이 페이지는 NextPDF Enterprise 청구 표면에 대한 심층 참조입니다. 이 표면은 두 계층으로 구성됩니다. NextPDF\Enterprise\Billing의 청구 모델은 플랜 등급, 할당량, 초과 정책, 중복 제거된 사용량 알림을 정의합니다. NextPDF\Enterprise\Billing\Substrate의 강제 substrate는 그 모델을 라이브 요청 경로에 fail-closed 및 동시성 안전하게 배치합니다. 진입점은 PlanRegistry, QuotaManager, OverageCalculator, BillingAlertService, QuotaEnforcementGuard입니다. 워크플로 수준 가이드는 Billing 기능 페이지를 참조하십시오.

이 기능은 NextPDF Enterprise(nextpdf/enterprise)에 포함되며 Enterprise 등급 라이선스 엔벨로프로 활성화됩니다. 해당 자격이 없는 배포는 이 기능의 클래스를 로드하지 않습니다. 에디션 비교 및 라이선스 받기.

Billing은 별도의 기능별 플래그가 없는 기본 Enterprise 기능입니다. Enterprise 패키지가 Core 패키지 옆에 설치되면 사용할 수 있습니다. NextPDF Core(Apache-2.0)와 NextPDF Pro에는 플랜, 할당량, 초과 모델이 없습니다. 이 표면에는 하위 등급 등가물이 없습니다. 플랜 포함 사항, 할당량, 상업 약관은 런타임 강제가 아니라 라이선스 계약에 의해 규율됩니다. 이 참조는 법률 또는 계약 의견이 아닙니다.

모든 심볼은 NextPDF\Enterprise\Billing 아래에 있습니다. substrate로 표시된 행은 NextPDF\Enterprise\Billing\Substrate 아래에 있습니다. TenantContextNextPDF\Enterprise\SaaS의 인증된 테넌트 타입입니다.

심볼매개변수기본 동작반환예외 또는 실패 조건참고
SaaSPlan (enum)문자열 기반 플랜 등급: standard, advanced, high_control예외를 던지지 않음label()은 표시 이름을 반환합니다
PlanDefinition::__constructSaaSPlan $plan, float $includedCuQuota, list<CapabilityCode> $capabilities, non-empty-string $priceTier, bool $intelligencePackIncluded, bool $privacyPackIncluded불변 플랜 값 객체; 입력을 주어진 대로 저장합니다새 인스턴스예외를 던지지 않음final readonly; 승격된 public 프로퍼티
PlanDefinition::includesCapabilityCapabilityCode $capability엄격한 동일성 멤버십 검사bool예외를 던지지 않음
PlanRegistry::__constructlist<PlanDefinition> $definitions정의를 등급별로 인덱싱합니다; 등급당 마지막 정의가 우선합니다새 레지스트리예외를 던지지 않음테스트 및 화이트 라벨 플랜 집합용
PlanRegistry::getSaaSPlan $plan정규 플랜 조회PlanDefinition플랜이 등록되지 않은 경우 InvalidArgumentException
PlanRegistry::hasSaaSPlan $plan등록 여부 확인bool예외를 던지지 않음
PlanRegistry::defaultRegistry (static)프로덕션 기본값: Standard 1,000 CU; Advanced 5,000 CU 및 Intelligence Pack; High Control 20,000 CU 및 Intelligence·Privacy PackPlanRegistry예외를 던지지 않음계약 약관이 사용자 정의 정의를 요구하지 않는 한 사용하십시오
OveragePolicy (enum)hard_stop, soft_stop, budget_alert예외를 던지지 않음httpStatusCode()는 402 / 429 / 200으로 매핑합니다; isBlocking()은 hard 및 soft stop에서만 true입니다
QuotaManager::__constructPlanRegistry $planRegistry, OveragePolicy $overagePolicy레지스트리를 하나의 정책에 바인딩합니다새 인스턴스예외를 던지지 않음
QuotaManager::checkQuotaTenantContext $tenant, SaaSPlan $plan, float $currentCu할당량 이하이거나 비차단 정책 하에서는 조용히 반환합니다void차단 정책 하에서 엄격한 초과 시 QuotaExceededException; 등록되지 않은 플랜에 대해 레지스트리에서 InvalidArgumentExceptionresetsAt = 다음 달 첫째 날, 자정 UTC
QuotaManager::remainingQuotaSaaSPlan $plan, float $currentCu순수 읽기; 절대 차단하지 않음float레지스트리 InvalidArgumentException초과 시 음수
QuotaManager::usagePercentageSaaSPlan $plan, float $currentCu순수 읽기; 절대 차단하지 않음float레지스트리 InvalidArgumentException포함 할당량이 양수가 아니면 0.0; 초과 시 1.0 초과
OverageCalculator::calculatePlanDefinition $plan, float $currentCu불변 초과 스냅샷을 계산합니다OverageResult예외를 던지지 않음final readonly, 무상태
OverageResultincludedCu, usedCu, overageCu, usageRatio, isOverage불변 계산 결과예외를 던지지 않음overageCu = max(0, used - included); isOverage는 엄격한 초과를 요구합니다
BillingAlertType (enum)quota_warning_80, quota_warning_100, budget_exceeded, monthly_cap_reached예외를 던지지 않음threshold() 0.8 / 1.0 / 1.0 / 1.0; severity() warning / critical / critical / critical
BillingAlertService::__constructAlertStateRepositoryInterface $alertState중복 제거 저장소를 바인딩합니다새 인스턴스예외를 던지지 않음
BillingAlertService::evaluateTenantContext $tenant, SaaSPlan $plan, PlanDefinition $planDef, float $currentCu아직 발생하지 않은 알림을 임계값 오름차순으로 발생시키고 기록합니다list<BillingAlertType>플랜/정의 불일치 시 InvalidArgumentException중복 제거 키: 테넌트, 유형, UTC YYYY-MM 기간
BillingAlertService::clearAlertsTenantContext $tenant현재 UTC 기간에 대한 테넌트의 발생 상태를 클리어합니다void리포지토리가 정의한 실패가 전파됩니다동일 기간 내에서 알림을 재무장합니다
AlertStateRepositoryInterfacehasAlertFired(), markAlertFired(), clearForPeriod()지속적 알림 중복 제거 지속성 계약메서드별구현 정의운영자가 복제본 전반의 지속성을 소유합니다
InMemoryAlertStateRepository배열 기반 발생 상태인터페이스별예외를 던지지 않음단일 요청 생명주기 및 테스트 전용
QuotaExceededExceptionReadonly currentCu, limitCu, resetsAt, tenantId, isSaaS배포 모드 인식 할당량 거부던져지는 예외httpStatusCode() 402 SaaS / 403 온프레미스; specCode() SPEC-BILLING-003 / SPEC-LIC-001; toErrorEnvelope()는 구조화된 오류 본문을 산출합니다
DeploymentMode (enum)saas, self_hosted_oss, local_development예외를 던지지 않음Substrate. enforcesQuota()Saas에서만 true입니다; 옵트아웃은 항상 명시적입니다
QuotaEnforcementGuard::__constructDeploymentMode, PlanResolverInterface, QuotaManager, UsageCounterStoreInterface라이브 할당량 게이트를 조립합니다새 인스턴스예외를 던지지 않음Substrate. final readonly
QuotaEnforcementGuard::enforce?TenantContext $tenant, non-empty-string $featureKey, float $amount = 1.0원자적 예약을 갖춘 fail-closed 할당량 게이트QuotaDecision (허용 결과만)아래 거부 분류 참조Substrate. 테넌트 인증 후, 청구 대상 핸들러 앞에 마운트하십시오
PlanResolverInterface::resolveTenantContext $tenant테넌트를 그 플랜 및 기능별 정책으로 해석합니다ResolvedPlanNoPlanForTenantExceptionSubstrate. 알 수 없는 테넌트에 대한 기본 플랜 폴백은 결함입니다
RegistryPlanResolverarray<non-empty-string, ResolvedPlan> $plansByTenant맵 기반 리졸버ResolvedPlan매핑되지 않은 테넌트에 대해 NoPlanForTenantExceptionSubstrate. 구성상 fail-closed
ResolvedPlan::policyFornon-empty-string $featureKey해석된 플랜에서의 정책 조회?QuotaPolicy예외를 던지지 않음Substrate. null은 알 수 없는 기능을 의미합니다; 가드가 이를 거부합니다
QuotaPolicynon-empty-string $featureKey, float $limit, OveragePolicy $overagePolicy기능별 한도 및 위반 정책예외를 던지지 않음Substrate. UNLIMITED = -1.0; 0.0 한도는 무제한이 아니라 제로 허용량입니다; isUnlimited(), isBlocking()
QuotaDecision정적 메서드 bypassed(), unlimited(), consumed()허용 결과 값 객체QuotaDecision예외를 던지지 않음Substrate. isAllowed()는 항상 true입니다; 모든 거부는 대신 예외를 던집니다
UsageCounter행 스냅샷: 테넌트, 기능, 기간 경계, used, limit, updatedAt불변 사용량 행예외를 던지지 않음Substrate. remaining()은 음수일 수 있습니다; wouldExceed()는 엄격합니다
UsageCounterStoreInterface::get테넌트, 기능, 기간 경계, float $limit사용량 행을 읽고, 없으면 used = 0으로 생성합니다UsageCounterUsageStoreUnavailableExceptionSubstrate. 백엔드 실패 시 절대 falsy 값을 반환하지 않습니다
UsageCounterStoreInterface::tryConsume테넌트, 기능, 기간 경계, float $amount, float $limit한도 내에서의 원자적 compare-and-set 예약?UsageCounter (예약이 한도를 위반하면 null)UsageStoreUnavailableExceptionSubstrate. 백킹 저장소에 대한 단일 원자적 작업이어야 합니다
InMemoryUsageCounterStore저장소 계약의 인프로세스 참조 구현인터페이스별인터페이스별Substrate. 단일 프로세스 전용; 원자성 불변식을 문서화합니다
QuotaEnforcementException (abstract)모든 substrate 거부의 기본 유형던져지는 예외 계열Substrate. 각 하위 유형이 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;

QuotaEnforcementGuard::enforce의 거부 분류

예외HTTP 상태발생 조건
MissingTenantContextException401SaaS 모드에서 인증된 테넌트 컨텍스트가 없음
NoPlanForTenantException402리졸버가 테넌트에 할당된 플랜을 찾지 못함
UnknownFeatureException402해석된 플랜이 기능 키에 대한 정책을 정의하지 않음
UsageStoreUnavailableException503사용량 저장소를 읽거나 원자적으로 업데이트할 수 없음; 양수가 아닌 $amount에 대해서도 발생
QuotaExceededException402 (SaaS) / 403 (온프레미스)차단 정책의 할당량이 초과되었거나, 동시 예약이 마지막 여유분을 소진함
  • 기본 레지스트리는 증가하는 CU 할당량과 기능 집합을 갖춘 세 가지 등급(Standard / Advanced / High Control)을 제공합니다. 등록되지 않은 플랜 요청은 명시적 InvalidArgumentException으로 실패합니다.
  • QuotaManager::checkQuota()는 두 조건이 모두 성립할 때만 예외를 발생시킵니다. 정책이 차단형이고, 현재 사용량이 포함 할당량을 엄격히 초과하는 경우입니다. 예산 알림 정책은 절대 발생시키지 않습니다; 초과는 알림을 통해 신호됩니다.
  • remainingQuota()usagePercentage()는 순수 읽기이며 절대 차단하지 않습니다. 초과 시 남은 할당량은 음수가 되고, 사용 백분율은 1.0을 초과합니다.
  • 알림은 임계값 오름차순으로 평가됩니다. 80% 경고, 100% 경고(critical), 그다음 예산 초과(critical)입니다. 예산 초과는 엄격한 초과에 게이트됩니다; 정확히 100% 사용량은 예산 초과가 아니라 100% 경고를 발생시킵니다.
  • 각 알림 유형은 테넌트당 청구 기간당 최대 한 번 발생합니다. 발생 상태는 AlertStateRepositoryInterface를 통해 기록되므로, 중복 제거는 선택한 구현만큼 지속됩니다.
  • 중복 제거 키는 UTC YYYY-MM 기간을 포함합니다. 따라서 새 달력 월은 모든 알림 유형을 자동으로 재무장합니다; 롤오버 재무장에는 클리어 호출이 필요하지 않습니다. clearAlerts()는 현재 기간을 클리어하여, 예를 들어 플랜 업그레이드 후처럼 기간 중간에 알림을 재무장합니다.
  • evaluate()의 플랜 불일치 가드는 제공된 플랜과 플랜 정의가 일치하지 않는 호출을 거부하여, 테넌트의 플랜과 다른 등급의 정의로부터 보호합니다.
  • 모든 기간 계산은 UTC에 고정됩니다. 할당량 초과 재설정 시점은 다음 달력 월의 첫째 날 자정 UTC입니다; 소프트 스톱 응답은 이를 재시도 기한으로 광고해야 합니다.
  • QuotaEnforcementGuard는 SaaS 모드에서 fail-closed입니다. 누락된 테넌트, 누락된 플랜, 알 수 없는 기능, 저장소 장애, 할당량 위반이 모두 거부됩니다; 어떤 것도 암묵적 허용으로 넘어가지 않습니다. 비SaaS 배포는 오직 비SaaS DeploymentMode로 가드를 구성함으로써만 옵트아웃합니다.
  • 차단 정책은 원자적 compare-and-set인 UsageCounterStoreInterface::tryConsume를 통해 사용량을 예약합니다. 동시 요청은 집합적으로 사용량을 한도 너머로 밀어낼 수 없습니다; 경쟁에서 진 쪽은 사전 검사가 통과했더라도 QuotaExceededException을 받습니다.
  • 예산 알림 정책 하에서 가드는 소비를 최선 노력으로 기록하며 절대 거부하지 않습니다; 소프트 상한을 넘는 예약도 여전히 한도에서 행을 기록합니다.
  • QuotaExceededException은 배포 모드를 인식합니다. SaaS 거부는 사양 코드 SPEC-BILLING-003과 함께 HTTP 402로 매핑되며 재시도 가능으로 표시됩니다; 온프레미스 거부는 SPEC-LIC-001과 함께 HTTP 403으로 매핑됩니다.
  • 라이브러리 자체는 HTTP 응답을 방출하지 않습니다. 선언된 상태 코드는 엣지 계층을 위한 계약이며, 엣지 계층은 던져진 거부를 응답으로 매핑하고 청구 대상 핸들러를 호출해서는 안 됩니다.
  • 양수가 아닌 포함 할당량. usagePercentage(), evaluate(), OverageCalculator::calculate()는 모두 0으로 나누는 대신 0.0 사용 비율을 산출합니다. 그러면 임계값 알림은 비율만으로는 절대 발생하지 않습니다.
  • 예산 알림과 큰 초과. 관리자와 가드 모두 허용 결과를 반환합니다. 예외의 부재를 할당량 내에 있다는 증거로 취급하지 마십시오; OverageResult 또는 알림 스트림을 참조하십시오.
  • 정확히 한도에서. currentCu == includedCuQuota에서의 checkQuota()는 통과합니다. BudgetExceeded는 엄격한 초과를 요구합니다. UsageCounter::wouldExceed() 역시 엄격합니다.
  • MonthlyCapReached. enum은 이 네 번째 알림 유형을 선언하지만, BillingAlertService::evaluate()는 절대 이를 방출하지 않습니다; 그 후보 목록은 세 가지 임계값 알림만 포함합니다. 이는 이 모듈 외부의 상한 추적 방출기를 위해 예약되어 있습니다.
  • 중복 등급 정의. PlanRegistry는 등급 값으로 인덱싱합니다; 등급에 대한 마지막 정의가 이전 정의를 조용히 대체합니다. 중복 제거된 목록으로 레지스트리를 구성하십시오.
  • 제로 허용량 대 무제한. QuotaPolicy 한도 0.0은 기간 내 모든 소비가 초과임을 의미합니다. 오직 음수 UNLIMITED 센티널만 계량을 비활성화합니다; isUnlimited()는 절대 차단하지 않습니다.
  • 양수가 아닌 예약 양. enforce()는 양수가 아닌 $amountUsageStoreUnavailableException(503)으로 fail-closed 거부합니다. 이는 저장소 장애가 아니라 호출자 결함입니다.
  • 저장소 장애. 모든 읽기 또는 예약 실패는 UsageStoreUnavailableException으로 표면화되어 거부됩니다. 가드는 계량기가 다운된 동안 계량되지 않은 작업을 절대 허용하지 않습니다.
  • 인메모리 구현. InMemoryAlertStateRepositoryInMemoryUsageCounterStore는 오직 하나의 PHP 프로세스 내에서만 정확합니다. 다중 복제본 배포는 실제 원자성을 갖춘 데이터스토어로 뒷받침되는 구현을 제공해야 합니다; read-then-write 저장소는 부하 하에서 할당량 초과를 허용하는 결함입니다.
  • FIPS 모드. 청구는 자체적으로 어떤 암호화 작업도 수행하지 않으며 FIPS 고유의 동작이 없습니다. 청구가 소비하는 테넌트 신원은 그 FIPS 태세가 SaaS 표면과 함께 문서화된 인증된 컨텍스트에서 비롯되어야 합니다.
주장표준
402 상태 코드는 향후 사용을 위해 예약되어 있습니다; 자체적인 규범적 요청 시맨틱을 담지 않습니다.RFC 9110§15.5.3
429는 클라이언트가 주어진 시간 내에 너무 많은 요청을 보냈음을 나타냅니다(“속도 제한”).RFC 6585§4
Retry-After는 사용자 에이전트가 후속 요청을 하기 전에 얼마나 기다려야 하는지를 나타냅니다.RFC 9110§10.2.3

모든 절은 의역되었습니다; NextPDF는 규범적 텍스트를 재현하지 않습니다. NextPDF는 이 표면에 대해 어떤 HTTP 프로토콜 적합성 또는 인증 주장도 하지 않습니다. OveragePolicy::httpStatusCode()가 선언하는 402 / 429 / 200 매핑과 가드의 401 / 402 / 503 거부 코드는 위 절에 정렬된 제품 관례입니다. RFC 9110은 402를 예약하므로, 여기서의 결제 거부 용도는 IETF가 정의한 시맨틱이 아니라 일반적인 업계 관례입니다. 소프트 스톱 재시도 기한(resetsAt)은 엣지 계층이 Retry-After 안내로 표면화해야 하는 값입니다. 실제 HTTP 응답, 헤더, 캐싱 동작을 방출하는 것은 호스팅 애플리케이션의 책임입니다.

  • PlanRegistry::defaultRegistry(), 하나의 OveragePolicy, QuotaManager로 모델을 구성하십시오; 알림을 위해 지속적 AlertStateRepositoryInterface 구현과 함께 BillingAlertService를 추가하십시오.
  • 테넌트 인증 후, 청구 대상 핸들러 앞의 요청 파이프라인에 QuotaEnforcementGuard를 마운트하십시오. 엣지에서 QuotaEnforcementException과 청구 QuotaExceededException을 잡아 httpStatusCode()를 응답으로 매핑하십시오.
  • 이 모듈의 플랜 정의는 청구의 단일 진실 공급원입니다; 배포의 다른 곳에서 병렬 청구 정의를 유지하지 마십시오.
  • 인메모리 구현은 전체 표면을 I/O 없이 단위 테스트 가능하게 만듭니다. 권장 경계 테스트: 정확히 할당량에서의 사용량, 한 단위 초과, 0.8 및 1.0에서의 비율 임계값, 플랜 불일치 가드, CAS 경쟁(마지막 여유 단위에 대한 두 예약), 저장소 장애 거부.
  • 코어 모델 클래스는 @since 2.2.0을 지니고; substrate는 @since 2.3.0을 지닙니다. 현재 패키지 라인은 3.1.0입니다.
  • 운영자는 알림 상태 리포지토리 및 사용량 저장소 구현, 복제본 전반의 지속성, 그리고 clearAlerts()를 통한 모든 기간 중간 알림 재무장을 소유합니다.

이 페이지는 외부에서 관찰 가능한 동작과 지원되는 공개 API 표면만 문서화합니다. 내부 네임스페이스 경로, 헬퍼 클래스, 메커니즘 표, 런북 파일명, 티켓 접두사는 범위 밖입니다.