# Validation Report: URS-036

**Title:** Mobile device support
**Date:** 2026-04-23T03:41:37.043Z
**Duration:** 123.6s
**Overall Status:** ✅ PASS

## User Requirement

> The system shall support access and use on mobile devices.

*Source: `User_Requirement_Specifications_ZuriMED_DeviceFlow.xlsx` — the run below proves the system meets this requirement.*

## Environment

- **Inbox URL:** http://localhost:64265
- **Database:** localhost:64266/cc_repinbox_dev

## Setup

Status: ✅ PASS

## Test Steps

Each step below corresponds to one Playwright test that ran sequentially. Screenshots and video recordings provide visual evidence of the UI behaviour.

### 1. Step 1a: Login form on iPhone 12 (empty) — ✅ PASS

**What this step proves:**

Confirms the login form is rendered and accessible on an iPhone 12 viewport (390×844 px) before credentials are entered. Verifies the form fields are visible and that no horizontal scroll occurs at the phone viewport width.

**Screenshots:**

![step 01 iphone 12 login empty](screenshots/step-01-iphone-12-login-empty.png)

**Video recording:**

[▶ Watch step recording](videos/step-01-iphone-12-login.webm)

---

### 2. Step 1b: Login form on iPhone 12 (filled) — ✅ PASS

**What this step proves:**

Shows the login form with credentials filled in, immediately before the submit button is tapped. Confirms all fields are reachable and readable on a mobile viewport.

**Screenshots:**

![step 01 iphone 12 login filled](screenshots/step-01-iphone-12-login-filled.png)

---

### 3. Step 1c: Home page on iPhone 12 after login — ✅ PASS

**What this step proves:**

Confirms a successful login redirected the browser away from /login and that the post-login home page renders without horizontal overflow on the iPhone 12 viewport.

**Screenshots:**

![step 01 iphone 12 home](screenshots/step-01-iphone-12-home.png)

---

### 4. Step 2a: Navigation drawer open on iPhone 12 — ✅ PASS

**What this step proves:**

Taps the hamburger menu button to open the mobile navigation drawer, then captures the full open state. Proves the primary navigation destinations are reachable by touch on a 390×844 px phone viewport.

**Screenshots:**

![step 02 drawer open iphone 12](screenshots/step-02-drawer-open-iphone-12.png)

**Video recording:**

[▶ Watch step recording](videos/step-02-nav-drawer.webm)

---

### 5. Step 2b: Billing page after drawer navigation — ✅ PASS

**What this step proves:**

Taps the Bill-Only nav link inside the open drawer and confirms the app routes to /billing. Also confirms the drawer auto-closes after navigation, matching the NavigationSidebar setOpenMobile(false) behavior.

**Screenshots:**

![step 02 billing after nav](screenshots/step-02-billing-after-nav.png)

---

### 6. Step 3a: Accounts cards on iPhone 12 — ✅ PASS

**What this step proves:**

Confirms the /sales-accounts page renders a vertical card list (not a table) on the iPhone 12 viewport. Asserts the three seeded ZuriMED account names appear inside the mobile-only card container and that no horizontal scroll is present.

**Screenshots:**

![step 03 accounts cards iphone 12](screenshots/step-03-accounts-cards-iphone-12.png)

**Video recording:**

[▶ Watch step recording](videos/step-03-accounts-mobile-cards.webm)

---

### 7. Step 3b: Account detail on iPhone 12 — ✅ PASS

**What this step proves:**

Taps a mobile card link and confirms the app navigates to the account detail page. Verifies the detail page loads without horizontal overflow on a phone viewport.

**Screenshots:**

![step 03 account detail iphone 12](screenshots/step-03-account-detail-iphone-12.png)

---

### 8. Step 4a: Billing cards on iPhone 12 — ✅ PASS

**What this step proves:**

Confirms the /billing page renders all four seeded Bill-Only Orders as tappable links on the iPhone 12 viewport, and that no horizontal scroll is present.

**Screenshots:**

