Organization Credit Ledger
Understand pooled organization credits, append-only accounting, expiry, idempotent spending, and refunds.
Synced with starter commit
7d452a6.
Credits belong to an organization, so every member uses one pooled balance. The ledger is append-only: never update or delete entries, and never bypass src/services/credit.ts with direct SQL.
Grants create positive rows with a unique transaction number and optional expiry. Spending runs under an organization advisory lock, replays the full ledger, consumes the earliest-expiring grants first, and inserts negative rows only when sufficient usable balance exists. A spend may be split into physical :part:n rows; API views collapse them back into one logical transaction. Refunds append compensating rows tied to the original spend.
balance_after records the accounting ledger total at insertion, not necessarily the currently spendable amount after expiry. Use the supplied organization credit summary for available, granted, consumed, and expired totals.
All money- or credit-affecting calls need a stable business idempotency key. Two calls with the same key must produce one ledger effect; tests enforce replay behavior. Monthly subscription grants and Stripe fulfillment also use deterministic transaction numbers. Admin grants are capped and audited.
When adding a paid feature, calculate cost in configuration, verify its plan entitlement, spend through the credit service, retain the root transaction number on the domain row, and append a refund if the downstream operation fails.