# 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
