Reframing Billing Storage explains why UBX-DB treats the billing ledger as a product feature instead of a maintenance chore, giving product, finance, and support teams one durable system to trust.
In most product teams the billing ledger is a reluctant hero. It is the system that everyone depends on to reconcile usage, issue invoices, unblock customer care tickets, and satisfy auditors, yet few teams choose to specialize in it. UBX-DB was born from that tension. It is a deliberately lean document database designed for usage and billing events, shaped by the realities of teams who need durable records, can tolerate milliseconds of extra work per request, and obsess over cost more than ever. Rather than copying the shape of a general-purpose database, it borrows the price profile and durability story of an object store and wraps it in a developer-first API. This post explores the system at a narrative level, what problems it solves, how it is pieced together, and why that composition matters, while steering clear of the implementation particulars hidden inside the repository.
The Ledger Problem
Usage ledgers sit in an awkward tier between transactional workloads and archival storage. Finance teams demand write amplification so small that nothing can get lost, compliance teams expect point-in-time lookups, and product leads insist that customers can self-serve reports. Traditional relational systems can satisfy those needs, but the operational footprint quickly balloons once multi-tenant isolation, schema evolution, and sudden query spikes enter the story. UBX-DB positions itself between raw object storage and a fully managed analytical warehouse. It leans on append-only economics to keep hot paths predictable yet avoids locking users inside batch processing mindsets. The database treats every document as an immutable event, keeps the idea of “account” front and center, and allows each tenant to grow from a handful of records to millions without migrating infrastructure. That balance, event-first thinking with pragmatic APIs, forms the spine of UBX-DB’s proposition.
Guiding Principles
The project was born with a clear charter captured in its early design notes: stay simple, stay affordable, and stay adaptable. Every major decision maps back to at least one of those guardrails. Simplicity means one process in front of storage, a single mental model for how documents flow, and request semantics that mirror HTTP expectations. Affordability shows up through object-store-aligned costs, per-request compute that spins up only when needed, and avoidance of stateful replicas that would sit idle for most tenants. Adaptability manifests as plug-and-play storage backends, the ability to run locally without any cloud dependencies, and query semantics rich enough for product analytics yet conservative enough to deliver predictable latency. These principles give the team the confidence to say “no” to features that look attractive but would drag the system towards heavyweight database territory.
Architecture Snapshot
Conceptually, UBX-DB is split into two layers: a stateless HTTP server that handles authentication, validation, and query orchestration, and a storage engine that knows how to append, read, and prune documents for each account. The boundary between them is formalized through a storage contract. Because the contract is narrow, append, lookup, query, delete, compact, close, the API layer is blissfully unaware of whether the backing store sits on a laptop, a mounted disk, or a remote bucket. Requests arrive through a lightweight Go service that uses a minimalist router. The server enforces tenant scoping via contextual metadata rather than embedding account identifiers inside payloads, so the same document schema works across all tenants. Downstream, the storage engine is free to choose its layout, as long as it honors the contract around pagination, filtering, and aggregations. This seam is what makes it possible to swap the current local filesystem driver with a future cloud-native backend without rewriting the API.
System flow at a glance
SDKs & Jobs] --> API[UBX-DB API Layer] Admin[Ops & Support Tools] --> API API --> Guard[Auth & Tenant Scoping] Guard --> Router[Validation & Query Orchestration] Router -->|Append Contract| Storage[(Pluggable Storage Driver)] Storage --> Ledger[(Immutable Ledger Files)] Storage --> Router Router --> Reports[Aggregations & Exports] Reports --> API
Multi-Tenant First
Billing storage is useless if it cannot enforce boundaries between customers. UBX-DB builds multi-tenancy into every layer. The API refuses requests that lack account context, the storage engine keeps independent partitions per account, and query semantics disallow filtering on account identifiers to prevent cross-tenant leakage. Each append, read, or delete runs through that isolation logic before touching storage, so there is no chance of accidentally leaking data from one tenant into another. Even secondary features, like pagination tokens and aggregation helpers, embed the account identity to avoid replay attacks across partitions. The result is a platform that can host a thousand smaller tenants in the same deployment without forcing any one of them to carry the cost of another.
Append-First Ingestion
UBX-DB treats every incoming record as an immutable event. The ingestion path is optimized for bursty writes: clients post batches of documents, the API validates structure and required fields, and the storage backend appends them to tenant-specific segments. Instead of coordinating long-lived transactions, the system commits data in micro-batches, allowing the storage layer to acknowledge the write as soon as it is durably persisted. This model keeps throughput consistent even when multiple tenants append simultaneously. By acknowledging the whole batch with a single round-trip, the API informs clients how many documents were accepted and how much work the system had to perform. That last detail, the “normalized cost” concept exposed in responses, gives downstream consumers a way to attribute usage-based spending back to specific operations without waiting for daily reports.
Querying Without Surprises
Read paths in UBX-DB are intentionally conservative: the service focuses on point lookups and narrow filters rather than arbitrary SQL. Clients express filters through simple field comparisons (field=value, range comparisons, membership checks), optionally add timestamp bounds, and receive either a page of documents or an aggregation result. The storage engine honors these constraints by scanning just enough segments to satisfy the request and stopping early once limits are met. For pagination, the service returns opaque tokens that encode how far the scan advanced within a tenant’s partition, sparing clients from managing offsets. Because the query language is limited, the storage engine can make deterministic decisions about which files to inspect and which to skip, keeping tail latency under control even as datasets grow.
Lightweight Aggregations
While the system avoids full SQL semantics, it embraces a handful of aggregations that billing teams use daily. Clients can ask for counts, sums, or unique counts over a field, combining those aggregations with the same filters and time windows used for document retrieval. The API orchestrates these requests by bypassing pagination when an aggregation is requested, ensuring that the storage engine reads all relevant events in one pass. The outcome is immediate roll-ups, monthly usage totals, unique subscriber counts, revenue sums, that power dashboards without shipping data into a separate warehouse. Importantly, the aggregation support sticks to deterministic operations that can execute over streaming data; anything that requires global ordering or complex joins remains out of scope, keeping the implementation lean.
Operating Efficiently
A key promise of UBX-DB is that it can run cheaply on Cloud Run without constant babysitting. To deliver on that, the storage engine embraces a tiered layout. Recent writes live in compact segments optimized for fast reads, while background compaction jobs periodically merge older segments into larger artifacts better suited for archival access. This compaction step is optional but highly recommended for tenants with steady workloads, as it trims storage overhead and keeps lookup times bounded even after months of accrual. Operational tooling exposes statistics about how many segments were compacted, how many documents moved, and which tenants benefited, giving operators feedback loops without peering into raw data. Because compaction runs through the same storage contract, it can operate offline or as a scheduled job in the cloud, whichever fits the deployment model.
Cost Story
Every product decision circles back to cost. UBX-DB borrows the price curve of object storage: documents are persisted in formats that map cleanly to blobs, the API is stateless and can scale down to zero, and compaction keeps total bytes in check. Designers modeled the economics using a simple formula with inputs like records per month, average payload size, request rates, and Cloud Run execution times. The resulting estimates show that even tenants pushing tens of millions of events per month stay within low double-digit monthly spend when hosted on mainstream cloud infrastructure. That affordability story is bolstered by usage headers so clients can implement internal chargeback or throttle themselves before costs spiral. The system intentionally avoids hidden dependencies, no proprietary indexes, no dedicated clusters, so operators understand exactly which levers control spend.
Local-First Developer Experience
A surprising amount of billing work still happens on laptops. Analysts need to inspect payloads, developers want to test integrations, and QA engineers must reproduce scenarios without touching production data. UBX-DB caters to that by shipping with a local backend that mimics cloud semantics. Running the service locally does not require credentials, remote buckets, or emulators; the same API surface behaves identically, just storing data on the developer’s machine. Because the storage contract is uniform, the local driver can be swapped with an object-store-backed driver later without refactoring application code. This approach shortens onboarding time, reduces reliance on shared staging environments, and encourages teams to build automated tests that spin up the database as part of their suite.
Reliability and Insight
Durability and observability go hand in hand. The ingestion path stamps every document with a timestamp when one is not provided, ensuring time-based queries can always reason about ordering. The API decorates responses with metadata such as the total number of documents scanned and the logical path to the tenant’s partition, empowering operators to spot anomalies quickly. Error handling distinguishes between user mistakes (malformed documents, invalid filters) and system faults, allowing clients to respond appropriately. On the observability front, the plan includes structured logging, request tracing, and per-tenant metrics so teams can track usage trends. Although the current implementation stays intentionally slim, the road is paved for deeper integrations with dashboards and alerting systems.
Security and Governance
Security concerns for billing systems revolve around data separation and auditability. UBX-DB enforces account scoping at every entry point and avoids accepting filters that could pierce that boundary. Deletions happen within the tenant context, producing consistent responses whether the document existed or not, so clients can build idempotent workflows. Future iterations aim to add fine-grained authorization layers, but the foundation is already set: the API trusts upstream authentication to inject the account identity and refuses to operate without it. This strategy keeps the surface area small and signals clearly where enterprises can hook in their identity providers or policy engines.
Roadmap Glimpse
The team keeps an intentionally short roadmap focused on deepening, not widening, the product. On the query side, more expressive predicates (combined filters, range helpers) are on the horizon, provided they do not compromise determinism. Operationally, there is appetite for elevating the compaction tool into a managed service that can schedule work, emit metrics, and retry automatically. Observability features, request tracing, per-account dashboards, health probes, are also in the pipeline, recognizing that teams need evidence when something feels off. Finally, the companion web console is slated for richer experiences: saved queries, quick charts, and guided bulk actions so non-engineers can navigate the ledger without shell access. Each item reinforces the core vision rather than turning UBX-DB into a general-purpose database.
Choosing Cloud Storage Wisely
One of the recurring questions is whether cheaper object stores outside the primary cloud provider are worth the egress trade-offs. The current stance is pragmatic: while alternative providers advertise attractive per-gigabyte prices, routing traffic between clouds introduces egress fees and latency that can erase savings. Inbound and outbound data charges stack up quickly when compaction jobs rewrite segments or when analytics dashboards trigger repeated reads. UBX-DB therefore gravitates toward keeping compute and storage within the same provider unless a team has a compelling reason to straddle clouds and can tolerate the operational complexity. The architecture does not preclude alternative backends, but the economic model urges teams to scrutinize the full picture before switching.
RapidAPI and Beyond
Some teams intend to expose UBX-DB-backed APIs through marketplaces such as RapidAPI. The design anticipates that scenario by encouraging thoughtful rate limits: cap daily requests to align with expected Cloud Run spend, constrain requests per second to prevent burst exhaustion, and keep the documents-per-request ceiling tight so abusive clients cannot overwhelm the service. Because UBX-DB already tracks normalized cost per call, operators can map marketplace quotas to real infrastructure impact, adjusting plans as demand grows. This plays into the broader philosophy of giving teams levers to manage cost without rewriting their systems.
Living with UBX-DB
Adopting UBX-DB means embracing a mindset: documents are immutable events, storage behaves like an object store, and analytics stay close to the write path. Teams that benefit the most are those who need trustworthy usage data, cannot justify dedicated database clusters, and enjoy the freedom of stateless services that scale on demand. The project is not a silver bullet for every analytics workload, nor does it aim to compete with mature data warehouses. Instead, it fills the space where invoices, usage dashboards, entitlement checks, and customer support interactions intersect. By focusing on that niche and staying disciplined about scope, UBX-DB offers a compelling alternative to rolling a bespoke solution for the hundredth time.
Closing Thoughts
UBX-DB proves that a billing-centric document store does not need to be bloated or expensive to operate. By fusing an approachable API with storage economics borrowed from object stores, it gives teams a durable ledger that grows with them. The careful separation between API and storage lets the system evolve without breaking contracts, while the multi-tenant focus keeps customer data safe. Just as importantly, the development experience remains approachable: teams can hack on the system locally, deploy it to Cloud Run when ready, and only opt into advanced features when they need them. As the roadmap unfolds, bringing smarter queries, richer observability, and tighter operational tooling, the project should remain true to its roots: simple, cost-conscious, and relentlessly focused on the billing and usage workloads that most products cannot live without. For a deeper architectural comparison, read how the MCP billing database pattern keeps storage layers predictable.