Enterprise phiên bản
Billing — Tài liệu tham chiếu chuyên sâu
Tổng quan nhanh
Phần tiêu đề “Tổng quan nhanh”Trang này là tài liệu tham chiếu sâu cho bề mặt billing của NextPDF Enterprise. Bề mặt có hai lớp. Mô hình billing trong NextPDF\Enterprise\Billing định nghĩa các bậc gói, các hạn mức, các chính sách vượt mức, và các cảnh báo sử dụng đã khử trùng lặp. Substrate thực thi trong NextPDF\Enterprise\Billing\Substrate đặt mô hình đó lên đường request trực tiếp, fail-closed và an toàn với đồng thời. Các điểm vào là PlanRegistry, QuotaManager, OverageCalculator, BillingAlertService, và QuotaEnforcementGuard. Để biết hướng dẫn ở mức luồng công việc, xem trang năng lực Billing.
Khả dụng và cấp phép
Phần tiêu đề “Khả dụng và cấp phép”Năng lực này được phát hành trong NextPDF Enterprise (nextpdf/enterprise) và kích hoạt với một license envelope bậc Enterprise. Một triển khai không có quyền đó sẽ không nạp các lớp của năng lực này. So sánh các phiên bản và lấy giấy phép.
Billing là một năng lực Enterprise nền tảng không có cờ riêng cho từng tính năng; nó có sẵn ngay khi gói Enterprise được cài đặt cạnh gói Core. NextPDF Core (Apache-2.0) và NextPDF Pro không có mô hình gói, hạn mức, hay vượt mức nào; bề mặt này không có bản tương đương ở bậc thấp hơn. Những gì gói bao gồm, các hạn mức, và các điều khoản thương mại được chi phối bởi thỏa thuận giấy phép, không phải bởi việc thực thi tại runtime; tài liệu tham chiếu này không phải là một ý kiến pháp lý hay hợp đồng.
Bề mặt API công khai
Phần tiêu đề “Bề mặt API công khai”Mọi ký hiệu nằm dưới NextPDF\Enterprise\Billing. Các dòng đánh dấu substrate nằm dưới NextPDF\Enterprise\Billing\Substrate. TenantContext là kiểu tenant đã xác thực từ NextPDF\Enterprise\SaaS.
| Ký hiệu | Tham số | Hành vi mặc định | Trả về | Ném hoặc thất bại với | Ghi chú |
|---|---|---|---|---|---|
SaaSPlan (enum) | — | Các bậc gói backed bằng chuỗi: standard, advanced, high_control | — | Không ném | label() trả về tên hiển thị |
PlanDefinition::__construct | SaaSPlan $plan, float $includedCuQuota, list<CapabilityCode> $capabilities, non-empty-string $priceTier, bool $intelligencePackIncluded, bool $privacyPackIncluded | Value object gói bất biến; lưu các đầu vào như được cung cấp | Instance mới | Không ném | final readonly; các thuộc tính public được promote |
PlanDefinition::includesCapability | CapabilityCode $capability | Kiểm tra thành viên theo định danh nghiêm ngặt | bool | Không ném | — |
PlanRegistry::__construct | list<PlanDefinition> $definitions | Lập chỉ mục các định nghĩa theo bậc; định nghĩa cuối cùng cho mỗi bậc thắng | Registry mới | Không ném | Dành cho test và các tập gói white-label |
PlanRegistry::get | SaaSPlan $plan | Tra cứu gói chuẩn (canonical) | PlanDefinition | InvalidArgumentException khi gói chưa được đăng ký | — |
PlanRegistry::has | SaaSPlan $plan | Kiểm tra đăng ký | bool | Không ném | — |
PlanRegistry::defaultRegistry (static) | — | Mặc định production: Standard 1,000 CU; Advanced 5,000 CU cộng Intelligence Pack; High Control 20,000 CU cộng Intelligence Pack và Privacy Pack | PlanRegistry | Không ném | Dùng trừ khi các điều khoản hợp đồng yêu cầu định nghĩa tùy chỉnh |
OveragePolicy (enum) | — | hard_stop, soft_stop, budget_alert | — | Không ném | httpStatusCode() ánh xạ 402 / 429 / 200; isBlocking() chỉ đúng với hard stop và soft stop |
QuotaManager::__construct | PlanRegistry $planRegistry, OveragePolicy $overagePolicy | Gắn registry với một chính sách | Instance mới | Không ném | — |
QuotaManager::checkQuota | TenantContext $tenant, SaaSPlan $plan, float $currentCu | Trả về im lặng khi ở mức hoặc dưới hạn mức, hoặc dưới một chính sách không chặn | void | QuotaExceededException khi vượt mức nghiêm ngặt dưới một chính sách chặn; InvalidArgumentException từ registry khi gói chưa đăng ký | resetsAt = ngày đầu tiên của tháng tiếp theo, nửa đêm UTC |
QuotaManager::remainingQuota | SaaSPlan $plan, float $currentCu | Đọc thuần; không bao giờ chặn | float | InvalidArgumentException từ registry | Âm khi vượt mức |
QuotaManager::usagePercentage | SaaSPlan $plan, float $currentCu | Đọc thuần; không bao giờ chặn | float | InvalidArgumentException từ registry | 0.0 khi hạn mức đi kèm không dương; trên 1.0 khi vượt mức |
OverageCalculator::calculate | PlanDefinition $plan, float $currentCu | Tính một snapshot vượt mức bất biến | OverageResult | Không ném | final readonly, không trạng thái |
OverageResult | includedCu, usedCu, overageCu, usageRatio, isOverage | Kết quả tính toán bất biến | — | Không ném | overageCu = max(0, used - included); isOverage yêu cầu vượt mức nghiêm ngặt |
BillingAlertType (enum) | — | quota_warning_80, quota_warning_100, budget_exceeded, monthly_cap_reached | — | Không ném | threshold() 0.8 / 1.0 / 1.0 / 1.0; severity() warning / critical / critical / critical |
BillingAlertService::__construct | AlertStateRepositoryInterface $alertState | Gắn kho khử trùng lặp | Instance mới | Không ném | — |
BillingAlertService::evaluate | TenantContext $tenant, SaaSPlan $plan, PlanDefinition $planDef, float $currentCu | Phát các cảnh báo chưa-phát theo thứ tự ngưỡng tăng dần và ghi lại chúng | list<BillingAlertType> | InvalidArgumentException khi gói/định nghĩa không khớp | Khóa dedup: tenant, loại, kỳ UTC YYYY-MM |
BillingAlertService::clearAlerts | TenantContext $tenant | Xóa trạng thái đã-phát của tenant cho kỳ UTC hiện tại | void | Các lỗi do repository định nghĩa được lan truyền | Vũ trang lại các cảnh báo trong cùng kỳ |
AlertStateRepositoryInterface | hasAlertFired(), markAlertFired(), clearForPeriod() | Contract lưu bền cho khử trùng lặp cảnh báo | Theo từng phương thức | Do hiện thực định nghĩa | Người vận hành sở hữu độ bền qua các bản sao |
InMemoryAlertStateRepository | — | Trạng thái đã-phát backed bằng mảng | Theo interface | Không ném | Chỉ cho vòng đời một-request và test |
QuotaExceededException | Chỉ đọc currentCu, limitCu, resetsAt, tenantId, isSaaS | Từ chối hạn mức nhận biết chế độ triển khai | — | Là throwable | httpStatusCode() 402 SaaS / 403 on-prem; specCode() SPEC-BILLING-003 / SPEC-LIC-001; toErrorEnvelope() cho ra một error body có cấu trúc |
DeploymentMode (enum) | — | saas, self_hosted_oss, local_development | — | Không ném | Substrate. enforcesQuota() chỉ đúng cho Saas; việc opt-out luôn tường minh |
QuotaEnforcementGuard::__construct | DeploymentMode, PlanResolverInterface, QuotaManager, UsageCounterStoreInterface | Lắp ráp cổng hạn mức trực tiếp | Instance mới | Không ném | Substrate. final readonly |
QuotaEnforcementGuard::enforce | ?TenantContext $tenant, non-empty-string $featureKey, float $amount = 1.0 | Cổng hạn mức fail-closed với đặt chỗ nguyên tử | QuotaDecision (chỉ các kết quả được phép) | Xem phân loại từ chối bên dưới | Substrate. Gắn sau khi xác thực tenant, trước handler tính phí |
PlanResolverInterface::resolve | TenantContext $tenant | Phân giải một tenant thành gói và các chính sách theo từng tính năng của nó | ResolvedPlan | NoPlanForTenantException | Substrate. Một fallback gói-mặc-định cho tenant không rõ là một khiếm khuyết |
RegistryPlanResolver | array<non-empty-string, ResolvedPlan> $plansByTenant | Resolver backed bằng map | ResolvedPlan | NoPlanForTenantException cho các tenant chưa được ánh xạ | Substrate. Fail-closed theo thiết kế |
ResolvedPlan::policyFor | non-empty-string $featureKey | Tra cứu chính sách trên gói đã phân giải | ?QuotaPolicy | Không ném | Substrate. null nghĩa là tính năng không rõ; guard từ chối nó |
QuotaPolicy | non-empty-string $featureKey, float $limit, OveragePolicy $overagePolicy | Giới hạn theo từng tính năng và chính sách khi vi phạm | — | Không ném | Substrate. UNLIMITED = -1.0; giới hạn 0.0 là không cho phép gì, không phải không giới hạn; isUnlimited(), isBlocking() |
QuotaDecision | Các static bypassed(), unlimited(), consumed() | Value object kết quả được phép | QuotaDecision | Không ném | Substrate. isAllowed() luôn đúng; mọi từ chối đều ném thay vì thế |
UsageCounter | Snapshot dòng: tenant, tính năng, biên kỳ, used, limit, updatedAt | Dòng sử dụng bất biến | — | Không ném | Substrate. remaining() có thể âm; wouldExceed() là nghiêm ngặt |
UsageCounterStoreInterface::get | Tenant, tính năng, biên kỳ, float $limit | Đọc dòng sử dụng, tạo nó với used = 0 khi vắng mặt | UsageCounter | UsageStoreUnavailableException | Substrate. Không bao giờ trả về giá trị falsy khi backend lỗi |
UsageCounterStoreInterface::tryConsume | Tenant, tính năng, biên kỳ, float $amount, float $limit | Đặt chỗ compare-and-set nguyên tử trong giới hạn | ?UsageCounter (null khi việc đặt chỗ sẽ vượt giới hạn) | UsageStoreUnavailableException | Substrate. Phải là một thao tác nguyên tử đơn lẻ đối với kho lưu trữ nền |
InMemoryUsageCounterStore | — | Hiện thực tham chiếu in-process của contract kho | Theo interface | Theo interface | Substrate. Chỉ một tiến trình; tài liệu hóa bất biến về tính nguyên tử |
QuotaEnforcementException (abstract) | — | Kiểu cơ sở của mọi từ chối substrate | — | Là họ throwable | Substrate. Mỗi subtype khai báo httpStatusCode() |
public function checkQuota(TenantContext $tenant, SaaSPlan $plan, float $currentCu): voidpublic function evaluate( TenantContext $tenant, SaaSPlan $plan, PlanDefinition $planDef, float $currentCu,): arraypublic function enforce(?TenantContext $tenant, string $featureKey, float $amount = 1.0): QuotaDecisionpublic function tryConsume( string $tenantId, string $featureKey, DateTimeImmutable $periodStart, DateTimeImmutable $periodEnd, float $amount, float $limit,): ?UsageCounter;Phân loại từ chối của QuotaEnforcementGuard::enforce
| Exception | Trạng thái HTTP | Được ném khi |
|---|---|---|
MissingTenantContextException | 401 | Chế độ SaaS mà không có ngữ cảnh tenant đã xác thực |
NoPlanForTenantException | 402 | Resolver không tìm thấy gói nào được gán cho tenant |
UnknownFeatureException | 402 | Gói đã phân giải không định nghĩa chính sách nào cho feature key |
UsageStoreUnavailableException | 503 | Không thể đọc hoặc cập nhật nguyên tử usage store; cũng được ném cho $amount không dương |
QuotaExceededException | 402 (SaaS) / 403 (on-prem) | Hạn mức của một chính sách chặn bị vượt, hoặc một đặt chỗ đồng thời đã tiêu thụ headroom cuối cùng |
Hợp đồng hành vi
Phần tiêu đề “Hợp đồng hành vi”- Registry mặc định cung cấp ba bậc (Standard / Advanced / High Control) với hạn mức CU và các tập năng lực tăng dần. Một yêu cầu cho gói chưa đăng ký thất bại với một
InvalidArgumentExceptiontường minh. QuotaManager::checkQuota()chỉ phát sinh khi cả hai điều kiện đúng: chính sách là chặn, và mức sử dụng hiện tại nghiêm ngặt vượt trên hạn mức đi kèm. Một chính sách budget-alert không bao giờ phát sinh; việc vượt mức được báo hiệu qua các cảnh báo.remainingQuota()vàusagePercentage()là các đọc thuần và không bao giờ chặn. Hạn mức còn lại trở thành âm khi vượt mức; phần trăm sử dụng vượt1.0khi vượt mức.- Các cảnh báo được đánh giá theo thứ tự ngưỡng tăng dần: cảnh báo 80%, cảnh báo 100% (critical), rồi budget-exceeded (critical). Budget-exceeded được gate trên việc vượt mức nghiêm ngặt; mức sử dụng đúng 100% phát ra cảnh báo 100%, không phải budget-exceeded.
- Mỗi loại cảnh báo phát ra nhiều nhất một lần cho mỗi tenant mỗi kỳ billing. Trạng thái đã-phát được ghi qua
AlertStateRepositoryInterface, nên việc khử trùng lặp bền như hiện thực được chọn. - Khóa khử trùng lặp nhúng kỳ UTC
YYYY-MM. Do đó một tháng dương lịch mới tự động vũ trang lại mọi loại cảnh báo; không cần lời gọi clear nào cho việc vũ trang lại khi chuyển kỳ.clearAlerts()xóa kỳ hiện tại, việc này vũ trang lại các cảnh báo giữa kỳ, ví dụ sau khi nâng cấp gói. - Một guard plan-mismatch trong
evaluate()từ chối một lời gọi khi gói được cung cấp và định nghĩa gói không khớp, bảo vệ chống lại một định nghĩa từ một bậc khác với gói của tenant. - Mọi phép tính kỳ được neo vào UTC. Thời điểm reset vượt-hạn-mức là ngày đầu tiên của tháng dương lịch tiếp theo lúc nửa đêm UTC; một phản hồi soft-stop nên quảng bá nó làm chân trời thử lại.
QuotaEnforcementGuardlà fail-closed trong chế độ SaaS. Thiếu tenant, thiếu gói, tính năng không rõ, sự cố kho, và vi phạm hạn mức đều từ chối; không có gì lọt qua thành một cho-phép ngầm định. Các triển khai không-SaaS chỉ opt out bằng cách dựng guard với mộtDeploymentModekhông-SaaS.- Các chính sách chặn đặt chỗ mức sử dụng qua
UsageCounterStoreInterface::tryConsume, một compare-and-set nguyên tử. Các request đồng thời không thể cùng nhau đẩy mức sử dụng vượt giới hạn; kẻ thua trong cuộc đua nhậnQuotaExceededExceptiondù pre-check đã qua. - Dưới một chính sách budget-alert, guard ghi lại mức tiêu thụ theo kiểu best-effort và không bao giờ từ chối; một đặt chỗ vượt trần mềm vẫn ghi dòng ở mức giới hạn.
QuotaExceededExceptionnhận biết chế độ triển khai: các từ chối SaaS ánh xạ tới HTTP 402 với spec codeSPEC-BILLING-003và được đánh dấu có thể thử lại; các từ chối on-prem ánh xạ tới HTTP 403 vớiSPEC-LIC-001.- Thư viện không tự phát ra các phản hồi HTTP. Các mã trạng thái được khai báo là contract cho lớp edge, lớp này ánh xạ một từ chối được ném thành một phản hồi và không được gọi handler tính phí.
Trường hợp biên và chế độ lỗi
Phần tiêu đề “Trường hợp biên và chế độ lỗi”- Hạn mức đi kèm không dương.
usagePercentage(),evaluate(), vàOverageCalculator::calculate()đều cho ra tỷ lệ sử dụng0.0thay vì chia cho không. Khi đó các cảnh báo ngưỡng không bao giờ phát chỉ từ tỷ lệ. - Budget-alert cộng với vượt mức lớn. Cả manager và guard đều trả về các kết quả được phép. Đừng coi việc không có exception là bằng chứng rằng đang trong hạn mức; hãy tham khảo
OverageResulthoặc luồng cảnh báo. - Đúng ở giới hạn.
checkQuota()tạicurrentCu == includedCuQuotathì qua.BudgetExceededyêu cầu vượt mức nghiêm ngặt.UsageCounter::wouldExceed()cũng nghiêm ngặt. MonthlyCapReached. Enum khai báo loại cảnh báo thứ tư này, nhưngBillingAlertService::evaluate()không bao giờ phát ra nó; danh sách ứng viên của nó chỉ bao gồm ba cảnh báo ngưỡng. Nó được dành riêng cho các emitter theo dõi cap bên ngoài module này.- Định nghĩa bậc trùng lặp.
PlanRegistrylập chỉ mục theo giá trị bậc; định nghĩa cuối cùng cho một bậc âm thầm thay thế các định nghĩa trước. Hãy dựng registry từ một danh sách đã khử trùng lặp. - Không-cho-phép so với không-giới-hạn. Một giới hạn
QuotaPolicybằng0.0nghĩa là mọi mức tiêu thụ trong kỳ đều là vượt mức. Chỉ sentinel âmUNLIMITEDmới vô hiệu hóa việc đo lường;isUnlimited()không bao giờ chặn. - Lượng đặt chỗ không dương.
enforce()từ chối một$amountkhông dương theo kiểu fail-closed vớiUsageStoreUnavailableException(503). Đây là khiếm khuyết của người gọi, không phải sự cố kho. - Sự cố kho. Bất kỳ lỗi đọc hay đặt chỗ nào đều nổi lên dưới dạng
UsageStoreUnavailableExceptionvà từ chối. Guard không bao giờ cho phép công việc không-được-đo trong khi bộ đo hỏng. - Các hiện thực in-memory.
InMemoryAlertStateRepositoryvàInMemoryUsageCounterStorechỉ đúng trong một tiến trình PHP. Các triển khai đa-bản-sao phải cung cấp các hiện thực được backed bởi một datastore có tính nguyên tử thực sự; một kho đọc-rồi-ghi là một khiếm khuyết cho phép vượt-hạn-mức dưới tải. - Chế độ FIPS. Billing không thực hiện thao tác mật mã nào của riêng nó và không có hành vi riêng cho FIPS. Định danh tenant mà nó tiêu thụ phải bắt nguồn từ một ngữ cảnh đã xác thực có tư thế FIPS được tài liệu hóa cùng với bề mặt SaaS.
Phù hợp tiêu chuẩn
Phần tiêu đề “Phù hợp tiêu chuẩn”| Khẳng định | Tiêu chuẩn | Điều khoản |
|---|---|---|
| Mã trạng thái 402 được dành riêng cho sử dụng tương lai; nó không mang ngữ nghĩa request quy chuẩn nào của riêng nó. | RFC 9110 | §15.5.3 |
| 429 cho biết client đã gửi quá nhiều request trong một khoảng thời gian nhất định (“rate limiting”). | RFC 6585 | §4 |
| Retry-After cho biết user agent nên chờ bao lâu trước khi thực hiện một request tiếp theo. | RFC 9110 | §10.2.3 |
Mọi điều khoản đều được diễn giải lại; NextPDF không tái hiện văn bản quy chuẩn. NextPDF không đưa ra khẳng định phù hợp hay chứng nhận giao thức HTTP nào cho bề mặt này. Ánh xạ 402 / 429 / 200 do OveragePolicy::httpStatusCode() khai báo và các mã từ chối 401 / 402 / 503 của guard là một quy ước sản phẩm phù hợp với các điều khoản trên: RFC 9110 dành riêng 402, nên việc dùng nó cho từ-chối-thanh-toán ở đây là quy ước ngành phổ biến, không phải một ngữ nghĩa do IETF định nghĩa. Chân trời thử lại soft-stop (resetsAt) là giá trị mà một lớp edge nên phơi bày làm hướng dẫn Retry-After. Việc phát ra các phản hồi HTTP thực, các header, và hành vi caching là trách nhiệm của ứng dụng chủ.
Ghi chú phát triển
Phần tiêu đề “Ghi chú phát triển”- Kết hợp mô hình từ
PlanRegistry::defaultRegistry(), mộtOveragePolicy, và mộtQuotaManager; thêmBillingAlertServicevới một hiện thựcAlertStateRepositoryInterfacebền để cảnh báo. - Gắn
QuotaEnforcementGuardtrong pipeline request sau khi xác thực tenant và trước handler tính phí. BắtQuotaEnforcementExceptionvàQuotaExceededExceptioncủa billing ở lớp edge và ánh xạhttpStatusCode()tới phản hồi. - Các định nghĩa gói trong module này là nguồn duy nhất của sự thật cho billing; đừng duy trì một định nghĩa billing song song ở nơi khác trong triển khai của bạn.
- Các hiện thực in-memory làm cho toàn bộ bề mặt có thể unit-test mà không cần I/O. Các test biên được khuyến nghị: mức sử dụng đúng ở hạn mức, một đơn vị trên, các ngưỡng tỷ lệ ở 0.8 và 1.0, guard plan-mismatch, cuộc đua CAS (hai đặt chỗ đối với đơn vị headroom cuối cùng), và từ chối do sự cố kho.
- Các lớp mô hình core mang
@since 2.2.0; substrate mang@since 2.3.0. Dòng gói hiện tại là 3.1.0. - Người vận hành sở hữu các hiện thực repository trạng thái cảnh báo và usage-store, độ bền của chúng qua các bản sao, và bất kỳ việc vũ trang lại cảnh báo giữa kỳ nào qua
clearAlerts().
Ranh giới công bố
Phần tiêu đề “Ranh giới công bố”Trang này chỉ tài liệu hóa hành vi quan sát được từ bên ngoài và bề mặt API công khai được hỗ trợ. Các đường dẫn namespace nội bộ, lớp helper, bảng cơ chế, tên tệp runbook, và tiền tố ticket nằm ngoài phạm vi.