# Validation Report: URS-034

**Title:** Export Order and Inventory History for Audits
**Date:** 2026-08-03T23:03:34.983Z
**Duration:** 59.7s
**Overall Status:** ✅ PASS

## User Requirement

> The system shall support exporting order and inventory history for audits.

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

## Environment

- **Inbox URL:** http://localhost:40997
- **Database:** localhost:32801/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 1: Exports page overview — ✅ PASS

**What this step proves:**

Logs in as an admin user (Dan Distributor) and navigates to the /exports page, confirming that export options for Orders and Inventory are visible to authorized users.

**Audit events generated by this step:**

*(Evidence matched by declared name — step timing not available or no events fell in window)*

| Time | Type | Action | User | Org | Performed |
|------|------|--------|------|-----|-----------|
| 2026-08-03 23:03:41Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:03:51Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:04:07Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:04:19Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:04:27Z | user_log | user:login | rana.reyes@corvetasurgical.com | Corveta Surgical Group | — |

**Screenshots:**

![step 01 exports page overview](screenshots/step-01-exports-page-overview.png)

![step 01 exports page all cards](screenshots/step-01-exports-page-all-cards.png)

**Video recording:**

[▶ Watch step recording](videos/step-01-exports-page.webm)

---

### 2. Step 2: Export order history — ✅ PASS

**What this step proves:**

Downloads the Orders CSV export, verifying that order history can be exported for audits and that the file contains the expected audit columns including order numbers, status, and creation dates. The download itself is audited: the endpoint writes an `export:orders` audit event capturing the acting user, timestamp, and the number of rows exported, so the act of exporting compliance data is itself traceable.

**Audit events generated by this step:**

*(Evidence scoped to step execution window: 2026-08-03T23:03:56.791Z → 2026-08-03T23:04:00.703Z)*

| Time | Type | Action | User | Org | Performed |
|------|------|--------|------|-----|-----------|
| 2026-08-03 23:03:57Z | export | export:orders | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |

**Screenshots:**

![step 02 before order export](screenshots/step-02-before-order-export.png)

![step 02 orders csv content](screenshots/step-02-orders-csv-content.png)

**Video recording:**

[▶ Watch step recording](videos/step-02-export-orders.webm)

---

### 3. Step 3: Order export verification — ✅ PASS

**What this step proves:**

Verifies the downloaded order CSV contains all required audit fields with non-empty values, confirming the export provides complete audit-ready data.

**Screenshots:**

![step 03 orders verification](screenshots/step-03-orders-verification.png)

**Video recording:**

[▶ Watch step recording](videos/step-03-verify-orders.webm)

---

### 4. Step 4: Export inventory — ✅ PASS

**What this step proves:**

Downloads the Inventory CSV export, verifying that inventory history is exportable for audits with the expected columns including location and quantity data. The download is audited: the endpoint writes an `export:inventory` audit event capturing the acting user, timestamp, and exported row count.

**Audit events generated by this step:**

*(Evidence matched by declared name — step timing not available or no events fell in window)*

| Time | Type | Action | User | Org | Performed |
|------|------|--------|------|-----|-----------|
| 2026-08-03 23:04:13Z | export | export:inventory | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |

**Screenshots:**

![step 04 after inventory export](screenshots/step-04-after-inventory-export.png)

![step 04 inventory csv content](screenshots/step-04-inventory-csv-content.png)

**Video recording:**

[▶ Watch step recording](videos/step-04-export-inventory.webm)

---

### 5. Step 5: Date range filtering — ✅ PASS

**What this step proves:**

Confirms that the date range filter on the orders export works correctly: a narrow historical range returns zero results while a wide range spanning the test data returns the expected records. Each filtered download writes its own `export:orders` audit event, and the applied `from`/`to` range is recorded in the event payload (`dateFrom`/`dateTo`) — proving that not only the export but the exact date window queried is captured for audit.

**Audit events generated by this step:**