![step 04 billing cards iphone 12](screenshots/step-04-billing-cards-iphone-12.png)

**Video recording:**

[▶ Watch step recording](videos/step-04-billing-mobile-cards.webm)

---

### 9. Step 4b: Billing detail on iPhone 12 — ✅ PASS

**What this step proves:**

Taps a billing card link and confirms the app navigates to the order detail page. Verifies the detail page loads without horizontal overflow on a phone viewport.

**Screenshots:**

![step 04 billing detail iphone 12](screenshots/step-04-billing-detail-iphone-12.png)

---

### 10. Step 5a: iPhone 12 /billing?filter=all — ✅ PASS

**What this step proves:**

Verifies the /billing page renders without horizontal overflow on iPhone 12 (390×844 px). Part of the full-matrix no-horizontal-scroll sweep covering all four phone profiles.

**Screenshots:**

![step 05 iphone 12 billing filter all](screenshots/step-05-iphone-12-billing-filter-all.png)

**Video recording:**

[▶ Watch step recording](videos/step-05-galaxy-s21-no-hscroll.webm)

---

### 11. Step 5b: iPhone 12 /sales-accounts — ✅ PASS

**What this step proves:**

Verifies the /sales-accounts page renders without horizontal overflow on iPhone 12 (390×844 px). Part of the full-matrix no-horizontal-scroll sweep.

**Screenshots:**

![step 05 iphone 12 sales accounts](screenshots/step-05-iphone-12-sales-accounts.png)

**Video recording:**

[▶ Watch step recording](videos/step-05-iphone-12-no-hscroll.webm)

---

### 12. Step 5c: iPhone 12 /orders/requests — ✅ PASS

**What this step proves:**

Verifies the /orders/requests page renders without horizontal overflow on iPhone 12 (390×844 px). Covers the order-request queue a field rep reaches from the mobile drawer.

**Screenshots:**

![step 05 iphone 12 orders requests](screenshots/step-05-iphone-12-orders-requests.png)

**Video recording:**

[▶ Watch step recording](videos/step-05-iphone-se-no-hscroll.webm)

---

### 13. Step 5d: iPhone 12 /packages — ✅ PASS

**What this step proves:**

Verifies the /packages page renders without horizontal overflow on iPhone 12 (390×844 px). Uses the DataTable mobile-row layout below the md breakpoint.

**Screenshots:**

![step 05 iphone 12 packages](screenshots/step-05-iphone-12-packages.png)

**Video recording:**

[▶ Watch step recording](videos/step-05-pixel-5-no-hscroll.webm)

---

### 14. Step 5e: iPhone 12 /inventory — ✅ PASS

**What this step proves:**

Verifies the /inventory page renders without horizontal overflow on iPhone 12 (390×844 px). Uses the DataTable mobile-row layout below the md breakpoint.

**Screenshots:**

![step 05 iphone 12 inventory](screenshots/step-05-iphone-12-inventory.png)

---

### 15. Step 5f: iPhone SE /billing?filter=all — ✅ PASS

**What this step proves:**

Verifies the /billing page renders without horizontal overflow on iPhone SE (375×667 px), the narrowest iOS viewport in the test matrix.

**Screenshots:**

![step 05 iphone se billing filter all](screenshots/step-05-iphone-se-billing-filter-all.png)

---

### 16. Step 5g: iPhone SE /sales-accounts — ✅ PASS

**What this step proves:**

Verifies the /sales-accounts page renders without horizontal overflow on iPhone SE (375×667 px), the narrowest iOS viewport in the test matrix.

**Screenshots:**

![step 05 iphone se sales accounts](screenshots/step-05-iphone-se-sales-accounts.png)

---

### 17. Step 5h: iPhone SE /orders/requests — ✅ PASS

**What this step proves:**

Verifies the /orders/requests page renders without horizontal overflow on iPhone SE (375×667 px), the narrowest iOS viewport in the test matrix.

**Screenshots:**

![step 05 iphone se orders requests](screenshots/step-05-iphone-se-orders-requests.png)

