# Case 2: New User Enrollment Flow - Complete Implementation

## Overview
This document describes the complete implementation of **Case 2: New User (App Not Installed)** enrollment flow for the Pathshalaa application.

## Flow Summary

### Student Journey
1. **Tutor shares enrollment link**: `https://your-domain.com/enroll/{enroll_id}`
2. **Student clicks link** (app not installed → opens in browser)
3. **Landing page displays**:
   - Group/Batch information
   - Download buttons for Android & iOS
   - Instructions
4. **Student downloads & installs app**
5. **Student opens app** and either:
   - **Option A (Recommended)**: App auto-detects pending enrollment via deep link/stored enrollment code
   - **Option B**: Student clicks enrollment link again
6. **Student registers/logs in**
7. **Auto-enrollment triggered** after successful authentication

---

## Implementation Components

### 1. Web Landing Page

#### Route
```php
// routes/web.php
Route::get('/enroll/{enroll_id}', [App\Http\Controllers\Web\EnrollmentLandingController::class, 'showEnrollmentPage'])
    ->name('enrollment.landing');
```

#### Controller
**File**: `app/Http/Controllers/Web/EnrollmentLandingController.php`

**Key Features**:
- Validates enrollment code
- Checks expiration
- Detects mobile device (Android/iOS)
- Attempts deep link redirect on mobile
- Shows download buttons
- Displays group/batch information

#### Views
**Files**:
- `resources/views/enrollment/landing.blade.php` - Main landing page
- `resources/views/enrollment/invalid.blade.php` - Invalid code page
- `resources/views/enrollment/expired.blade.php` - Expired code page
- `resources/views/enrollment/error.blade.php` - Error page

**Landing Page Features**:
- Responsive design
- Group/batch information display
- Android/iOS download buttons
- Deep link auto-redirect attempt
- QR code for desktop users
- LocalStorage enrollment code storage
- Visual instructions

---

### 2. Pending Enrollment System

#### Database Migration
**File**: `database/migrations/2025_12_05_152249_create_pending_enrollments_table.php`

**Schema**:
```php
pending_enrollments
├── id (primary key)
├── device_id (nullable, indexed)
├── enrollment_code (10 chars, indexed)
├── user_id (nullable, indexed)
├── status (enum: pending, completed, expired)
├── expires_at (timestamp)
├── completed_at (timestamp)
├── created_at
└── updated_at
```

#### Model
**File**: `app/Models/PendingEnrollment.php`

**Key Methods**:
- `isExpired()` - Check if enrollment has expired
- `markAsCompleted()` - Mark enrollment as completed
- `user()` - Relationship to User model
- `group()` - Relationship to Group model

---

### 3. Pending Enrollment API

#### Controller
**File**: `app/Http/Controllers/Api/V2/PendingEnrollmentController.php`

#### Endpoints

##### Store Pending Enrollment
```http
POST /api/v2/pending-enrollment/store
Content-Type: application/json

{
  "enrollment_code": "ABC1234567",
  "device_id": "device-unique-id" // optional
}
```

**Response (Success)**:
```json
{
  "status": true,
  "message": "Pending enrollment stored successfully",
  "data": {
    "pending_enrollment_id": 1,
    "enrollment_code": "ABC1234567",
    "expires_at": "2025-12-06 15:22:49",
    "group": {
      "id": 123,
      "name": "Class 10 - Mathematics"
    }
  }
}
```

**Usage**: Call this API when the app opens from a deep link but the user is not logged in.

##### Get Pending Enrollment by Device
```http
GET /api/v2/pending-enrollment/{device_id}
```

**Response (Success)**:
```json
{
  "status": true,
  "message": "Pending enrollment found",
  "data": {
    "pending_enrollment_id": 1,
    "enrollment_code": "ABC1234567",
    "expires_at": "2025-12-06 15:22:49",
    "group": {
      "id": 123,
      "name": "Class 10 - Mathematics"
    }
  }
}
```

**Usage**: Check for pending enrollments when app starts up.

---

### 4. Auto-Enrollment on Registration/Login

#### Updated Files
**File**: `app/Http/Controllers/RegisterController.php`

#### Enhanced Registration
```http
POST /api/register
Content-Type: application/json

{
  "name": "John Doe",
  "email": "john@example.com",
  "password": "password123",
  "c_password": "password123",
  "enrollment_code": "ABC1234567", // optional - triggers auto-enrollment
  "device_id": "device-unique-id"   // optional - for pending enrollment lookup
}
```

**Response (Success with Auto-Enrollment)**:
```json
{
  "success": true,
  "data": {
    "token": "1|abcd1234...",
    "name": "John Doe",
    "auto_enrollment": {
      "status": "enrolled",
      "group_id": 123,
      "group_name": "Class 10 - Mathematics",
      "class": "Class 10",
      "school": "ABC School"
    }
  },
  "message": "User register successfully."
}
```

#### Enhanced Login
```http
POST /api/login
Content-Type: application/json

{
  "email": "john@example.com",
  "password": "password123",
  "enrollment_code": "ABC1234567", // optional
  "device_id": "device-unique-id"   // optional
}
```

