# CRITICAL GAP: Pricing Page to Paid Plans Signup ## Issue Not Covered in Previous Documentation **Discovered:** Marketing pricing page analysis **Severity:** HIGH - Payment flow is broken --- ## Problem Identified ### Current State (Broken) **Pricing Page:** [`frontend/src/marketing/pages/Pricing.tsx:307-316`](frontend/src/marketing/pages/Pricing.tsx:307) ALL plan cards (Starter $89, Growth $139, Scale $229) have identical buttons: ```tsx Start free trial ``` **This means:** - ❌ User clicks "Start free trial" on Growth ($139/month) - ❌ Goes to https://app.igny8.com/signup - ❌ Gets FREE TRIAL with free-trial plan (0 payment) - ❌ NO WAY to actually sign up for paid plans from pricing page ### What's Missing **There is NO paid plan signup flow at all.** --- ## Required Solution ### Option A: Query Parameter Routing (RECOMMENDED) **Pricing page buttons:** ```tsx // Starter Get Started - $89/mo // Growth Get Started - $139/mo // Scale Get Started - $229/mo // Free trial stays same Start Free Trial ``` **App signup page logic:** ```tsx // In SignUpForm.tsx const searchParams = new URLSearchParams(window.location.search); const planSlug = searchParams.get('plan'); if (planSlug) { // Paid plan signup - show payment form navigate('/payment', { state: { planSlug } }); } else { // Free trial - current simple form // Continue with free trial registration } ``` **Backend:** ```python # RegisterSerializer checks plan query/body plan_slug = request.data.get('plan_slug') or request.GET.get('plan') if plan_slug in ['starter', 'growth', 'scale']: # Paid plan - requires payment plan = Plan.objects.get(slug=plan_slug) account.status = 'pending_payment' # Create Subscription with status='pending_payment' # Wait for payment confirmation else: # Free trial plan = Plan.objects.get(slug='free-trial') account.status = 'trial' # Immediate access ``` ### Option B: Separate Payment Route **Pricing page:** ```tsx // Paid plans go to /payment Get Started - $89/mo // Free trial stays /signup Start Free Trial ``` **Create new route:** - `/signup` - Free trial only (current implementation) - `/payment` - Paid plans with payment form --- ## Implementation Required ### 1. Update Pricing Page CTAs **File:** [`frontend/src/marketing/pages/Pricing.tsx:307`](frontend/src/marketing/pages/Pricing.tsx:307) Add plan data to tiers: ```tsx const tiers = [ { name: "Starter", slug: "starter", // NEW price: "$89", // ... rest }, // ... ]; ``` Update CTA button logic: ```tsx {tier.price === "Free" ? "Start free trial" : `Get ${tier.name} - ${tier.price}/mo`} ``` ### 2. Create Payment Flow Page **File:** `frontend/src/pages/Payment.tsx` (NEW) ```tsx import { useLocation, useNavigate } from 'react-router-dom'; import { useState, useEffect } from 'react'; export default function Payment() { const location = useLocation(); const navigate = useNavigate(); const [selectedPlan, setSelectedPlan] = useState(null); useEffect(() => { const params = new URLSearchParams(location.search); const planSlug = params.get('plan'); if (!planSlug) { // No plan selected, redirect to pricing navigate('/pricing'); return; } // Load plan details from API fetch(`/api/v1/auth/plans/?slug=${planSlug}`) .then(res => res.json()) .then(data => setSelectedPlan(data.results[0])); }, [location]); return (

Complete Your Subscription

