# Mobile Sign-In API Documentation

Version: 1.0
Spec: 028-mobile-sign-in-modernization
Status: Production Ready

## Overview

The Mobile Sign-In API provides a public-facing self-service check-in system for customers. Customers scan a QR code to start a session, identify themselves, provide container count, sign terms, and join the buy queue.

## Base URL

```
/{typeNum}/mobile-signin
```

Where `{typeNum}` is the store identifier (e.g., `ou00`, `pa00`).

## Environment Variables

| Variable | Required | Description |
|----------|----------|-------------|
| `RECAPTCHA_SITE_KEY` | Yes | Google reCAPTCHA v3 site key |
| `RECAPTCHA_SECRET_KEY` | Yes | Google reCAPTCHA v3 secret key |
| `RECAPTCHA_THRESHOLD` | No | Score threshold (default: 0.5) |
| `ABLY_KEY` | No | Ably API key for real-time updates |
| `ABLY_PUBLIC_KEY` | No | Ably public key for client subscriptions |
| `REDIS_URL` | No | Redis connection for rate limiting |
| `VAPID_PUBLIC_KEY` | No | VAPID public key for push notifications |
| `VAPID_PRIVATE_KEY` | No | VAPID private key for push notifications |
| `VAPID_SUBJECT` | No | VAPID subject (mailto: or https:) |
| `ANALYTICS_ENABLED` | No | Enable analytics tracking (default: true) |
| `LOG_DIR` | No | Analytics log directory (default: /tmp) |

## Public Endpoints

### GET `/{typeNum}/mobile-signin`

Landing page - creates new session and renders sign-in form.

**Rate Limit:** 10 sessions per IP per hour

**Response:** HTML page with:
- Session token (UUID v4)
- CSRF token
- reCAPTCHA v3 integration
- Store settings (required fields, accepted ID types)

### POST `/{typeNum}/mobile-signin/check`

Look up customer by identification.

**Request Body:**
```json
{
  "sessionToken": "uuid-v4-token",
  "csrf_token": "csrf-token",
  "recaptcha_token": "recaptcha-response",
  "recaptcha_version": "v3",
  "idType": "dl|stateId|phone",
  "idValue": "ABC123456",
  "idState": "TX"
}
```

**Success Response (found):**
```json
{
  "success": true,
  "found": true,
  "customer": {
    "firstName": "John",
    "lastName": "Doe",
    "phone": "555-123-4567"
  },
  "newCSRF": "new-csrf-token"
}
```

**Success Response (not found):**
```json
{
  "success": true,
  "found": false,
  "newCSRF": "new-csrf-token"
}
```

**Error Response (reCAPTCHA v2 required):**
```json
{
  "success": false,
  "requireV2": true,
  "error": "Additional verification required"
}
```

### POST `/{typeNum}/mobile-signin/register`

Register new customer.

**Request Body:**
```json
{
  "sessionToken": "uuid-v4-token",
  "csrf_token": "csrf-token",
  "recaptcha_token": "recaptcha-response",
  "recaptcha_version": "v3",
  "idType": "dl",
  "idValue": "ABC123456",
  "idState": "TX",
  "firstName": "John",
  "lastName": "Doe",
  "phone": "555-123-4567",
  "email": "john@example.com",
  "address": "123 Main St",
  "city": "Austin",
  "zip": "78701"
}
```

**Success Response:**
```json
{
  "success": true,
  "customerId": 12345,
  "newCSRF": "new-csrf-token"
}
```

### POST `/{typeNum}/mobile-signin/submit`

Submit sign-in and join queue.

**Request Body:**
```json
{
  "sessionToken": "uuid-v4-token",
  "csrf_token": "csrf-token",
  "customerId": 12345,
  "containerCount": 3,
  "signatureData": "data:image/png;base64,...",
  "signatureType": "canvas",
  "smsOptIn": true,
  "hasDesignerItems": false,
  "termsVersion": "v1"
}
```

**Success Response:**
```json
{
  "success": true,
  "buyId": 67890,
  "queuePosition": 4,
  "estimatedWait": {
    "min": 12,
    "max": 20
  },
  "statusUrl": "/ou00/mobile-signin/status/uuid-token"
}
```