*(Evidence matched by declared name — step timing not available or no events fell in window)*

| Time | Type | Action | User | Org | Performed |
|------|------|--------|------|-----|-----------|
| 2026-08-03 23:03:57Z | export | export:orders | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:04:20Z | export | export:orders | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:04:20Z | export | export:orders | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |

**Screenshots:**

![step 05 date range comparison](screenshots/step-05-date-range-comparison.png)

**Video recording:**

[▶ Watch step recording](videos/step-05-date-range-filter.webm)

---

### 6. Step 6: Permission restriction — ✅ PASS

**What this step proves:**

Logs in as Rana Reyes (Sales Rep without export permissions) and verifies that the /exports page and the direct CSV endpoint deny access, enforcing role-based export access control.

**Audit events generated by this step:**

*(Evidence matched by declared name — step timing not available or no events fell in window)*

| Time | Type | Action | User | Org | Performed |
|------|------|--------|------|-----|-----------|
| 2026-08-03 23:03:41Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:03:51Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:04:07Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:04:19Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:04:27Z | user_log | user:login | rana.reyes@corvetasurgical.com | Corveta Surgical Group | — |

**Screenshots:**

![step 06 rep exports restricted](screenshots/step-06-rep-exports-restricted.png)

**Video recording:**

[▶ Watch step recording](videos/step-06-permission-restriction.webm)

---

## 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.

### Exports feature flag enabled — ✅ PASS

**Assertion:** The "exports" feature flag should be enabled for Corveta

```sql
SELECT id, value FROM feature_flags
      WHERE id = 'exports' AND organization_id = $1
```

| id | value |
| --- | --- |
| exports | true |

### Admin role has exports:access — ✅ PASS

**Assertion:** The Corveta Admin role should have exports:access permission

```sql
SELECT p.permission FROM permissions p
      WHERE p.actor_id = $1 AND p.permission = 'exports:access'
```

| permission |
| --- |
| exports:access |

### Sales rep role lacks exports:access — ✅ PASS

**Assertion:** The Sales Rep role should NOT have exports:access permission

```sql
SELECT p.permission FROM permissions p
      WHERE p.actor_id = $1 AND p.permission = 'exports:access'
```

*No rows returned*

### Order requests exist for organization — ✅ PASS

**Assertion:** At least one order request should exist for Corveta

```sql
SELECT COUNT(*) as count,
        MIN(created_at) as oldest_order,
        MAX(created_at) as newest_order
      FROM order_requests
      WHERE requesting_organization_id = $1 OR fulfilling_organization_id = $1
```

| count | oldest_order | newest_order |
| --- | --- | --- |
| 3 | 2026-07-04T23:03:35.017Z | 2026-07-29T23:03:35.017Z |

### Inventory items exist for organization — ✅ PASS

**Assertion:** At least one inventory item with positive quantity should exist for Corveta

```sql
SELECT COUNT(*) as count
      FROM inventory_items
      WHERE organization_id = $1
        AND (quantity_ready > 0 OR quantity_backordered > 0 OR quantity_in_transit > 0)
```

| count |
| --- |
| 13 |

### Admin user has Admin role — ✅ PASS

**Assertion:** Dan Distributor should have the Admin role for Corveta

```sql
SELECT u.email, u.name, r.name as role_name, r.id as role_id
      FROM users u
      JOIN user_roles ur ON ur.user_id = u.id
      JOIN roles r ON r.id = ur.role_id
      WHERE u.id = $1 AND ur.organization_id = $2
```

| email | name | role_name | role_id |
| --- | --- | --- | --- |
| dan.distributor@corvetasurgical.com | Dan Distributor | Corveta Admin | 40e1f2a3-b4c5-6789-4567-890123456789 |

### Orders export download is audited — ✅ PASS

**Assertion:** Downloading the orders CSV should write an "export:orders" audit event capturing the acting user, row count, and any date range applied

