# 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 ```python @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 | ## Related Documentation - [Data Model](data-model.md) — Entity relationships - [Feature Gating](feature-gating.md) — Feature access control and UI integration - [Stripe Integration](stripe-integration.md) — Payment setup - [Tier Management](tier-management.md) — Admin guide for tier management - [Subscription Workflow](subscription-workflow.md) — Subscription lifecycle - [Metrics Provider Pattern](../../architecture/metrics-provider-pattern.md) — Protocol-based metrics - [Capacity Monitoring](../../operations/capacity-monitoring.md) — Monitoring guide - [Capacity Planning](../../architecture/capacity-planning.md) — Infrastructure sizing