# Solution Design Document: Manage Team Members

**Specification ID:** 014-manage-employees-unified
**Version:** 1.0
**Status:** DRAFT
**Last Updated:** December 2025
**Depends On:** 007-unified-users-auth (implemented)

---

## Validation Checklist

- [ ] All required sections are complete
- [ ] No [NEEDS CLARIFICATION] markers remain
- [ ] All context sources are listed with relevance ratings
- [ ] Project commands are discovered from actual project files
- [ ] Constraints → Strategy → Design → Implementation path is logical
- [ ] Architecture pattern is clearly stated with rationale
- [ ] Every component in diagram has directory mapping
- [ ] Every interface has specification
- [ ] Error handling covers all error types
- [ ] Quality requirements are specific and measurable
- [ ] Every quality requirement has test coverage
- [ ] **All architecture decisions confirmed by user**
- [ ] Component names consistent across diagrams
- [ ] A developer could implement from this design

---

## Constraints

| ID | Constraint | Impact |
|----|------------|--------|
| CON-1 | **PHP 8.x, Slim 2.6.2, Twig 1.44.8** | Must use existing framework patterns and conventions |
| CON-2 | **Bootstrap 5.3.3 Design System** | All UI must use `tokens.css`, `admin-theme.css`, no Bootstrap 3 classes |
| CON-3 | **Unified Users Table (Spec 007)** | All data must come from central `users` + `userStoreAssignments` tables |
| CON-4 | **Backward Compatibility** | Existing API endpoints must continue working during transition |
| CON-5 | **Permission Model** | Must use existing `uri_employees` permission hook via `checkAccess()` |
| CON-6 | **DataTables Integration** | Existing DataTables patterns for sortable, searchable tables |
| CON-7 | **Multi-Store Architecture** | TypeNum pattern for store isolation, central auth database |

---

## Implementation Context

### Required Context Sources

```yaml
# Internal documentation and patterns
- doc: docs/specs/007-unified-users-auth - done/solution-design.md
  relevance: CRITICAL
  why: "Defines unified users table schema and authentication architecture"

- doc: docs/specs/007-unified-users-auth - done/product-requirements.md
  relevance: HIGH
  why: "Business requirements for unified user system"

- doc: CLAUDE.md
  relevance: HIGH
  why: "Project conventions, CSS framework, database naming conventions"

# Source code files that must be understood
- file: userfrosting/src/BuyerKiosk/Auth/Models/UnifiedUser.php
  relevance: CRITICAL
  why: "Core user model from spec 007"

- file: userfrosting/src/BuyerKiosk/Auth/Models/StoreAssignment.php
  relevance: CRITICAL
  why: "Store assignment model with clock PIN storage"

- file: userfrosting/src/BuyerKiosk/Employee/EmployeeManager.php
  relevance: HIGH
  why: "Current employee management facade - must understand for migration"

- file: userfrosting/src/BuyerKiosk/Employee/WhenIWorkProvider.php
  relevance: HIGH
  why: "External sync implementation that must be updated"

- file: userfrosting/templates/themes/default/employees/employees.html
  relevance: MEDIUM
  why: "Current template structure - will be replaced"

- file: public_html/js/admin/employees.js
  relevance: MEDIUM
  why: "Current JavaScript - will be rewritten"

- file: public_html/css/admin/tokens.css
  relevance: HIGH
  why: "Design system tokens to use"

- file: public_html/css/admin/admin-theme.css
  relevance: HIGH
  why: "Bootstrap 5 customizations"
```

### Implementation Boundaries

- **Must Preserve**:
  - API endpoint paths (`/:typeNum/api/employees/*`) for mobile app compatibility
  - Permission hook `uri_employees`
  - WhenIWork sync functionality
  - Clock PIN verification logic for time punches

- **Can Modify**:
  - Template HTML/CSS (complete redesign)
  - JavaScript (complete rewrite)
  - Controller logic (refactor to use unified users)
  - Route handlers (update data sources)

- **Must Not Touch**:
  - `users` table schema (defined by spec 007)
  - `userStoreAssignments` table schema (defined by spec 007)
  - Authentication middleware
  - Mobile API response shapes

### External Interfaces

#### System Context Diagram

```
┌──────────────────────────────────────────────────────────────────────────┐
│                       MANAGE TEAM MEMBERS CONTEXT                         │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────┐                                                         │
│  │ Store       │                                                         │
│  │ Manager     │──────────┐                                              │
│  └─────────────┘          │                                              │
│                           │ HTTPS (Session Auth)                         │
│                           ▼                                              │
│  ┌──────────────────────────────────────────────────────────────────┐   │
│  │               MANAGE TEAM MEMBERS PAGE                            │   │
│  │  ┌───────────────┐  ┌───────────────┐  ┌───────────────┐         │   │
│  │  │ Team List     │  │ Detail Modal  │  │ Add Wizard    │         │   │
│  │  │ (DataTable)   │  │ (Tabbed)      │  │ (Multi-step)  │         │   │
│  │  └───────────────┘  └───────────────┘  └───────────────┘         │   │
│  └──────────────────────────────────────────────────────────────────┘   │
│                           │                                              │
│         ┌─────────────────┼─────────────────┐                            │
│         │                 │                 │                            │
│         ▼                 ▼                 ▼                            │
│  ┌─────────────┐   ┌─────────────┐   ┌─────────────┐                    │
│  │ Team Member │   │ Invitation  │   │ WhenIWork   │                    │
│  │ API         │   │ Service     │   │ Sync API    │                    │
│  └─────────────┘   └─────────────┘   └─────────────┘                    │
│         │                 │                 │                            │
│         │                 │                 │                            │
│         ▼                 ▼                 ▼                            │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │                    CENTRAL DATABASE (kiosk_users)                │    │
│  │  ┌─────────┐  ┌────────────────────┐  ┌───────────────────┐     │    │
│  │  │ users   │  │ userStoreAssignments │  │ employee_invitations │     │    │
│  │  └─────────┘  └────────────────────┘  └───────────────────┘     │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                                                          │
│                           │                                              │
│                           ▼                                              │
│                    ┌─────────────┐                                       │
│                    │ WhenIWork   │ (External)                            │
│                    │ API         │                                       │
│                    └─────────────┘                                       │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘
```

#### Interface Specifications

```yaml
# Inbound Interfaces
inbound:
  - name: "Store Manager Web Interface"
    type: HTTPS
    format: HTML + JSON API
    authentication: PHP Session
    data_flow: "CRUD operations on team members"

  - name: "Mobile App API (Legacy)"
    type: HTTPS
    format: REST JSON
    authentication: API Key (Legacy)
    data_flow: "Read-only employee list for mobile"

# Outbound Interfaces
outbound:
  - name: "WhenIWork API"
    type: HTTPS
    format: REST JSON
    authentication: API Key
    data_flow: "Employee sync from scheduling system"
    criticality: HIGH

  - name: "Email Service (Twilio/SendGrid)"
    type: HTTPS
    format: REST JSON
    authentication: API Key
    data_flow: "Invitation emails"
    criticality: MEDIUM

# Data Interfaces
data:
  - name: "Central Database (kiosk_users)"
    type: MySQL
    connection: PDO
    tables: [users, userStoreAssignments, employee_invitations, userSyncLog, authAuditLog]
    data_flow: "Team member persistence"
```

