Files
orion/app/modules/billing/docs/subscription-system.md
Samir Boulahtit f141cc4e6a docs: migrate module documentation to single source of truth
Move 39 documentation files from top-level docs/ into each module's
docs/ folder, accessible via symlinks from docs/modules/. Create
data-model.md files for 10 modules with full schema documentation.
Replace originals with redirect stubs. Remove empty guide stubs.

Modules migrated: tenancy, billing, loyalty, marketplace, orders,
messaging, cms, catalog, inventory, hosting, prospecting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 23:38:37 +01:00

9.1 KiB

Subscription & Billing System

The platform provides a comprehensive subscription and billing system for managing merchant subscriptions, feature-based usage limits, and payments through Stripe.

Overview

The billing system enables:

  • Subscription Tiers: Database-driven tier definitions with configurable feature limits
  • Feature Provider Pattern: Modules declare features and usage via FeatureProviderProtocol, aggregated by FeatureAggregatorService
  • Dynamic Usage Tracking: Quantitative features (orders, products, team members) tracked per merchant with dynamic limits from TierFeatureLimit
  • Binary Feature Gating: Toggle-based features (analytics, API access, white-label) controlled per tier
  • Merchant-Level Billing: Subscriptions are per merchant+platform, not per store
  • Stripe Integration: Checkout sessions, customer portal, and webhook handling
  • Add-ons: Optional purchasable items (domains, SSL, email packages)
  • Capacity Forecasting: Growth trends and scaling recommendations
  • Background Jobs: Automated subscription lifecycle management

Architecture

Key Concepts

The billing system uses a feature provider pattern where:

  1. TierFeatureLimit replaces hardcoded tier columns (orders_per_month, products_limit, team_members). Each feature limit is a row linking a tier to a feature code with a limit_value.
  2. MerchantFeatureOverride provides per-merchant exceptions to tier defaults.
  3. Module feature providers implement FeatureProviderProtocol to supply current usage data.
  4. FeatureAggregatorService collects usage from all providers and combines it with tier limits to produce FeatureSummary records.
┌──────────────────────────────────────────────────────────────┐
│                   Frontend Page Request                        │
│   (Store Billing, Admin Subscriptions, Admin Store Detail)    │
└──────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌──────────────────────────────────────────────────────────────┐
│                  FeatureAggregatorService                      │
│    (app/modules/billing/services/feature_service.py)          │
│                                                                │
│    • Collects feature providers from all enabled modules       │
│    • Queries TierFeatureLimit for limit values                 │
│    • Queries MerchantFeatureOverride for per-merchant limits   │
│    • Calls provider.get_current_usage() for live counts        │
│    • Returns FeatureSummary[] with current/limit/percentage    │
└──────────────────────────────────────────────────────────────┘
             │                    │                    │
             ▼                    ▼                    ▼
    ┌────────────────┐  ┌────────────────┐  ┌────────────────┐
    │ catalog module  │  │ orders module   │  │ tenancy module  │
    │ products count  │  │ orders count    │  │ team members    │
    └────────────────┘  └────────────────┘  └────────────────┘

Feature Types

Type Description Example
Quantitative Has a numeric limit with usage tracking max_products (limit: 200, current: 150)
Binary Toggle-based, either enabled or disabled analytics_dashboard (enabled/disabled)

FeatureSummary Dataclass

@dataclass
class FeatureSummary:
    code: str           # e.g., "max_products"
    name_key: str       # i18n key for display name
    limit: int | None   # None = unlimited
    current: int        # Current usage count
    remaining: int      # Remaining before limit
    percent_used: float # 0.0 to 100.0
    feature_type: str   # "quantitative" or "binary"
    scope: str          # "tier" or "merchant_override"

Services

Service Purpose
FeatureAggregatorService Aggregates usage from module providers, resolves tier limits + overrides
BillingService Subscription operations, checkout, portal
SubscriptionService Subscription CRUD, tier lookups
AdminSubscriptionService Admin subscription management
StripeService Core Stripe API operations
CapacityForecastService Growth trends, projections

Background Tasks

Task Schedule Purpose
reset_period_counters Daily Reset order counters at period end
check_trial_expirations Daily Expire trials without payment method
sync_stripe_status Hourly Sync status with Stripe
cleanup_stale_subscriptions Weekly Clean up old cancelled subscriptions
capture_capacity_snapshot Daily Capture capacity metrics snapshot

API Endpoints

Store Billing API (/api/v1/store/billing)

Endpoint Method Purpose
/subscription GET Current subscription status
/tiers GET Available tiers for upgrade
/usage GET Dynamic usage metrics (from feature providers)
/checkout POST Create Stripe checkout session
/portal POST Create Stripe customer portal session
/invoices GET Invoice history
/change-tier POST Upgrade/downgrade tier
/addons GET Available add-on products
/my-addons GET Store's purchased add-ons
/addons/purchase POST Purchase an add-on
/cancel POST Cancel subscription
/reactivate POST Reactivate cancelled subscription

Admin Subscription API (/api/v1/admin/subscriptions)

Endpoint Method Purpose
/tiers GET/POST List/create tiers
/tiers/{code} PATCH/DELETE Update/delete tier
/stats GET Subscription statistics
/merchants/{id}/platforms/{pid} GET/PUT Get/update merchant subscription
/store/{store_id} GET Convenience: subscription + usage for a store

Admin Feature Management API (/api/v1/admin/subscriptions/features)

Endpoint Method Purpose
/catalog GET Feature catalog grouped by category
/tiers/{code}/limits GET/PUT Get/upsert feature limits for a tier
/merchants/{id}/overrides GET/PUT Get/upsert merchant feature overrides

Subscription Tiers

Tiers are stored in subscription_tiers with feature limits in tier_feature_limits:

SubscriptionTier (essential)
    ├── TierFeatureLimit: max_products = 200
    ├── TierFeatureLimit: max_orders_per_month = 100
    ├── TierFeatureLimit: max_team_members = 1
    └── TierFeatureLimit: basic_analytics (binary, enabled)

SubscriptionTier (professional)
    ├── TierFeatureLimit: max_products = NULL (unlimited)
    ├── TierFeatureLimit: max_orders_per_month = 500
    ├── TierFeatureLimit: max_team_members = 3
    └── TierFeatureLimit: analytics_dashboard (binary, enabled)

Add-ons

Code Name Category Price
domain Custom Domain domain €15/year
ssl_premium Premium SSL ssl €49/year
email_5 5 Email Addresses email €5/month
email_10 10 Email Addresses email €9/month
email_25 25 Email Addresses email €19/month

Exception Handling

Exception HTTP Description
PaymentSystemNotConfiguredException 503 Stripe not configured
TierNotFoundException 404 Invalid tier code
StripePriceNotConfiguredException 400 No Stripe price for tier
NoActiveSubscriptionException 400 Operation requires subscription
SubscriptionNotCancelledException 400 Cannot reactivate active subscription