# Signup Fixes - December 9, 2024 ## Issues Identified ### 1. Free Signup - User Logged Out Immediately **Root Cause:** Token storage race condition - Tokens were being set in Zustand state but not persisting to localStorage fast enough - Navigation happened before tokens were saved - API interceptor couldn't find tokens → 401 → logout **Symptoms:** - User creates account successfully - Gets redirected to /sites - Immediately logged out (< 1 second) ### 2. Paid Signup - Payment Methods Not Loading **Root Cause:** Wrong API endpoint - Frontend called `/v1/billing/admin/payment-methods/` - This endpoint requires authentication - Signup page is not authenticated → 401 error - Backend already had public endpoint at `/v1/billing/admin/payment-methods/` with `AllowAny` permission **Symptoms:** - Error message shown instead of payment options - Cannot complete paid plan signup ### 3. Multi-Step Form Over-Complicated **Root Cause:** Unnecessary complexity - 3-step wizard for paid plans (Account → Billing → Payment) - Billing step not needed (can use email as billing_email) - Created friction in signup flow **Symptoms:** - Long signup process - Users confused about multiple steps - Higher abandonment rate --- ## Fixes Implemented ### Fix 1: Token Persistence (authStore.ts) **File:** `/data/app/igny8/frontend/src/store/authStore.ts` **Changes:** ```typescript // In both login() and register() functions: // CRITICAL: Also set tokens as separate items for API interceptor if (newToken) { localStorage.setItem('access_token', newToken); } if (newRefreshToken) { localStorage.setItem('refresh_token', newRefreshToken); } ``` **Why This Works:** - Zustand persist middleware is async - API interceptor checks `localStorage.getItem('access_token')` - By setting tokens immediately in separate keys, API calls work right away - No more race condition between persist and navigation --- ### Fix 2: Payment Method Endpoint (Already Working!) **Backend:** `/data/app/igny8/backend/igny8_core/business/billing/views.py` **Existing Code (line 181):** ```python @action(detail=False, methods=['get'], url_path='payment-methods', permission_classes=[AllowAny]) def list_payment_methods(self, request): """ Get available payment methods for a specific country. Query params: country: ISO 2-letter country code (default: '*' for global) """ country = request.GET.get('country', '*').upper() methods = PaymentMethodConfig.objects.filter( Q(country_code=country) | Q(country_code='*'), is_enabled=True ).order_by('sort_order') serializer = PaymentMethodConfigSerializer(methods, many=True) return Response(serializer.data, status=status.HTTP_200_OK) ``` **URL:** `/v1/billing/admin/payment-methods/` - ✅ Has `AllowAny` permission - ✅ Returns payment methods filtered by country - ✅ Already working - frontend just needs to use it correctly --- ### Fix 3: Simplified Signup Form **New File:** `/data/app/igny8/frontend/src/components/auth/SignUpFormSimplified.tsx` **Changes:** - **Single page form** - all fields on one screen - **Conditional payment section** - only shows for paid plans - **Auto-loads payment methods** - fetches on component mount for paid plans - **Removed billing step** - uses email as billing_email by default - **Cleaner UX** - progress from top to bottom, no wizard **Form Structure:** ``` ┌─────────────────────────────────────┐ │ First Name / Last Name │ │ Email │ │ Account Name (optional) │ │ Password │ │ │ │ [IF PAID PLAN] │ │ ┌─ Payment Method ─────────────┐ │ │ │ ○ Credit/Debit Card │ │ │ │ ○ Bank Transfer │ │ │ │ ○ Local Wallet │ │ │ └──────────────────────────────┘ │ │ │ │ ☑ Agree to Terms │ │ │ │ [Submit Button] │ └─────────────────────────────────────┘ ``` **Updated File:** `/data/app/igny8/frontend/src/pages/AuthPages/SignUp.tsx` ```typescript // Changed from: import SignUpFormEnhanced from "../../components/auth/SignUpFormEnhanced"; // To: import SignUpFormSimplified from "../../components/auth/SignUpFormSimplified"; ``` --- ## Backend Changes Summary ### 1. Billing URLs (billing/urls.py) **Added:** `payment-configs` router registration ```python router.register(r'payment-configs', BillingViewSet, basename='payment-configs') ``` **Purpose:** - Exposes payment method configurations for public access - Used during signup to show available payment options --- ## Testing Checklist ### Free Signup Flow - [ ] Go to `/signup` (no plan parameter) - [ ] Fill in: First Name, Last Name, Email, Password - [ ] Check "Agree to Terms" - [ ] Click "Start Free Trial" - [ ] **Expected:** - Account created with 1000 credits - Redirected to `/sites` - Stay logged in (tokens persist) - Can create site immediately ### Paid Signup Flow (Starter Plan) - [ ] Go to `/signup?plan=starter` - [ ] Fill in: First Name, Last Name, Email, Password - [ ] See payment methods section appear - [ ] Select "Bank Transfer" payment method - [ ] Check "Agree to Terms" - [ ] Click "Create Account & Continue to Payment" - [ ] **Expected:** - Account created with status `pending_payment` - Redirected to `/account/plans` - Stay logged in - See pending payment banner with instructions ### Payment Methods Loading - [ ] Open `/signup?plan=starter` - [ ] After form loads, check that payment methods section shows: - Loading spinner initially - Then 3-4 payment options (Stripe, Bank Transfer, etc.) - Each with icon and description - No error messages --- ## File Changes Summary ### Frontend Files Modified 1. ✅ `/frontend/src/store/authStore.ts` - Fixed token persistence 2. ✅ `/frontend/src/pages/AuthPages/SignUp.tsx` - Use simplified form 3. ✅ `/frontend/src/components/auth/SignUpFormSimplified.tsx` - NEW single-page form ### Backend Files Modified 1. ✅ `/backend/igny8_core/business/billing/urls.py` - Added payment-configs router ### Frontend Files Created 1. ✅ `/frontend/src/components/auth/SignUpFormSimplified.tsx` ### Files No Longer Used (Keep for Reference) 1. `/frontend/src/components/auth/SignUpFormEnhanced.tsx` - Old multi-step form 2. `/frontend/src/components/billing/BillingFormStep.tsx` - Billing info step 3. `/frontend/src/components/billing/PaymentMethodSelect.tsx` - Separate payment selector --- ## API Endpoints Used ### Registration ``` POST /v1/auth/register/ Content-Type: application/json { "email": "user@example.com", "password": "SecurePass123!", "password_confirm": "SecurePass123!", "first_name": "John", "last_name": "Doe", "account_name": "John's Business", // optional "plan_slug": "starter", // optional (defaults to "free") "payment_method": "bank_transfer" // required for paid plans } Response: { "success": true, "data": { "user": { ... }, "tokens": { "access": "eyJ...", "refresh": "eyJ...", "access_expires_at": "2024-12-09T...", "refresh_expires_at": "2024-12-09T..." } } } ``` ### Payment Methods (Public) ``` GET /v1/billing/admin/payment-methods/?country=US No authentication required Response: [ { "id": 1, "payment_method": "stripe", "display_name": "Credit/Debit Card", "instructions": null, "country_code": "*", "is_enabled": true, "sort_order": 1 }, { "id": 2, "payment_method": "bank_transfer", "display_name": "Bank Transfer", "instructions": "Transfer to: Account 123456789...", "country_code": "*", "is_enabled": true, "sort_order": 2 } ] ``` --- ## Known Issues (Not in Scope) 1. **Site.industry field not required** - Can create sites without industry 2. **Missing Subscription.plan field** - Subscription doesn't link to plan directly 3. **Duplicate date fields** - Period dates in both Subscription and Invoice 4. **Payment method stored in 3 places** - Account, Subscription, Payment models These are documented in `IMPLEMENTATION-PLAN-SIGNUP-TO-PAYMENT-WORKFLOW.md` but not critical for signup to work. --- ## Next Steps 1. **Build Frontend** ```bash cd /data/app/igny8/frontend npm run build ``` 2. **Test Free Signup** - Create account without plan parameter - Verify tokens persist - Verify account has 1000 credits 3. **Test Paid Signup** - Create account with `?plan=starter` - Verify payment methods load - Verify account created with `pending_payment` status 4. **Monitor for Issues** - Check browser console for errors - Check network tab for failed API calls - Verify localStorage has `access_token` and `refresh_token` --- ## Rollback Instructions If issues occur, revert these changes: ### Frontend ```bash git checkout HEAD -- src/store/authStore.ts git checkout HEAD -- src/pages/AuthPages/SignUp.tsx rm src/components/auth/SignUpFormSimplified.tsx ``` ### Backend ```bash git checkout HEAD -- igny8_core/business/billing/urls.py ``` Then use the old multi-step form: ```typescript // In SignUp.tsx import SignUpFormEnhanced from "../../components/auth/SignUpFormEnhanced"; ``` --- ## Success Criteria ✅ Free signup works - user stays logged in ✅ Paid signup works - payment methods load ✅ Single-page form is simpler and faster ✅ Tokens persist correctly ✅ No authentication errors on signup