**Response** (Same format as registration with auto_enrollment data)

#### Auto-Enrollment Logic
The system checks for pending enrollments in this order:
1. If `enrollment_code` is provided → Look for pending enrollment
2. If `device_id` is provided → Look for pending enrollment
3. If pending enrollment not found but code provided → Attempt direct enrollment
4. Validates group exists and enrollment code not expired
5. Checks if user already enrolled
6. Creates/reactivates enrollment
7. Marks pending enrollment as completed

---

### 5. Configuration

#### App Config
**File**: `config/app.php`

Add these environment variables to `.env`:
```env
APP_SCHEME=pathshalaa
PLAY_STORE_URL=https://play.google.com/store/apps/details?id=com.pathshalaa.app
APP_STORE_URL=https://apps.apple.com/app/pathshalaa/id1234567890
```

**Config Values Added**:
```php
'app_scheme' => env('APP_SCHEME', 'pathshalaa'),
'play_store_url' => env('PLAY_STORE_URL', 'https://play.google.com/store/apps/details?id=your.app.id'),
'app_store_url' => env('APP_STORE_URL', 'https://apps.apple.com/app/your-app-id'),
```

---

## Mobile App Implementation Guide

### Deep Link Setup

#### Android (AndroidManifest.xml)
```xml
<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="pathshalaa"
            android:host="enroll" />
    </intent-filter>
</activity>
```

#### iOS (Info.plist)
```xml
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>pathshalaa</string>
        </array>
        <key>CFBundleURLName</key>
        <string>com.pathshalaa.app</string>
    </dict>
</array>
```

### App Flow Implementation

#### 1. Handle Deep Link on App Open
```javascript
// React Native Example
import { Linking } from 'react-native';

useEffect(() => {
  // Handle initial URL (app opened from link)
  Linking.getInitialURL().then(url => {
    if (url) {
      handleEnrollmentDeepLink(url);
    }
  });

  // Handle URL when app is already open
  const subscription = Linking.addEventListener('url', ({ url }) => {
    handleEnrollmentDeepLink(url);
  });

  return () => subscription.remove();
}, []);

function handleEnrollmentDeepLink(url) {
  // Example: pathshalaa://enroll/ABC1234567
  const match = url.match(/enroll\/([A-Z0-9]{10})/i);
  if (match) {
    const enrollmentCode = match[1];
    handleEnrollment(enrollmentCode);
  }
}
```

#### 2. Store Pending Enrollment
```javascript
async function handleEnrollment(enrollmentCode) {
  const isLoggedIn = await checkIfUserLoggedIn();

  if (!isLoggedIn) {
    // User not logged in - store pending enrollment
    const deviceId = await getDeviceId(); // Use device unique ID

    try {
      const response = await fetch('https://your-api.com/api/v2/pending-enrollment/store', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          enrollment_code: enrollmentCode,
          device_id: deviceId
        })
      });

      const data = await response.json();

      if (data.status) {
        // Store enrollment code locally as backup
        await AsyncStorage.setItem('pending_enrollment_code', enrollmentCode);

        // Show enrollment info and prompt to login/register
        showEnrollmentPrompt(data.data.group);
      }
    } catch (error) {
      console.error('Failed to store pending enrollment:', error);
    }
  } else {
    // User is logged in - enroll directly
    enrollInGroup(enrollmentCode);
  }
}
```

#### 3. Include Enrollment Code in Registration/Login
```javascript
async function registerUser(userData) {
  const enrollmentCode = await AsyncStorage.getItem('pending_enrollment_code');
  const deviceId = await getDeviceId();

  const response = await fetch('https://your-api.com/api/register', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      ...userData,
      enrollment_code: enrollmentCode,
      device_id: deviceId
    })
  });

  const data = await response.json();

  if (data.success && data.data.auto_enrollment) {
    // Auto-enrollment successful!
    const enrollment = data.data.auto_enrollment;

    if (enrollment.status === 'enrolled') {
      // Clear pending enrollment
      await AsyncStorage.removeItem('pending_enrollment_code');

      // Show success message
      showEnrollmentSuccess(enrollment.group_name);

      // Navigate to group/batch screen
      navigateToGroup(enrollment.group_id);
    }
  }

  return data;
}

async function loginUser(credentials) {
  const enrollmentCode = await AsyncStorage.getItem('pending_enrollment_code');
  const deviceId = await getDeviceId();

  const response = await fetch('https://your-api.com/api/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      ...credentials,
      enrollment_code: enrollmentCode,
      device_id: deviceId
    })
  });

  const data = await response.json();

  if (data.success && data.data.auto_enrollment) {
    // Handle auto-enrollment (same as registration)
    handleAutoEnrollmentSuccess(data.data.auto_enrollment);
  }

  return data;
}
```

