Files
bakery-ia/REARCHITECTURE_PROPOSAL.md
2026-01-13 22:22:38 +01:00

32 KiB

User Registration & Subscription Architecture Rearchitecture Proposal

Executive Summary

This proposal outlines a comprehensive rearchitecture of the user registration, payment processing, and subscription management flow to address the current limitations and implement the requested multi-phase registration process.

Current Architecture Analysis

Current Flow Limitations

  1. Monolithic Registration Process: The current flow combines user creation, payment processing, and subscription creation in a single step
  2. Tenant-Subscription Coupling: Subscriptions are created and immediately linked to tenants during registration
  3. Payment Processing Timing: Payment is processed before user creation is complete
  4. Onboarding Complexity: The onboarding flow assumes immediate tenant creation with subscription

Key Components Analysis

Frontend Components

  • RegisterForm.tsx: Multi-step form handling basic info, subscription selection, and payment
  • PaymentForm.tsx: Stripe payment processing component
  • RegisterTenantStep.tsx: Tenant creation during onboarding

Backend Services

  • Auth Service: User creation, authentication, and onboarding progress tracking
  • Tenant Service: Tenant creation, subscription management, and payment processing
  • Shared Clients: Inter-service communication between auth and tenant services

Current Data Flow

graph TD
    A[Frontend RegisterForm] -->|User Data + Payment| B[Auth Service Register]
    B -->|Create User| C[User Created]
    B -->|Call Tenant Service| D[Tenant Service Payment Customer]
    D -->|Create Payment Customer| E[Payment Customer Created]
    C -->|Return Tokens| F[User Authenticated]
    F -->|Onboarding| G[RegisterTenantStep]
    G -->|Create Tenant + Subscription| H[Tenant Service Create Tenant]
    H -->|Create Subscription| I[Subscription Created]

Proposed Architecture

New Multi-Phase Registration Flow

graph TD
    subgraph Frontend
        A1[Basic Info Form] -->|Email + Password| A2[Subscription Selection]
        A2 -->|Plan + Billing Cycle| A3[Payment Form]
        A3 -->|Payment Method| A4[Process Payment]
    end
    
    subgraph Backend Services
        A4 -->|User Data + Payment| B1[Auth Service Register]
        B1 -->|Create User| B2[User Created with Payment ID]
        B2 -->|Call Tenant Service| B3[Tenant Service Create Subscription]
        B3 -->|Create Subscription| B4[Subscription Created]
        B4 -->|Return Subscription ID| B2
        B2 -->|Return Auth Tokens| A4
    end
    
    subgraph Onboarding
        A4 -->|Success| C1[Onboarding Flow]
        C1 -->|Tenant Creation| C2[RegisterTenantStep]
        C2 -->|Tenant Data| C3[Tenant Service Create Tenant]
        C3 -->|Link Subscription| C4[Link Subscription to Tenant]
        C4 -->|Complete| C5[Onboarding Complete]
    end

Detailed Component Changes

1. Frontend Changes

RegisterForm.tsx Modifications:

  • Phase 1: Collect only email and password (basic info)
  • Phase 2: Plan selection with billing cycle options
  • Phase 3: Payment form with address and card details
  • Payment Processing: Call new backend endpoint with complete registration data

New Payment Flow:

// Current: handleRegistrationSubmit calls authService.register directly
// New: handleRegistrationSubmit calls new registration endpoint
const handleRegistrationSubmit = async (paymentMethodId?: string) => {
  try {
    const registrationData = {
      email: formData.email,
      password: formData.password,
      full_name: formData.full_name,
      subscription_plan: selectedPlan,
      billing_cycle: billingCycle,
      payment_method_id: paymentMethodId,
      coupon_code: isPilot ? couponCode : undefined,
      // Address and billing info
      address: billingAddress,
      postal_code: billingPostalCode,
      city: billingCity,
      country: billingCountry
    };

    // Call new registration endpoint
    const response = await authService.registerWithSubscription(registrationData);
    
    // Handle success and redirect to onboarding
    onSuccess?.();
  } catch (err) {
    // Handle errors
  }
};

