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>
This commit is contained in:
182
app/modules/billing/docs/subscription-system.md
Normal file
182
app/modules/billing/docs/subscription-system.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user