Documentation
¶
Overview ¶
Package finance is the ZAP-native money subsystem: a per-CUSTOMER, double-entry PREPAID WALLET on the native ledger core. It is the in-process implementation of cloud's types.FinanceClient (package alias finance.Client, mirroring commerce.Client) — the ONE money seam the ai prepaid gate, the admin grant, and the edge meter all bill through.
ONE LIGHTWEIGHT FILE PER ORG. Each org's books are an isolated Hanzo Base (SQLite) file at <dataDir>/orgs/<org>/finance.db (a separate <...>/finance-test.db for sandbox money, so test and live never mix). There is NO shared or relational database — the file IS the tenant boundary, so one org's wallet writes can never appear in another org's read. A file opens on first use and is cached; opens are serialized so a concurrent first touch opens exactly once.
MONEY-SAFETY. Every write is a BALANCED double-entry posting inside the org's own file: a deposit is funding:platform → wallet (credit the customer, debit the platform float); a usage debit is wallet → revenue:platform (debit the customer, credit platform revenue) — so every customer debit IS a platform-revenue credit in one atomic entry, and a file's postings always sum to zero. Both writes are idempotent on their ref (the ledger's (kind,program,ref) idempotency): a usage debit on RequestID and a deposit on DepositInput.Ref, so a retried debit or a fixed-ref backfill posts AT MOST ONCE; a deposit with an empty Ref takes a fresh ref and stays additive (grants stack). Amounts are int64 minor units (USD cents) — no float ever touches a balance. A balance read is the settled ledger balance, clamped at zero; transient holds are the caller's in-pod concern, never persisted here.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MigrateOrg ¶
MigrateOrg carries an org's existing prepaid balance into its native finance wallet, EXACTLY ONCE — the cutover primitive that moves each tenant's money from the legacy commerce ledger onto the ONE finance ledger. It deposits balanceCents into org's pooled wallet (subject == the org slug) under the FIXED idempotency ref "backfill:<org>", so a re-run (a retried operator call, a replayed job) finds the existing entry and credits the wallet at most once — returning the original entry id, moving no money. A non-positive balance is skipped ("" , nil): there is nothing to carry. It resolves the process-wide finance client published at boot; a nil client (finance not co-resident on this deployment) is an error, since there is no wallet to migrate into.
func New ¶
func New(dataDir string) *ledgerFinance
New returns a finance client rooting each org's prepaid wallet file under dataDir (<dataDir>/orgs/<org>/finance.db, or finance-test.db in sandbox mode). Files open lazily on first use.
func Publish ¶
func Publish(c Client)
Publish records the process-wide finance client. Called once at boot; nil clears.
func SetUsageHook ¶
SetUsageHook installs the post-debit hook (the cap alert-fire). Pass nil to clear.
Types ¶
type Client ¶
type Client = types.FinanceClient
Client is the in-process inter-subsystem seam cloud's money paths call. It IS cloud's types.FinanceClient — one narrow interface (BalanceCents + Deposit + RecordUsage), kept as an alias so a value satisfies both names with no adapter (mirrors commerce.Client).
type UsageRow ¶
type UsageRow struct {
ID string `json:"id"`
Cents int64 `json:"cents"`
Model string `json:"model"`
CreatedAt int64 `json:"createdAt"`
}
UsageRow is one recorded usage debit — the READ twin of RecordUsage. The SAME wallet→revenue posting a metered call wrote is read back here, so the usage a customer SEES is exactly what drained their wallet. Cents is the debit magnitude (USD minor units); Model is the metered-unit label the debit carried (Entry.Memo); CreatedAt is unix seconds.