### Project Commands

```bash
# Testing
./test.sh                           # Run all tests
./test.sh --testsuite unit          # Run unit tests only
./test.sh --testsuite integration   # Run integration tests only
./test.sh --stan                    # Run tests + PHPStan analysis

# CSS Build
php userfrosting/conductor build-css           # Development build
php userfrosting/conductor build-css --minify  # Production build
php userfrosting/conductor build-css --watch   # Watch mode

# Deployment
./deploy.sh                         # Test + deploy

# Database Migrations
php userfrosting/conductor run      # Run pending migrations
```

---

## Solution Strategy

### Architecture Pattern

**Pattern**: Feature-Based Modular Architecture with Unified Data Layer

The solution reorganizes the employee management feature to:
1. **Single Data Source**: All queries go to central `users` + `userStoreAssignments` tables
2. **Feature Controller**: New `TeamMemberController` handles all page and API operations
3. **Service Layer**: Business logic in dedicated services (TeamMemberService, InvitationService)
4. **Modern UI**: Complete frontend rebuild with Bootstrap 5 and modular JavaScript

### Integration Approach

```
┌─────────────────────────────────────────────────────────────────────────┐
│                        INTEGRATION LAYERS                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  PRESENTATION LAYER                                                     │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │  team-members.html (Twig)    team-members.js (ES6 Module)       │   │
│  │  team-members.css            team-member-modal.js               │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                              │                                          │
│                              ▼                                          │
│  CONTROLLER LAYER                                                       │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │  TeamMemberController (Page + API handlers)                      │   │
│  │  - GET /admin/:typeNum/team-members (page)                       │   │
│  │  - GET/POST/PUT/DELETE /api/:typeNum/team-members/* (API)        │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                              │                                          │
│                              ▼                                          │
│  SERVICE LAYER                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │  TeamMemberService    InvitationService    SyncService           │   │
│  │  - CRUD operations    - Send/manage        - WhenIWork sync      │   │
│  │  - PIN management     - Token validation   - Audit logging       │   │
│  │  - Login toggle       - Registration       - Dedup detection     │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                              │                                          │
│                              ▼                                          │
│  DATA LAYER (Existing from Spec 007)                                    │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │  UnifiedUser Model        StoreAssignment Model                  │   │
│  │  - users table            - userStoreAssignments table           │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
```

### Key Decisions

| Decision | Choice | Rationale |
|----------|--------|-----------|
| **Data Source** | Unified `users` table only | Single source of truth per spec 007 |
| **API Endpoints** | Keep legacy paths for compatibility | Mobile app depends on existing endpoints |
| **UI Framework** | Bootstrap 5 + DataTables | Consistent with design system |
| **JavaScript** | ES6 Module pattern | Modern, maintainable, testable |
| **Modal Pattern** | Full modal with tabs | User preference, cleaner than slide-out |

---

## Building Block View

### Components

```
┌──────────────────────────────────────────────────────────────────────────┐
│                      COMPONENT ARCHITECTURE                               │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │                         FRONTEND COMPONENTS                         │ │
│  ├────────────────────────────────────────────────────────────────────┤ │
│  │                                                                    │ │
│  │  ┌─────────────┐   ┌─────────────┐   ┌─────────────┐              │ │
│  │  │ TeamList    │   │ DetailModal │   │ AddWizard   │              │ │
│  │  │ Component   │   │ Component   │   │ Component   │              │ │
│  │  │             │   │             │   │             │              │ │
│  │  │ - DataTable │   │ - Tabs:     │   │ - Step 1:   │              │ │
│  │  │ - Search    │   │   Profile   │   │   Basic     │              │ │
│  │  │ - Filters   │   │   Employ    │   │ - Step 2:   │              │ │
│  │  │ - Row Actn  │   │   Access    │   │   Access    │              │ │
│  │  │             │   │   Activity  │   │ - Step 3:   │              │ │
│  │  │             │   │             │   │   Review    │              │ │
│  │  └──────┬──────┘   └──────┬──────┘   └──────┬──────┘              │ │
│  │         │                 │                 │                      │ │
│  │         └─────────────────┼─────────────────┘                      │ │
│  │                           │                                        │ │
│  │                           ▼                                        │ │
│  │                   ┌───────────────┐                                │ │
│  │                   │ TeamMemberAPI │ (JavaScript Service)           │ │
│  │                   │ - fetch/CRUD  │                                │ │
│  │                   │ - error handl │                                │ │
│  │                   └───────────────┘                                │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │                         BACKEND COMPONENTS                          │ │
│  ├────────────────────────────────────────────────────────────────────┤ │
│  │                                                                    │ │
│  │  ┌──────────────────────────────────────────────────────────────┐ │ │
│  │  │                    TeamMemberController                       │ │ │
│  │  │  Routes:                                                      │ │ │
│  │  │  - GET  /admin/:typeNum/team-members          (page)          │ │ │
│  │  │  - GET  /:typeNum/api/team-members            (list)          │ │ │
│  │  │  - GET  /:typeNum/api/team-members/:id        (detail)        │ │ │
│  │  │  - POST /:typeNum/api/team-members            (create)        │ │ │
│  │  │  - PUT  /:typeNum/api/team-members/:id        (update)        │ │ │
│  │  │  - DELETE /:typeNum/api/team-members/:id      (deactivate)    │ │ │
│  │  │  - POST /:typeNum/api/team-members/:id/pin    (set PIN)       │ │ │
│  │  │  - POST /:typeNum/api/team-members/:id/login  (toggle login)  │ │ │
│  │  │  - POST /:typeNum/api/team-members/sync       (WhenIWork)     │ │ │
│  │  │  - POST /:typeNum/api/team-members/:id/invite (send invite)   │ │ │
│  │  └──────────────────────────────────────────────────────────────┘ │ │
│  │                           │                                        │ │
│  │         ┌─────────────────┼─────────────────┐                      │ │
│  │         ▼                 ▼                 ▼                      │ │
│  │  ┌─────────────┐   ┌─────────────┐   ┌─────────────┐              │ │
│  │  │ TeamMember  │   │ Invitation  │   │ Sync        │              │ │
│  │  │ Service     │   │ Service     │   │ Service     │              │ │
│  │  └─────────────┘   └─────────────┘   └─────────────┘              │ │
│  │         │                 │                 │                      │ │
│  │         └─────────────────┼─────────────────┘                      │ │
│  │                           ▼                                        │ │
│  │  ┌──────────────────────────────────────────────────────────────┐ │ │
│  │  │              DATA MODELS (From Spec 007)                      │ │ │
│  │  │  UnifiedUser          StoreAssignment                         │ │ │
│  │  └──────────────────────────────────────────────────────────────┘ │ │
│  │                                                                    │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘
```

### Directory Map

