# Product Requirements Document: Login & Authentication Flow

**Spec ID:** 002-login-auth-flow
**Created:** 2024-12-24
**Status:** Complete
**Author:** Product Team
**SDD Aligned:** 2024-12-24

---

## 1. Executive Summary

### 1.1 Problem Statement

BuyerKiosk team members currently lack a dedicated mobile app for managing their work schedules and time tracking. Employees working across multiple store locations need a seamless way to:
- Authenticate once and access all their assigned stores
- View schedules and hours worked
- Clock in/out when physically present at a store location
- Switch between stores without re-authenticating

### 1.2 Proposed Solution

A Flutter mobile app with a streamlined authentication flow featuring:
- Single email/password login with user-scoped JWT tokens
- Automatic store detection and selection for multi-store employees
- Biometric authentication (Face ID/Touch ID) for quick subsequent access
- Geofenced clock-in/out integrated into the home screen
- Foreground-only location checks for v1 (background monitoring in P1)

### 1.3 Success Metrics

| Metric | Target | Measurement |
|--------|--------|-------------|
| Login success rate | > 95% | Successful logins / total attempts |
| Time to first interaction | < 3 seconds | Splash → Home for returning users |
| Biometric adoption | > 60% | Users with biometric enabled after 30 days |
| Clock-in accuracy | 100% | Clock-ins only within geofence |

---

## 2. Context & Background

### 2.1 Current State

- Employees use third-party scheduling tools (WhenIWork/Homebase)
- No unified mobile experience across BuyerKiosk stores
- Clock-in requires separate systems or manual tracking
- Multi-store employees must juggle multiple logins

### 2.2 Business Drivers

- **Cost reduction:** Eliminate third-party scheduling tool subscriptions
- **Data ownership:** Keep employee scheduling data in-house
- **Integration:** Tight integration with existing BuyerKiosk backend
- **Experience:** Modern, branded mobile experience for team members

### 2.3 Technical Context

**API Architecture:**
- Base URL: `/api/mobile/scheduling`
- User-scoped JWT tokens (single token works for all assigned stores)
- Store context passed via URL path: `/{typeNum}/schedule`
- Geofence validation via `StoreContextMiddleware`

**Token Design:**
```
JWT Payload (User-Scoped):
{
  "userId": 123,
  "iat": 1703424000,
  "exp": 1703510400
}
```

**Login Response:**
```json
{
  "accessToken": "eyJ...",
  "refreshToken": "abc123...",
  "expiresIn": 86400,
  "refreshExpiresAt": "2024-01-07T00:00:00Z",
  "user": {
    "userId": 123,
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@example.com"
  },
  "stores": [
    {
      "typeNum": "ou00",
      "storeName": "Ottawa Store",
      "role": "manager",
      "roleId": 2,
      "isManager": true,
      "employeeId": 456
    },
    {
      "typeNum": "pa00",
      "storeName": "Paris Store",
      "role": "buyer",
      "roleId": 4,
      "isManager": false,
      "employeeId": 789
    }
  ],
  "requiresStoreSelection": true
}
```

---

## 3. User Personas

### 3.1 Single-Store Employee

**Profile:** Sarah, Buyer at Ottawa Store
- Works at one location only
- Checks schedule weekly
- Clocks in/out daily
- Moderate tech comfort

**Needs:**
- Quick login without friction
- See today's shift at a glance
- One-tap clock in when at work

**Pain Points:**
- Forgetting passwords
- Multiple apps for different functions

### 3.2 Multi-Store Employee

**Profile:** Marcus, Regional Manager
- Oversees 3 store locations
- Travels between stores weekly
- Reviews schedules and hours across locations
- High tech comfort

**Needs:**
- Single login for all stores
- Easy switching between store contexts
- Know which store he's viewing at all times

**Pain Points:**
- Managing multiple credentials
- Confusion about which store's data is displayed

### 3.3 New Employee

**Profile:** Alex, newly hired
- First week on the job
- Unfamiliar with BuyerKiosk systems
- Learning the ropes

**Needs:**
- Clear onboarding flow
- Simple, obvious UI
- Help text when stuck

**Pain Points:**
- Not knowing their credentials
- Overwhelmed by features

---

## 4. User Journeys

### 4.1 First-Time Login (Single Store)

