# Subscription Workflow Plan ## Overview End-to-end subscription management workflow for stores on the platform. --- ## 1. Store Subscribes to a Tier ### 1.1 New Store Registration Flow ``` Store Registration → Select Tier → Trial Period → Payment Setup → Active Subscription ``` **Steps:** 1. Store creates account (existing flow) 2. During onboarding, store 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 `StoreSubscription` 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 store 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 # StoreSubscription - 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/store/subscription/tiers` | GET | List available tiers for selection | | `/api/v1/store/subscription/select-tier` | POST | Select tier during onboarding | | `/api/v1/store/subscription/setup-payment` | POST | Create Stripe checkout for payment | --- ## 2. Admin Views Subscription on Store Page ### 2.1 Store Detail Page Enhancement **Location:** `/admin/stores/{store_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/store-detail.html` - Add subscription card - `static/admin/js/store-detail.js` - Load subscription data - `app/api/v1/admin/stores.py` - Include subscription in store response ### 2.3 Admin Quick Actions From the store page, admin can: - **Change Tier** - Upgrade/downgrade store - **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 store 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 store by email │ │ │ │ [Cancel] [Apply Change] │ └─────────────────────────────────────────────────────────┘ ``` ### 3.2 Store-Initiated Change **Location:** Store dashboard → Billing page → [Change Plan] **Flow:** 1. Store clicks "Change Plan" on billing page 2. Shows tier comparison with current tier highlighted 3. Store 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/{store_id}/change-tier` | POST | Admin | Change store's tier | | `/api/v1/store/billing/change-tier` | POST | Store | Request tier change | | `/api/v1/store/billing/preview-change` | POST | Store | 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. Store Billing Page ``` /store/{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 store 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 ``` Store 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 StoreAddOn record ↓ Provision add-on (domain registration, email setup) ``` ### 4.3 Add-on Management **Store 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: `store_addons` Table ```python class StoreAddOn(Base): id = Column(Integer, primary_key=True) store_id = Column(Integer, ForeignKey("stores.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 StoreSubscription - [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 Store Page (PARTIALLY COMPLETE) - [x] Add subscription card to store 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: Store Billing Page (COMPLETED) - [x] Create `/store/{code}/billing` page - [x] Show current plan and usage - [x] Add tier comparison/change UI - [x] Implement tier change API (store) - [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 StoreAddOn management (via billing page) - [x] Add contextual upsell prompts - [x] **FIX:** Fix Stripe webhook to create StoreAddOn 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 stores) - [ ] 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/store/billing.html` | Store billing page | DONE | | `static/store/js/billing.js` | Billing page JS | DONE | | `app/api/v1/store/billing.py` | Store billing endpoints | DONE | | `models/database/feature.py` | Feature & StoreFeatureOverride 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/store/features.py` | Store features API | DONE | | `app/api/v1/store/usage.py` | Store 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/store-detail.html` | Add subscription card | DONE | | `static/admin/js/store-detail.js` | Load subscription data | DONE | | `app/api/v1/admin/stores.py` | Include subscription in response | DONE | | `app/api/v1/admin/__init__.py` | Register features router | DONE | | `app/api/v1/store/__init__.py` | Register features/usage routers | DONE | | `app/services/subscription_service.py` | Tier change logic | DONE | | `app/templates/store/partials/sidebar.html` | Add Billing link | DONE | | `app/templates/store/base.html` | Load feature/upgrade stores | DONE | | `app/templates/store/dashboard.html` | Add tier badge & usage bars | DONE | | `app/handlers/stripe_webhook.py` | Create StoreAddOn 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→storeBilling | | 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 store templates too | --- ## 7. API Summary ### Admin APIs ``` GET /admin/stores/{id} # Includes subscription POST /admin/subscriptions/{store_id}/change-tier POST /admin/subscriptions/{store_id}/override-limits POST /admin/subscriptions/{store_id}/extend-trial POST /admin/subscriptions/{store_id}/cancel ``` ### Store APIs ``` GET /store/billing/subscription # Current subscription GET /store/billing/tiers # Available tiers POST /store/billing/preview-change # Preview tier change POST /store/billing/change-tier # Request tier change POST /store/billing/checkout # Stripe checkout session GET /store/billing/addons # Available add-ons GET /store/billing/my-addons # Store's add-ons POST /store/billing/addons/purchase # Purchase add-on DELETE /store/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 store 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?