Data model
Key objects Owostack stores and how they relate
Data model
Owostack stores a small set of objects designed to answer two questions quickly:
- Is the customer allowed to use feature X right now?
- If they use feature X, how do we account for it?
Everything in the data model serves one of these two purposes.
Object graph
Organization
├── Provider Account (credentials for Paystack, Dodo, etc.)
├── Plan
│ └── Plan Feature (feature config: limit, reset, overage, creditCost)
├── Feature (boolean, metered, or static)
├── Credit System (groups features that share a prepaid balance)
├── Credit Pack (purchasable top-up tied to a credit system)
└── Customer
├── Subscription (links customer → plan, tracks billing period)
├── Entitlement (resolved from plan features — what the customer can do)
├── Meter State (usage counter per metered feature per period)
├── Credit System Balance (prepaid balance per credit system)
└── Payment Method (card on file for overage/addon billing)Organization
The top-level container. All plans, features, customers, and provider accounts belong to an organization. Each organization has its own API keys, webhooks, and billing data.
Customer
A person or account that subscribes to plans and consumes features. Identified by email or an external ID you provide. Owostack auto-creates customers on the first attach(), check(), or track() call if you pass customerData.
Plan and Plan Feature
A plan is a subscription tier (e.g. "Starter", "Pro"). Plans belong to a plan group — switching between plans in the same group is treated as an upgrade or downgrade; switching across groups creates a separate subscription.
Each plan has plan features that configure how a feature behaves on that plan: the limit, reset interval, overage policy, and credit cost.
Feature
A capability in your product. Three types:
- Boolean — on/off access (e.g. "analytics dashboard")
- Metered — numeric limit with usage tracking (e.g. "10,000 API calls/month")
- Static — a fixed configuration value
Features are defined once and attached to plans with plan-specific configuration.
Subscription
Links a customer to a plan. Tracks the billing period (currentPeriodStart, currentPeriodEnd), status (active, trialing, canceled, past_due, pending_cancel), and the provider's subscription reference.
Usage meters reset at the start of each billing period based on the subscription's period boundaries.
Entitlement
The resolved permission a customer has for a specific feature. Entitlements are computed from the customer's active subscription and its plan features. When a plan switch happens, entitlements are re-provisioned automatically.
Meter State
Per-customer, per-feature usage counter for the current billing period. Stored in Cloudflare Durable Objects for atomic, race-free increments under high concurrency.
Credit System and Balance
A credit system groups features that share a prepaid balance. Customers buy credit packs to top up their balance in a specific credit system. When track() is called on a feature with a creditCost, credits are deducted from the matching credit system balance.
Balances are stored in credit_system_balances with a unique index on (customerId, creditSystemId) for atomic upserts.
Provider references
Most objects store a provider-side ID alongside the internal Owostack ID:
Plan.providerPlanId— the plan's ID on Paystack/DodoSubscription.providerSubscriptionCode— the provider's subscription referenceCustomer.providerCustomerId— the customer's ID on the providerPaymentMethod.token— authorization code (Paystack) or on-demand subscription ID (Dodo)
This dual-reference design lets Owostack reconcile webhook events with internal state without ambiguity.
Environments
Owostack runs separate deployments for test and live, each with its own database. Provider accounts, subscriptions, and all billing data are fully isolated between environments. The only shared resource is the authentication database (user accounts and organizations).