```
┌─────────────────────────────────────────────────────────────────┐
│ JOURNEY: First Login - Single Store Employee                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. Open app                                                    │
│     ↓                                                           │
│  2. See splash screen (purple gradient, logo, loading)          │
│     ↓                                                           │
│  3. Redirected to login screen                                  │
│     ↓                                                           │
│  4. Enter email + password                                      │
│     ↓                                                           │
│  5. API returns token + 1 store                                 │
│     ↓                                                           │
│  6. Auto-select single store (skip picker)                      │
│     ↓                                                           │
│  7. Prompt: "Enable Face ID for faster login?"                  │
│     ↓                                                           │
│  8. → Home screen                                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### 4.2 First-Time Login (Multi-Store)

```
┌─────────────────────────────────────────────────────────────────┐
│ JOURNEY: First Login - Multi-Store Employee                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. Open app                                                    │
│     ↓                                                           │
│  2. See splash screen                                           │
│     ↓                                                           │
│  3. Login with email + password                                 │
│     ↓                                                           │
│  4. API returns token + multiple stores                         │
│     ↓                                                           │
│  5. Show store picker: "Select a store to view"                 │
│     - Ottawa Store (Manager)                                    │
│     - Paris Store (Buyer)                                       │
│     ↓                                                           │
│  6. User taps "Ottawa Store"                                    │
│     ↓                                                           │
│  7. Store saved locally as "last selected"                      │
│     ↓                                                           │
│  8. Prompt: "Enable Face ID?"                                   │
│     ↓                                                           │
│  9. → Home screen (Ottawa context)                              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### 4.3 Returning User (Biometric Enabled)

```
┌─────────────────────────────────────────────────────────────────┐
│ JOURNEY: Returning User with Biometric                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. Open app                                                    │
│     ↓                                                           │
│  2. Splash screen (~1 second)                                   │
│     ↓                                                           │
│  3. Detect: has tokens + biometric enabled                      │
│     ↓                                                           │
│  4. Show biometric prompt: "Use Face ID to unlock"              │
│     ↓                                                           │
│  5. User authenticates with Face ID                             │
│     ↓                                                           │
│  6. Load last-selected store from local storage                 │
│     ↓                                                           │
│  7. → Home screen (previous store context)                      │
│                                                                 │
│  Total time: < 3 seconds                                        │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### 4.4 Store Switching

```
┌─────────────────────────────────────────────────────────────────┐
│ JOURNEY: Switching Stores                                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. User is on Home screen (Ottawa context)                     │
│     ↓                                                           │
│  2. Tap store name in app bar header                            │
│     ↓                                                           │
│  3. Store picker modal appears:                                 │
│     ✓ Ottawa Store (current)                                    │
│       Paris Store                                               │
│     ↓                                                           │
│  4. Tap "Paris Store"                                           │
│     ↓                                                           │
│  5. Modal closes, app bar updates to "Paris Store"              │
│     ↓                                                           │
│  6. Home screen refreshes with Paris data                       │
│     ↓                                                           │
│  7. "Paris" saved as new last-selected store                    │
│                                                                 │
│  Note: NO new token needed - same JWT works!                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### 4.5 Clock-In (Within Geofence)

```
┌─────────────────────────────────────────────────────────────────┐
│ JOURNEY: Clock-In at Store (v1 - Foreground Only)                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. User arrives at Ottawa store                                │
│     ↓                                                           │
│  2. User opens app                                              │
│     ↓                                                           │
│  3. Home screen loads → fetches clock status with location      │
│     ↓                                                           │
│  4. Client detects: within geofence                             │
│     ↓                                                           │
│  5. Home screen shows: Clock In button (enabled)                │
│     ↓                                                           │
│  6. User taps "Clock In"                                        │
│     ↓                                                           │
│  7. API: POST /{typeNum}/clock/in with lat/lng                  │
│     (Server validates geofence for security)                    │
│     ↓                                                           │
│  8. Success: "Clocked in at 9:02 AM"                            │
│     ↓                                                           │
│  9. Home screen updates: Shows elapsed time, Clock Out button   │
│                                                                 │
│  Note: v1 uses foreground-only location. Background monitoring  │
│  and push notifications deferred to P1.                         │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### 4.6 Smart Store Detection (P1 - Deferred)

```
┌─────────────────────────────────────────────────────────────────┐
│ JOURNEY: Smart Store Detection (DEFERRED TO P1)                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. User has Paris Store selected in app                        │
│     ↓                                                           │
│  2. User physically arrives at Ottawa store                     │
│     ↓                                                           │
│  3. Background location detects: within Ottawa geofence         │
│     ↓                                                           │
│  4. App detects mismatch: viewing Paris, at Ottawa              │
│     ↓                                                           │
│  5. Show suggestion banner on Home:                             │
│     "You're at Ottawa Store. Switch to clock in?"               │
│     [Switch to Ottawa] [Dismiss]                                │
│     ↓                                                           │
│  6a. User taps "Switch to Ottawa"                               │
│      → Store context switches, clock-in enabled                 │
│                                                                 │
│  6b. User taps "Dismiss"                                        │
│      → Banner hidden, stays on Paris context                    │
│                                                                 │
│  NOTE: This feature requires background location (P1).          │
│  v1 relies on manual store switching via header.                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### 4.7 Session Expiry

