- Add comprehensive feature-gating-system.md documenting: - Database models (Feature, VendorFeatureOverride) - 30 features across 8 categories with tier requirements - FeatureService and UsageService APIs - Backend enforcement (decorator, dependency patterns) - Frontend integration (Alpine stores, Jinja macros) - Admin and vendor API endpoints - Update subscription-workflow-plan.md with completion status - Add feature-gating-system.md to mkdocs.yml navigation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
455 lines
20 KiB
Markdown
455 lines
20 KiB
Markdown
# Subscription Workflow Plan
|
|
|
|
## Overview
|
|
|
|
End-to-end subscription management workflow for vendors on the platform.
|
|
|
|
---
|
|
|
|
## 1. Vendor Subscribes to a Tier
|
|
|
|
### 1.1 New Vendor Registration Flow
|
|
|
|
```
|
|
Vendor Registration → Select Tier → Trial Period → Payment Setup → Active Subscription
|
|
```
|
|
|
|
**Steps:**
|
|
1. Vendor creates account (existing flow)
|
|
2. During onboarding, vendor selects a tier:
|
|
- Show tier comparison cards (Essential, Professional, Business, Enterprise)
|
|
- Highlight features and limits for each tier
|
|
- Default to 14-day trial on selected tier
|
|
3. Create `VendorSubscription` record with:
|
|
- `tier` = selected tier code
|
|
- `status` = "trial"
|
|
- `trial_ends_at` = now + 14 days
|
|
- `period_start` / `period_end` set for trial period
|
|
4. Before trial ends, prompt vendor to add payment method
|
|
5. On payment method added → Create Stripe subscription → Status becomes "active"
|
|
|
|
### 1.2 Database Changes Required
|
|
|
|
**Add FK relationship to `subscription_tiers`:**
|
|
```python
|
|
# VendorSubscription - Add proper FK
|
|
tier_id = Column(Integer, ForeignKey("subscription_tiers.id"), nullable=True)
|
|
tier_code = Column(String(20), nullable=False) # Keep for backwards compat
|
|
|
|
# Relationship
|
|
tier_obj = relationship("SubscriptionTier", backref="subscriptions")
|
|
```
|
|
|
|
**Migration:**
|
|
1. Add `tier_id` column (nullable initially)
|
|
2. Populate `tier_id` from existing `tier` code values
|
|
3. Add FK constraint
|
|
|
|
### 1.3 API Endpoints
|
|
|
|
| Endpoint | Method | Description |
|
|
|----------|--------|-------------|
|
|
| `/api/v1/vendor/subscription/tiers` | GET | List available tiers for selection |
|
|
| `/api/v1/vendor/subscription/select-tier` | POST | Select tier during onboarding |
|
|
| `/api/v1/vendor/subscription/setup-payment` | POST | Create Stripe checkout for payment |
|
|
|
|
---
|
|
|
|
## 2. Admin Views Subscription on Vendor Page
|
|
|
|
### 2.1 Vendor Detail Page Enhancement
|
|
|
|
**Location:** `/admin/vendors/{vendor_id}`
|
|
|
|
**New Subscription Card:**
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Subscription [Edit] │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Tier: Professional Status: Active │
|
|
│ Price: €99/month Since: Jan 15, 2025 │
|
|
│ Next Billing: Feb 15, 2025 │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Usage This Period │
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
│ │ Orders │ │ Products │ │ Team Members │ │
|
|
│ │ 234 / 500 │ │ 156 / ∞ │ │ 2 / 3 │ │
|
|
│ │ ████████░░ │ │ ████████████ │ │ ██████░░░░ │ │
|
|
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Add-ons: Custom Domain (mydomain.com), 5 Email Addresses │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.2 Files to Modify
|
|
|
|
- `app/templates/admin/vendor-detail.html` - Add subscription card
|
|
- `static/admin/js/vendor-detail.js` - Load subscription data
|
|
- `app/api/v1/admin/vendors.py` - Include subscription in vendor response
|
|
|
|
### 2.3 Admin Quick Actions
|
|
|
|
From the vendor page, admin can:
|
|
- **Change Tier** - Upgrade/downgrade vendor
|
|
- **Override Limits** - Set custom limits (enterprise deals)
|
|
- **Extend Trial** - Give more trial days
|
|
- **Cancel Subscription** - With reason
|
|
- **Manage Add-ons** - Add/remove add-ons
|
|
|
|
---
|
|
|
|
## 3. Tier Upgrade/Downgrade
|
|
|
|
### 3.1 Admin-Initiated Change
|
|
|
|
**Location:** Admin vendor page → Subscription card → [Edit] button
|
|
|
|
**Modal: Change Subscription Tier**
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ Change Subscription Tier [X] │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ Current: Professional (€99/month) │
|
|
│ │
|
|
│ New Tier: │
|
|
│ ○ Essential (€49/month) - Downgrade │
|
|
│ ● Business (€199/month) - Upgrade │
|
|
│ ○ Enterprise (Custom) - Contact required │
|
|
│ │
|
|
│ When to apply: │
|
|
│ ○ Immediately (prorate current period) │
|
|
│ ● At next billing cycle (Feb 15, 2025) │
|
|
│ │
|
|
│ [ ] Notify vendor by email │
|
|
│ │
|
|
│ [Cancel] [Apply Change] │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 3.2 Vendor-Initiated Change
|
|
|
|
**Location:** Vendor dashboard → Billing page → [Change Plan]
|
|
|
|
**Flow:**
|
|
1. Vendor clicks "Change Plan" on billing page
|
|
2. Shows tier comparison with current tier highlighted
|
|
3. Vendor selects new tier
|
|
4. For upgrades:
|
|
- Show prorated amount for immediate change
|
|
- Or option to change at next billing
|
|
- Redirect to Stripe checkout if needed
|
|
5. For downgrades:
|
|
- Always schedule for next billing cycle
|
|
- Show what features they'll lose
|
|
- Confirmation required
|
|
|
|
### 3.3 API Endpoints
|
|
|
|
| Endpoint | Method | Actor | Description |
|
|
|----------|--------|-------|-------------|
|
|
| `/api/v1/admin/subscriptions/{vendor_id}/change-tier` | POST | Admin | Change vendor's tier |
|
|
| `/api/v1/vendor/billing/change-tier` | POST | Vendor | Request tier change |
|
|
| `/api/v1/vendor/billing/preview-change` | POST | Vendor | Preview proration |
|
|
|
|
### 3.4 Stripe Integration
|
|
|
|
**Upgrade (Immediate):**
|
|
```python
|
|
stripe.Subscription.modify(
|
|
subscription_id,
|
|
items=[{"price": new_price_id}],
|
|
proration_behavior="create_prorations"
|
|
)
|
|
```
|
|
|
|
**Downgrade (Scheduled):**
|
|
```python
|
|
stripe.Subscription.modify(
|
|
subscription_id,
|
|
items=[{"price": new_price_id}],
|
|
proration_behavior="none",
|
|
billing_cycle_anchor="unchanged"
|
|
)
|
|
# Store scheduled change in our DB
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Add-ons Upselling
|
|
|
|
### 4.1 Where Add-ons Are Displayed
|
|
|
|
#### A. Vendor Billing Page
|
|
```
|
|
/vendor/{code}/billing
|
|
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Available Add-ons │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ ┌─────────────────────┐ ┌─────────────────────┐ │
|
|
│ │ 🌐 Custom Domain │ │ 📧 Email Package │ │
|
|
│ │ €15/year │ │ From €5/month │ │
|
|
│ │ Use your own domain │ │ 5, 10, or 25 emails │ │
|
|
│ │ [Add to Plan] │ │ [Add to Plan] │ │
|
|
│ └─────────────────────┘ └─────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────────────────┐ ┌─────────────────────┐ │
|
|
│ │ 🔒 Premium SSL │ │ 💾 Extra Storage │ │
|
|
│ │ €49/year │ │ €5/month per 10GB │ │
|
|
│ │ EV certificate │ │ More product images │ │
|
|
│ │ [Add to Plan] │ │ [Add to Plan] │ │
|
|
│ └─────────────────────┘ └─────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
#### B. Contextual Upsells
|
|
|
|
**When vendor hits a limit:**
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ ⚠️ You've reached your order limit for this month │
|
|
│ │
|
|
│ Upgrade to Professional to get 500 orders/month │
|
|
│ [Upgrade Now] [Dismiss] │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**In settings when configuring domain:**
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 🌐 Custom Domain │
|
|
│ │
|
|
│ Your shop is available at: myshop.platform.com │
|
|
│ │
|
|
│ Want to use your own domain like www.myshop.com? │
|
|
│ Add the Custom Domain add-on for just €15/year │
|
|
│ │
|
|
│ [Add Custom Domain] │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
#### C. Upgrade Prompts in Tier Comparison
|
|
|
|
When showing tier comparison, highlight what add-ons come included:
|
|
- Professional: Includes 1 custom domain
|
|
- Business: Includes custom domain + 5 email addresses
|
|
- Enterprise: All add-ons included
|
|
|
|
### 4.2 Add-on Purchase Flow
|
|
|
|
```
|
|
Vendor clicks [Add to Plan]
|
|
↓
|
|
Modal: Configure Add-on
|
|
- Domain: Enter domain name, check availability
|
|
- Email: Select package (5/10/25)
|
|
↓
|
|
Create Stripe checkout session for add-on price
|
|
↓
|
|
On success: Create VendorAddOn record
|
|
↓
|
|
Provision add-on (domain registration, email setup)
|
|
```
|
|
|
|
### 4.3 Add-on Management
|
|
|
|
**Vendor can view/manage in Billing page:**
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Your Add-ons │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Custom Domain myshop.com €15/year [Manage] │
|
|
│ Email Package 5 addresses €5/month [Manage] │
|
|
│ │
|
|
│ Next billing: Feb 15, 2025 │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 4.4 Database: `vendor_addons` Table
|
|
|
|
```python
|
|
class VendorAddOn(Base):
|
|
id = Column(Integer, primary_key=True)
|
|
vendor_id = Column(Integer, ForeignKey("vendors.id"))
|
|
addon_product_id = Column(Integer, ForeignKey("addon_products.id"))
|
|
|
|
# Config (e.g., domain name, email count)
|
|
config = Column(JSON, nullable=True)
|
|
|
|
# Stripe
|
|
stripe_subscription_item_id = Column(String(100))
|
|
|
|
# Status
|
|
status = Column(String(20)) # active, cancelled, pending_setup
|
|
provisioned_at = Column(DateTime)
|
|
|
|
# Billing
|
|
quantity = Column(Integer, default=1)
|
|
|
|
created_at = Column(DateTime)
|
|
cancelled_at = Column(DateTime, nullable=True)
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Implementation Phases
|
|
|
|
**Last Updated:** December 31, 2025
|
|
|
|
### Phase 1: Database & Core (COMPLETED)
|
|
- [x] Add `tier_id` FK to VendorSubscription
|
|
- [x] Create migration with data backfill
|
|
- [x] Update subscription service to use tier relationship
|
|
- [x] Update admin subscription endpoints
|
|
- [x] **NEW:** Add Feature model with 30 features across 8 categories
|
|
- [x] **NEW:** Create FeatureService with caching for tier-based feature checking
|
|
- [x] **NEW:** Add UsageService for limit tracking and upgrade recommendations
|
|
|
|
### Phase 2: Admin Vendor Page (PARTIALLY COMPLETE)
|
|
- [x] Add subscription card to vendor detail page
|
|
- [x] Show usage meters (orders, products, team)
|
|
- [ ] Add "Edit Subscription" modal
|
|
- [ ] Implement tier change API (admin)
|
|
- [x] **NEW:** Add Admin Features page (`/admin/features`)
|
|
- [x] **NEW:** Admin features API (list, update, toggle)
|
|
|
|
### Phase 3: Vendor Billing Page (COMPLETED)
|
|
- [x] Create `/vendor/{code}/billing` page
|
|
- [x] Show current plan and usage
|
|
- [x] Add tier comparison/change UI
|
|
- [x] Implement tier change API (vendor)
|
|
- [x] Add Stripe checkout integration for upgrades
|
|
- [x] **NEW:** Add feature gate macros for templates
|
|
- [x] **NEW:** Add Alpine.js feature store
|
|
- [x] **NEW:** Add Alpine.js upgrade prompts store
|
|
- [x] **FIX:** Resolved 89 JS architecture violations (JS-005 through JS-009)
|
|
|
|
### Phase 4: Add-ons (COMPLETED)
|
|
- [x] Seed add-on products in database
|
|
- [x] Add "Available Add-ons" section to billing page
|
|
- [x] Implement add-on purchase flow
|
|
- [x] Create VendorAddOn management (via billing page)
|
|
- [x] Add contextual upsell prompts
|
|
- [x] **FIX:** Fix Stripe webhook to create VendorAddOn records
|
|
|
|
### Phase 5: Polish & Testing (IN PROGRESS)
|
|
- [ ] Email notifications for tier changes
|
|
- [x] Webhook handling for Stripe events
|
|
- [x] Usage limit enforcement updates
|
|
- [ ] End-to-end testing (manual testing required)
|
|
- [x] Documentation (feature-gating-system.md created)
|
|
|
|
### Phase 6: Remaining Work (NEW)
|
|
- [ ] Admin tier change modal (upgrade/downgrade vendors)
|
|
- [ ] Admin subscription override UI (custom limits for enterprise)
|
|
- [ ] Trial extension from admin panel
|
|
- [ ] Email notifications for tier changes
|
|
- [ ] Email notifications for approaching limits
|
|
- [ ] Grace period handling for failed payments
|
|
- [ ] Integration tests for full billing workflow
|
|
- [ ] Stripe test mode checkout verification
|
|
|
|
---
|
|
|
|
## 6. Files Created/Modified
|
|
|
|
**Last Updated:** December 31, 2025
|
|
|
|
### New Files (Created)
|
|
| File | Purpose | Status |
|
|
|------|---------|--------|
|
|
| `app/templates/vendor/billing.html` | Vendor billing page | DONE |
|
|
| `static/vendor/js/billing.js` | Billing page JS | DONE |
|
|
| `app/api/v1/vendor/billing.py` | Vendor billing endpoints | DONE |
|
|
| `models/database/feature.py` | Feature & VendorFeatureOverride models | DONE |
|
|
| `app/services/feature_service.py` | Feature access control service | DONE |
|
|
| `app/services/usage_service.py` | Usage tracking & limits service | DONE |
|
|
| `app/core/feature_gate.py` | @require_feature decorator & dependency | DONE |
|
|
| `app/api/v1/vendor/features.py` | Vendor features API | DONE |
|
|
| `app/api/v1/vendor/usage.py` | Vendor usage API | DONE |
|
|
| `app/api/v1/admin/features.py` | Admin features API | DONE |
|
|
| `app/templates/admin/features.html` | Admin features management page | DONE |
|
|
| `app/templates/shared/macros/feature_gate.html` | Jinja2 feature gate macros | DONE |
|
|
| `static/shared/js/feature-store.js` | Alpine.js feature store | DONE |
|
|
| `static/shared/js/upgrade-prompts.js` | Alpine.js upgrade prompts | DONE |
|
|
| `alembic/versions/n2c3d4e5f6a7_add_features_table.py` | Features migration | DONE |
|
|
| `docs/implementation/feature-gating-system.md` | Feature gating documentation | DONE |
|
|
|
|
### Modified Files
|
|
| File | Changes | Status |
|
|
|------|---------|--------|
|
|
| `models/database/subscription.py` | Add tier_id FK | DONE |
|
|
| `models/database/__init__.py` | Export Feature models | DONE |
|
|
| `app/templates/admin/vendor-detail.html` | Add subscription card | DONE |
|
|
| `static/admin/js/vendor-detail.js` | Load subscription data | DONE |
|
|
| `app/api/v1/admin/vendors.py` | Include subscription in response | DONE |
|
|
| `app/api/v1/admin/__init__.py` | Register features router | DONE |
|
|
| `app/api/v1/vendor/__init__.py` | Register features/usage routers | DONE |
|
|
| `app/services/subscription_service.py` | Tier change logic | DONE |
|
|
| `app/templates/vendor/partials/sidebar.html` | Add Billing link | DONE |
|
|
| `app/templates/vendor/base.html` | Load feature/upgrade stores | DONE |
|
|
| `app/templates/vendor/dashboard.html` | Add tier badge & usage bars | DONE |
|
|
| `app/handlers/stripe_webhook.py` | Create VendorAddOn on purchase | DONE |
|
|
| `app/routes/admin_pages.py` | Add features page route | DONE |
|
|
| `static/shared/js/api-client.js` | Add postFormData() & getBlob() | DONE |
|
|
|
|
### Architecture Fixes (48 files)
|
|
| Rule | Files Fixed | Description |
|
|
|------|-------------|-------------|
|
|
| JS-003 | billing.js | Rename billingData→vendorBilling |
|
|
| JS-005 | 15 files | Add init guards |
|
|
| JS-006 | 39 files | Add try/catch to async init |
|
|
| JS-008 | 5 files | Use apiClient not fetch |
|
|
| JS-009 | 30 files | Use Utils.showToast |
|
|
| TPL-009 | validate_architecture.py | Check vendor templates too |
|
|
|
|
---
|
|
|
|
## 7. API Summary
|
|
|
|
### Admin APIs
|
|
```
|
|
GET /admin/vendors/{id} # Includes subscription
|
|
POST /admin/subscriptions/{vendor_id}/change-tier
|
|
POST /admin/subscriptions/{vendor_id}/override-limits
|
|
POST /admin/subscriptions/{vendor_id}/extend-trial
|
|
POST /admin/subscriptions/{vendor_id}/cancel
|
|
```
|
|
|
|
### Vendor APIs
|
|
```
|
|
GET /vendor/billing/subscription # Current subscription
|
|
GET /vendor/billing/tiers # Available tiers
|
|
POST /vendor/billing/preview-change # Preview tier change
|
|
POST /vendor/billing/change-tier # Request tier change
|
|
POST /vendor/billing/checkout # Stripe checkout session
|
|
|
|
GET /vendor/billing/addons # Available add-ons
|
|
GET /vendor/billing/my-addons # Vendor's add-ons
|
|
POST /vendor/billing/addons/purchase # Purchase add-on
|
|
DELETE /vendor/billing/addons/{id} # Cancel add-on
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Questions to Resolve
|
|
|
|
1. **Trial without payment method?**
|
|
- Allow full trial without card, or require card upfront?
|
|
|
|
2. **Downgrade handling:**
|
|
- What happens if vendor has more products than new tier allows?
|
|
- Block downgrade, or just prevent new products?
|
|
|
|
3. **Enterprise tier:**
|
|
- Self-service or contact sales only?
|
|
- Custom pricing in UI or hidden?
|
|
|
|
4. **Add-on provisioning:**
|
|
- Domain: Use reseller API or manual process?
|
|
- Email: Integrate with email provider or manual?
|
|
|
|
5. **Grace period:**
|
|
- How long after payment failure before suspension?
|
|
- What gets disabled first?
|