```
userfrosting/
├── src/BuyerKiosk/
│   └── TeamMember/                           # NEW: Feature directory
│       ├── Controllers/
│       │   └── TeamMemberController.php      # NEW: Page and API controller
│       ├── Services/
│       │   ├── TeamMemberService.php         # NEW: Business logic
│       │   ├── InvitationService.php         # MODIFY: Move from UserEmployee
│       │   └── SyncService.php               # NEW: Extracted sync logic
│       └── DTOs/
│           └── TeamMemberDTO.php             # NEW: Data transfer object
│
├── routes/
│   └── team-members.php                      # NEW: Route definitions
│
├── templates/themes/default/
│   └── team-members/                         # NEW: Template directory
│       ├── team-members.html                 # NEW: Main page template
│       └── partials/
│           ├── list-table.html               # NEW: DataTable partial
│           ├── detail-modal.html             # NEW: Detail modal
│           ├── add-wizard.html               # NEW: Add wizard modal
│           ├── login-modal.html              # NEW: Login setup modal
│           └── filter-chips.html             # NEW: Filter UI partial

public_html/
├── css/admin/modules/
│   └── team-members.css                      # NEW: Page-specific styles
│
└── js/admin/
    └── team-members/                         # NEW: JS module directory
        ├── index.js                          # NEW: Main module entry
        ├── api.js                            # NEW: API client
        ├── list.js                           # NEW: DataTable management
        ├── detail-modal.js                   # NEW: Detail modal logic
        ├── add-wizard.js                     # NEW: Add wizard logic
        └── login-modal.js                    # NEW: Login setup logic
```

---

## User Interface Design

### Page Layout

```
┌──────────────────────────────────────────────────────────────────────────┐
│  HEADER BAR                                                              │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │ ← Back    Team Members                    [Sync] [+ Add Member]    │ │
│  │           Store Name - City               Last sync: 5 min ago     │ │
│  └────────────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────────────┤
│  SEARCH & FILTERS                                                        │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │ [🔍 Search by name or email...                                    ]│ │
│  │                                                                    │ │
│  │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ [Clear All]   │ │
│  │ │ ● Active │ │ Has Login│ │ Has PIN  │ │ WhenIWork│               │ │
│  │ └──────────┘ └──────────┘ └──────────┘ └──────────┘               │ │
│  └────────────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────────────┤
│  DATA TABLE                                                              │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │ ┌──┬────────┬──────────────┬──────────┬──────────┬────────────────┐│ │
│  │ │  │ Photo  │ Name         │ Position │ Status   │ Actions        ││ │
│  │ ├──┼────────┼──────────────┼──────────┼──────────┼────────────────┤│ │
│  │ │  │ (img)  │ John Smith   │ Buyer    │ ●Active  │ [🔐][✎][⋮]    ││ │
│  │ │  │        │ john@ex.com  │          │ 🔑 🔢 📱 │                ││ │
│  │ ├──┼────────┼──────────────┼──────────┼──────────┼────────────────┤│ │
│  │ │  │ (img)  │ Jane Doe     │ Sorter   │ ●Active  │ [🔐][✎][⋮]    ││ │
│  │ │  │        │ jane@ex.com  │          │ 🔢 📱    │                ││ │
│  │ └──┴────────┴──────────────┴──────────┴──────────┴────────────────┘│ │
│  │                                                                    │ │
│  │ Showing 1-25 of 47                              [<] [1] [2] [>]    │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  LEGEND: 🔑 = Has Login  🔢 = Has PIN  📱 = WhenIWork Source            │
└──────────────────────────────────────────────────────────────────────────┘
```

### Table Row Detail

```
┌──────────────────────────────────────────────────────────────────────────┐
│  TABLE ROW ANATOMY                                                        │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌──┬────────┬──────────────────────────┬──────────┬────────┬──────────┐│
│  │☐ │ Avatar │ Name + Email             │ Position │ Status │ Actions  ││
│  │  │        │                          │ + Role   │ + Icons│          ││
│  └──┴────────┴──────────────────────────┴──────────┴────────┴──────────┘│
│                                                                          │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │                                                                    │ │
│  │  ☐  ┌────┐  John Smith                 Buyer         ● Active     │ │
│  │     │    │  john.smith@example.com     ┌──────────┐  🔑 🔢 📱      │ │
│  │     │ JS │                             │  Buyer   │               │ │
│  │     │    │                             │  (blue)  │               │ │
│  │     └────┘                             └──────────┘               │ │
│  │     32x32                                                         │ │
│  │     avatar                                                        │ │
│  │                                                                    │ │
│  │                                         ┌─────────────────────────┐│ │
│  │                                         │ 🔐 Can Login Toggle     ││ │
│  │                                         │ ┌────┐ ┌────┐ ┌───────┐ ││ │
│  │                                         │ │ ✎ │ │Edit│ │   ⋮   │ ││ │
│  │                                         │ └────┘ └────┘ └───────┘ ││ │
│  │                                         │        Deactivate       ││ │
│  │                                         └─────────────────────────┘│ │
│  │                                                                    │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  ICON LEGEND:                                                            │
│  🔑 = Has BuyerKiosk Login (green if enabled)                           │
│  🔢 = Has Clock PIN set (green if set)                                   │
│  📱 = External source (WhenIWork badge)                                  │
│                                                                          │
│  ACTIONS:                                                                │
│  🔐 = Login toggle (switch component)                                   │
│  ✎ = Edit (opens detail modal)                                          │
│  ⋮ = More menu (Deactivate, Reactivate if inactive)                     │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘
```

### Status Icons Specification

```yaml
# Status Icons in Table Row
icons:
  login_access:
    has_login:
      icon: "fa-key"
      color: "var(--success-600)" # Green
      tooltip: "Can log into BuyerKiosk"
    no_login:
      icon: "fa-key"
      color: "var(--neutral-400)" # Gray
      tooltip: "No BuyerKiosk login"
    pending_invite:
      icon: "fa-envelope"
      color: "var(--warning-500)" # Yellow
      tooltip: "Invitation pending"

  clock_pin:
    has_pin:
      icon: "fa-hashtag"
      color: "var(--success-600)" # Green
      tooltip: "Clock PIN set"
    no_pin:
      icon: "fa-hashtag"
      color: "var(--neutral-400)" # Gray
      tooltip: "No clock PIN"

  external_source:
    wheniwork:
      icon: "fa-calendar-alt"
      color: "var(--info-500)" # Blue
      tooltip: "Synced from WhenIWork"
    homebase:
      icon: "fa-home"
      color: "var(--info-500)" # Blue
      tooltip: "Synced from Homebase"
    homegrown:
      # No icon shown for manual entries

# Status Badge Colors
status_badges:
  active:
    class: "badge bg-success"
    text: "Active"
  inactive:
    class: "badge bg-secondary"
    text: "Inactive"
  on_leave:
    class: "badge bg-warning text-dark"
    text: "On Leave"
```

### Detail Modal (Tabbed)