2. Auth Service Changes

New Registration Endpoint:

@router.post("/api/v1/auth/register-with-subscription")
async def register_with_subscription(
    user_data: UserRegistrationWithSubscription,
    auth_service: EnhancedAuthService = Depends(get_auth_service)
):
    """Register user and create subscription in one call"""
    
    # Step 1: Create user
    user = await auth_service.register_user(user_data)
    
    # Step 2: Create payment customer via tenant service
    payment_result = await auth_service.create_payment_customer_via_tenant_service(
        user_data, 
        user_data.payment_method_id
    )
    
    # Step 3: Create subscription via tenant service
    subscription_result = await auth_service.create_subscription_via_tenant_service(
        user.id,
        user_data.subscription_plan,
        user_data.payment_method_id,
        user_data.billing_cycle,
        user_data.coupon_code
    )
    
    # Step 4: Store subscription ID in user's onboarding progress
    await auth_service.save_subscription_to_onboarding_progress(
        user.id,
        subscription_result.subscription_id,
        user_data
    )
    
    return {
        **user,
        subscription_id: subscription_result.subscription_id
    }

Enhanced Auth Service Methods:

class EnhancedAuthService:
    
    async def create_subscription_via_tenant_service(
        self, 
        user_id: str,
        plan_id: str,
        payment_method_id: str,
        billing_cycle: str,
        coupon_code: Optional[str] = None
    ) -> Dict[str, Any]:
        """Create subscription via tenant service during registration"""
        
        try:
            from shared.clients.tenant_client import TenantServiceClient
            from app.core.config import settings
            
            tenant_client = TenantServiceClient(settings)
            
            # Prepare user data for tenant service
            user_data = await self.get_user_data_for_tenant_service(user_id)
            
            # Call tenant service to create subscription
            result = await tenant_client.create_subscription_for_registration(
                user_data=user_data,
                plan_id=plan_id,
                payment_method_id=payment_method_id,
                billing_cycle=billing_cycle,
                coupon_code=coupon_code
            )
            
            return result
            
        except Exception as e:
            logger.error("Failed to create subscription via tenant service", 
                        user_id=user_id, error=str(e))
            raise
    
    async def save_subscription_to_onboarding_progress(
        self,
        user_id: str,
        subscription_id: str,
        registration_data: Dict[str, Any]
    ):
        """Store subscription info in onboarding progress for later tenant linking"""
        
        try:
            # Get or create onboarding progress
            progress = await self.onboarding_repo.get_user_progress(user_id)
            
            if not progress:
                progress = await self.onboarding_repo.create_user_progress(user_id)
            
            # Store subscription data in user_registered step
            step_data = {
                "subscription_id": subscription_id,
                "subscription_plan": registration_data.subscription_plan,
                "billing_cycle": registration_data.billing_cycle,
                "coupon_code": registration_data.coupon_code,
                "payment_method_id": registration_data.payment_method_id,
                "payment_customer_id": registration_data.payment_customer_id,
                "created_at": datetime.now(timezone.utc).isoformat(),
                "status": "pending_tenant_linking"
            }
            
            await self.onboarding_repo.upsert_user_step(
                user_id=user_id,
                step_name="user_registered",
                completed=True,
                step_data=step_data
            )
            
            logger.info("Subscription data saved to onboarding progress",
                       user_id=user_id,
                       subscription_id=subscription_id)
            
        except Exception as e:
            logger.error("Failed to save subscription to onboarding progress",
                        user_id=user_id, error=str(e))
            raise

3. Tenant Service Changes

New Subscription Creation Endpoint:

