Files
igny8/multi-tenancy/in-progress/SIGNUP-FIXES-DEC-9-2024.md
2025-12-09 02:43:51 +00:00

335 lines
9.7 KiB
Markdown

# 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