```
┌──────────────────────────────────────────────────────────────────────────┐
│  DETAIL MODAL - TABBED LAYOUT                                            │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │                                                              [×]   │ │
│  │  ┌────────┐                                                        │ │
│  │  │        │  John Smith                                            │ │
│  │  │  (img) │  john.smith@example.com                               │ │
│  │  │   80x80│  📱 WhenIWork                                         │ │
│  │  └────────┘                                                        │ │
│  │                                                                    │ │
│  │  ┌──────────┬────────────┬─────────────────┬──────────┐           │ │
│  │  │ Profile  │ Employment │ Access & Security│ Activity │           │ │
│  │  └──────────┴────────────┴─────────────────┴──────────┘           │ │
│  │  ─────────────────────────────────────────────────────             │ │
│  │                                                                    │ │
│  │  ┌─────────────────────────────────────────────────────────────┐  │ │
│  │  │                     TAB CONTENT AREA                         │  │ │
│  │  │                                                              │  │ │
│  │  │  (See individual tab layouts below)                          │  │ │
│  │  │                                                              │  │ │
│  │  │                                                              │  │ │
│  │  │                                                              │  │ │
│  │  │                                                              │  │ │
│  │  └─────────────────────────────────────────────────────────────┘  │ │
│  │                                                                    │ │
│  │  ┌──────────────────────────────────────────────────────────────┐ │ │
│  │  │                                    [Cancel]  [Save Changes]  │ │ │
│  │  └──────────────────────────────────────────────────────────────┘ │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘
```

### Tab 1: Profile

```
┌──────────────────────────────────────────────────────────────────────────┐
│  TAB: PROFILE                                                            │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  Photo                                                                   │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │  ┌────────┐                                                        │ │
│  │  │        │  [Upload Photo]  [Remove]                              │ │
│  │  │  80x80 │                                                        │ │
│  │  │        │  📱 Photo managed by WhenIWork (override available)    │ │
│  │  └────────┘                                                        │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  Basic Information                                                       │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │  First Name *           Last Name *                                │ │
│  │  ┌─────────────────┐    ┌─────────────────┐                        │ │
│  │  │ John         🔒 │    │ Smith        🔒 │   🔒 = read-only       │ │
│  │  └─────────────────┘    └─────────────────┘   (external source)    │ │
│  │                                                                    │ │
│  │  Email                       Phone                                 │ │
│  │  ┌─────────────────────┐    ┌─────────────────┐                    │ │
│  │  │ john@example.com 🔒 │    │ (555) 123-4567  │                    │ │
│  │  └─────────────────────┘    └─────────────────┘                    │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  Emergency Contact                                                       │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │  Name                        Phone                                 │ │
│  │  ┌─────────────────────┐    ┌─────────────────┐                    │ │
│  │  │ Jane Smith          │    │ (555) 987-6543  │                    │ │
│  │  └─────────────────────┘    └─────────────────┘                    │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘
```

### Tab 2: Employment

```
┌──────────────────────────────────────────────────────────────────────────┐
│  TAB: EMPLOYMENT                                                         │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  Position & Role                                                         │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │  Position                    Role                                  │ │
│  │  ┌─────────────────────┐    ┌─────────────────────┐                │ │
│  │  │ Buyer               │    │ Buyer            ▼  │                │ │
│  │  └─────────────────────┘    └─────────────────────┘                │ │
│  │                                                                    │ │
│  │  Role Color Preview                                                │ │
│  │  ┌──────────────────────┐                                          │ │
│  │  │ ████ Buyer           │  [Change Color]                         │ │
│  │  └──────────────────────┘                                          │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  Employment Status                                                       │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │  Status                                                            │ │
│  │  ○ Active   ○ Inactive   ○ On Leave                                │ │
│  │                                                                    │ │
│  │  ┌──────────────────────────────────────────────────────────────┐ │ │
│  │  │  Leave Period (if On Leave selected)                         │ │ │
│  │  │  Start Date             End Date                              │ │ │
│  │  │  ┌───────────────┐     ┌───────────────┐                      │ │ │
│  │  │  │ 12/15/2025    │     │ 01/15/2026    │                      │ │ │
│  │  │  └───────────────┘     └───────────────┘                      │ │ │
│  │  └──────────────────────────────────────────────────────────────┘ │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  Employment Dates                                                        │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │  Hire Date                  Termination Date                       │ │
│  │  ┌─────────────────────┐    ┌─────────────────────┐                │ │
│  │  │ 03/15/2023          │    │                     │                │ │
│  │  └─────────────────────┘    └─────────────────────┘                │ │
│  │                                                                    │ │
│  │  Hourly Rate                DRS Employee ID                        │ │
│  │  ┌─────────────────────┐    ┌─────────────────────┐                │ │
│  │  │ $ 18.50             │    │ DRS-12345           │                │ │
│  │  └─────────────────────┘    └─────────────────────┘                │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘
```

### Tab 3: Access & Security

```
┌──────────────────────────────────────────────────────────────────────────┐
│  TAB: ACCESS & SECURITY                                                  │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  BuyerKiosk Login                                                        │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │                                                                    │ │
│  │  Can log into BuyerKiosk                                          │ │
│  │  ┌──────────────────────────────────────────────────────────────┐ │ │
│  │  │  [═══════●]  ON                                              │ │ │
│  │  │                                                              │ │ │
│  │  │  Username: jsmith                                            │ │ │
│  │  │  Last login: Dec 8, 2025 at 2:34 PM                          │ │ │
│  │  │  MFA: Enabled ✓                                               │ │ │
│  │  └──────────────────────────────────────────────────────────────┘ │ │
│  │                                                                    │ │
│  │  ⚠️ Disabling login will prevent this user from accessing         │ │
│  │     BuyerKiosk. Their clock PIN will remain active.               │ │
│  │                                                                    │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  Clock PIN                                                               │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │                                                                    │ │
│  │  PIN for time clock verification                                   │ │
│  │  ┌──────────────────────────────────────────────────────────────┐ │ │
│  │  │  Current PIN: ••••••  (set)                                  │ │ │
│  │  │                                                              │ │ │
│  │  │  New PIN (4-6 digits)                                        │ │ │
│  │  │  ┌────────────────────┐                                      │ │ │
│  │  │  │ ______             │  [Update PIN]  [Remove PIN]          │ │ │
│  │  │  └────────────────────┘                                      │ │ │
│  │  └──────────────────────────────────────────────────────────────┘ │ │
│  │                                                                    │ │
│  │  ℹ️ Clock PIN is independent of login access. Team members can     │ │
│  │     clock in/out with just a PIN, even without a BuyerKiosk login.│ │
│  │                                                                    │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
│  Daily Reports                                                           │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │  ☐ Receive daily performance email                                 │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘
```

### Tab 4: Activity

