# Validation Report: URS-008

**Title:** Restrict Reps from Editing Accounts Outside Assigned Organization
**Date:** 2026-04-23T03:35:29.564Z
**Duration:** 44.4s
**Overall Status:** ✅ PASS

## User Requirement

> The system shall restrict reps from editing accounts outside their assigned organization.

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

## Environment

- **Inbox URL:** http://localhost:62393
- **Database:** localhost:62394/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:**

Establishes the authenticated session for Bob Kauffman (StellarTech sales rep, role downgraded by setup). A successful login is the precondition for every subsequent step — without it, cross-organization failures would be indistinguishable from an unauthenticated redirect.

**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-04-23 03:35:35Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:35:40Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:35:48Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:35:57Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:36:08Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |

**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: Foreign-org account absent from list — ✅ PASS

**What this step proves:**

Navigates to /sales-accounts and asserts that the foreign-organization account's name and UUID do not appear anywhere on the page. The list query filters by the caller's organization, so a StellarTech rep must see only StellarTech-owned accounts. Proving absence-from-list closes the first half of the isolation story: the foreign account cannot be discovered through the app's normal navigation.

**Screenshots:**

![step 02 rep accounts list](screenshots/step-02-rep-accounts-list.png)

**Video recording:**

[▶ Watch step recording](videos/step-02-rep-accounts-list.webm)

---

### 3. Step 3: In-organization account detail loads — ✅ PASS

**What this step proves:**

Loads the BOSS account detail page — BOSS is owned by Bob's own organization (StellarTech). Confirming this page renders normally rules out the scenario where the Step 4 failure is caused by a broad access bug. It is the "negative control" that bounds the cross-org check.

**Screenshots:**

![step 03 in org account detail](screenshots/step-03-in-org-account-detail.png)

**Video recording:**

[▶ Watch step recording](videos/step-03-rep-in-org-account.webm)

---

### 4. Step 4: Rep receives 404 on foreign-org account URL — ✅ PASS

**What this step proves:**

Navigates the rep directly to the foreign-organization account URL. The server-side route resolves through `getSalesAccountWithOrgCheck`, which returns null when the user's organization matches neither the account's distributor nor manufacturer; the route then throws a 404. Asserting both the HTTP status and the rendered error text proves the block is enforced on the server, not only in the UI.

**Screenshots:**

![step 04 rep foreign org 404](screenshots/step-04-rep-foreign-org-404.png)

**Video recording:**

[▶ Watch step recording](videos/step-04-rep-foreign-org-404.webm)

---

### 5. Step 5: Admin also blocked — org-scoped, not role-scoped — ✅ PASS

**What this step proves:**

Repeats Step 4 as Dan Distributor (StellarTech admin). The admin has sales_accounts:manage but is still in StellarTech, so the organization filter must still return null and the route must still 404. Proving this isolates the restriction as organization-scoped — the URS requirement is met by organization membership, not by 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-04-23 03:35:35Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:35:40Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:35:48Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:35:57Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:36:08Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |

**Screenshots:**

![step 05 admin foreign org 404](screenshots/step-05-admin-foreign-org-404.png)

**Video recording:**

[▶ Watch step recording](videos/step-05-admin-foreign-org-404.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.

### Rep has Sales Representative role — ✅ PASS

**Assertion:** Bob Kauffman should have the Sales Representative role in StellarTech so the test exercises a "rep" per the URS wording

```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 |
| --- | --- | --- | --- |
| bob.kauffman@stellartech.com | Bob Kauffman | Sales Representative | d2e3f4a5-b6c7-8901-def0-123456789abc |

### Sales Rep role has sales_accounts:view — ✅ PASS

**Assertion:** The Sales Representative role must include sales_accounts:view so that absence-from-list is an organization scoping effect, not a permission gap

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

| permission |
| --- |
| sales_accounts:view |

### Rep belongs only to StellarTech — ✅ PASS

**Assertion:** Bob Kauffman must have exactly one organization membership — StellarTech — so visiting the foreign-owned account cannot succeed via a second membership

```sql
SELECT ur.organization_id, o.name
      FROM user_roles ur
      JOIN organizations o ON o.id = ur.organization_id
      WHERE ur.user_id = $1
```

| organization_id | name |
| --- | --- |
| b2c3d4e5-f6a7-8901-bcde-f12345678901 | StellarTech Medical Solutions |

### Foreign distributor organization exists — ✅ PASS

**Assertion:** The ephemeral foreign organization inserted by setup must exist and be distinct from StellarTech, providing the target for the cross-org isolation proof

```sql
SELECT id, name, active FROM organizations WHERE id = $1
```

| id | name | active |
| --- | --- | --- |
| f0f0f0f0-0008-4f00-af00-000000000008 | Acme Distribution Partners (URS-008 Fixture) | true |

### Foreign sales account owned entirely by foreign org — ✅ PASS

**Assertion:** The foreign sales account must set organization_id, distributor_organization_id, and manufacturer_organization_id all to the foreign org — no StellarTech linkage exists on any scoping column

```sql
SELECT id, name, status,
        organization_id,
        distributor_organization_id,
        manufacturer_organization_id
      FROM sales_accounts
      WHERE id = $1
```

| id | name | status | organization_id | distributor_organization_id | manufacturer_organization_id |
| --- | --- | --- | --- | --- | --- |
| f0f0f0f0-0008-4f00-acc0-000000000008 | Acme Diagnostics Center | active | f0f0f0f0-0008-4f00-af00-000000000008 | f0f0f0f0-0008-4f00-af00-000000000008 | f0f0f0f0-0008-4f00-af00-000000000008 |

### Rep has no assignment to foreign sales account — ✅ PASS

**Assertion:** Bob Kauffman must not have any assignment row — active or inactive — linking him to the foreign-owned sales account

```sql
SELECT id, active, representative_type, organization_id
      FROM sales_account_user_assignments
      WHERE user_id = $1 AND sales_account_id = $2
```

*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 5: Admin also blocked — org-scoped, not role-scoped | `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-04-23T03:35:27.651Z

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

5 event(s) captured:

| Time | Type | Action | User | Org | Object ID | Performed | Reason |
|------|------|--------|------|-----|-----------|-----------|--------|
| 2026-04-23 03:35:35Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:35:40Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:35:48Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:35:57Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:36:08Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — | — |  |