@router.post("/api/v1/subscriptions/create-for-registration")
async def create_subscription_for_registration(
    user_data: Dict[str, Any],
    plan_id: str = Query(...),
    payment_method_id: str = Query(...),
    billing_cycle: str = Query("monthly"),
    coupon_code: Optional[str] = Query(None),
    payment_service: PaymentService = Depends(get_payment_service),
    db: AsyncSession = Depends(get_db)
):
    """
    Create subscription during user registration (before tenant creation)
    
    This endpoint creates a subscription that is not yet linked to any tenant.
    The subscription will be linked to a tenant during the onboarding flow.
    """
    
    try:
        # Use orchestration service for complete workflow
        orchestration_service = SubscriptionOrchestrationService(db)
        
        # Create subscription without tenant_id (tenant-independent subscription)
        result = await orchestration_service.create_tenant_independent_subscription(
            user_data,
            plan_id,
            payment_method_id,
            billing_cycle,
            coupon_code
        )
        
        logger.info("Tenant-independent subscription created for registration",
                   user_id=user_data.get('user_id'),
                   subscription_id=result["subscription_id"])
        
        return {
            "success": True,
            "subscription_id": result["subscription_id"],
            "customer_id": result["customer_id"],
            "status": result["status"],
            "plan": result["plan"],
            "billing_cycle": result["billing_cycle"]
        }
        
    except Exception as e:
        logger.error("Failed to create tenant-independent subscription",
                    error=str(e),
                    user_id=user_data.get('user_id'))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to create subscription"
        )

Enhanced Subscription Orchestration Service:

class SubscriptionOrchestrationService:
    
    async def create_tenant_independent_subscription(
        self,
        user_data: Dict[str, Any],
        plan_id: str,
        payment_method_id: str,
        billing_cycle: str = "monthly",
        coupon_code: Optional[str] = None
    ) -> Dict[str, Any]:
        """
        Create a subscription that is not linked to any tenant yet
        
        This subscription will be linked to a tenant during onboarding
        when the user creates their bakery/tenant.
        """
        
        try:
            logger.info("Creating tenant-independent subscription",
                       user_id=user_data.get('user_id'),
                       plan_id=plan_id)
            
            # Step 1: Create customer in payment provider
            customer = await self.payment_service.create_customer(user_data)
            
            # Step 2: Handle coupon logic
            trial_period_days = 0
            coupon_discount = None
            
            if coupon_code:
                coupon_service = CouponService(self.db_session)
                success, discount_applied, error = await coupon_service.redeem_coupon(
                    coupon_code,
                    None,  # No tenant_id yet
                    base_trial_days=0
                )
                
                if success and discount_applied:
                    coupon_discount = discount_applied
                    trial_period_days = discount_applied.get("total_trial_days", 0)
            
            # Step 3: Create subscription in payment provider
            stripe_subscription = await self.payment_service.create_payment_subscription(
                customer.id,
                plan_id,
                payment_method_id,
                trial_period_days if trial_period_days > 0 else None,
                billing_cycle
            )
            
            # Step 4: Create local subscription record WITHOUT tenant_id
            subscription_record = await self.subscription_service.create_tenant_independent_subscription_record(
                stripe_subscription.id,
                customer.id,
                plan_id,
                stripe_subscription.status,
                stripe_subscription.current_period_start,
                stripe_subscription.current_period_end,
                trial_period_days if trial_period_days > 0 else None,
                billing_cycle,
                user_data.get('user_id')
            )
            
            # Step 5: Store subscription in pending_tenant_linking state
            await self.subscription_service.mark_subscription_as_pending_tenant_linking(
                subscription_record.id,
                user_data.get('user_id')
            )
            
            return {
                "success": True,
                "customer_id": customer.id,
                "subscription_id": stripe_subscription.id,
                "status": stripe_subscription.status,
                "plan": plan_id,
                "billing_cycle": billing_cycle,
                "trial_period_days": trial_period_days,
                "current_period_end": stripe_subscription.current_period_end.isoformat(),
                "coupon_applied": bool(coupon_discount),
                "user_id": user_data.get('user_id')
            }
            
        except Exception as e:
            logger.error("Failed to create tenant-independent subscription",
                        error=str(e),
                        user_id=user_data.get('user_id'))
            raise