```
┌─────────────────────────────────────────────────────────────────┐
│ JOURNEY: Session Expiry & Refresh                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. User makes API request                                      │
│     ↓                                                           │
│  2. API returns 401 (token expired)                             │
│     ↓                                                           │
│  3. Interceptor catches 401                                     │
│     ↓                                                           │
│  4. Attempt silent refresh: POST /auth/refresh                  │
│     ↓                                                           │
│  5a. Refresh succeeds:                                          │
│      → Store new tokens, retry original request                 │
│      → User never notices                                       │
│                                                                 │
│  5b. Refresh fails (refresh token expired):                     │
│      → Clear stored tokens                                      │
│      → Redirect to login screen                                 │
│      → Show: "Your session expired. Please sign in again."      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

---

## 5. Functional Requirements

### 5.1 Must Have (P0)

#### FR-001: Splash Screen
**Description:** Display branded splash screen while checking authentication status.

**Acceptance Criteria:**
- [ ] Purple gradient background (#667eea → #764ba2)
- [ ] White BuyerKiosk logo centered
- [ ] Loading indicator below logo
- [ ] Automatically checks for stored tokens on load
- [ ] Transitions to appropriate screen based on auth state
- [ ] Display time: minimum 1 second, maximum 3 seconds

#### FR-002: Email/Password Login
**Description:** Authenticate users with email and password.

**Acceptance Criteria:**
- [ ] Email input field with email keyboard type
- [ ] Password input field with show/hide toggle
- [ ] "Sign In" button submits form
- [ ] Loading state on button during API call
- [ ] Error message displayed for invalid credentials
- [ ] Error message displayed for network errors
- [ ] On success: store access token, refresh token, user data, stores list
- [ ] On success: navigate based on store count (picker or home)

#### FR-003: Store Selection (Multi-Store Users)
**Description:** Allow users with multiple stores to select which store to view.

**Acceptance Criteria:**
- [ ] Display store picker as bottom sheet after login if `stores.length > 1`
- [ ] Show each store with: name, role badge (Manager/Buyer/etc.)
- [ ] Tapping a store selects it and proceeds to home
- [ ] Save selected store to local storage as "last selected"
- [ ] Skip picker if user has only one store (auto-select)

#### FR-004: Store Switcher
**Description:** Allow authenticated users to switch between their assigned stores.

**Acceptance Criteria:**
- [ ] Current store name displayed in app bar header with dropdown arrow (if multi-store user)
- [ ] Tapping store name opens store picker bottom sheet
- [ ] Current store marked with checkmark
- [ ] Selecting different store updates context immediately
- [ ] No API call needed for switch (same token)
- [ ] All screens refresh with new store's data via Riverpod reactivity

#### FR-005: Biometric Authentication
**Description:** Allow users to authenticate with Face ID or Touch ID on subsequent launches.

**Acceptance Criteria:**
- [ ] Prompt to enable biometric after first successful login
- [ ] If enabled + tokens exist: show biometric prompt on app launch
- [ ] Successful biometric → restore last-selected store → home screen
- [ ] Failed biometric → offer retry or "Use Password" option
- [ ] Can be disabled in Settings
- [ ] Falls back gracefully if device doesn't support biometric

#### FR-006: Token Management
**Description:** Handle JWT token storage, refresh, and expiry.

**Acceptance Criteria:**
- [ ] Store access token securely (flutter_secure_storage with Keychain/Keystore)
- [ ] Store refresh token securely
- [ ] Automatically refresh access token on 401 response (via Dio interceptor)
- [ ] Retry original request after successful refresh
- [ ] If refresh fails: clear tokens, redirect to login with message
- [ ] Token refresh is invisible to user when successful
- [ ] Queue concurrent requests during refresh to avoid race conditions

#### FR-007: Home Screen with Clock Status
**Description:** Display clock-in/out status and actions on home screen.

**Acceptance Criteria:**
- [ ] Show current store name in header (tappable for multi-store users)
- [ ] Display today's scheduled shift (if any)
- [ ] Show clock status: "Not Clocked In" / "Clocked In at X:XX" / "On Break"
- [ ] If clocked in: show elapsed time (updates live)
- [ ] If within geofence: show Clock In / Clock Out button
- [ ] If outside geofence: show message "You must be at the store to clock in/out"
- [ ] Fetch clock status on screen load
- [ ] Pull-to-refresh to update clock status and location

#### FR-008: Geofence Detection (v1 - Foreground Only)
**Description:** Determine if user is within store's geofence for clock actions.

**v1 Scope (Foreground-Only):**
- [ ] Request "When In Use" location permission on first clock-related action
- [ ] Check current location when Home screen loads
- [ ] Check current location on pull-to-refresh
- [ ] Client-side geofence pre-check for UX (enable/disable clock button)
- [ ] Server-side geofence validation for security (on clock in/out API calls)
- [ ] Enable clock buttons only when within geofence
- [ ] Show message when outside geofence: "You must be at the store to clock in"

**Deferred to P1:**
- Background location monitoring
- Push notifications when entering geofence
- Smart store detection banners
- "Always" location permission request

#### FR-009: Bottom Navigation
**Description:** Provide primary navigation between app sections.

**Acceptance Criteria:**
- [ ] Four tabs: Home, Schedule, Hours, Settings
- [ ] Active tab highlighted with primary color
- [ ] Icons and labels for each tab
- [ ] Smooth transitions between tabs
- [ ] Maintains scroll position within each tab

#### FR-010: Access Revocation Handling
**Description:** Handle when user's store access is revoked during an active session.

**Acceptance Criteria:**
- [ ] On 403 response for store-scoped endpoint: check if store access was revoked
- [ ] If revoked: clear all tokens from secure storage
- [ ] Redirect to login screen
- [ ] Show message: "Your access has been updated. Please sign in again."
- [ ] User must re-authenticate to get updated store list

### 5.2 Should Have (P1)

#### FR-011: Smart Store Detection
**Description:** Detect when user is at a different store than currently selected.

**Acceptance Criteria:**
- [ ] If at Store A's geofence but viewing Store B
- [ ] Show suggestion banner: "You're at [Store A]. Switch to clock in?"
- [ ] "Switch" button changes store context
- [ ] "Dismiss" button hides banner for current session
- [ ] Banner reappears if user leaves and returns to geofence
- [ ] If background permission is denied: only evaluate when app is active

#### FR-012: Remember Last Store
**Description:** Persist last-selected store across app launches.

**Acceptance Criteria:**
- [ ] Save selected store's typeNum to local storage
- [ ] On app launch: auto-select last store (skip picker)
- [ ] If last store no longer in user's stores list: show picker

#### FR-013: Geofence Entry Notification
**Description:** Notify user when they enter a store's geofence.

**Acceptance Criteria:**
- [ ] Push notification: "You've arrived at [Store Name]"
- [ ] Notification action: opens app to home screen
- [ ] Respects notification preferences
- [ ] Only fires once per geofence entry (not repeatedly)
- [ ] Disabled if background location permission is not granted

### 5.3 Could Have (P2)

#### FR-014: Login Error Recovery
**Description:** Provide helpful recovery options for login failures.

**Acceptance Criteria:**
- [ ] "Contact Manager" help text for account issues
- [ ] Retry button for network errors
- [ ] Error messages include a clear next step (e.g., "Check your connection and try again")

#### FR-015: Session Activity Indicator
**Description:** Show when session is about to expire.

**Acceptance Criteria:**
- [ ] Warning when access token has < 5 minutes remaining
- [ ] Prompt to extend session
- [ ] Graceful handling of expiry during use

### 5.4 Won't Have (Out of Scope for v1)

- **PIN Login:** PIN authentication is for kiosk devices, not personal mobile app
- **Offline Mode:** Require internet connection; show offline message if disconnected
- **Multi-device Management:** Session management across devices
- **Password Reset:** Will be handled via web portal initially
- **Account Creation:** Employees are created by managers in web admin

---

## 6. Non-Functional Requirements

### 6.1 Performance

| Metric | Requirement |
|--------|-------------|
| Splash to login | < 2 seconds |
| Login API response | < 3 seconds |
| Biometric → home | < 2 seconds |
| Store switch | < 1 second |
| Location fix | < 5 seconds |

### 6.2 Security

- Tokens stored in platform-secure storage (Keychain/Keystore)
- No sensitive data in plain text storage
- Biometric authentication uses platform APIs (no custom implementation)
- Network requests over HTTPS only
- No logging of credentials or tokens

### 6.3 Accessibility

- Minimum touch target size: 44x44 pts
- Color contrast ratio: 4.5:1 for text
- Screen reader compatible labels
- Support for dynamic type sizing

### 6.4 Reliability

- Graceful handling of network failures
- Retry logic for transient errors
- Clear error messages (not technical jargon)
- No crashes on auth state edge cases

---

## 7. Design Specifications

### 7.1 Splash Screen

```
┌─────────────────────────────────────┐
│                                     │
│     Background: Gradient            │
│     #667eea → #764ba2              │
│     (135° angle)                    │
│                                     │
│         ┌─────────────┐             │
│         │  BUYERKIOSK │             │
│         │    LOGO     │             │
│         │   (white)   │             │
│         └─────────────┘             │
│                                     │
│            ○ ○ ○                    │
│         (loading dots)              │
│                                     │
└─────────────────────────────────────┘
```

### 7.2 Login Screen

```
┌─────────────────────────────────────┐
│                                     │
│     Background: #f8fafc (neutral50) │
│                                     │
│         ┌─────────────┐             │
│         │    LOGO     │             │
│         │  (purple)   │             │
│         └─────────────┘             │
│                                     │
│        BuyerKiosk Team              │
│   Sign in to manage your schedule   │
│                                     │
│  ┌─────────────────────────────┐    │
│  │ 📧  Email                   │    │
│  └─────────────────────────────┘    │
│                                     │
│  ┌─────────────────────────────┐    │
│  │ 🔒  Password          👁    │    │
│  └─────────────────────────────┘    │
│                                     │
│  ┌─────────────────────────────┐    │
│  │         Sign In             │    │
│  │   (purple gradient button)  │    │
│  └─────────────────────────────┘    │
│                                     │
│   Need help? Contact your manager   │
│                                     │
└─────────────────────────────────────┘
```

### 7.3 Store Picker

```
┌─────────────────────────────────────┐
│                                     │
│        Select a Store               │
│                                     │
│  ┌─────────────────────────────┐    │
│  │  🏪  Ottawa Store           │    │
│  │      Manager           ✓    │    │
│  └─────────────────────────────┘    │
│                                     │
│  ┌─────────────────────────────┐    │
│  │  🏪  Paris Store            │    │
│  │      Buyer                  │    │
│  └─────────────────────────────┘    │
│                                     │
└─────────────────────────────────────┘
```

### 7.4 Home Screen (Clocked Out, Within Geofence)

```
┌─────────────────────────────────────┐
│  ← Ottawa Store ▼               ⚙️  │
├─────────────────────────────────────┤
│                                     │
│          Good morning, Sarah!       │
│                                     │
│  ┌─────────────────────────────┐    │
│  │  TODAY'S SHIFT              │    │
│  │  9:00 AM - 5:00 PM          │    │
│  │  Buyer • 8 hours            │    │
│  └─────────────────────────────┘    │
│                                     │
│  ┌─────────────────────────────┐    │
│  │        ⏱️                   │    │
│  │    Not Clocked In           │    │
│  │                             │    │
│  │  ┌───────────────────────┐  │    │
│  │  │      CLOCK IN         │  │    │
│  │  │   (purple button)     │  │    │
│  │  └───────────────────────┘  │    │
│  └─────────────────────────────┘    │
│                                     │
├─────────────────────────────────────┤
│  🏠 Home  📅 Schedule  ⏰ Hours  ⚙️  │
└─────────────────────────────────────┘
```

### 7.5 Home Screen (Outside Geofence)

```
┌─────────────────────────────────────┐
│  ← Ottawa Store ▼               ⚙️  │
├─────────────────────────────────────┤
│                                     │
│          Good morning, Sarah!       │
│                                     │
│  ┌─────────────────────────────┐    │
│  │  TODAY'S SHIFT              │    │
│  │  9:00 AM - 5:00 PM          │    │
│  │  Buyer • 8 hours            │    │
│  └─────────────────────────────┘    │
│                                     │
│  ┌─────────────────────────────┐    │
│  │        ⏱️                   │    │
│  │    Not Clocked In           │    │
│  │                             │    │
│  │    (no clock button -       │    │
│  │     outside geofence)       │    │
│  └─────────────────────────────┘    │
│                                     │
├─────────────────────────────────────┤
│  🏠 Home  📅 Schedule  ⏰ Hours  ⚙️  │
└─────────────────────────────────────┘
```

### 7.6 Permission UX (v1 - Foreground Only)

**v1 Location Permission Flow:**
- Request "When In Use" location permission when user first attempts to view clock status
- Pre-permission copy: Title "Enable location access" with body "Allow location access to verify you're at the store for clock-in."
- If denied: show disabled clock button with message "Location required to clock in"
- Provide Settings shortcut to enable location later

**Deferred to P1:**
- "Always" location permission request
- Background geofence monitoring
- Arrival notification banners

---

## 8. API Endpoints

### 8.1 Authentication

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/auth/login` | POST | Login with email/password |
| `/auth/refresh` | POST | Refresh access token |
| `/auth/logout` | POST | Revoke refresh token |

