- 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>
20 KiB
20 KiB
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:
- Vendor creates account (existing flow)
- 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
- Create
VendorSubscriptionrecord with:tier= selected tier codestatus= "trial"trial_ends_at= now + 14 daysperiod_start/period_endset for trial period
- Before trial ends, prompt vendor to add payment method
- On payment method added → Create Stripe subscription → Status becomes "active"
1.2 Database Changes Required
Add FK relationship to subscription_tiers:
# 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:
- Add
tier_idcolumn (nullable initially) - Populate
tier_idfrom existingtiercode values - 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 cardstatic/admin/js/vendor-detail.js- Load subscription dataapp/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:
- Vendor clicks "Change Plan" on billing page
- Shows tier comparison with current tier highlighted
- Vendor selects new tier
- For upgrades:
- Show prorated amount for immediate change
- Or option to change at next billing
- Redirect to Stripe checkout if needed
- 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):
stripe.Subscription.modify(
subscription_id,
items=[{"price": new_price_id}],
proration_behavior="create_prorations"
)
Downgrade (Scheduled):
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
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)
- Add
tier_idFK to VendorSubscription - Create migration with data backfill
- Update subscription service to use tier relationship
- Update admin subscription endpoints
- NEW: Add Feature model with 30 features across 8 categories
- NEW: Create FeatureService with caching for tier-based feature checking
- NEW: Add UsageService for limit tracking and upgrade recommendations
Phase 2: Admin Vendor Page (PARTIALLY COMPLETE)
- Add subscription card to vendor detail page
- Show usage meters (orders, products, team)
- Add "Edit Subscription" modal
- Implement tier change API (admin)
- NEW: Add Admin Features page (
/admin/features) - NEW: Admin features API (list, update, toggle)
Phase 3: Vendor Billing Page (COMPLETED)
- Create
/vendor/{code}/billingpage - Show current plan and usage
- Add tier comparison/change UI
- Implement tier change API (vendor)
- Add Stripe checkout integration for upgrades
- NEW: Add feature gate macros for templates
- NEW: Add Alpine.js feature store
- NEW: Add Alpine.js upgrade prompts store
- FIX: Resolved 89 JS architecture violations (JS-005 through JS-009)
Phase 4: Add-ons (COMPLETED)
- Seed add-on products in database
- Add "Available Add-ons" section to billing page
- Implement add-on purchase flow
- Create VendorAddOn management (via billing page)
- Add contextual upsell prompts
- FIX: Fix Stripe webhook to create VendorAddOn records
Phase 5: Polish & Testing (IN PROGRESS)
- Email notifications for tier changes
- Webhook handling for Stripe events
- Usage limit enforcement updates
- End-to-end testing (manual testing required)
- 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
-
Trial without payment method?
- Allow full trial without card, or require card upfront?
-
Downgrade handling:
- What happens if vendor has more products than new tier allows?
- Block downgrade, or just prevent new products?
-
Enterprise tier:
- Self-service or contact sales only?
- Custom pricing in UI or hidden?
-
Add-on provisioning:
- Domain: Use reseller API or manual process?
- Email: Integrate with email provider or manual?
-
Grace period:
- How long after payment failure before suspension?
- What gets disabled first?