```
┌──────────────────────────────────────────────────────────────────────────┐
│  TAB: ACTIVITY                                                           │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  Recent Activity                                                         │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │                                                                    │ │
│  │  ┌────────────────────────────────────────────────────────────┐   │ │
│  │  │ 🔑 Login access enabled                                    │   │ │
│  │  │    by Sarah Manager · Dec 8, 2025 at 2:30 PM               │   │ │
│  │  │    Method: Admin-created credentials                       │   │ │
│  │  └────────────────────────────────────────────────────────────┘   │ │
│  │                                                                    │ │
│  │  ┌────────────────────────────────────────────────────────────┐   │ │
│  │  │ 🔢 Clock PIN updated                                       │   │ │
│  │  │    by Sarah Manager · Dec 8, 2025 at 2:25 PM               │   │ │
│  │  └────────────────────────────────────────────────────────────┘   │ │
│  │                                                                    │ │
│  │  ┌────────────────────────────────────────────────────────────┐   │ │
│  │  │ 📱 Synced from WhenIWork                                   │   │ │
│  │  │    System · Dec 8, 2025 at 10:00 AM                        │   │ │
│  │  │    Updated: name, email, photo                              │   │ │
│  │  └────────────────────────────────────────────────────────────┘   │ │
│  │                                                                    │ │
│  │  ┌────────────────────────────────────────────────────────────┐   │ │
│  │  │ ➕ Team member created                                      │   │ │
│  │  │    System (WhenIWork sync) · Dec 1, 2025 at 9:00 AM        │   │ │
│  │  └────────────────────────────────────────────────────────────┘   │ │
│  │                                                                    │ │
│  │  [Load More...]                                                    │ │
│  │                                                                    │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘
```

### Login Setup Modal

```
┌──────────────────────────────────────────────────────────────────────────┐
│  LOGIN SETUP MODAL                                                       │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │                                                              [×]   │ │
│  │                                                                    │ │
│  │  Set up BuyerKiosk access for John Smith                          │ │
│  │                                                                    │ │
│  │  ─────────────────────────────────────────────────────────────    │ │
│  │                                                                    │ │
│  │  How should John set up their account?                            │ │
│  │                                                                    │ │
│  │  ┌──────────────────────────────────────────────────────────────┐ │ │
│  │  │  ○ Send Email Invitation                                     │ │ │
│  │  │    John will receive an email to create their own password.  │ │ │
│  │  │    Email: john.smith@example.com                             │ │ │
│  │  └──────────────────────────────────────────────────────────────┘ │ │
│  │                                                                    │ │
│  │  ┌──────────────────────────────────────────────────────────────┐ │ │
│  │  │  ● Create Credentials Now                                    │ │ │
│  │  │    You'll set John's username and password.                  │ │ │
│  │  │                                                              │ │ │
│  │  │    Username *                                                │ │ │
│  │  │    ┌────────────────────────────────────────────────────┐   │ │ │
│  │  │    │ jsmith                                              │   │ │ │
│  │  │    └────────────────────────────────────────────────────┘   │ │ │
│  │  │                                                              │ │ │
│  │  │    Password *                            [👁] [Generate]     │ │ │
│  │  │    ┌────────────────────────────────────────────────────┐   │ │ │
│  │  │    │ ••••••••••••                                        │   │ │ │
│  │  │    └────────────────────────────────────────────────────┘   │ │ │
│  │  │    Min 8 characters                                         │ │ │
│  │  │                                                              │ │ │
│  │  │    ☐ Also set clock PIN                                     │ │ │
│  │  │    ┌────────────────────────────────────────────────────┐   │ │ │
│  │  │    │ ______                                              │   │ │ │
│  │  │    └────────────────────────────────────────────────────┘   │ │ │
│  │  │    4-6 digits                                               │ │ │
│  │  │                                                              │ │ │
│  │  └──────────────────────────────────────────────────────────────┘ │ │
│  │                                                                    │ │
│  │  ┌──────────────────────────────────────────────────────────────┐ │ │
│  │  │                         [Cancel]  [Enable Login Access]      │ │ │
│  │  └──────────────────────────────────────────────────────────────┘ │ │
│  │                                                                    │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘
```

### Add Team Member Wizard

```
┌──────────────────────────────────────────────────────────────────────────┐
│  ADD WIZARD - STEP INDICATOR                                             │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │                                                              [×]   │ │
│  │                                                                    │ │
│  │  Add Team Member                                                   │ │
│  │                                                                    │ │
│  │      ●────────────○────────────○                                   │ │
│  │   Basic Info    Access      Review                                 │ │
│  │                                                                    │ │
│  └────────────────────────────────────────────────────────────────────┘ │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────────────┐
│  STEP 1: BASIC INFO                                                      │
├──────────────────────────────────────────────────────────────────────────┤
│  │                                                                    │ │
│  │  Photo (optional)                                                  │ │
│  │  ┌────────┐                                                        │ │
│  │  │  + Add │  [Upload Photo]                                        │ │
│  │  │  Photo │                                                        │ │
│  │  └────────┘                                                        │ │
│  │                                                                    │ │
│  │  First Name *               Last Name *                            │ │
│  │  ┌─────────────────────┐    ┌─────────────────────┐                │ │
│  │  │                     │    │                     │                │ │
│  │  └─────────────────────┘    └─────────────────────┘                │ │
│  │                                                                    │ │
│  │  Email                       Phone                                 │ │
│  │  ┌─────────────────────┐    ┌─────────────────────┐                │ │
│  │  │                     │    │                     │                │ │
│  │  └─────────────────────┘    └─────────────────────┘                │ │
│  │                                                                    │ │
│  │  Position                    Role                                  │ │
│  │  ┌─────────────────────┐    ┌─────────────────────┐                │ │
│  │  │                     │    │ Select...        ▼  │                │ │
│  │  └─────────────────────┘    └─────────────────────┘                │ │
│  │                                                                    │ │
│  │                              [Cancel]  [Next: Access →]            │ │
└──────────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────────────┐
│  STEP 2: ACCESS                                                          │
├──────────────────────────────────────────────────────────────────────────┤
│  │                                                                    │ │
│  │  Clock PIN                                                         │ │
│  │  ┌──────────────────────────────────────────────────────────────┐ │ │
│  │  │  ☑ Set clock PIN for time clock verification                 │ │ │
│  │  │                                                              │ │ │
│  │  │  PIN (4-6 digits)                                            │ │ │
│  │  │  ┌────────────────────────────────────────────────────┐      │ │ │
│  │  │  │ 1234                                                │      │ │ │
│  │  │  └────────────────────────────────────────────────────┘      │ │ │
│  │  └──────────────────────────────────────────────────────────────┘ │ │
│  │                                                                    │ │
│  │  BuyerKiosk Login                                                  │ │
│  │  ┌──────────────────────────────────────────────────────────────┐ │ │
│  │  │  ☑ Enable BuyerKiosk login access                            │ │ │
│  │  │                                                              │ │ │
│  │  │  ○ Send invitation email                                     │ │ │
│  │  │  ● Create credentials now                                    │ │ │
│  │  │                                                              │ │ │
│  │  │  Username *                                                  │ │ │
│  │  │  ┌────────────────────────────────────────────────────┐      │ │ │
│  │  │  │ jdoe                                                │      │ │ │
│  │  │  └────────────────────────────────────────────────────┘      │ │ │
│  │  │                                                              │ │ │
│  │  │  Password *                              [👁] [Generate]      │ │ │
│  │  │  ┌────────────────────────────────────────────────────┐      │ │ │
│  │  │  │ ••••••••••••                                        │      │ │ │
│  │  │  └────────────────────────────────────────────────────┘      │ │ │
│  │  └──────────────────────────────────────────────────────────────┘ │ │
│  │                                                                    │ │
│  │                    [← Back]  [Cancel]  [Next: Review →]            │ │
└──────────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────────────┐
│  STEP 3: REVIEW                                                          │
├──────────────────────────────────────────────────────────────────────────┤
│  │                                                                    │ │
│  │  Review New Team Member                                            │ │
│  │                                                                    │ │
│  │  ┌──────────────────────────────────────────────────────────────┐ │ │
│  │  │  ┌────────┐                                                  │ │ │
│  │  │  │        │  Jane Doe                                        │ │ │
│  │  │  │  (img) │  jane.doe@example.com                            │ │ │
│  │  │  │        │  (555) 123-4567                                  │ │ │
│  │  │  └────────┘                                                  │ │ │
│  │  │                                                              │ │ │
│  │  │  Position: Buyer                                             │ │ │
│  │  │  Role: Buyer (blue badge)                                    │ │ │
│  │  │                                                              │ │ │
│  │  │  ─────────────────────────────────────────────────────────  │ │ │
│  │  │                                                              │ │ │
│  │  │  ✓ Clock PIN will be set: ••••                               │ │ │
│  │  │  ✓ BuyerKiosk login enabled                                  │ │ │
│  │  │    Username: jdoe                                            │ │ │
│  │  │    Password: (will be created)                               │ │ │
│  │  │                                                              │ │ │
│  │  └──────────────────────────────────────────────────────────────┘ │ │
│  │                                                                    │ │
│  │                    [← Back]  [Cancel]  [Add Team Member]           │ │
└──────────────────────────────────────────────────────────────────────────┘
```