New Subscription Service Methods:

class SubscriptionService:
    
    async def create_tenant_independent_subscription_record(
        self,
        subscription_id: str,
        customer_id: str,
        plan: str,
        status: str,
        current_period_start: datetime,
        current_period_end: datetime,
        trial_period_days: Optional[int] = None,
        billing_cycle: str = "monthly",
        user_id: Optional[str] = None
    ) -> Subscription:
        """Create subscription record without tenant_id"""
        
        try:
            subscription_data = {
                "subscription_id": subscription_id,
                "customer_id": customer_id,
                "plan": plan,
                "status": status,
                "current_period_start": current_period_start,
                "current_period_end": current_period_end,
                "trial_period_days": trial_period_days,
                "billing_cycle": billing_cycle,
                "user_id": user_id,
                "tenant_id": None,  # No tenant linked yet
                "is_tenant_linked": False,
                "created_at": datetime.now(timezone.utc),
                "updated_at": datetime.now(timezone.utc)
            }
            
            subscription = await self.subscription_repo.create(subscription_data)
            
            logger.info("Tenant-independent subscription record created",
                       subscription_id=subscription.id,
                       user_id=user_id)
            
            return subscription
            
        except Exception as e:
            logger.error("Failed to create tenant-independent subscription record",
                        error=str(e))
            raise
    
    async def mark_subscription_as_pending_tenant_linking(
        self,
        subscription_id: str,
        user_id: str
    ):
        """Mark subscription as pending tenant linking"""
        
        try:
            await self.subscription_repo.update(
                subscription_id,
                {
                    "status": "pending_tenant_linking",
                    "tenant_linking_status": "pending",
                    "user_id": user_id
                }
            )
            
            logger.info("Subscription marked as pending tenant linking",
                       subscription_id=subscription_id,
                       user_id=user_id)
            
        except Exception as e:
            logger.error("Failed to mark subscription as pending tenant linking",
                        error=str(e),
                        subscription_id=subscription_id)
            raise

4. Onboarding Flow Changes

Enhanced RegisterTenantStep:

// When tenant is created, link the pending subscription
const handleSubmit = async () => {
  if (!validateForm()) {
    return;
  }
  
  try {
    let tenant;
    if (tenantId) {
      // Update existing tenant
      const updateData: TenantUpdate = { ... };
      tenant = await updateTenant.mutateAsync({ tenantId, updateData });
    } else {
      // Create new tenant and link subscription
      const registrationData: BakeryRegistrationWithSubscription = {
        ...formData,
        // Include subscription linking data from onboarding progress
        subscription_id: wizardContext.state.subscriptionId,
        link_existing_subscription: true
      };
      
      tenant = await registerBakery.mutateAsync(registrationData);
    }
    
    // Continue with onboarding
    onComplete({ tenant, tenantId: tenant.id });
    
  } catch (error) {
    console.error('Error registering bakery:', error);
    setErrors({ submit: t('onboarding:steps.tenant_registration.errors.register') });
  }
};

Enhanced Tenant Creation Endpoint:

@router.post(route_builder.build_base_route("register", include_tenant_prefix=False))
async def register_bakery(
    bakery_data: BakeryRegistrationWithSubscription,
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    tenant_service: EnhancedTenantService = Depends(get_enhanced_tenant_service),
    db: AsyncSession = Depends(get_db)
):
    """Register a new bakery/tenant with subscription linking"""
    
    try:
        // Create tenant first
        result = await tenant_service.create_bakery(bakery_data, current_user["user_id"])
        tenant_id = result["tenant_id"]
        
        // Check if we need to link an existing subscription
        if bakery_data.link_existing_subscription and bakery_data.subscription_id:
            // Link the pending subscription to this tenant
            subscription_result = await tenant_service.link_subscription_to_tenant(
                tenant_id,
                bakery_data.subscription_id,
                current_user["user_id"]
            )
            
            logger.info("Subscription linked to tenant during registration",
                       tenant_id=tenant_id,
                       subscription_id=bakery_data.subscription_id)
        else:
            // Fallback to current behavior for backward compatibility
            // Create new subscription if needed
            pass
        
        return result
        
    except Exception as e:
        logger.error("Failed to register bakery with subscription linking",
                    error=str(e),
                    user_id=current_user["user_id"])
        raise

New Tenant Service Method for Subscription Linking:

class EnhancedTenantService:
    
    async def link_subscription_to_tenant(
        self,
        tenant_id: str,
        subscription_id: str,
        user_id: str
    ) -> Dict[str, Any]:
        """Link a pending subscription to a tenant"""
        
        try:
            async with self.database_manager.get_session() as db_session:
                async with UnitOfWork(db_session) as uow:
                    # Register repositories
                    subscription_repo = uow.register_repository(
                        "subscriptions", SubscriptionRepository, Subscription
                    )
                    tenant_repo = uow.register_repository(
                        "tenants", TenantRepository, Tenant
                    )
                    
                    # Get the subscription
                    subscription = await subscription_repo.get_by_id(subscription_id)
                    
                    if not subscription:
                        raise HTTPException(
                            status_code=status.HTTP_404_NOT_FOUND,
                            detail="Subscription not found"
                        )
                    
                    # Verify subscription is in pending_tenant_linking state
                    if subscription.tenant_linking_status != "pending":
                        raise HTTPException(
                            status_code=status.HTTP_400_BAD_REQUEST,
                            detail="Subscription is not in pending tenant linking state"
                        )
                    
                    # Verify subscription belongs to this user
                    if subscription.user_id != user_id:
                        raise HTTPException(
                            status_code=status.HTTP_403_FORBIDDEN,
                            detail="Subscription does not belong to this user"
                        )
                    
                    # Update subscription with tenant_id
                    update_data = {
                        "tenant_id": tenant_id,
                        "is_tenant_linked": True,
                        "tenant_linking_status": "completed",
                        "linked_at": datetime.now(timezone.utc)
                    }
                    
                    await subscription_repo.update(subscription_id, update_data)
                    
                    # Update tenant with subscription information
                    tenant_update = {
                        "stripe_customer_id": subscription.customer_id,
                        "subscription_status": subscription.status,
                        "subscription_plan": subscription.plan,
                        "subscription_tier": subscription.plan,
                        "billing_cycle": subscription.billing_cycle,
                        "trial_period_days": subscription.trial_period_days
                    }
                    
                    await tenant_repo.update_tenant(tenant_id, tenant_update)
                    
                    # Commit transaction
                    await uow.commit()
                    
                    logger.info("Subscription successfully linked to tenant",
                               tenant_id=tenant_id,
                               subscription_id=subscription_id,
                               user_id=user_id)
                    
                    return {
                        "success": True,
                        "tenant_id": tenant_id,
                        "subscription_id": subscription_id,
                        "status": "linked"
                    }
                    
        except Exception as e:
            logger.error("Failed to link subscription to tenant",
                        error=str(e),
                        tenant_id=tenant_id,
                        subscription_id=subscription_id,
                        user_id=user_id)
            raise

Database Schema Changes

New Subscription Table Structure

-- Add new columns to subscriptions table
ALTER TABLE subscriptions ADD COLUMN IF NOT EXISTS user_id UUID;
ALTER TABLE subscriptions ADD COLUMN IF NOT EXISTS is_tenant_linked BOOLEAN DEFAULT FALSE;
ALTER TABLE subscriptions ADD COLUMN IF NOT EXISTS tenant_linking_status VARCHAR(50);
ALTER TABLE subscriptions ADD COLUMN IF NOT EXISTS linked_at TIMESTAMP;

