# Mobile Device Pairing Flow

## Overview

This document explains the complete device pairing flow between mobile apps (Android/iOS) and the MyCloudVault server.

## Pairing Flow Steps

### Step 1: Dashboard Generates QR Code

The web dashboard generates a temporary pairing token:

**Endpoint:** `POST /api/devices/generate-token`

**Request:** No body required

**Response:**
```json
{
  "success": true,
  "token": "abc123def456...",
  "expiresAt": "2026-01-14T02:00:00.000Z",
  "qrData": "{\"type\":\"cloudvault_pairing\",\"version\":\"1.0\",\"serverUrl\":\"http://server:5173\",\"token\":\"abc123...\",\"expiresAt\":\"2026-01-14T02:00:00.000Z\"}"
}
```

**Token Properties:**
- Expires in 5 minutes
- Single-use only
- Stored in server memory (not database)

### Step 2: Mobile App Scans QR Code

The mobile app scans the QR code and parses the `qrData` JSON string:

```json
{
  "type": "cloudvault_pairing",
  "version": "1.0",
  "serverUrl": "http://192.168.1.100:5173",
  "token": "abc123def456...",
  "expiresAt": "2026-01-14T02:00:00.000Z"
}
```

**Mobile App Should:**
1. Validate `type === "cloudvault_pairing"`
2. Check `expiresAt` hasn't passed
3. Extract `serverUrl` and `token`
4. Proceed to Step 3

### Step 3: Mobile App Registers Device

The mobile app calls the pairing endpoint with the token and device info:

**Endpoint:** `POST /api/devices/pair`

**Request Body:**
```json
{
  "token": "abc123def456...",
  "deviceId": "unique-device-id-from-os",
  "name": "John's iPhone 15 Pro",
  "model": "iPhone 15 Pro",
  "osVersion": "iOS 17.2",
  "platform": "ios",
  "storageTotal": 256,
  "storageUsed": 128
}
```

**Required Fields:**
- `token` - The token from QR code
- `deviceId` - Unique device identifier (UUID recommended)
- `name` - Human-readable device name

**Optional Fields:**
- `model` - Device model (e.g., "Samsung Galaxy S23", "iPhone 15 Pro")
- `osVersion` - OS version (e.g., "Android 14", "iOS 17.2")
- `platform` - "android" or "ios"
- `storageTotal` - Total storage in GB
- `storageUsed` - Used storage in GB

**Success Response (201):**
```json
{
  "success": true,
  "device": {
    "id": 1,
    "deviceId": "unique-device-id-from-os",
    "name": "John's iPhone 15 Pro",
    "model": "iPhone 15 Pro",
    "androidVersion": "iOS 17.2",
    "pairingToken": "permanent-token-xyz789...",
    "isConnected": true,
    "lastSeen": "2026-01-14T01:30:00.000Z",
    "storageTotal": 256,
    "storageUsed": 128,
    "createdAt": "2026-01-14T01:30:00.000Z",
    "updatedAt": "2026-01-14T01:30:00.000Z"
  },
  "message": "Device paired successfully"
}
```

**Re-pairing Response (200):**
If device already exists, it updates the existing record:
```json
{
  "success": true,
  "device": { /* updated device */ },
  "message": "Device re-paired successfully"
}
```

**Error Responses:**

**400 - Missing Fields:**
```json
{
  "success": false,
  "error": "Missing required field: token"
}
```

**401 - Invalid Token:**
```json
{
  "success": false,
  "error": "Invalid or expired pairing token"
}
```

**500 - Server Error:**
```json
{
  "success": false,
  "error": "Failed to pair device",
  "message": "Error details..."
}
```

### Step 4: Store Permanent Token

The mobile app should store the `pairingToken` from the response securely:

**iOS:** Use Keychain
**Android:** Use EncryptedSharedPreferences or Keystore

**This token is used for all future API calls:**
- Backup uploads
- Backup downloads
- Status updates
- Communication with server

## Token Types

### Temporary Pairing Token (from QR code)
- **Lifetime:** 5 minutes
- **Usage:** Single-use only
- **Purpose:** Initial pairing authentication
- **Storage:** Server memory (not database)

