# Validation Report: URS-003

**Title:** Audit Log Tracking of All User Actions
**Date:** 2026-08-03T23:01:56.698Z
**Duration:** 53.8s
**Overall Status:** ✅ PASS

## User Requirement

> The system shall record user actions related to data creation and modification.

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

## Environment

- **Inbox URL:** http://localhost:44295
- **Database:** localhost:42015/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: Rep login — ✅ PASS

**What this step proves:**

The sales representative (Blair Bennett) authenticates using valid credentials. On successful login the client-side logEvent() helper writes a user_log row with action=user:login to the audit_events table. This is verified in the DB validation phase to confirm that every login event is captured regardless of user role.

**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:02:03Z | user_log | user:login | blair.bennett@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:02:11Z | user_log | user:login | blair.bennett@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:02:31Z | user_log | user:login | blair.bennett@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:02:48Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |

**Screenshots:**

![step 01 rep logged in](screenshots/step-01-rep-logged-in.png)

**Video recording:**

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

---

### 2. Step 2: Create order — ✅ PASS

**What this step proves:**

The rep navigates through the four-step order request wizard and submits a consignment order. The createOrderRequest service function calls logDecision with action=order_request_created and performed=true immediately after the INSERT, writing a synchronous audit row that proves the creation event. A separate decision:auto_approve_order row is written later by a delayed Restate handler once the ORDER_REQUEST_SUBMISSION_DELAY_MS grace window expires, and is therefore out of scope for this test's observation window.

**Audit events generated by this step:**

*(Evidence scoped to step execution window: 2026-08-03T23:02:19.400Z → 2026-08-03T23:02:26.791Z)*

| Time | Type | Action | User | Org | Performed |
|------|------|--------|------|-----|-----------|
| 2026-08-03 23:02:25Z | checklist | checklists.create | blair.bennett@corvetasurgical.com | Vantis | — |
| 2026-08-03 23:02:25Z | decision | order_request_created | blair.bennett@corvetasurgical.com | Vantis | yes |

**Screenshots:**

![step 02 order step2 account selected](screenshots/step-02-order-step2-account-selected.png)

![step 02 order step3 products](screenshots/step-02-order-step3-products.png)

![step 02 order step4 review](screenshots/step-02-order-step4-review.png)

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

**Video recording:**

[▶ Watch step recording](videos/step-02-create-order.webm)

---

### 3. Step 3: Edit order item — ✅ PASS

**What this step proves:**

The rep opens the newly created order and edits a line item quantity during the submission grace period. The editOrderRequestItem service function calls logDecision with action=update_order_request_item and performed=true, writing a synchronous audit row immediately. This confirms that data-modification events within an order are captured inline at the point of change.

**Audit events generated by this step:**

*(Evidence scoped to step execution window: 2026-08-03T23:02:36.637Z → 2026-08-03T23:02:44.277Z)*

| Time | Type | Action | User | Org | Performed |
|------|------|--------|------|-----|-----------|
| 2026-08-03 23:02:40Z | decision | update_order_request_item | blair.bennett@corvetasurgical.com | Vantis | yes |
| 2026-08-03 23:02:40Z | decision | reevaluate_order_request_issues | blair.bennett@corvetasurgical.com | Vantis | no |

**Screenshots:**

![step 03 order detail](screenshots/step-03-order-detail.png)

![step 03 edit dialog open](screenshots/step-03-edit-dialog-open.png)

![step 03 after edit](screenshots/step-03-after-edit.png)

**Video recording:**

[▶ Watch step recording](videos/step-03-edit-order.webm)

---

### 4. Step 4: Admin login — ✅ PASS

**What this step proves:**

The administrator (Dan Distributor) authenticates using valid credentials. The login event writes a user_log row with action=user:login to audit_events, identically to the rep's login in Step 1. This confirms that audit logging of authentication events is role-agnostic and applies uniformly to every authenticated user in the system.

**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:02:03Z | user_log | user:login | blair.bennett@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:02:11Z | user_log | user:login | blair.bennett@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:02:31Z | user_log | user:login | blair.bennett@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-08-03 23:02:48Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |

**Screenshots:**

![step 04 admin logged in](screenshots/step-04-admin-logged-in.png)