-- Add index for user-based subscription queries
CREATE INDEX IF NOT EXISTS idx_subscriptions_user_id ON subscriptions(user_id);
CREATE INDEX IF NOT EXISTS idx_subscriptions_linking_status ON subscriptions(tenant_linking_status);

-- Add constraint to ensure tenant_id is NULL when not linked
ALTER TABLE subscriptions ADD CONSTRAINT chk_tenant_linking 
    CHECK ((is_tenant_linked = FALSE AND tenant_id IS NULL) OR 
           (is_tenant_linked = TRUE AND tenant_id IS NOT NULL));

Onboarding Progress Data Structure

{
  "user_id": "user-uuid",
  "current_step": "user_registered",
  "steps": [
    {
      "step_name": "user_registered",
      "completed": true,
      "completed_at": "2025-10-15T10:30:00Z",
      "data": {
        "subscription_id": "sub-uuid",
        "subscription_plan": "professional",
        "billing_cycle": "yearly",
        "coupon_code": "PILOT2025",
        "payment_method_id": "pm-123",
        "payment_customer_id": "cus-456",
        "status": "pending_tenant_linking",
        "created_at": "2025-10-15T10:30:00Z"
      }
    }
  ]
}

Error Handling & Recovery

Error Scenarios and Recovery Strategies

  1. Payment Processing Failure

    • Scenario: Payment fails during registration
    • Recovery: Rollback user creation, show error to user, allow retry
    • Implementation: Transaction management in auth service
  2. Subscription Creation Failure

    • Scenario: Subscription creation fails after user creation
    • Recovery: User created but marked as "registration_incomplete", allow retry in onboarding
    • Implementation: Store registration state, provide recovery endpoint
  3. Tenant Linking Failure

    • Scenario: Tenant creation succeeds but subscription linking fails
    • Recovery: Tenant created with default trial subscription, manual linking available
    • Implementation: Fallback to current behavior, admin notification
  4. Orphaned Subscriptions

    • Scenario: User registers but never completes onboarding
    • Recovery: Cleanup task to cancel subscriptions after 30 days
    • Implementation: Background job to monitor pending subscriptions

Monitoring and Alerts

# Subscription linking monitoring
class SubscriptionMonitoringService:
    
    async def monitor_pending_subscriptions(self):
        """Monitor subscriptions pending tenant linking"""
        
        pending_subscriptions = await self.subscription_repo.get_pending_tenant_linking()
        
        for subscription in pending_subscriptions:
            created_days_ago = (datetime.now(timezone.utc) - subscription.created_at).days
            
            if created_days_ago > 30:
                # Cancel subscription and notify user
                await self.cancel_orphaned_subscription(subscription.id)
                await self.notify_user_about_cancellation(subscription.user_id)
            elif created_days_ago > 7:
                # Send reminder to complete onboarding
                await self.send_onboarding_reminder(subscription.user_id)

Migration Strategy

Phase 1: Backend Implementation

  1. Database Migration: Add new columns to subscriptions table
  2. Auth Service Updates: Implement new registration endpoint
  3. Tenant Service Updates: Implement tenant-independent subscription creation
  4. Shared Clients: Update inter-service communication

Phase 2: Frontend Implementation

  1. Registration Form: Update to collect billing address
  2. Payment Flow: Integrate with new backend endpoints
  3. Onboarding Flow: Add subscription linking logic

Phase 3: Testing and Validation

  1. Unit Tests: Verify individual component behavior
  2. Integration Tests: Test service-to-service communication
  3. End-to-End Tests: Validate complete user journey
  4. Load Testing: Ensure performance under load

