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>
183 lines
9.1 KiB
Markdown
183 lines
9.1 KiB
Markdown
# 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
|