---

### 18. Step 5i: iPhone SE /packages — ✅ PASS

**What this step proves:**

Verifies the /packages page renders without horizontal overflow on iPhone SE (375×667 px), the narrowest iOS viewport in the test matrix.

**Screenshots:**

![step 05 iphone se packages](screenshots/step-05-iphone-se-packages.png)

---

### 19. Step 5j: iPhone SE /inventory — ✅ PASS

**What this step proves:**

Verifies the /inventory page renders without horizontal overflow on iPhone SE (375×667 px), the narrowest iOS viewport in the test matrix.

**Screenshots:**

![step 05 iphone se inventory](screenshots/step-05-iphone-se-inventory.png)

---

### 20. Step 5k: Android Pixel 5 /billing?filter=all — ✅ PASS

**What this step proves:**

Verifies the /billing page renders without horizontal overflow on Android Pixel 5 (432×864 px). Tests responsive layout on an Android Chrome user agent.

**Screenshots:**

![step 05 pixel 5 billing filter all](screenshots/step-05-pixel-5-billing-filter-all.png)

---

### 21. Step 5l: Android Pixel 5 /sales-accounts — ✅ PASS

**What this step proves:**

Verifies the /sales-accounts page renders without horizontal overflow on Android Pixel 5 (432×864 px). Tests responsive layout on an Android Chrome user agent.

**Screenshots:**

![step 05 pixel 5 sales accounts](screenshots/step-05-pixel-5-sales-accounts.png)

---

### 22. Step 5m: Android Pixel 5 /orders/requests — ✅ PASS

**What this step proves:**

Verifies the /orders/requests page renders without horizontal overflow on Android Pixel 5 (432×864 px). Tests responsive layout on an Android Chrome user agent.

**Screenshots:**

![step 05 pixel 5 orders requests](screenshots/step-05-pixel-5-orders-requests.png)

---

### 23. Step 5n: Android Pixel 5 /packages — ✅ PASS

**What this step proves:**

Verifies the /packages page renders without horizontal overflow on Android Pixel 5 (432×864 px). Tests responsive layout on an Android Chrome user agent.

**Screenshots:**

![step 05 pixel 5 packages](screenshots/step-05-pixel-5-packages.png)

---

### 24. Step 5o: Android Pixel 5 /inventory — ✅ PASS

**What this step proves:**

Verifies the /inventory page renders without horizontal overflow on Android Pixel 5 (432×864 px). Tests responsive layout on an Android Chrome user agent.

**Screenshots:**

![step 05 pixel 5 inventory](screenshots/step-05-pixel-5-inventory.png)

---

### 25. Step 5p: Android Galaxy S21 /billing?filter=all — ✅ PASS

**What this step proves:**

Verifies the /billing page renders without horizontal overflow on Android Galaxy S21 (360×800 px), the narrowest viewport in the full mobile matrix.

**Screenshots:**

![step 05 galaxy s21 billing filter all](screenshots/step-05-galaxy-s21-billing-filter-all.png)

---

### 26. Step 5q: Android Galaxy S21 /sales-accounts — ✅ PASS

**What this step proves:**

Verifies the /sales-accounts page renders without horizontal overflow on Android Galaxy S21 (360×800 px), the narrowest viewport in the full mobile matrix.

**Screenshots:**

![step 05 galaxy s21 sales accounts](screenshots/step-05-galaxy-s21-sales-accounts.png)

---

### 27. Step 5r: Android Galaxy S21 /orders/requests — ✅ PASS

**What this step proves:**

Verifies the /orders/requests page renders without horizontal overflow on Android Galaxy S21 (360×800 px), the narrowest viewport in the full mobile matrix.

**Screenshots:**

![step 05 galaxy s21 orders requests](screenshots/step-05-galaxy-s21-orders-requests.png)

---

### 28. Step 5s: Android Galaxy S21 /packages — ✅ PASS

**What this step proves:**

Verifies the /packages page renders without horizontal overflow on Android Galaxy S21 (360×800 px), the narrowest viewport in the full mobile matrix.

