# Onboarding System

## Overview

The onboarding system manages the complete setup flow for new organizations, from email verification to subscription selection.

## Features

### Email Verification with OTP
- **Spatie Laravel One-Time Passwords** package integration
- Secure 6-digit OTP codes
- 10-minute expiration
- Rate limiting (60 seconds between requests)
- Automatic email delivery

### Onboarding Steps

1. **Pending Verification** - Organization created, admin needs to verify email
2. **Email Verified** - Email confirmed, ready for plan selection
3. **Plan Selection** - Admin selects subscription plan
4. **Payment Pending** - Awaiting payment (if not trial)
5. **Completed** - Onboarding finished, full access granted

## Implementation

### Models

**User Fields:**
- `must_verify_email` - Boolean flag requiring email verification
- `first_login_completed` - Tracks if onboarding is complete
- `last_otp_sent_at` - Rate limiting timestamp
- `email_verified_at` - Verification timestamp

**Organization Fields:**
- `onboarding_step` - Current step in onboarding process
- `onboarding_completed_at` - Completion timestamp
- `onboarding_notes` - Admin notes

### Services

**OtpService** (`app/Services/OtpService.php`)
- `generateAndSendOtp(User $user)` - Generate and send OTP
- `validateOtp(User $user, string $code)` - Validate OTP code
- `canResend(User $user)` - Check rate limiting
- `secondsUntilCanResend(User $user)` - Get cooldown time
- `getRemainingAttempts(User $user)` - Get remaining attempts

### Controllers

**VerificationController** (`app/Http/Controllers/Auth/VerificationController.php`)
- `show()` - Display verification page, auto-generate OTP
- `verifyOtp(Request $request)` - Validate OTP and update organization step
- `resend(Request $request)` - Resend OTP with rate limiting

**OnboardingController** (`app/Http/Controllers/OnboardingController.php`)
- `index()` - Route to appropriate onboarding step
- `welcome()` - Welcome screen
- `selectPlan()` - Plan selection
- `storePlan(Request $request)` - Save plan and create subscription
- `payment()` - Payment screen
- `complete()` - Completion screen
- `finish()` - Mark onboarding complete

### Middleware

**EnsureEmailIsVerified** (`app/Http/Middleware/EnsureEmailIsVerified.php`)
- Redirects unverified users to verification page
- Skips system admins

**CheckOnboardingStatus** (`app/Http/Middleware/CheckOnboardingStatus.php`)
- Redirects incomplete onboarding to appropriate step
- Whitelists verification and onboarding routes

### Routes

```php
// Email Verification
Route::get('/email/verify', [VerificationController::class, 'show'])
     ->name('verification.notice');
Route::post('/email/verify', [VerificationController::class, 'verifyOtp'])
     ->name('verification.verify.otp');
Route::post('/email/verification-notification', [VerificationController::class, 'resend'])
     ->name('verification.send');

// Onboarding
Route::middleware(['auth', 'email.verified'])->prefix('onboarding')->group(function () {
    Route::get('/', [OnboardingController::class, 'index'])->name('onboarding.index');
    Route::get('/welcome', [OnboardingController::class, 'welcome'])->name('onboarding.welcome');
    Route::get('/select-plan', [OnboardingController::class, 'selectPlan'])->name('onboarding.select-plan');
    Route::post('/select-plan', [OnboardingController::class, 'storePlan'])->name('onboarding.store-plan');
    Route::get('/payment', [OnboardingController::class, 'payment'])->name('onboarding.payment');
    Route::get('/complete', [OnboardingController::class, 'complete'])->name('onboarding.complete');
    Route::get('/finish', [OnboardingController::class, 'finish'])->name('onboarding.finish');
});
```

## Email Templates

**VerifyEmailOtp** (`app/Mail/VerifyEmailOtp.php`)
- Professional email template
- Large, centered OTP code
- Security warnings
- 10-minute expiration notice

**Template:** `resources/views/emails/auth/verify-email-otp.blade.php`

## Views

**Verification Page** (`resources/views/auth/verify-email.blade.php`)
- Clean, user-friendly interface
- Large OTP input field
- Auto-submit on 6 digits
- Resend button with countdown
- Security tips

**Onboarding Pages:**
- `resources/views/onboarding/welcome.blade.php`
- `resources/views/onboarding/select-plan.blade.php`
- `resources/views/onboarding/payment.blade.php`
- `resources/views/onboarding/complete.blade.php`

## Security Features

### Spatie Package (Built-in)
- Cryptographically secure code generation
- Automatic expiration
- Database storage
- Automatic cleanup of expired codes

### Custom Implementation
- Rate limiting (60 seconds between requests)
- Activity logging (all verification events)
- Middleware protection
- Email verification required before onboarding

## Usage

### Creating Organization Admin

```php
// SystemAdmin creates organization
$org = Organization::create([
    'name' => 'Company Name',
    'email' => 'admin@company.com',
    'phone' => '+254700000000',
    'address' => 'Nairobi, Kenya',
    'status' => 'active',
    'onboarding_step' => 'pending_verification',
]);

// Create admin user
$user = User::create([
    'name' => 'Admin Name',
    'email' => 'admin@company.com',
    'password' => bcrypt('secure-password'),
    'organization_id' => $org->id,
    'must_verify_email' => true,
    'first_login_completed' => false,
]);

$user->assignRole('org_admin');
```

### Testing OTP Flow

```bash
# Generate OTP for user
php artisan otp:generate user@example.com

# Get current OTP code
php artisan otp:get user@example.com
```

## Flow Diagram

```
SystemAdmin creates Organization
         ↓
Organization Admin receives credentials
         ↓
Admin logs in for first time
         ↓
Middleware detects must_verify_email = true
         ↓
Redirected to /email/verify
         ↓
OTP generated automatically
         ↓
Email sent with 6-digit code
         ↓
Admin enters OTP code
         ↓
OtpService validates code
         ↓
Email marked as verified
         ↓
Organization step → email_verified
         ↓
Activity logged
         ↓
Redirected to /onboarding
         ↓
Admin selects subscription plan
         ↓
Onboarding complete!
```

## Configuration

### Mail Settings (.env)
```env
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=your-email@gmail.com
MAIL_FROM_NAME="${APP_NAME}"
```

### OTP Settings
- **Code Length:** 6 digits
- **Expiration:** 10 minutes
- **Rate Limit:** 60 seconds between requests
- **Storage:** Database (one_time_passwords table)

## Troubleshooting

### Email Not Received
1. Check spam folder
2. Verify mail configuration
3. Check Laravel logs: `tail -f storage/logs/laravel.log`
4. Get OTP directly: `php artisan otp:get user@example.com`

### Rate Limiting
```bash
# Reset rate limit for user
php artisan tinker --execute="
\$user = App\Models\User::where('email', 'user@example.com')->first();
\$user->update(['last_otp_sent_at' => null]);
"
```

### Clear Expired OTPs
```bash
php artisan tinker --execute="
Spatie\OneTimePasswords\Models\OneTimePassword::where('expires_at', '<', now())->delete();
"
```

## Related Documentation

- [Subscription System](SUBSCRIPTION_SYSTEM_COMPLETE.md)
- [Multi-Tenancy](MULTI_TENANCY.md)
- [Activity Logging](ACTIVITY_LOG_INTEGRATION.md)
- [Email Configuration](MODULES/12_EMAIL_CONFIGURATION.md)