#### 4. Check for Pending Enrollment on App Startup
```javascript
async function checkPendingEnrollmentOnStartup() {
  const isLoggedIn = await checkIfUserLoggedIn();

  if (isLoggedIn) {
    // Already logged in - check if there's a pending enrollment
    const deviceId = await getDeviceId();

    try {
      const response = await fetch(`https://your-api.com/api/v2/pending-enrollment/${deviceId}`);
      const data = await response.json();

      if (data.status && data.data) {
        // Found pending enrollment - enroll the user
        enrollInGroup(data.data.enrollment_code);
      }
    } catch (error) {
      // No pending enrollment or error - continue normally
    }
  }
}
```

---

## Testing Guide

### Test Case 1: Basic Flow
1. Generate enrollment link as tutor
2. Open link on mobile device without app installed
3. Verify landing page shows:
   - Group name and details
   - Download buttons
   - Instructions
4. Click download button → Install app
5. Open app and register new account
6. Verify user is NOT automatically enrolled (manual re-click needed)

### Test Case 2: Deep Link Flow
1. Generate enrollment link
2. Open link on mobile device without app
3. Install app
4. Click enrollment link again
5. App opens with deep link
6. Verify enrollment code is stored
7. Register/login
8. Verify auto-enrollment successful

### Test Case 3: LocalStorage Flow (Browser)
1. Open enrollment link in mobile browser
2. Browser stores enrollment code in localStorage
3. Install app
4. App reads enrollment code from localStorage (if shared)
5. Register/login with enrollment code
6. Verify auto-enrollment

### Test Case 4: Pending Enrollment API
```bash
# Store pending enrollment
curl -X POST https://your-api.com/api/v2/pending-enrollment/store \
  -H "Content-Type: application/json" \
  -d '{
    "enrollment_code": "ABC1234567",
    "device_id": "test-device-123"
  }'

# Get pending enrollment
curl https://your-api.com/api/v2/pending-enrollment/test-device-123

# Register with auto-enrollment
curl -X POST https://your-api.com/api/register \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Test User",
    "email": "test@example.com",
    "password": "password123",
    "c_password": "password123",
    "enrollment_code": "ABC1234567",
    "device_id": "test-device-123"
  }'
```

---

## Security Considerations

1. **Enrollment Code Expiration**: All codes have an expiry date
2. **Pending Enrollment Expiration**: Stored for 24 hours only
3. **Device ID Privacy**: Device IDs are optional and hashed
4. **Code Validation**: All enrollment codes validated before use
5. **Status Tracking**: Enrollments marked as completed/expired

---

## Database Queries

### Check Pending Enrollments
```sql
SELECT * FROM pending_enrollments WHERE status = 'pending' AND expires_at > NOW();
```

### Clean Up Expired Enrollments
```sql
UPDATE pending_enrollments SET status = 'expired' WHERE status = 'pending' AND expires_at < NOW();
```

### Get Enrollment Statistics
```sql
SELECT
  status,
  COUNT(*) as count,
  DATE(created_at) as date
FROM pending_enrollments
GROUP BY status, DATE(created_at)
ORDER BY date DESC;
```

---

## Troubleshooting

### Issue: Auto-enrollment not working
**Solution**: Check:
1. Enrollment code is valid and not expired
2. Group exists and is active
3. `enrollment_code` or `device_id` passed in registration/login
4. Pending enrollment record exists in database

### Issue: Deep link not opening app
**Solution**: Check:
1. Deep link scheme matches config (`pathshalaa://`)
2. AndroidManifest.xml / Info.plist configured correctly
3. App is installed and scheme is registered
4. Intent filter / URL type is set up properly

### Issue: Landing page not showing group info
**Solution**: Check:
1. Enrollment code is correct
2. Group status is active (status = 1)
3. Group has not been deleted
4. Enrollment code hasn't expired

---

## Future Enhancements

1. **Firebase Dynamic Links**: Use Firebase for better deferred deep linking
2. **Branch.io Integration**: Advanced deep linking with attribution
3. **SMS/Email Links**: Send enrollment links via SMS/Email
4. **Batch Enrollment**: Allow multiple students to enroll simultaneously
5. **Enrollment Analytics**: Track enrollment funnel metrics
6. **Custom Branding**: Customize landing page per school/tutor

---

## Related Files Reference

### Controllers
- `app/Http/Controllers/Web/EnrollmentLandingController.php`
- `app/Http/Controllers/Api/V2/PendingEnrollmentController.php`
- `app/Http/Controllers/RegisterController.php`

### Models
- `app/Models/PendingEnrollment.php`

### Views
- `resources/views/enrollment/landing.blade.php`
- `resources/views/enrollment/invalid.blade.php`
- `resources/views/enrollment/expired.blade.php`
- `resources/views/enrollment/error.blade.php`

### Routes
- `routes/web.php` (line 94)
- `routes/api.php` (lines 262-266)

### Migrations
- `database/migrations/2025_12_05_152249_create_pending_enrollments_table.php`

### Configuration
- `config/app.php` (lines 66-68)

---

## Support & Maintenance

For questions or issues:
1. Check logs in `storage/logs/laravel.log`
2. Review error responses from API
3. Verify database records in `pending_enrollments` table
4. Test with sample enrollment codes

---

**Implementation Date**: December 5, 2025
**Version**: 1.0
**Status**: ✅ Complete & Ready for Production