**Screenshots:**

![step 05 galaxy s21 packages](screenshots/step-05-galaxy-s21-packages.png)

---

### 29. Step 5t: Android Galaxy S21 /inventory — ✅ PASS

**What this step proves:**

Verifies the /inventory page renders without horizontal overflow on Android Galaxy S21 (360×800 px), the narrowest viewport in the full mobile matrix.

**Screenshots:**

![step 05 galaxy s21 inventory](screenshots/step-05-galaxy-s21-inventory.png)

---

### 30. Step 6a: Touch targets on /billing?filter=all — ✅ PASS

**What this step proves:**

Measures every visible interactive element inside <main> on /billing on the iPhone 12 viewport and records each element's bounding box. Fails if any element's width AND height both fall below the 24 px hard minimum from WCAG 2.5.8 Target Size (Minimum). Elements below the 44 px Apple HIG recommendation are logged for review but do not fail the step.

**Screenshots:**

![step 06 touch targets billing filter all](screenshots/step-06-touch-targets-billing-filter-all.png)

**Video recording:**

[▶ Watch step recording](videos/step-06-touch-targets.webm)

---

### 31. Step 6b: Touch targets on /sales-accounts — ✅ PASS

**What this step proves:**

Measures every visible interactive element inside <main> on /sales-accounts on the iPhone 12 viewport. Fails if any element falls below the 24 px WCAG 2.5.8 hard minimum on both axes.

**Screenshots:**

![step 06 touch targets sales accounts](screenshots/step-06-touch-targets-sales-accounts.png)

---

### 32. Step 6c: Touch targets on /orders/requests — ✅ PASS

**What this step proves:**

Measures every visible interactive element inside <main> on /orders/requests on the iPhone 12 viewport. Fails if any element falls below the 24 px WCAG 2.5.8 hard minimum on both axes.

**Screenshots:**

![step 06 touch targets orders requests](screenshots/step-06-touch-targets-orders-requests.png)

---

### 33. Step 6d: Touch targets on /packages — ✅ PASS

**What this step proves:**

Measures every visible interactive element inside <main> on /packages on the iPhone 12 viewport. Fails if any element falls below the 24 px WCAG 2.5.8 hard minimum on both axes.

**Screenshots:**

![step 06 touch targets packages](screenshots/step-06-touch-targets-packages.png)

---

### 34. Step 6e: Touch targets on /inventory — ✅ PASS

**What this step proves:**

Measures every visible interactive element inside <main> on /inventory on the iPhone 12 viewport. Fails if any element falls below the 24 px WCAG 2.5.8 hard minimum on both axes.

**Screenshots:**

![step 06 touch targets inventory](screenshots/step-06-touch-targets-inventory.png)

---

### 35. Step 7a: Pixel 5 billing — ✅ PASS

**What this step proves:**

Smoke test on Android Pixel 5: navigates to /billing after login and confirms the first seeded order is visible without horizontal overflow. Console errors are captured and fail the step if any are found.

**Screenshots:**

![step 07 pixel 5 billing](screenshots/step-07-pixel-5-billing.png)

**Video recording:**

[▶ Watch step recording](videos/step-07-pixel-5-smoke.webm)

---

### 36. Step 7b: Pixel 5 accounts — ✅ PASS

**What this step proves:**

Smoke test on Android Pixel 5: navigates to /sales-accounts and confirms the BOSS account card is visible inside the mobile-only wrapper without horizontal overflow.

**Screenshots:**

![step 07 pixel 5 accounts](screenshots/step-07-pixel-5-accounts.png)

---

## Database Validations

The following SQL queries ran against the application database after the Playwright scenarios completed. Each query asserts a specific condition that proves the feature under test persisted its data correctly.

### Login user alex.admin@zurimed.com exists — ✅ PASS

**Assertion:** Exactly one user with id=alexAdmin should be seeded

```sql

    SELECT id, email, name
      FROM users
     WHERE id = $1
```