```sql
SELECT ae.created_at,
        ae.action,
        u.email AS user_email,
        ae.payload->>'exportType' AS export_type,
        ae.payload->>'rowCount' AS row_count,
        ae.payload->>'dateFrom' AS date_from,
        ae.payload->>'dateTo' AS date_to
      FROM audit_events ae
      LEFT JOIN users u ON u.id = ae.user_id
      WHERE ae.organization_id = $1
        AND ae.event_type = 'export'
        AND ae.action = 'export:orders'
        AND ae.created_at >= NOW() - INTERVAL '30 minutes'
      ORDER BY ae.created_at DESC
      LIMIT 10
```

| created_at | action | user_email | export_type | row_count | date_from | date_to |
| --- | --- | --- | --- | --- | --- | --- |
| 2026-08-03T23:04:20.713Z | export:orders | dan.distributor@corvetasurgical.com | orders | 4 | 2024-08-03 | 2026-08-03 |
| 2026-08-03T23:04:20.681Z | export:orders | dan.distributor@corvetasurgical.com | orders | 0 | 2020-01-01 | 2020-01-02 |
| 2026-08-03T23:03:57.403Z | export:orders | dan.distributor@corvetasurgical.com | orders | 4 | 2026-05-03 | 2026-08-03 |

### Inventory export download is audited — ✅ PASS

**Assertion:** Downloading the inventory CSV should write an "export:inventory" audit event capturing the acting user and row count

```sql
SELECT ae.created_at,
        ae.action,
        u.email AS user_email,
        ae.payload->>'exportType' AS export_type,
        ae.payload->>'rowCount' AS row_count
      FROM audit_events ae
      LEFT JOIN users u ON u.id = ae.user_id
      WHERE ae.organization_id = $1
        AND ae.event_type = 'export'
        AND ae.action = 'export:inventory'
        AND ae.created_at >= NOW() - INTERVAL '30 minutes'
      ORDER BY ae.created_at DESC
      LIMIT 10
```

| created_at | action | user_email | export_type | row_count |
| --- | --- | --- | --- | --- |
| 2026-08-03T23:04:13.400Z | export:inventory | dan.distributor@corvetasurgical.com | inventory | 13 |

## Audit & Email Assertion Ledger

Per-declaration outcome of every `expectedAuditActions` and `expectedEmailTemplates` entry written into the orchestrator. Missing evidence here is a real test failure, not a soft warning.

### Audit Action Assertions

Each row asserts that a declared `expectedAuditActions` entry produced a matching row in `audit_events`. A ❌ flips overall status to FAIL — the declaration is real proof, not just an annotation.

| Step | Expected Audit Action | Found |
|------|-----------------------|-------|
| Step 1: Exports page overview | `user_log:user:login` | ✅ |
| Step 2: Export order history | `export:export:orders` | ✅ |
| Step 4: Export inventory | `export:export:inventory` | ✅ |
| Step 5: Date range filtering | `export:export:orders` | ✅ |
| Step 6: Permission restriction | `user_log:user:login` | ✅ |

## 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-08-03T23:03:33.098Z

<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>

9 event(s) captured:

| Time | Type | Action | User | Org | Object ID | Performed | Reason |
|------|------|--------|------|-----|-----------|-----------|--------|
| 2026-08-03 23:03:41Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — | — |  |
| 2026-08-03 23:03:51Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — | — |  |
| 2026-08-03 23:03:57Z | export | export:orders | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — | — |  |
| 2026-08-03 23:04:07Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — | — |  |
| 2026-08-03 23:04:13Z | export | export:inventory | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — | — |  |
| 2026-08-03 23:04:19Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — | — |  |
| 2026-08-03 23:04:20Z | export | export:orders | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — | — |  |
| 2026-08-03 23:04:20Z | export | export:orders | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — | — |  |
| 2026-08-03 23:04:27Z | user_log | user:login | rana.reyes@corvetasurgical.com | Corveta Surgical Group | — | — |  |
