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:
2026-03-08 23:38:37 +01:00
parent 2287f4597d
commit f141cc4e6a
140 changed files with 19921 additions and 17723 deletions

View File

@@ -1,434 +1,3 @@
# Feature Gating System
## Overview
The feature gating system provides tier-based access control for platform features. It allows restricting functionality based on store subscription tiers (Essential, Professional, Business, Enterprise) with contextual upgrade prompts when features are locked.
**Implemented:** December 31, 2025
## Architecture
### Database Models
Located in `models/database/feature.py`:
| Model | Purpose |
|-------|---------|
| `Feature` | Feature definitions with tier requirements |
| `StoreFeatureOverride` | Per-store feature overrides (enable/disable) |
### Feature Model Structure
```python
class Feature(Base):
__tablename__ = "features"
id: int # Primary key
code: str # Unique feature code (e.g., "analytics_dashboard")
name: str # Display name
description: str # User-facing description
category: str # Feature category
minimum_tier_code: str # Minimum tier required (essential/professional/business/enterprise)
minimum_tier_order: int # Tier order for comparison (1-4)
is_active: bool # Whether feature is available
created_at: datetime
updated_at: datetime
```
### Tier Ordering
| Tier | Order | Code |
|------|-------|------|
| Essential | 1 | `essential` |
| Professional | 2 | `professional` |
| Business | 3 | `business` |
| Enterprise | 4 | `enterprise` |
## Feature Categories
30 features organized into 8 categories:
### 1. Analytics
| Feature Code | Name | Min Tier |
|-------------|------|----------|
| `basic_analytics` | Basic Analytics | Essential |
| `analytics_dashboard` | Analytics Dashboard | Professional |
| `advanced_analytics` | Advanced Analytics | Business |
| `custom_reports` | Custom Reports | Enterprise |
### 2. Product Management
| Feature Code | Name | Min Tier |
|-------------|------|----------|
| `basic_products` | Product Management | Essential |
| `bulk_product_edit` | Bulk Product Edit | Professional |
| `product_variants` | Product Variants | Professional |
| `product_bundles` | Product Bundles | Business |
| `inventory_alerts` | Inventory Alerts | Professional |
### 3. Order Management
| Feature Code | Name | Min Tier |
|-------------|------|----------|
| `basic_orders` | Order Management | Essential |
| `order_automation` | Order Automation | Professional |
| `advanced_fulfillment` | Advanced Fulfillment | Business |
| `multi_warehouse` | Multi-Warehouse | Enterprise |
### 4. Marketing
| Feature Code | Name | Min Tier |
|-------------|------|----------|
| `discount_codes` | Discount Codes | Professional |
| `abandoned_cart` | Abandoned Cart Recovery | Business |
| `email_marketing` | Email Marketing | Business |
| `loyalty_program` | Loyalty Program | Enterprise |
### 5. Support
| Feature Code | Name | Min Tier |
|-------------|------|----------|
| `basic_support` | Email Support | Essential |
| `priority_support` | Priority Support | Professional |
| `phone_support` | Phone Support | Business |
| `dedicated_manager` | Dedicated Account Manager | Enterprise |
### 6. Integration
| Feature Code | Name | Min Tier |
|-------------|------|----------|
| `basic_api` | Basic API Access | Professional |
| `advanced_api` | Advanced API Access | Business |
| `webhooks` | Webhooks | Business |
| `custom_integrations` | Custom Integrations | Enterprise |
### 7. Branding
| Feature Code | Name | Min Tier |
|-------------|------|----------|
| `basic_theme` | Theme Customization | Essential |
| `custom_domain` | Custom Domain | Professional |
| `white_label` | White Label | Enterprise |
| `custom_checkout` | Custom Checkout | Enterprise |
### 8. Team
| Feature Code | Name | Min Tier |
|-------------|------|----------|
| `team_management` | Team Management | Professional |
| `role_permissions` | Role Permissions | Business |
| `audit_logs` | Audit Logs | Business |
## Services
### FeatureService
Located in `app/services/feature_service.py`:
```python
class FeatureService:
"""Service for managing tier-based feature access."""
# In-memory caching (refreshed every 5 minutes)
_feature_cache: dict[str, Feature] = {}
_cache_timestamp: datetime | None = None
CACHE_TTL_SECONDS = 300
def has_feature(self, db: Session, store_id: int, feature_code: str) -> bool:
"""Check if store has access to a feature."""
def get_available_features(self, db: Session, store_id: int) -> list[str]:
"""Get list of feature codes available to store."""
def get_all_features_with_status(self, db: Session, store_id: int) -> list[dict]:
"""Get all features with availability status for store."""
def get_feature_info(self, db: Session, feature_code: str) -> dict | None:
"""Get full feature information including tier requirements."""
```
### UsageService
Located in `app/services/usage_service.py`:
```python
class UsageService:
"""Service for tracking and managing store usage against tier limits."""
def get_usage_summary(self, db: Session, store_id: int) -> dict:
"""Get comprehensive usage summary with limits and upgrade info."""
def check_limit(self, db: Session, store_id: int, limit_type: str) -> dict:
"""Check specific limit with detailed info."""
def get_upgrade_info(self, db: Session, store_id: int) -> dict:
"""Get upgrade recommendations based on current usage."""
```
## Backend Enforcement
### Decorator Pattern
```python
from app.core.feature_gate import require_feature
@router.get("/analytics/advanced")
@require_feature("advanced_analytics")
async def get_advanced_analytics(
db: Session = Depends(get_db),
store_id: int = Depends(get_current_store_id)
):
# Only accessible if store has advanced_analytics feature
pass
```
### Dependency Pattern
```python
from app.core.feature_gate import RequireFeature
@router.get("/marketing/loyalty")
async def get_loyalty_program(
db: Session = Depends(get_db),
_: None = Depends(RequireFeature("loyalty_program"))
):
# Only accessible if store has loyalty_program feature
pass
```
### Exception Handling
When a feature is not available, `FeatureNotAvailableException` is raised:
```python
class FeatureNotAvailableException(Exception):
def __init__(self, feature_code: str, required_tier: str):
self.feature_code = feature_code
self.required_tier = required_tier
super().__init__(f"Feature '{feature_code}' requires {required_tier} tier")
```
HTTP Response (403):
```json
{
"detail": "Feature 'advanced_analytics' requires Professional tier or higher",
"feature_code": "advanced_analytics",
"required_tier": "Professional",
"upgrade_url": "/store/orion/billing"
}
```
## API Endpoints
### Store Features API
Base: `/api/v1/store/features`
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/features/available` | GET | List available feature codes |
| `/features` | GET | All features with availability status |
| `/features/{code}` | GET | Single feature info |
| `/features/{code}/check` | GET | Quick availability check |
### Store Usage API
Base: `/api/v1/store/usage`
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/usage` | GET | Full usage summary with limits |
| `/usage/check/{limit_type}` | GET | Check specific limit (orders/products/team_members) |
| `/usage/upgrade-info` | GET | Upgrade recommendations |
### Admin Features API
Base: `/api/v1/admin/features`
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/features` | GET | List all features |
| `/features/{id}` | GET | Get feature details |
| `/features/{id}` | PUT | Update feature |
| `/features/{id}/toggle` | POST | Toggle feature active status |
| `/features/stores/{store_id}/overrides` | GET | Get store overrides |
| `/features/stores/{store_id}/overrides` | POST | Create override |
## Frontend Integration
### Alpine.js Feature Store
Located in `static/shared/js/feature-store.js`:
```javascript
// Usage in templates
$store.features.has('analytics_dashboard') // Check feature
$store.features.loaded // Loading state
$store.features.getFeature('advanced_api') // Get feature details
```
### Alpine.js Upgrade Store
Located in `static/shared/js/upgrade-prompts.js`:
```javascript
// Usage in templates
$store.upgrade.shouldShowLimitWarning('orders')
$store.upgrade.getUsageString('products')
$store.upgrade.hasUpgradeRecommendation
```
### Jinja2 Macros
Located in `app/templates/shared/macros/feature_gate.html`:
#### Feature Gate Container
```jinja2
{% from "shared/macros/feature_gate.html" import feature_gate %}
{% call feature_gate("analytics_dashboard") %}
<div>Analytics content here - only visible if feature available</div>
{% endcall %}
```
#### Feature Locked Card
```jinja2
{% from "shared/macros/feature_gate.html" import feature_locked %}
{{ feature_locked("advanced_analytics", "Advanced Analytics", "Get deeper insights") }}
```
#### Upgrade Banner
```jinja2
{% from "shared/macros/feature_gate.html" import upgrade_banner %}
{{ upgrade_banner("custom_domain") }}
```
#### Usage Limit Warning
```jinja2
{% from "shared/macros/feature_gate.html" import limit_warning %}
{{ limit_warning("orders") }} {# Shows warning when approaching limit #}
```
#### Usage Progress Bar
```jinja2
{% from "shared/macros/feature_gate.html" import usage_bar %}
{{ usage_bar("products", "Products") }}
```
#### Tier Badge
```jinja2
{% from "shared/macros/feature_gate.html" import tier_badge %}
{{ tier_badge() }} {# Shows current tier as colored badge #}
```
## Store Dashboard Integration
The store dashboard (`/store/{code}/dashboard`) now includes:
1. **Tier Badge**: Shows current subscription tier in header
2. **Usage Bars**: Visual progress bars for orders, products, team members
3. **Upgrade Prompts**: Contextual upgrade recommendations when approaching limits
4. **Feature Gates**: Locked sections for premium features
## Admin Features Page
Located at `/admin/features`:
- View all 30 features in categorized table
- Toggle features on/off globally
- Filter by category
- Search by name/code
- View tier requirements
## Admin Tier Management UI
Located at `/admin/subscription-tiers`:
### Overview
The subscription tiers admin page provides full CRUD functionality for managing subscription tiers and their feature assignments.
### Features
1. **Stats Cards**: Display total tiers, active tiers, public tiers, and estimated MRR
2. **Tier Table**: Sortable list of all tiers with:
- Display order
- Code (colored badge by tier)
- Name
- Monthly/Annual pricing
- Feature count
- Status (Active/Private/Inactive)
- Actions (Edit Features, Edit, Activate/Deactivate)
3. **Create/Edit Modal**: Form with all tier fields:
- Code and Name
- Monthly and Annual pricing (in cents)
- Display order
- Stripe IDs (optional)
- Description
- Active/Public toggles
4. **Feature Assignment Slide-over Panel**:
- Opens when clicking the puzzle-piece icon
- Shows all features grouped by category
- Binary features: checkbox selection with Select all/Deselect all per category
- Quantitative features: checkbox + numeric limit input for `limit_value`
- Feature count in footer
- Save to update tier's feature assignments via `TierFeatureLimitEntry[]`
### Files
| File | Purpose |
|------|---------|
| `app/templates/admin/subscription-tiers.html` | Page template |
| `static/admin/js/subscription-tiers.js` | Alpine.js component |
| `app/routes/admin_pages.py` | Route registration |
### API Endpoints Used
| Action | Method | Endpoint |
|--------|--------|----------|
| Load tiers | GET | `/api/v1/admin/subscriptions/tiers` |
| Load stats | GET | `/api/v1/admin/subscriptions/stats` |
| Create tier | POST | `/api/v1/admin/subscriptions/tiers` |
| Update tier | PATCH | `/api/v1/admin/subscriptions/tiers/{code}` |
| Delete tier | DELETE | `/api/v1/admin/subscriptions/tiers/{code}` |
| Load feature catalog | GET | `/api/v1/admin/subscriptions/features/catalog` |
| Get tier feature limits | GET | `/api/v1/admin/subscriptions/features/tiers/{code}/limits` |
| Update tier feature limits | PUT | `/api/v1/admin/subscriptions/features/tiers/{code}/limits` |
## Migration
The features are seeded via Alembic migration:
```
alembic/versions/n2c3d4e5f6a7_add_features_table.py
```
This creates:
- `features` table with 30 default features
- `store_feature_overrides` table for per-store exceptions
## Testing
Unit tests located in:
- `tests/unit/services/test_feature_service.py`
- `tests/unit/services/test_usage_service.py`
Run tests:
```bash
pytest tests/unit/services/test_feature_service.py -v
pytest tests/unit/services/test_usage_service.py -v
```
## Architecture Compliance
All JavaScript files follow architecture rules:
- JS-003: Alpine components use `store*` naming convention
- JS-005: Init guards prevent duplicate initialization
- JS-006: Async operations have try/catch error handling
- JS-008: API calls use `apiClient` (not raw `fetch()`)
- JS-009: Notifications use `Utils.showToast()`
## Related Documentation
- [Subscription Billing](../features/subscription-billing.md) - Core subscription system
- [Subscription Workflow Plan](./subscription-workflow-plan.md) - Implementation roadmap
This document has moved to the billing module docs: [Feature Gating](../modules/billing/feature-gating.md)