Credit account, quota and my subscription – system description

The account and credit ledger, the visible-scope rule, the top-up, charge and manual usage endpoints, the quota engine's decisions and the self-service view.

Overview

Management of user credit accounts and the self-service balance and usage view. The "Credit account" menu item is hidden (reachable by direct address); "My subscription" appears for every signed-in user. Table names carry the installation's own prefix in the database.

Data model

TableRole
subscription_accountaccount: user, home client (company_client_id), allow_negative, credit_limit
subscription_creditcredit ledger (Dlbtcredit: balance(), grant(), charge(), entries())
usage, usage_eventusage and events
permission_scopethe subscription_usage content rule

Visible scope

Super admin: every account. Others: getAllowedAccountUserIds() – their own row, plus the users listed in a subscription_usage content rule if they have one; otherwise every user of their own client. Row endpoints are guarded by accountInScope().

Endpoints

EndpointKeyBehaviour
account.list, account.entrieslist (BASE)balance, negative limit; the expander shows 100 credit entries and per-function usage
account.topuptopup (SYSTEM)out: Dlbtcredit::charge() (error_no_cover); in: Dlbtbilling::payIn() (credit + invoice + draft voucher), on failure Dlbtcredit::grant()
account.setlimitsetlimit (SYSTEM)reads and saves allow_negative, credit_limit
account.openopen (SYSTEM)ensureAccount(user_id)
account.usageaddusageaddonly for functions not measured automatically; new manual id, Dlbtquota::consume(..., 'manual', id)
account.usagereverseusagereversereverseUsageEvent()
account.my, usage, entrieslist, requestordermy (SYSTEM)own balance, allowances (Dlbtresource::balances), wallet, rewards, orders, per-function rows and quota, 500-entry credit ledger; requestorder notifies the users in the visible scope who may order

Quota engine (Dlbtquota)

check($user, $feature, $qty) → ok, overage (used up but coverable), need_credit (priced, no cover), need_plan (no price, only a plan change). The limit comes from the limit fields of the user's own row, otherwise from the plan; an allowance in the resource ledger decides if present; with metered every unit is charged. Price: overage price, otherwise unit price. The overage rule defaults to the setting (automatic credit charge by default). Money source: the client's wallet if available, otherwise the user's credit account. consume() records after a successful operation, idempotently.

Known limitations

  • setlimit exits on its error branch before writing the response (empty answer).
  • open does not check the content scope of the given user.
  • usagereverse checks the content scope AFTER reversing.
  • my, usage, entrieslist and requestorder call no canAction; the viewable user is limited to the visible scope.