### Permanent Device Token (from pairing response)
- **Lifetime:** Permanent (until device unpaired)
- **Usage:** All API requests
- **Purpose:** Device authentication
- **Storage:** Database + mobile app secure storage

## Mobile App Implementation Example

```typescript
// Step 1: Scan QR Code
const qrData = JSON.parse(scannedQRCode);

if (qrData.type !== 'cloudvault_pairing') {
  throw new Error('Invalid QR code');
}

if (new Date(qrData.expiresAt) < new Date()) {
  throw new Error('QR code expired');
}

// Step 2: Get device info
const deviceInfo = {
  token: qrData.token,
  deviceId: await getDeviceId(), // OS-specific UUID
  name: await getDeviceName(), // e.g., "John's iPhone"
  model: await getDeviceModel(), // e.g., "iPhone 15 Pro"
  osVersion: await getOSVersion(), // e.g., "iOS 17.2"
  platform: Platform.OS, // 'ios' or 'android'
  storageTotal: await getTotalStorage(),
  storageUsed: await getUsedStorage(),
};

// Step 3: Pair device
const response = await fetch(`${qrData.serverUrl}/api/devices/pair`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(deviceInfo),
});

const result = await response.json();

if (!result.success) {
  throw new Error(result.error);
}

// Step 4: Store permanent token securely
await secureStorage.set('cloudvault_token', result.device.pairingToken);
await secureStorage.set('cloudvault_server', qrData.serverUrl);
await secureStorage.set('cloudvault_device_id', result.device.deviceId);

// Step 5: Navigate to main app screen
navigation.navigate('Home');
```

## Testing the Flow

### Test with cURL

**1. Generate token:**
```bash
curl -X POST http://localhost:5173/api/devices/generate-token
```

**2. Pair device:**
```bash
curl -X POST http://localhost:5173/api/devices/pair \
  -H "Content-Type: application/json" \
  -d '{
    "token": "TOKEN_FROM_STEP_1",
    "deviceId": "test-device-123",
    "name": "Test Device",
    "model": "Test Model",
    "osVersion": "Test OS 1.0",
    "platform": "test"
  }'
```

**3. Verify device appears:**
```bash
curl http://localhost:5173/api/devices
```

## Common Issues

### Issue: "Invalid or expired pairing token"
**Cause:** Token expired (>5 minutes) or already used
**Solution:** Generate a new QR code and scan again

### Issue: Device not showing in dashboard
**Cause:** Pairing request failed or didn't complete
**Solution:** Check server logs, verify request body format

### Issue: QR code won't scan
**Cause:** QR code generation failed or corrupted
**Solution:** Refresh dashboard, generate new code

## Security Considerations

1. **Token Expiration:** Temporary tokens expire in 5 minutes
2. **Single-Use:** Each temporary token can only be used once
3. **HTTPS Required:** Use HTTPS in production (not HTTP)
4. **Secure Storage:** Store permanent tokens in secure storage
5. **Token Rotation:** Consider implementing token rotation for long-term security

## Dashboard Verification

After successful pairing, the device should appear in the dashboard:

**Location:** Dashboard → Devices section

**Display:**
- Device name
- Device model
- Connection status (green dot = connected)
- Last seen timestamp

**If device doesn't appear:**
1. Check server logs for errors
2. Verify pairing response was successful
3. Refresh dashboard (auto-refreshes every 30 seconds)
4. Check database: `SELECT * FROM devices;`

## API Reference Summary

| Endpoint | Method | Purpose | Auth Required |
|----------|--------|---------|---------------|
| `/api/devices/generate-token` | POST | Generate QR code token | No |
| `/api/devices/pair` | POST | Register device | Token (from QR) |
| `/api/devices` | GET | List all devices | No* |
| `/api/devices/:deviceId` | GET | Get device details | No* |

*Note: In production, these should require admin authentication.

## Next Steps

After successful pairing:
1. Store permanent token securely
2. Implement backup upload flow (see BACKUP_UPLOAD_API.md)
3. Implement backup restore flow (see BACKUP_RESTORE_API.md)
4. Implement periodic status updates
5. Handle token refresh/rotation