{selectedPlan && ( <>

{selectedPlan.name} - ${selectedPlan.price}/{selectedPlan.billing_cycle}

{/* Payment method selection */}

Select Payment Method

{/* If bank transfer selected, show form */}
)}
); } ``` ### 3. Update Backend Registration **File:** [`backend/igny8_core/auth/serializers.py:276`](backend/igny8_core/auth/serializers.py:276) Add plan_slug handling: ```python def create(self, validated_data): from django.db import transaction from igny8_core.business.billing.models import CreditTransaction with transaction.atomic(): # Check for plan_slug in request plan_slug = validated_data.get('plan_slug') if plan_slug in ['starter', 'growth', 'scale']: # PAID PLAN - requires payment plan = Plan.objects.get(slug=plan_slug, is_active=True) account_status = 'pending_payment' initial_credits = 0 # No credits until payment # Do NOT create CreditTransaction yet else: # FREE TRIAL - immediate access try: plan = Plan.objects.get(slug='free-trial', is_active=True) except Plan.DoesNotExist: plan = Plan.objects.get(slug='free', is_active=True) account_status = 'trial' initial_credits = plan.get_effective_credits_per_month() # ... create user and account ... account = Account.objects.create( name=account_name, slug=slug, owner=user, plan=plan, credits=initial_credits, status=account_status ) # Only log credits for trial (paid accounts get credits after payment) if account_status == 'trial' and initial_credits > 0: CreditTransaction.objects.create( account=account, transaction_type='subscription', amount=initial_credits, balance_after=initial_credits, description=f'Free trial credits from {plan.name}', metadata={'registration': True, 'trial': True} ) # ... rest of code ... ``` --- ## Current Pricing Page Button Behavior **All buttons currently do this:** ``` igny8.com/pricing ├─ Starter card → "Start free trial" → https://app.igny8.com/signup ├─ Growth card → "Start free trial" → https://app.igny8.com/signup └─ Scale card → "Start free trial" → https://app.igny8.com/signup ``` **Result:** NO WAY to sign up for paid plans. --- ## Recommended Implementation ### Marketing Site (igny8.com) ```tsx // Pricing.tsx - Update tier CTAs {tier.price === "Free" ? ( Start Free Trial ) : ( Get {tier.name} - {tier.price}/mo )} ``` ### App Site (app.igny8.com) ```tsx // SignUpForm.tsx - Check for plan parameter useEffect(() => { const params = new URLSearchParams(window.location.search); const planSlug = params.get('plan'); if (planSlug && ['starter', 'growth', 'scale'].includes(planSlug)) { // Redirect to payment page navigate(`/payment?plan=${planSlug}`); } // Otherwise continue with free trial signup }, []); ``` ### Payment Page (NEW) - Route: `/payment?plan=starter` - Shows: Plan details, payment method selection - Options: Bank Transfer (active), Stripe (coming soon), PayPal (coming soon) - Flow: Collect info → Create pending account → Send payment instructions --- ## Update to Requirements ### Add to FINAL-IMPLEMENTATION-REQUIREMENTS.md **New Section: E. Paid Plans Signup Flow** ```markdown ### CRITICAL ISSUE E: No Paid Plan Signup Path #### Problem Marketing pricing page shows paid plans ($89, $139, $229) but all buttons go to free trial signup. No way for users to actually subscribe to paid plans. #### Fix 1. Pricing page buttons must differentiate: - Free trial: /signup (no params) - Paid plans: /signup?plan=starter (with plan slug) 2. Signup page must detect plan parameter: - If plan=paid → Redirect to /payment - If no plan → Free trial signup 3. Create /payment page: - Show selected plan details - Payment method selection (bank transfer active, others coming soon) - Collect user info + payment details - Create account with status='pending_payment' - Send payment instructions 4. Backend must differentiate: - Free trial: immediate credits and access - Paid plans: 0 credits, pending_payment status, wait for confirmation ``` --- ## Files That Need Updates ### Frontend 1. `frontend/src/marketing/pages/Pricing.tsx:307` - Add plan slug to CTAs 2. `frontend/src/components/auth/SignUpForm.tsx` - Detect plan param, redirect to payment 3. `frontend/src/pages/Payment.tsx` - NEW FILE - Payment flow page 4. `frontend/src/App.tsx` - Add /payment route ### Backend 5. `backend/igny8_core/auth/serializers.py:276` - Handle plan_slug for paid plans 6. `backend/igny8_core/auth/views.py:978` - Expose plan_slug in RegisterSerializer --- ## This Was Missing From All Previous Documentation ✅ Free trial flow - COVERED ❌ Paid plan subscription flow - **NOT COVERED** **This is a critical gap that needs to be added to the implementation plan.**