# Billing Data Model ## Entity Relationship Overview ``` ┌───────────────────┐ │ SubscriptionTier │ └────────┬──────────┘ │ 1:N ▼ ┌───────────────────┐ ┌──────────────────────┐ │ TierFeatureLimit │ │ MerchantSubscription │ │ (feature limits) │ │ (per merchant+plat) │ └───────────────────┘ └──────────┬───────────┘ │ ┌──────────┼──────────────┐ ▼ ▼ ▼ ┌────────────┐ ┌──────────┐ ┌─────────────┐ │ BillingHist│ │StoreAddOn│ │FeatureOverride│ └────────────┘ └──────────┘ └─────────────┘ │ ▼ ┌────────────┐ │AddOnProduct│ └────────────┘ ┌──────────────────────┐ │StripeWebhookEvent │ (idempotency tracking) └──────────────────────┘ ``` ## Core Entities ### SubscriptionTier Defines available subscription plans with pricing and Stripe integration. | Column | Type | Description | |--------|------|-------------| | `id` | Integer | Primary key | | `code` | String | Unique tier code (`essential`, `professional`, `business`, `enterprise`) | | `name` | String | Display name | | `price_monthly_cents` | Integer | Monthly price in cents | | `price_annual_cents` | Integer | Annual price in cents (optional) | | `stripe_product_id` | String | Stripe product ID | | `stripe_price_monthly_id` | String | Stripe monthly price ID | | `stripe_price_annual_id` | String | Stripe annual price ID | | `display_order` | Integer | Sort order on pricing pages | | `is_active` | Boolean | Available for subscription | | `is_public` | Boolean | Visible to stores | ### TierFeatureLimit Per-tier feature limits — each row links a tier to a feature code with a limit value. | Column | Type | Description | |--------|------|-------------| | `id` | Integer | Primary key | | `tier_id` | Integer | FK to SubscriptionTier | | `feature_code` | String | Feature identifier (e.g., `max_products`) | | `limit_value` | Integer | Numeric limit (NULL = unlimited) | | `enabled` | Boolean | Whether feature is enabled for this tier | ### MerchantSubscription Per-merchant+platform subscription state. Subscriptions are merchant-level, not store-level. | Column | Type | Description | |--------|------|-------------| | `id` | Integer | Primary key | | `merchant_id` | Integer | FK to Merchant | | `platform_id` | Integer | FK to Platform | | `tier_id` | Integer | FK to SubscriptionTier | | `tier_code` | String | Tier code (denormalized for convenience) | | `status` | SubscriptionStatus | `trial`, `active`, `past_due`, `cancelled`, `expired` | | `stripe_customer_id` | String | Stripe customer ID | | `stripe_subscription_id` | String | Stripe subscription ID | | `trial_ends_at` | DateTime | Trial expiry | | `period_start` | DateTime | Current billing period start | | `period_end` | DateTime | Current billing period end | ### MerchantFeatureOverride Per-merchant exceptions to tier defaults (e.g., enterprise custom limits). | Column | Type | Description | |--------|------|-------------| | `id` | Integer | Primary key | | `merchant_id` | Integer | FK to Merchant | | `feature_code` | String | Feature identifier | | `limit_value` | Integer | Override limit (NULL = unlimited) | ## Add-on Entities ### AddOnProduct Purchasable add-on items (domains, SSL, email packages). | Column | Type | Description | |--------|------|-------------| | `id` | Integer | Primary key | | `code` | String | Unique add-on code | | `name` | String | Display name | | `category` | AddOnCategory | `domain`, `ssl`, `email` | | `price_cents` | Integer | Price in cents | | `billing_period` | BillingPeriod | `monthly` or `yearly` | ### StoreAddOn Add-ons purchased by individual stores. | Column | Type | Description | |--------|------|-------------| | `id` | Integer | Primary key | | `store_id` | Integer | FK to Store | | `addon_product_id` | Integer | FK to AddOnProduct | | `config` | JSON | Configuration (e.g., domain name) | | `stripe_subscription_item_id` | String | Stripe subscription item ID | | `status` | String | `active`, `cancelled`, `pending_setup` | ## Supporting Entities ### BillingHistory Invoice and payment history records. ### StripeWebhookEvent Idempotency tracking for Stripe webhook events. Prevents duplicate event processing. ## Key Relationships - A **SubscriptionTier** has many **TierFeatureLimits** (one per feature) - A **Merchant** has one **MerchantSubscription** per Platform - A **MerchantSubscription** references one **SubscriptionTier** - A **Merchant** can have many **MerchantFeatureOverrides** (per-feature) - A **Store** can purchase many **StoreAddOns** - Feature limits are resolved: MerchantFeatureOverride > TierFeatureLimit > default