9.7 KiB
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/withAllowAnypermission
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:
// 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):
@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
AllowAnypermission - ✅ 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
// 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
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
- Account created with status
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
- ✅
/frontend/src/store/authStore.ts- Fixed token persistence - ✅
/frontend/src/pages/AuthPages/SignUp.tsx- Use simplified form - ✅
/frontend/src/components/auth/SignUpFormSimplified.tsx- NEW single-page form
Backend Files Modified
- ✅
/backend/igny8_core/business/billing/urls.py- Added payment-configs router
Frontend Files Created
- ✅
/frontend/src/components/auth/SignUpFormSimplified.tsx
Files No Longer Used (Keep for Reference)
/frontend/src/components/auth/SignUpFormEnhanced.tsx- Old multi-step form/frontend/src/components/billing/BillingFormStep.tsx- Billing info step/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)
- Site.industry field not required - Can create sites without industry
- Missing Subscription.plan field - Subscription doesn't link to plan directly
- Duplicate date fields - Period dates in both Subscription and Invoice
- 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
-
Build Frontend
cd /data/app/igny8/frontend npm run build -
Test Free Signup
- Create account without plan parameter
- Verify tokens persist
- Verify account has 1000 credits
-
Test Paid Signup
- Create account with
?plan=starter - Verify payment methods load
- Verify account created with
pending_paymentstatus
- Create account with
-
Monitor for Issues
- Check browser console for errors
- Check network tab for failed API calls
- Verify localStorage has
access_tokenandrefresh_token
Rollback Instructions
If issues occur, revert these changes:
Frontend
git checkout HEAD -- src/store/authStore.ts
git checkout HEAD -- src/pages/AuthPages/SignUp.tsx
rm src/components/auth/SignUpFormSimplified.tsx
Backend
git checkout HEAD -- igny8_core/business/billing/urls.py
Then use the old multi-step form:
// 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