Documentation
¶
Overview ¶
manager.go is the PER-TENANT selector over the treasury Store: it resolves each request to its OWN Hanzo Base (SQLite) file instead of a process-wide singleton, so one tenant's finance/ledger writes can NEVER appear in another tenant's reads. This is the storage side of the standing Hanzo rule — Postgres stays a supported option (Formance, one layer up), but every tenant's books run live on its own Base file.
TWO file classes, one opener:
- the HOUSE ledger — the platform's OWN reserve fund (fund:reserve, revenue:*, payout:*): a SINGLE single-writer, overdraw-guarded file. It CANNOT be split per tenant (the reserve overdraw guard is one atomic balance), so it is one fixed file — the pre-existing {DataDir}/treasury.db, kept verbatim so live reserve capital is never orphaned by a path change.
- a CUSTOMER ledger — one isolated file per tenant at {DataDir}/finance/{slug}.db, opened on first use and cached.
It CONSUMES the treasury's canonical Base opener (Open, over github.com/hanzoai/ sqlite — the ONE Hanzo Base driver) rather than importing ledgercore's per-tenant opener: that opener is a test-only helper deliberately kept unexported because it registers modernc's database/sql "sqlite" driver, which would COLLIDE with the hanzoai/sqlite registration this store already carries. ledgercore's own contract is "production callers supply their own *bun.DB to New" — which Open does — so the per-tenant file selection lives HERE, over Open, and the slug guard matches ledgercore's per-tenant guard exactly.
Package sqlstore backs the treasury ledger.Store/ledger.Tx port with ledgercore — the ONE Hanzo double-entry engine (github.com/hanzo-fi/ledger) — over a single per-deployment SQLite file. It carries the storage concern the core deliberately does not, and NOTHING else.
THE CONVERGENCE: the treasury no longer hand-rolls its own double-entry SQL. The accounting truth — every account balance and the reserve overdraw guard — is computed by ledgercore (postings -> moves -> balances + a hash-chained log), the SAME engine the ledger's own store uses, so there is exactly one double-entry implementation across the stack. This adapter only translates the treasury's vocabulary (int64 cents, a Kind/Program/Ref idempotency key, a signed-Posting Entry) onto ledgercore, and holds the revenue-share policy — which is Hanzo config, NOT accounting — in a small side table.
The treasury's engine (clients/treasury/ledger) and its on-chain Root (a commitment over Entries) are UNCHANGED: this adapter round-trips each Entry verbatim (stored as ledgercore transaction metadata), so the Root is identical to the previous hand-rolled store's, independent of how ledgercore derives its own postings and balances.
It imports the core (ledger), the ONE engine (ledgercore), and the one Hanzo SQLite driver — never cloud, zip, or IAM — so it stays Base-compatible and travels with the core when it is lifted to hanzoai/finance.
Index ¶
- Constants
- type Manager
- type Store
- func (s *Store) Balance(ctx context.Context, account string) (int64, error)
- func (s *Store) BalancesWithPrefix(ctx context.Context, prefix string) (map[string]int64, error)
- func (s *Store) Close() error
- func (s *Store) Entries(ctx context.Context, limit int) ([]ledger.Entry, error)
- func (s *Store) Policy(ctx context.Context) (ledger.Policy, error)
- func (s *Store) SetPolicy(ctx context.Context, p ledger.Policy) error
- func (s *Store) Tx(ctx context.Context, fn func(ledger.Tx) error) error
Constants ¶
const HouseSlug = "house"
HouseSlug names the platform's OWN reserve/house ledger — the single (single-writer, overdraw-guarded) book behind every backed payout. It is RESERVED: tenantSlug routes a literal "house" tenant to a hashed slug, so a caller can never open the house fund by naming its org "house".
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager opens and caches one *Store per tenant. It is safe for concurrent use. Each distinct tenant maps to a distinct file; the mapping is INJECTIVE (it never folds "acme" and "ACME" into one bucket — that would itself be a cross-tenant break) and can never traverse the path or collide with the reserved house file.
func NewManager ¶
NewManager roots the per-tenant treasury stores under dataDir: the house ledger at {dataDir}/treasury.db (preserved) and customer ledgers under {dataDir}/finance/. The finance dir (and thus dataDir) is created if absent.
func (*Manager) Close ¶
Close closes every open store (house + tenants). Idempotent; returns the first close error, if any.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the SQLite-backed treasury ledger persistence. ONE file holds the whole chart of accounts, journal and policy for a deployment. It is serialized on a single connection so ledgercore's read-then-write balance guard is atomic under load.