Phase 4: Deployment and Rollout

  1. Feature Flags: Enable gradual rollout
  2. A/B Testing: Compare with existing flow
  3. Monitoring: Track key metrics and errors
  4. Rollback Plan: Prepare for quick rollback if needed

Benefits of the New Architecture

1. Improved User Experience

  • Clear Separation of Concerns: Users understand each step of the process
  • Progressive Commitment: Users can complete registration without immediate tenant creation
  • Flexible Onboarding: Users can explore the platform before committing to a specific bakery

2. Better Error Handling

  • Isolated Failure Points: Failures in one step don't cascade to others
  • Recovery Paths: Clear recovery mechanisms for each failure scenario
  • Graceful Degradation: System remains functional even with partial failures

3. Enhanced Business Flexibility

  • Multi-Tenant Support: Users can create multiple tenants with the same subscription
  • Subscription Portability: Subscriptions can be moved between tenants
  • Trial Management: Better control over trial periods and conversions

4. Improved Security

  • Data Isolation: Sensitive payment data handled separately from user data
  • Audit Trails: Clear tracking of subscription lifecycle
  • Compliance: Better support for GDPR and payment industry standards

5. Scalability

  • Microservice Alignment: Better separation between auth and tenant services
  • Independent Scaling: Services can be scaled independently
  • Future Extensibility: Easier to add new features and integrations

Implementation Timeline

Phase Duration Key Activities
1. Analysis & Design 2 weeks Architecture review, technical design, stakeholder approval
2. Backend Implementation 4 weeks Database changes, service updates, API development
3. Frontend Implementation 3 weeks Form updates, payment integration, onboarding changes
4. Testing & QA 3 weeks Unit tests, integration tests, E2E tests, performance testing
5. Deployment & Rollout 2 weeks Staging deployment, production rollout, monitoring setup
6. Post-Launch Ongoing Bug fixes, performance optimization, feature enhancements

Risks and Mitigation

Technical Risks

  1. Data Consistency: Risk of inconsistent state between services

    • Mitigation: Strong transaction management, idempotent operations, reconciliation jobs
  2. Performance Impact: Additional service calls may impact performance

    • Mitigation: Caching, async processing, performance optimization
  3. Complexity Increase: More moving parts increase system complexity

    • Mitigation: Clear documentation, comprehensive monitoring, gradual rollout

Business Risks

  1. User Confusion: Multi-step process may confuse some users

    • Mitigation: Clear UI guidance, progress indicators, help documentation
  2. Conversion Impact: Additional steps may reduce conversion rates

    • Mitigation: A/B testing, user feedback, iterative improvements
  3. Support Burden: New flow may require additional support

    • Mitigation: Comprehensive documentation, self-service recovery, support training

Success Metrics

Key Performance Indicators

  1. Registration Completion Rate: Percentage of users completing registration
  2. Onboarding Completion Rate: Percentage of users completing onboarding
  3. Error Rates: Frequency of errors in each step
  4. Conversion Rates: Percentage of visitors becoming paying customers
  5. User Satisfaction: Feedback and ratings from users

Monitoring Dashboard

Registration Funnel:
- Step 1 (Basic Info): 100%
- Step 2 (Plan Selection): 85%
- Step 3 (Payment): 75%
- Onboarding Completion: 60%

Error Metrics:
- Registration Errors: < 1%
- Payment Errors: < 2%
- Subscription Linking Errors: < 0.5%

Performance Metrics:
- Registration Time: < 5s
- Payment Processing Time: < 3s
- Tenant Creation Time: < 2s

Conclusion

This rearchitecture proposal addresses the current limitations by implementing a clear separation between user registration, payment processing, and tenant creation. The new multi-phase approach provides better user experience, improved error handling, and enhanced business flexibility while maintaining backward compatibility and providing clear migration paths.

The proposed solution aligns with modern microservice architectures and provides a solid foundation for future growth and feature enhancements.