### GET `/{typeNum}/mobile-signin/status/{sessionToken}`

Status page - displays queue position and wait time.

**Response:** HTML page with:
- Queue position
- Estimated wait time (if enabled)
- Real-time updates via Ably
- PWA install tutorial

### GET `/{typeNum}/mobile-signin/status/{sessionToken}/poll`

Polling endpoint for Ably fallback.

**Rate Limit:** 2 requests per 30 seconds per session

**Response:**
```json
{
  "success": true,
  "queuePosition": 3,
  "estimatedWait": {
    "min": 9,
    "max": 15
  },
  "status": "waiting",
  "isYourTurn": false
}
```

### POST `/{typeNum}/mobile-signin/push/subscribe`

Register push notification subscription.

**Request Body:**
```json
{
  "sessionToken": "uuid-v4-token",
  "subscription": {
    "endpoint": "https://fcm.googleapis.com/fcm/send/...",
    "keys": {
      "p256dh": "base64-key",
      "auth": "base64-auth"
    }
  }
}
```

**Response:**
```json
{
  "success": true
}
```

## Admin Endpoints

### GET `/admin/{typeNum}/settings/mobile-signin`

Admin settings page.

**Permissions Required:** `uri_store_settings`

**Response:** HTML page with settings form.

### POST `/admin/{typeNum}/settings/mobile-signin`

Update mobile sign-in settings.

**Permissions Required:** `uri_store_settings`

**Request Body:**
```json
{
  "mobileSigninEnabled": true,
  "mobileSigninRequiredFields": ["firstName", "lastName", "phone"],
  "mobileSigninAcceptedIdTypes": ["dl", "stateId"],
  "mobileSigninTermsHtml": "<p>By checking in, you agree to...</p>",
  "mobileSigninShowWaitEstimate": true,
  "mobileSigninShowDesignerQuestion": false
}
```

### GET `/admin/{typeNum}/mobile-signin/flyer.pdf`

Download printable QR code flyer.

**Permissions Required:** `uri_store_settings`

**Response:** PDF file (8.5x11, concept-branded)

## Real-Time Events (Ably)

### Per-Session Channel

Pattern: `mobile-signin:{typeNum}:{sessionToken}`

**Events:**
- `queue_joined` - Customer added to queue
- `position_updated` - Queue position changed
- `your_turn` - Customer is #1 in queue

### Workspace Channel

Pattern: `{typeNum}`

**Events:**
- `queue_updated` - Queue has changed (triggers workspace refresh)

## Security

- **CSRF Protection:** All POST endpoints require valid CSRF token
- **Rate Limiting:** IP-based (10/hour) + Session-based polling (2/30s)
- **Session Security:** UUID v4 tokens with 1-hour TTL
- **Cross-store Prevention:** Sessions validated against store
- **reCAPTCHA:** v3 with v2 fallback (3 attempts, then 15-min block)
- **Signature Integrity:** SHA256 hash verification

## Database Tables

- `mobileSigninSessions` - Session tracking
- `mobileSigninSignatures` - Signature storage (7-year retention)
- `mobileSigninPushSubscriptions` - Push notification subscriptions
- `buyQueue` - Extended with mobile sign-in fields:
  - `mobileSigninSessionId`
  - `signatureId`
  - `smsOptIn`
  - `hasDesignerItems`
  - `containerCount`

## Migrations

1. `20260108_001_mobile_signin_sessions.json`
2. `20260108_002_mobile_signin_signatures.json`
3. `20260108_003_buyqueue_mobile_signin_fields.json`
4. `20260108_004_store_settings_mobile_signin.json`
5. `20260109_001_mobile_signin_push_subscriptions.json`

## Error Codes

| Code | Description |
|------|-------------|
| 400 | Bad request (validation error) |
| 403 | CSRF validation failed |
| 404 | Session not found |
| 429 | Rate limited |
| 440 | Session expired |
| 503 | Mobile sign-in disabled for store |
