AuroraMeter. Plan
(Aurora Meter v1.0.0)
View Source
A billing plan: an id, a monthly price (minor units / cents), a map of feature configurations and any recurring credit allowances it grants.
Feature configs:
{:limit, n, :hard}: hard cap; blocks atn.{:metered, included, unit_price}: allow overage; bill beyondincluded.{:counter}: measured, never blocked, never billed; no denominator.{:feature, boolean}: plain feature access (no quota).{:feature, non_neg_integer}: a plan-level value with no counter behind it (seats, retention days, projects): always entitled; read it withAuroraMeter.feature_value/3.
recurring_credits is a list of allowance declarations in declaration order,
each a map of name, amount, category, rollover and expires. It is
empty unless the plan declares AuroraMeter.Plans.recurring_credits/2, which
is what makes recurring grants off by default. AuroraMeter.Credits.Recurrences
is the engine that reads it; a new declaration kind was added here rather than
a new feature kind so every feature_config/0 consumer is untouched.
Identity
A plan is identified by {id, version}, not by id alone. version is a
short opaque string the host chooses ("1" when a block declares none),
effective_at is the UTC instant from which that version is the one a new
subscription gets (nil means "from the beginning"), and fingerprint is the
sha256 of the version's commercial content. Two deploys of the same
{id, version} with different content raise
AuroraMeter.PlanVersionConflictError rather than repricing every tenant:
see Plans.
Summary
Types
One recurring allowance, as AuroraMeter.Plans.recurring_credits/2 declares it.
Functions
The version every plan block carries when it does not declare one.
Types
@type feature_config() :: {:limit, non_neg_integer(), :hard} | {:metered, non_neg_integer(), number()} | {:counter} | {:feature, boolean() | non_neg_integer()}
@type recurring_credit() :: %{ name: atom(), amount: pos_integer(), category: :promotional | :paid | :adjustment, rollover: non_neg_integer(), expires: :period_end | :never | {:seconds, pos_integer()} }
One recurring allowance, as AuroraMeter.Plans.recurring_credits/2 declares it.
expires is :period_end (the lot expires when the period it was granted for
ends), :never, or {:seconds, n} counted from the grant.
@type t() :: %AuroraMeter.Plan{ effective_at: DateTime.t() | nil, features: %{optional(atom()) => feature_config()}, fingerprint: binary() | nil, id: atom(), price: non_neg_integer(), recurring_credits: [recurring_credit()], version: String.t() }
Functions
@spec base_version() :: String.t()
The version every plan block carries when it does not declare one.
It is the version AuroraMeter.Plans.register!/0 backfills onto every
subscription written before plan versions existed, so a tenant's commercial
contract is named rather than implied (D05).