---

## Interface Specifications

### API Endpoints

```yaml
# Team Member API Endpoints
endpoints:
  list:
    method: GET
    path: /:typeNum/api/team-members
    description: Get paginated list of team members for store
    query_params:
      search: string (optional) - filter by name/email
      status: enum(active,inactive,on_leave) (optional)
      hasLogin: boolean (optional)
      hasPin: boolean (optional)
      source: enum(homegrown,wheniwork,homebase) (optional)
      page: integer (default: 1)
      perPage: integer (default: 25, max: 100)
      sortBy: enum(name,position,status,assignedAt) (default: name)
      sortDir: enum(asc,desc) (default: asc)
    response:
      success:
        data: array of TeamMemberDTO
        meta:
          total: integer
          page: integer
          perPage: integer
          totalPages: integer
      error:
        error: string
        message: string

  get:
    method: GET
    path: /:typeNum/api/team-members/:id
    description: Get single team member details
    response:
      success:
        data: TeamMemberDTO (full details including activity log)
      error:
        error: "not_found"
        message: "Team member not found"

  create:
    method: POST
    path: /:typeNum/api/team-members
    description: Create new team member (homegrown stores only)
    request:
      firstName: string (required)
      lastName: string (required)
      email: string (optional)
      phone: string (optional)
      position: string (optional)
      role: string (optional)
      clockPin: string (optional, 4-6 digits)
      enableLogin: boolean (optional)
      loginMethod: enum(invite,admin) (required if enableLogin)
      username: string (required if loginMethod=admin)
      password: string (required if loginMethod=admin)
    response:
      success:
        data: TeamMemberDTO
        message: "Team member created"
      error:
        error: "validation_error" | "username_taken" | "email_exists"
        message: string
        details: object (field-specific errors)

  update:
    method: PUT
    path: /:typeNum/api/team-members/:id
    description: Update team member
    request:
      # All fields optional - only provided fields are updated
      firstName: string
      lastName: string
      email: string
      phone: string
      position: string
      role: string
      roleColor: string (hex)
      emergencyContactName: string
      emergencyContactPhone: string
      hireDate: date
      terminationDate: date
      leaveStartDate: date
      leaveEndDate: date
      hourlyRate: decimal
      drsEmployeeId: string
      dailyEmailEnabled: boolean
    response:
      success:
        data: TeamMemberDTO
        message: "Team member updated"
      error:
        error: "not_found" | "validation_error" | "external_field"
        message: string

  deactivate:
    method: DELETE
    path: /:typeNum/api/team-members/:id
    description: Deactivate team member (soft delete)
    response:
      success:
        message: "Team member deactivated"
      error:
        error: "not_found"
        message: string

  reactivate:
    method: POST
    path: /:typeNum/api/team-members/:id/reactivate
    description: Reactivate previously deactivated team member
    response:
      success:
        data: TeamMemberDTO
        message: "Team member reactivated"
      error:
        error: "not_found" | "already_active"
        message: string

  setPin:
    method: POST
    path: /:typeNum/api/team-members/:id/pin
    description: Set or remove clock PIN
    request:
      pin: string (4-6 digits, or empty to remove)
    response:
      success:
        message: "PIN updated" | "PIN removed"
      error:
        error: "invalid_pin" | "not_found"
        message: string

  toggleLogin:
    method: POST
    path: /:typeNum/api/team-members/:id/login
    description: Enable or disable login access
    request:
      enabled: boolean (required)
      # If enabling:
      method: enum(invite,admin) (required if enabled=true)
      username: string (required if method=admin)
      password: string (required if method=admin)
      clockPin: string (optional, 4-6 digits)
    response:
      success:
        data: TeamMemberDTO
        message: "Login access enabled" | "Login access disabled"
        invitationSent: boolean (if method=invite)
      error:
        error: "username_taken" | "email_required" | "validation_error"
        message: string

  invite:
    method: POST
    path: /:typeNum/api/team-members/:id/invite
    description: Send or resend invitation email
    request:
      email: string (optional - uses existing if not provided)
    response:
      success:
        message: "Invitation sent"
        expiresAt: datetime
      error:
        error: "email_required" | "already_has_login"
        message: string

  sync:
    method: POST
    path: /:typeNum/api/team-members/sync
    description: Sync from external provider (WhenIWork)
    response:
      success:
        added: integer
        updated: integer
        deactivated: integer
        errors: array of strings
        message: "Sync completed"
      error:
        error: "sync_failed" | "provider_error"
        message: string
        details: object

  activity:
    method: GET
    path: /:typeNum/api/team-members/:id/activity
    description: Get activity log for team member
    query_params:
      page: integer (default: 1)
      perPage: integer (default: 20)
    response:
      success:
        data: array of ActivityLogEntry
        meta:
          total: integer
          page: integer
```

### Data Transfer Objects