| id | email | name |
| --- | --- | --- |
| f6a7b8c9-d0e1-2345-f123-456789012345 | alex.admin@zurimed.com | Alex Admin |

### At least 4 seeded billing orders exist — ✅ PASS

**Assertion:** >= 4 ZBO-2025-* orders should be seeded by zurimedDemo

```sql

    SELECT order_number, status
      FROM billing_orders
     WHERE order_number = ANY($1)
     ORDER BY order_number
```

| order_number | status |
| --- | --- |
| ZBO-2025-001 | draft |
| ZBO-2025-002 | submitted |
| ZBO-2025-003 | invoice_sent |
| ZBO-2025-004 | invoice_voided |

### At least 3 active ZuriMED sales accounts exist — ✅ PASS

**Assertion:** >= 3 active sales_accounts rows for ZuriMED

```sql

    SELECT id, name, status
      FROM sales_accounts
     WHERE manufacturer_organization_id = $1 AND status = 'active'
     ORDER BY name
```

| id | name | status |
| --- | --- | --- |
| fea7b8c9-d0e1-2345-0123-456789012345 | BOSS Surgical Account Request | active |
| 2ac9d0e1-f2a3-4567-2345-678901234567 | Connecticut Ortho Account Request | active |
| 1fb8c9d0-e1f2-3456-1234-567890123456 | Copley Hospital Account Request | active |

### At least 8 ZuriMED products exist — ✅ PASS

**Assertion:** >= 8 products rows for ZuriMED

```sql

    SELECT count(*)::int AS product_count
      FROM org_products
     WHERE organization_id = $1
```

| product_count |
| --- |
| 12 |

## Audit Log Events

Every row written to `audit_events` while this test was running (scoped to the demo organizations). Provides compliance evidence that user actions are traced end-to-end (URS-003).

**Capture window start:** 2026-04-23T03:41:35.107Z

<details><summary>Query used to capture events</summary>

```sql
SELECT
    ae.created_at,
    ae.event_type,
    ae.action,
    ae.user_id,
    u.email AS user_email,
    ae.organization_id,
    o.name AS organization_name,
    ae.object_id,
    ae.secondary_object_id,
    ae.payload,
    ae.route,
    ae.trace_id
  FROM audit_events ae
  LEFT JOIN users u ON u.id = ae.user_id
  LEFT JOIN organizations o ON o.id = ae.organization_id
  WHERE ae.created_at >= $1
    AND ae.organization_id = ANY($2::uuid[])
  ORDER BY ae.created_at ASC
```
</details>

10 event(s) captured:

| Time | Type | Action | User | Org | Object ID | Performed | Reason |
|------|------|--------|------|-----|-----------|-----------|--------|
| 2026-04-23 03:41:45Z | user_log | user:login | alex.admin@zurimed.com | ZuriMED | — | — |  |
| 2026-04-23 03:41:46Z | user_log | user:login | alex.admin@zurimed.com | ZuriMED | — | — |  |
| 2026-04-23 03:41:57Z | user_log | user:login | alex.admin@zurimed.com | ZuriMED | — | — |  |
| 2026-04-23 03:42:04Z | user_log | user:login | alex.admin@zurimed.com | ZuriMED | — | — |  |
| 2026-04-23 03:42:13Z | user_log | user:login | alex.admin@zurimed.com | ZuriMED | — | — |  |
| 2026-04-23 03:42:29Z | user_log | user:login | alex.admin@zurimed.com | ZuriMED | — | — |  |
| 2026-04-23 03:42:45Z | user_log | user:login | alex.admin@zurimed.com | ZuriMED | — | — |  |
| 2026-04-23 03:43:00Z | user_log | user:login | alex.admin@zurimed.com | ZuriMED | — | — |  |
| 2026-04-23 03:43:16Z | user_log | user:login | alex.admin@zurimed.com | ZuriMED | — | — |  |
| 2026-04-23 03:43:36Z | user_log | user:login | alex.admin@zurimed.com | ZuriMED | — | — |  |