**Video recording:**

[▶ Watch step recording](videos/step-04-admin-login.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.

### audit_events table has the expected schema — ✅ PASS

**Assertion:** Table public.audit_events should expose at least: id, organization_id, user_id, event_type, action, object_id, payload, created_at

```sql
SELECT column_name
                 FROM information_schema.columns
                 WHERE table_schema = 'public' AND table_name = 'audit_events'
```

| column_name |
| --- |
| id |
| organization_id |
| user_id |
| contact_id |
| event_type |
| action |
| object_id |
| secondary_object_id |
| payload |
| route |
| trace_id |
| created_at |
| url |

### rep login was audited (Blair) — ✅ PASS

**Assertion:** Blair logging in should produce at least one user_log row with action=user:login.

```sql
SELECT id, action, event_type, user_id, organization_id, payload, created_at
                 FROM audit_events
                 WHERE created_at >= $1
                   AND user_id = $2
                   AND event_type = 'user_log'
                   AND action = 'user:login'
                 ORDER BY created_at ASC
```

| id | action | event_type | user_id | organization_id | payload | created_at |
| --- | --- | --- | --- | --- | --- | --- |
| 019fc9dc-e127-757f-94cb-8373c3b85f99 | user:login | user_log | 17b8c9d0-e1f2-3456-1234-567890123456 | b2c3d4e5-f6a7-8901-bcde-f12345678901 | `{"email":"blair.bennett@corvetasurgical.com"}` | 2026-08-03T23:02:03.964Z |
| 019fc9dc-fe2c-75b3-9975-246ac193c141 | user:login | user_log | 17b8c9d0-e1f2-3456-1234-567890123456 | b2c3d4e5-f6a7-8901-bcde-f12345678901 | `{"email":"blair.bennett@corvetasurgical.com"}` | 2026-08-03T23:02:11.288Z |
| 019fc9dd-4b64-73de-8a0e-0e4b6beaff98 | user:login | user_log | 17b8c9d0-e1f2-3456-1234-567890123456 | b2c3d4e5-f6a7-8901-bcde-f12345678901 | `{"email":"blair.bennett@corvetasurgical.com"}` | 2026-08-03T23:02:31.030Z |

### admin login was audited (Dan) — ✅ PASS

**Assertion:** Dan logging in should produce at least one user_log row with action=user:login.

```sql
SELECT id, action, event_type, user_id, organization_id, payload, created_at
                 FROM audit_events
                 WHERE created_at >= $1
                   AND user_id = $2
                   AND event_type = 'user_log'
                   AND action = 'user:login'
                 ORDER BY created_at ASC
```

| id | action | event_type | user_id | organization_id | payload | created_at |
| --- | --- | --- | --- | --- | --- | --- |
| 019fc9dd-8f6f-7229-9ef3-47731c198cbe | user:login | user_log | c3d4e5f6-a7b8-9012-cdef-123456789012 | b2c3d4e5-f6a7-8901-bcde-f12345678901 | `{"email":"dan.distributor@corvetasurgical.com"}` | 2026-08-03T23:02:48.464Z |

### order_request_created decision was audited for Blair — ✅ PASS

**Assertion:** Creating an order request should produce a decision audit_events row with action=order_request_created for the acting user.

```sql
SELECT id, action, event_type, user_id, object_id, payload, created_at
                 FROM audit_events
                 WHERE created_at >= $1
                   AND user_id = $2
                   AND event_type = 'decision'
                   AND action = 'order_request_created'
                 ORDER BY created_at DESC
```

| id | action | event_type | user_id | object_id | payload | created_at |
| --- | --- | --- | --- | --- | --- | --- |
| 019fc9dd-3468-7830-b8f9-8bbd3f0fb05d | order_request_created | decision | 17b8c9d0-e1f2-3456-1234-567890123456 | 019fc9dd-3464-75e0-be4e-951d2b8f2e19 | `{"reason":"Order request OR-1 created (importSource=manual)","priority":"normal","itemCount":1,"orderType":"dropship","performed":true,"entityType":"order_request","importSource":"manual","requestNumber":"OR-1","selfFulfilled":false,"resolvedLocationId":"6ea3b4c5-d6e7-8901-6789-012345678901","resolvedSalesAccountId":"fea7b8c9-d0e1-2345-0123-456789012345","fulfillingOrganizationId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","requestingOrganizationId":"b2c3d4e5-f6a7-8901-bcde-f12345678901"}` | 2026-08-03T23:02:25.063Z |

### update_order_request_item decision was audited for Blair — ✅ PASS

**Assertion:** Editing an order item should produce a decision audit_events row with action=update_order_request_item for the acting user.

```sql
SELECT id, action, event_type, user_id, object_id, payload, created_at
                 FROM audit_events
                 WHERE created_at >= $1
                   AND user_id = $2
                   AND event_type = 'decision'
                   AND action = 'update_order_request_item'
                 ORDER BY created_at DESC
```

| id | action | event_type | user_id | object_id | payload | created_at |
| --- | --- | --- | --- | --- | --- | --- |
| 019fc9dd-6fbc-7c57-a549-714768d12ec5 | update_order_request_item | decision | 17b8c9d0-e1f2-3456-1234-567890123456 | 019fc9dd-3464-75e0-be4e-951d2b8f2e19 | `{"reason":"Item quantity or notes updated during the submission grace period","performed":true,"entityType":"order_request"}` | 2026-08-03T23:02:40.213Z |

### audit rows for Blair have required fields populated — ✅ PASS

**Assertion:** Every audit_events row for Blair during the run should have non-null event_type and organization_id. (`created_at` is NOT NULL by schema constraint.)

```sql
SELECT id,
                        (event_type IS NULL)        AS missing_event_type,
                        (organization_id IS NULL)   AS missing_org
                 FROM audit_events
                 WHERE created_at >= $1
                   AND user_id = $2
                   AND (
                     event_type IS NULL OR
                     organization_id IS NULL
                   )
```

*No rows returned*

### no audit rows leaked to other organizations (test actors only) — ✅ PASS

**Assertion:** Audit rows written during the run by the test actors (Blair, Dan, Rana) must belong to one of the demo organizations (Vantis or Corveta).

```sql
SELECT id, organization_id, user_id, event_type, action, created_at
                 FROM audit_events
                 WHERE created_at >= $1
                   AND user_id = ANY($2::uuid[])
                   AND organization_id <> ALL($3::uuid[])
```

*No rows returned*

## 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: Rep login | `user_log:user:login` | ✅ |
| Step 2: Create order | `decision:order_request_created` | ✅ |
| Step 3: Edit order item | `decision:update_order_request_item` | ✅ |
| Step 4: Admin login | `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:01:54.936Z

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

8 event(s) captured:

| Time | Type | Action | User | Org | Object ID | Performed | Reason |
|------|------|--------|------|-----|-----------|-----------|--------|
| 2026-08-03 23:02:03Z | user_log | user:login | blair.bennett@corvetasurgical.com | Corveta Surgical Group | — | — |  |
| 2026-08-03 23:02:11Z | user_log | user:login | blair.bennett@corvetasurgical.com | Corveta Surgical Group | — | — |  |
| 2026-08-03 23:02:25Z | checklist | checklists.create | blair.bennett@corvetasurgical.com | Vantis | 019fc9dd-3483-73be-96c2-3f5a909d07e9 | — |  |
| 2026-08-03 23:02:25Z | decision | order_request_created | blair.bennett@corvetasurgical.com | Vantis | 019fc9dd-3464-75e0-be4e-951d2b8f2e19 | yes | Order request OR-1 created (importSource=manual) |
| 2026-08-03 23:02:31Z | user_log | user:login | blair.bennett@corvetasurgical.com | Corveta Surgical Group | — | — |  |
| 2026-08-03 23:02:40Z | decision | update_order_request_item | blair.bennett@corvetasurgical.com | Vantis | 019fc9dd-3464-75e0-be4e-951d2b8f2e19 | yes | Item quantity or notes updated during the submission grace period |
| 2026-08-03 23:02:40Z | decision | reevaluate_order_request_issues | blair.bennett@corvetasurgical.com | Vantis | 019fc9dd-3464-75e0-be4e-951d2b8f2e19 | no | Order request issues were unchanged after an edit |
| 2026-08-03 23:02:48Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — | — |  |