```yaml
# TeamMemberDTO - Full team member representation
TeamMemberDTO:
  id: integer

  # Profile
  firstName: string
  lastName: string
  displayName: string
  email: string | null
  phone: string | null
  photoUrl: string | null
  avatarOverride: boolean

  # Employment
  position: string | null
  role: string | null
  roleColor: string | null
  hireDate: date | null
  terminationDate: date | null
  leaveStartDate: date | null
  leaveEndDate: date | null
  hourlyRate: decimal | null
  drsEmployeeId: string | null
  dailyEmailEnabled: boolean

  # Emergency Contact
  emergencyContactName: string | null
  emergencyContactPhone: string | null

  # Status
  status: enum(active, inactive, on_leave)
  isActive: boolean

  # Source
  source: enum(homegrown, wheniwork, homebase)
  externalId: string | null
  lastSyncedAt: datetime | null

  # Access
  canLogin: boolean
  username: string | null
  lastLoginAt: datetime | null
  mfaEnabled: boolean
  hasClockPin: boolean
  hasPendingInvitation: boolean
  invitationExpiresAt: datetime | null

  # Store Assignment
  assignedAt: datetime
  deactivatedAt: datetime | null

  # Computed
  isEditable: boolean  # true if source=homegrown or field is local-only
  editableFields: array of string  # which fields can be edited

# ActivityLogEntry - Single activity log item
ActivityLogEntry:
  id: integer
  eventType: string
  description: string
  details: object | null
  performedBy: string  # username or "System"
  performedAt: datetime
```

---

## Runtime View

### Primary Flow: Load Team Members Page

```
┌─────────────────────────────────────────────────────────────────────────┐
│                    PAGE LOAD SEQUENCE                                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  User                Browser              Server              Database  │
│   │                    │                    │                    │      │
│   │ Navigate to        │                    │                    │      │
│   │ /admin/ou00/team-members               │                    │      │
│   │───────────────────>│                    │                    │      │
│   │                    │ GET page           │                    │      │
│   │                    │───────────────────>│                    │      │
│   │                    │                    │ Check session      │      │
│   │                    │                    │ Check permissions  │      │
│   │                    │                    │ Check store access │      │
│   │                    │                    │───────────────────>│      │
│   │                    │                    │ Get store config   │      │
│   │                    │                    │<───────────────────│      │
│   │                    │<───────────────────│                    │      │
│   │                    │ HTML page          │                    │      │
│   │                    │                    │                    │      │
│   │                    │ Initialize JS      │                    │      │
│   │                    │ ─────────────>     │                    │      │
│   │                    │                    │                    │      │
│   │                    │ GET /api/team-members?page=1            │      │
│   │                    │───────────────────>│                    │      │
│   │                    │                    │───────────────────>│      │
│   │                    │                    │ SELECT users       │      │
│   │                    │                    │ JOIN assignments   │      │
│   │                    │                    │ WHERE typeNum=ou00 │      │
│   │                    │                    │<───────────────────│      │
│   │                    │<───────────────────│                    │      │
│   │                    │ JSON response      │                    │      │
│   │                    │                    │                    │      │
│   │                    │ Render DataTable   │                    │      │
│   │<───────────────────│                    │                    │      │
│   │ Display page       │                    │                    │      │
│   │                    │                    │                    │      │
└─────────────────────────────────────────────────────────────────────────┘
```

### Flow: Enable Login Access (Admin-Create)

```
┌─────────────────────────────────────────────────────────────────────────┐
│                    LOGIN ENABLE FLOW                                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  User                Browser              Server              Database  │
│   │                    │                    │                    │      │
│   │ Toggle login ON    │                    │                    │      │
│   │───────────────────>│                    │                    │      │
│   │                    │ Show login modal   │                    │      │
│   │                    │<──────────────     │                    │      │
│   │                    │                    │                    │      │
│   │ Select "Create     │                    │                    │      │
│   │ credentials"       │                    │                    │      │
│   │ Enter username,    │                    │                    │      │
│   │ password           │                    │                    │      │
│   │───────────────────>│                    │                    │      │
│   │                    │ Validate inputs    │                    │      │
│   │                    │ ─────────────>     │                    │      │
│   │                    │                    │                    │      │
│   │                    │ POST /api/team-members/:id/login        │      │
│   │                    │ {enabled:true,method:'admin',           │      │
│   │                    │  username:'jsmith',password:'xxx'}      │      │
│   │                    │───────────────────>│                    │      │
│   │                    │                    │ Check username     │      │
│   │                    │                    │ unique             │      │
│   │                    │                    │───────────────────>│      │
│   │                    │                    │<───────────────────│      │
│   │                    │                    │ UPDATE users       │      │
│   │                    │                    │ SET canLogin=1,    │      │
│   │                    │                    │ username=?,        │      │
│   │                    │                    │ password=hash()    │      │
│   │                    │                    │───────────────────>│      │
│   │                    │                    │<───────────────────│      │
│   │                    │                    │ INSERT authAuditLog│      │
│   │                    │                    │───────────────────>│      │
│   │                    │                    │<───────────────────│      │
│   │                    │<───────────────────│                    │      │
│   │                    │ Success response   │                    │      │
│   │                    │                    │                    │      │
│   │                    │ Close modal        │                    │      │
│   │                    │ Update row icons   │                    │      │
│   │                    │ Show toast         │                    │      │
│   │<───────────────────│                    │                    │      │
│   │                    │                    │                    │      │
└─────────────────────────────────────────────────────────────────────────┘
```

### Flow: WhenIWork Sync

```
┌─────────────────────────────────────────────────────────────────────────┐
│                    WHENIWORK SYNC FLOW                                   │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  User     Browser     Server     Database     WhenIWork API             │
│   │         │           │           │              │                    │
│   │ Click   │           │           │              │                    │
│   │ "Sync"  │           │           │              │                    │
│   │────────>│           │           │              │                    │
│   │         │ Show      │           │              │                    │
│   │         │ spinner   │           │              │                    │
│   │         │           │           │              │                    │
│   │         │ POST /sync│           │              │                    │
│   │         │──────────>│           │              │                    │
│   │         │           │ Get API   │              │                    │
│   │         │           │ credentials              │                    │
│   │         │           │──────────>│              │                    │
│   │         │           │<──────────│              │                    │
│   │         │           │           │              │                    │
│   │         │           │ GET /users│              │                    │
│   │         │           │───────────│─────────────>│                    │
│   │         │           │<──────────│──────────────│                    │
│   │         │           │           │              │                    │
│   │         │           │ For each WhenIWork user: │                    │
│   │         │           │──────────>│              │                    │
│   │         │           │ Find by   │              │                    │
│   │         │           │ externalId│              │                    │
│   │         │           │ or email  │              │                    │
│   │         │           │<──────────│              │                    │
│   │         │           │           │              │                    │
│   │         │           │ UPSERT    │              │                    │
│   │         │           │ user      │              │                    │
│   │         │           │──────────>│              │                    │
│   │         │           │<──────────│              │                    │
│   │         │           │           │              │                    │
│   │         │           │ UPSERT    │              │                    │
│   │         │           │ assignment│              │                    │
│   │         │           │ (preserve │              │                    │
│   │         │           │  clockPin)│              │                    │
│   │         │           │──────────>│              │                    │
│   │         │           │<──────────│              │                    │
│   │         │           │           │              │                    │
│   │         │           │ Log sync  │              │                    │
│   │         │           │──────────>│              │                    │
│   │         │           │<──────────│              │                    │
│   │         │           │           │              │                    │
│   │         │<──────────│           │              │                    │
│   │         │ {added:2, │           │              │                    │
│   │         │  updated:5│           │              │                    │
│   │         │  deact:1} │           │              │                    │
│   │         │           │           │              │                    │
│   │         │ Hide spin │           │              │                    │
│   │         │ Show toast│           │              │                    │
│   │         │ Reload    │           │              │                    │
│   │         │ table     │           │              │                    │
│   │<────────│           │           │              │                    │
│   │         │           │           │              │                    │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## Error Handling

### Error Types and Responses

```yaml
# Validation Errors (400)
validation_error:
  status: 400
  response:
    error: "validation_error"
    message: "Invalid input data"
    details:
      field_name: "Error message for field"
  user_display: Form field highlighting with inline error messages