### 8.2 Store-Scoped (use selected typeNum in path)

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/{typeNum}/clock/status` | POST | Get clock status + geofence check |
| `/{typeNum}/clock/in` | POST | Clock in |
| `/{typeNum}/clock/out` | POST | Clock out |
| `/{typeNum}/schedule/today` | POST | Get today's shift |

---

## 9. Resolved Questions & Architecture Decisions

| # | Question | Decision |
|---|----------|----------|
| 1 | Geofence radius per store | 200 meters (656 ft) standard radius - covers parking lot |
| 2 | Logo asset for splash screen | White logo available (`assets/images/logo_white.svg`) |
| 3 | Store access revoked mid-session | Force re-login: clear tokens, redirect to login with message |
| 4 | Login flow (store-scoped vs user-scoped) | User-scoped JWT - login returns stores array, pick after auth |
| 5 | Store context management | Global Riverpod Provider (`storeProvider`) for reactive updates |
| 6 | Geofencing approach for v1 | Foreground-only location checks; background monitoring deferred to P1 |
| 7 | Repository layer structure | Repository per feature: `AuthRepository`, `ClockRepository` |
| 8 | Token refresh strategy | Intercept 401 in Dio, refresh token, retry original request |
| 9 | Store picker UI pattern | Bottom sheet modal |
| 10 | Geofence validation approach | Client pre-check for UX + Server validation for security |
| 11 | Clock status refresh strategy | Fetch on screen load + pull-to-refresh (no auto-polling for v1) |
| 12 | Data models approach | Update existing `user_model.dart` Freezed models to match API spec |

---

## 10. Appendix

### 10.1 Auth State Diagram

```
                    ┌─────────────┐
                    │   Initial   │
                    └──────┬──────┘
                           │
                    Check tokens
                           │
            ┌──────────────┴──────────────┐
            │                             │
       Has tokens                    No tokens
            │                             │
    ┌───────┴───────┐                     │
    │               │                     │
Biometric ON   Biometric OFF              │
    │               │                     │
    ▼               │                     ▼
┌─────────┐         │              ┌─────────────┐
│Biometric│         │              │    Login    │
│ Screen  │         │              │   Screen    │
└────┬────┘         │              └──────┬──────┘
     │              │                     │
  Success           │              Enter credentials
     │              │                     │
     └──────────────┴─────────────────────┘
                    │
             Load last store
                    │
            ┌───────┴───────┐
            │               │
       Single store    Multi store
            │               │
       Auto-select     Show picker
            │          (bottom sheet)
            │               │
            └───────┬───────┘
                    │
                    ▼
             ┌────────────┐
             │   Home     │
             │  Screen    │
             └────────────┘
                    │
       v1: "When In Use" location
       (foreground checks only)
```

### 10.2 Related Specifications

- `001-team-mobile-app` - Overall app PRD
- `docs/employee-api.yaml` - API specification
- `docs/STYLE_GUIDE.md` - Brand design system

---

*Last updated: 2024-12-24 | Aligned with SDD architecture decisions*
