6. The data model
From monetize main c9b473a5. Field lists are verbatim from the structs they cite.
6.1 The five rules the model rests on
These are the rules the code is built to (they were first written down as "the base model" in 2026-09; the code still names them by number in its comments):
| # | the rule | what it forbids | where it is real |
| 1 | reserve → ensure → capture. Lock the money, buy the iron, then draw; a failure at any point releases | charging for what was not delivered | crates/monetize/src/transaction.rs:1-50 |
| 2 | No balance. Every byte bought is attached to one customer's order | buying ahead, inventory, credit, "paid, not yet provisioned" | the reference <product>/<tenant>/<date>+<caps> on every row; Resource labelled monetize_ref at the cloud |
| 3 | The ledger is the only state, append-only, written BEFORE every external call | any number that cannot be rebuilt from the rows | ledger.rs:79-88; Ledger::attempt |
| 4 | Three seams: who takes money (Payment), who sells iron (Cloud), who counts usage (the product's report) |
vendor or product logic in the engine | chapter 3 |
| 5 | The product counts, monetize decides. The product measures and enforces at its one choke point; monetize owns the money and measures nothing | monetize measuring; the product knowing about money | Pulled answers every usage verb from the main's report (monetize-product/src/pulled.rs:141-143) |
Rule 2 is the one that kills ideas: is every byte we bought owned by a specific order? If not, it does not ship.
6.2 The stores on the box
All under <data>/monetize/ unless said (crates/monetize-server/src/config.rs:1672-1700):
| store | holds | written by |
ledger.redb |
tables steps (reference, seq) → Row, open, entitlements (product, tenant) → Fact, recent, pushes |
the transaction, the estate orders, the nonpay engine (crates/monetize/src/ledger.rs:1-36) |
usage.redb |
the tenants' meters as reported | the fleet reports |
signups.redb |
tables signups, refunds, minted, card_checks, welcomes, name_holds |
the signup engine (signup.rs:56-84) |
callbacks.redb, reconcile.redb |
vendor deliveries seen; reconcile cursors | the webhook; the reconcile job |
fleet.redb |
the Guardian store: estates, keys (pinned box keys), boxes, orders, counters (the sequences), auto_fix, cases, holds |
the fleet door, the Guardian (crates/monetize-guardian/src/store.rs:16-24) |
estate-orders/<company>/run.json, journal, laid.json, grow-<role>.journal |
one private estate's run, its cloud journal, what was laid | the estate driver |
nonpay.journal |
the nonpay engine's steps | nonpay.rs:74 |
signing.key |
the Ed25519 seed (32 bytes) every fact and order is signed with; one derived key per product | minted once at first start (crates/monetize/src/sign.rs; monetize-front/src/intake.rs:1105-1145) |
<name>-spend.json, <name>-guest-state.json, signup-guest-state.<product>.json |
a cloud's spend cap state, a cloud guest's state, a signup guest's state | the hosts |
attach/tokens.json, data/joined/<estate>.json |
one-shot attach tokens; enrolled estates | the attach door |
test-purchases.json |
the console's test buys | test_purchase.rs:36 |
<data>/monetize-ui/state.redb |
the console's passkeys and sessions | the console (monetize-admin/src/lib.rs:28) |
<data>/money/lines.log |
every money line PID 1 saw, in its own home | money_log.rs |
<data>/solo/door-feed.json, door-feed.taken, door-feed.next.json |
the feed in force, its receipt, the staged next feed | the door, PID 1 |
Backup: the ledger backup is one deterministic bundle (MFB1 magic; the manifest, ledger.jsonl, entitlements.jsonl, pushes.jsonl, usage.jsonl, signups.jsonl, refunds.jsonl, passes.jsonl, nonpay.jsonl, secret/signing.key, the identities), named snapshot-<unix>-<sha256>.mfb, made through Ledger.Export over loopback (crates/monetize-front/src/ledger_backup.rs). The off-box copy seals the export, the signing key, the custody and the journals with age to the operator's X25519 recipient every 360 min and PUTs it to the object store (monetize-admin/src/offsite.rs:1-28).
6.3 The ledger rows
Step kinds (crates/monetize/src/ledger.rs:89-352): Reserved { reference, handle, purchase }, Declined, Ensured, Destroyed, Captured, Settled, Released, EntitlementPushed { fact }, Reclaimed, Grown, RefundRequested, Reversed, TenantDeleted, UsersGranted, RoomTakenBack, Instance { reference, product, tenant, company, host, phase, monthly, paid_until_unix_ms, vendor, operator_test, note }.
The grammar of one attempt (:79-88):
Reserved (Ensured | Destroyed)* ( Captured ( EntitlementPushed | Destroyed* Released ) | Released )
Declined stands alone
The fold: Attempt { handle, purchase, ensured, captured, settlement, closed } with Closed::{ Released { reason }, Pushed { fact } } (:402-434). A Sale (:1727-1820) is the customer-facing fold: reference, product, tenant, price, cost, fee, vendor_tax, vendor_tax_basis_points, market, vat_basis_points, vendor, livemode, cloud, caps, delta, started_unix_ms, at_unix_ms, steps, drawn, outcome, refunded_minor, lost_minor, dispute, customer_tax_id, customer_country, granted_unix_ms, back_steps, with SaleOutcome::{ Granted, Refunded { reason, drawn }, Declined { reason }, Open }.
6.4 The purchase and the plan
pub struct Purchase { product, tenant, caps, delta, resources, price, market, cost,
vat_basis_points, policy, starts_unix_ms, payer, absorb, users, plan } // transaction.rs:91-155
pub struct Order { product, tenant, caps } // order.rs:40-45
pub enum Period { Month, Year }
pub struct PlanTerms { verb, period, size_bytes, month_price, accounts, cost_month, until_unix_ms, credit } // plan.rs:81-104
pub struct PlanSpec { size_bytes, period, target }
pub struct Policy { period, grace_days: 14, retention_days: 90 } // order.rs:99-117
The account's state is derived, never stored (order.rs:131-146): Free; else Paid until paid_until; then Grace; then Suspended; then Retention.
6.5 The signed entitlement fact
What a product holds about a tenant, verified offline with the public half it was given at enrolment (monetize_pubkey), on one atomic load and a map lookup; no network call on the request path (crates/monetize-product/src/lib.rs:631-692; crates/monetize-embed/src/signing.rs:111-166):
pub struct EntitlementFact {
pub tenant: TenantId,
pub plan: String, // the order reference
pub state: State, // Free | Paid | Grace | Suspended | Retention
pub paid_until_unix_ms: Option<u64>,
pub caps: BTreeMap<String, u64>, // meter → cap
pub source: String, // "operator" | "payment:<vendor>:<reference>" | "nonpay:deleted"
pub signature: Vec<u8>, // V1: Ed25519 over the canonical JSON of the fields above
pub issued_unix_ms: Option<u64>,
pub issued_signature: Vec<u8>, // V2: the same, with `issued` inside
}
The product refuses a fact not newer than the one it holds, a lone issued time, and a lone issued signature. It arrives as the entitlement order on the pull channel; the newest per tenant wins.
6.6 The estate run
EstateRun (crates/monetize-server/src/estate_order.rs:849-1110) is one private estate: the reference, the company, the host, the account, the quote (sizes, twin_plan, the price), the phase and its history, laid (what the cloud answered, per role), release_of per role, dns, paid_until, captured_at_ms, growth (the signed EstateGrowth), reminded (<paid_until>:<kind>:<day> per mail), stopped, new_account (the account a visitor's order makes, once, by its session), the vendor handle, operator_test, the spend cap fixed at its order, and the custody's sealed material. The Instance ledger row mirrors its phase, monthly price and paid_until.
6.7 The account records
pub struct PaidSignup { vendor, session, reference, email, username, product, plan, amount: Money, tax: Money, paid_at_unix_ms, customer_country } // monetize-pay/src/signup.rs:43-102
pub struct SignupRecord { signup: PaidSignup, state: SignupState, recorded_at_unix_ms, estate, card } // signup.rs:535-554
pub enum SignupState { Pending, Created { namespace, username, at_unix_ms }, Refused { reason, at_unix_ms, words, … } }
pub struct NewAccount { product, plan, currency, username, email, welcome_url, session, estate, site, back_to, cancel_to, test_payer } // estate_order/account.rs:185-216
pub struct SignupPlan { amount_minor, currency, cap_bytes, period_days } // config.rs:655-666
A free account plan is one with amount_minor = 0 (signup.rs:462-464). A name is held for 35 min while a page runs (NAME_HOLD_MS); a pending signup is forgotten after 24 h (PENDING_CEILING_MS).
6.8 The fleet store and the pinned keys
Per estate the Guardian store keeps (crates/monetize-guardian/src/store.rs): the estate record (product, instance, the laid roles), one pinned box key per role (the Ed25519 public key the box first presented inside its pin window), the box record (last heard, health, build), the open orders (SignedOrder until acked), the per-instance sequence counter, the auto-fix switch, the cases, and the holds. forget_box removes the key, the record and the pin window (:248-264). An order is SignedOrder { seq, product, instance, role, kind, body (JSON), issued_unix_ms, not_after_unix_ms, signature } (crates/monetize-embed/src/fleet.rs:142-154), signed under the domain nordisk-order-v1.
6.9 What signs what
| signer | key | signs | verified by |
| the ONE box | signing.key, derived per product |
entitlement facts, orders, EstateGrowth, the attach CA's issue |
the product (offline), every box (monetize_pubkey) |
| a box | its fleet key <data>/fleet/box.ed25519 |
Fleet.Report/Orders/Ask |
the ONE box against the pinned key |
| a front | the estate client key | Fleet.Ask as the front |
the ONE box |
| the release manager | plugin-signing.pk8 (CMS, chained to the plugin root) |
every plugin .p7s and the plugin list |
the box against guest_trust_roots |
| the korp root | the root seed on the operator's machine | the box's media and the live app | korp at boot and at stage_on against the enrolled root |
| the vendor | its webhook secret | webhook deliveries | the host's hmac door |