# Authentication Errors (401)
unauthorized:
  status: 401
  response:
    error: "unauthorized"
    message: "Please log in to continue"
  user_display: Redirect to login page

# Permission Errors (403)
forbidden:
  status: 403
  response:
    error: "forbidden"
    message: "You don't have permission to perform this action"
  user_display: Toast notification with error message

# Not Found (404)
not_found:
  status: 404
  response:
    error: "not_found"
    message: "Team member not found"
  user_display: Toast notification, optionally refresh list

# Conflict (409)
username_taken:
  status: 409
  response:
    error: "username_taken"
    message: "This username is already in use"
    suggestions: ["jsmith1", "jsmith2"]
  user_display: Inline error on username field with suggestions

email_exists:
  status: 409
  response:
    error: "email_exists"
    message: "This email is already associated with another account"
  user_display: Inline error on email field

# External Service Error (502)
sync_failed:
  status: 502
  response:
    error: "sync_failed"
    message: "Could not connect to WhenIWork"
    details:
      provider: "wheniwork"
      error_code: "API_TIMEOUT"
  user_display: Toast notification with retry option

# Server Error (500)
internal_error:
  status: 500
  response:
    error: "internal_error"
    message: "An unexpected error occurred"
  user_display: Toast notification suggesting retry or contact support
```

---

## Architecture Decisions

| ID | Decision | Choice | Rationale | Trade-offs | Status |
|----|----------|--------|-----------|------------|--------|
| ADR-1 | UI Layout | Data Table + Modal | User preference, consistent with other admin pages | More clicks than inline editing | **Confirmed** |
| ADR-2 | Detail Modal | Tabbed sections | Organizes complex form, allows future expansion | More complex JS | **Confirmed** |
| ADR-3 | Login toggle | On-row toggle + modal | Quick visual status, guided setup flow | Extra modal for setup | **Confirmed** |
| ADR-4 | PIN entry | In detail panel only | Reduces row complexity | Extra click to set PIN | **Confirmed** |
| ADR-5 | Add flow | Multi-step wizard | Guided creation, reduces errors | More implementation work | **Confirmed** |
| ADR-6 | Filter UI | Search + chip filters | Balance of power and simplicity | Limited advanced filtering | **Confirmed** |
| ADR-7 | Data source | Unified users only | Single source of truth per spec 007 | Must migrate legacy data | **Confirmed** |
| ADR-8 | API compatibility | Keep legacy paths | Mobile app dependency | Some route duplication | **Confirmed** |

---

## Quality Requirements

| Requirement | Target | Test Method |
|-------------|--------|-------------|
| Page load time | < 2 seconds | Lighthouse performance audit |
| API response time | < 500ms | PHPUnit integration tests |
| Table render time | < 1 second for 100 rows | Manual testing |
| Search filter delay | < 300ms debounce | JS unit tests |
| Mobile responsiveness | Usable on 375px width | Manual device testing |
| Accessibility | WCAG 2.1 AA | axe-core automated tests |
| Browser support | Chrome, Safari, Firefox, Edge (latest 2 versions) | BrowserStack testing |

---

## Risks and Technical Debt

### Known Technical Issues

- **Legacy employees table still exists**: Must query unified users, not legacy table
- **EmployeeManager has dual-mode logic**: Should be deprecated after migration
- **Current JS is 1,600+ lines monolith**: Complete rewrite needed

### Implementation Gotchas

- **PIN preserved during sync**: WhenIWork sync MUST NOT overwrite `clockPin` field
- **Avatar override flag**: If `avatarOverride=true`, sync should not update photo
- **Store assignment vs user**: Deactivation should update `userStoreAssignments`, not delete user
- **Username uniqueness**: Check across ALL users, not just current store

---

## Test Specifications

### Critical Test Scenarios

**Scenario 1: Load Team Members List**
```gherkin
Given: Store manager is logged in with uri_employees permission
And: Store ou00 has 10 active team members
When: Manager navigates to /admin/ou00/team-members
Then: Page loads within 2 seconds
And: DataTable displays 10 rows
And: Each row shows photo, name, position, status, and action buttons
```

**Scenario 2: Enable Login Access (Admin-Create)**
```gherkin
Given: Team member "John Smith" exists with canLogin=false
When: Manager toggles "Can Login" ON
And: Selects "Create credentials now"
And: Enters username "jsmith" and password "SecurePass123"
And: Clicks "Enable Login Access"
Then: User record updated with canLogin=true
And: Password is hashed with Argon2id
And: Audit log entry created
And: Row icons update to show login enabled
And: Toast shows "Login access enabled"
```

**Scenario 3: WhenIWork Sync Preserves PIN**
```gherkin
Given: Team member from WhenIWork has clockPin="1234"
When: Admin clicks "Sync from WhenIWork"
And: WhenIWork returns updated data for the team member
Then: Name, email, phone are updated from WhenIWork
But: clockPin remains "1234"
And: Sync summary shows "Updated: 1"
```

**Scenario 4: Deactivate Team Member with Login**
```gherkin
Given: Team member has canLogin=true and clockPin set
When: Manager clicks "Deactivate" from row actions
And: Confirms deactivation
Then: Store assignment isActive=false
But: User canLogin is unchanged
But: clockPin is unchanged
And: Team member hidden from default list view
And: Team member visible when "Show Inactive" filter enabled
```

---

## Glossary

### Domain Terms

| Term | Definition | Context |
|------|------------|---------|
| Team Member | A person associated with a store, regardless of login access | Replaces "Employee" in UI |
| Clock PIN | 4-6 digit code for time punch verification | Stored in userStoreAssignments |
| Store Assignment | Link between a user and a store with store-specific data | userStoreAssignments table |
| External Source | WhenIWork or Homebase sync origin | source field in users table |
| Homegrown | Manually created (not synced from external) | source='homegrown' |

### Technical Terms

| Term | Definition | Context |
|------|------------|---------|
| Unified Users | Central users table from spec 007 | Data source for all team members |
| canLogin | Boolean flag enabling system authentication | users.canLogin field |
| TypeNum | Store identifier pattern (e.g., ou00, pa00) | URL parameter for store context |
| DTOs | Data Transfer Objects for API responses | TeamMemberDTO, ActivityLogEntry |

---

## Document History

| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.0 | December 2025 | Claude | Initial SDD with comprehensive UI specifications |
