# Validation Report: URS-002

**Title:** Role-Based Access Control (Rep, Principal, Admin)
**Date:** 2026-04-23T03:33:42.056Z
**Duration:** 110.0s
**Overall Status:** ✅ PASS

## User Requirement

> The system shall enforce role‑based access control (such as, rep, principal, admin).

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

## Environment

- **Inbox URL:** http://localhost:61668
- **Database:** localhost:61669/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: Sales Rep login and navigation menu — ✅ PASS

**What this step proves:**

The Sales Representative role logs in and the sidebar navigation is inspected. Only items the role has permission to access are visible; administrative items such as Settings and Billing are hidden. This confirms that the application enforces role-based navigation visibility server-side.

**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:33:49Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:33:56Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:04Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:12Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:21Z | user_log | user:login | ryan.delauintana@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:28Z | user_log | user:login | ryan.delauintana@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:36Z | user_log | user:login | ryan.delauintana@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:43Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:51Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:59Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:35:12Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:35:26Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |

**Screenshots:**

![step 01 sales rep navigation](screenshots/step-01-sales-rep-navigation.png)

**Video recording:**

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

---

### 2. Step 2: Sales Rep can view orders — ✅ PASS

**What this step proves:**

The Sales Rep navigates to the Orders page and it loads successfully without an error page. This confirms that the Sales Representative role includes the order-viewing permission and that permitted routes are accessible.

**Screenshots:**

![step 02 sales rep orders](screenshots/step-02-sales-rep-orders.png)

**Video recording:**

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

---

### 3. Step 3: Sales Rep denied access to Role Management — ✅ PASS

**What this step proves:**

The Sales Rep attempts to navigate directly to /settings/roles by URL, bypassing the hidden navigation link. The test captures the HTTP response status from the initial navigation and accepts either of the two legitimate server-side denial mechanisms: (a) the route loader renders an "Error Encountered" page because the org:manage_roles permission check failed, or (b) the request is redirected to /login because the auth guard invalidated the session. The screencast chapter for this step records which mechanism fired (and the observed HTTP status). Either response proves server-side enforcement, not just link hiding.

**Screenshots:**

![step 03 sales rep roles denied](screenshots/step-03-sales-rep-roles-denied.png)

**Video recording:**

[▶ Watch step recording](videos/step-03-sales-rep-roles-denied.webm)

---

### 4. Step 4: Sales Rep denied access to Billing — ✅ PASS

**What this step proves:**

The Sales Rep attempts to navigate directly to /billing by URL. The test captures the HTTP response status and accepts either the error-page or login-redirect denial mechanism. The screencast chapter records the observed mechanism and status. This confirms that billing permissions are enforced at the route level for non-admin roles regardless of how the user constructs the request.

**Screenshots:**

![step 04 sales rep billing denied](screenshots/step-04-sales-rep-billing-denied.png)

**Video recording:**

[▶ Watch step recording](videos/step-04-sales-rep-billing-denied.webm)

---

### 5. Step 5: Employee login and navigation menu — ✅ PASS

**What this step proves:**

The Employee role logs in and the sidebar navigation is inspected. The Employee's visible navigation items differ from the Sales Rep's, confirming that each role has an independently configured permission set and that the navigation reflects that configuration accurately.

**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:33:49Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:33:56Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:04Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:12Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:21Z | user_log | user:login | ryan.delauintana@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:28Z | user_log | user:login | ryan.delauintana@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:36Z | user_log | user:login | ryan.delauintana@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:43Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:51Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:59Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:35:12Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:35:26Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |

**Screenshots:**

![step 05 employee navigation](screenshots/step-05-employee-navigation.png)

**Video recording:**

[▶ Watch step recording](videos/step-05-employee-nav.webm)

---

### 6. Step 6: Employee can view orders — ✅ PASS

**What this step proves:**

The Employee navigates to the Orders page and it loads successfully, confirming that the Employee role includes the order-viewing permission and that access to shared features is properly granted across multiple roles.

**Screenshots:**

![step 06 employee orders](screenshots/step-06-employee-orders.png)

**Video recording:**

[▶ Watch step recording](videos/step-06-employee-orders.webm)

---

### 7. Step 7: Employee denied access to Role Management — ✅ PASS

**What this step proves:**

The Employee attempts to navigate directly to /settings/roles by URL. The test captures the HTTP response status and accepts either denial mechanism (error page or login redirect). The screencast chapter records which mechanism fired. This confirms that org:manage_roles is admin-only and the same server-side check applies regardless of which non-admin role makes the request.

**Screenshots:**

![step 07 employee roles denied](screenshots/step-07-employee-roles-denied.png)

**Video recording:**

[▶ Watch step recording](videos/step-07-employee-roles-denied.webm)

---

### 8. Step 8: Admin login and navigation menu — ✅ PASS

**What this step proves:**

The Admin role logs in and the full sidebar navigation is inspected. All expected admin-level navigation items are present, confirming that the admin role is assigned the complete set of permissions needed to manage the organization.

**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:33:49Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:33:56Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:04Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:12Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:21Z | user_log | user:login | ryan.delauintana@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:28Z | user_log | user:login | ryan.delauintana@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:36Z | user_log | user:login | ryan.delauintana@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:43Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:51Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:34:59Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:35:12Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:35:26Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |

**Screenshots:**

![step 08 admin navigation](screenshots/step-08-admin-navigation.png)

**Video recording:**

[▶ Watch step recording](videos/step-08-admin-nav.webm)

---

### 9. Step 9: Admin can access Settings — ✅ PASS

**What this step proves:**

The Admin navigates to the Settings page and it loads without error. This confirms that the settings access permission is correctly assigned to the admin role and that the route loader grants access as expected.

**Screenshots:**

![step 09 admin settings](screenshots/step-09-admin-settings.png)

**Video recording:**

[▶ Watch step recording](videos/step-09-admin-settings.webm)

---

### 10. Step 10: Admin can access role management — ✅ PASS

**What this step proves:**

The Admin navigates to /settings/roles. The test asserts both the HTTP layer (the navigation returns a 2xx status from the route loader, proving the org:manage_roles permission check passed server-side) and the UI layer (the page renders its specific "Roles" heading, a "Create Role" action link, and either the roles table or the documented empty-state message). A broken page that merely contained the word "role" somewhere would fail these assertions. Together with Step 3 (same route denied for Sales Rep) this proves the permission is correctly gated both ways.

**Screenshots:**

![step 10 admin roles](screenshots/step-10-admin-roles.png)

**Video recording:**

[▶ Watch step recording](videos/step-10-admin-roles.webm)

---

### 11. Step 11: Anonymous user redirected to login — ✅ PASS

**What this step proves:**

An unauthenticated browser navigates directly to /orders/requests without a session cookie. The server-side route loader detects the missing authentication and redirects to /login. This confirms that authentication is required for all application routes and cannot be bypassed.

**Screenshots:**

![step 11 anonymous redirect](screenshots/step-11-anonymous-redirect.png)

**Video recording:**

[▶ Watch step recording](videos/step-11-anonymous-denied.webm)

---

### 12. Step 12: Sales Rep blocked from multiple restricted URLs — ✅ PASS

**What this step proves:**

The Sales Rep attempts to access four restricted URLs in sequence: /settings/roles, /settings/members, /billing, and /settings/products. Each request is blocked by the server-side permission check, and the test captures a separate screenshot for every URL so the compliance report has independent visual evidence per denial. Each screencast chapter also records which denial mechanism fired (error page vs. login redirect) along with the observed HTTP status. This confirms that RBAC enforcement is comprehensive across administrative routes, not limited to the pages tested individually in earlier steps.

**Screenshots:**

![step 12 01 settings roles denied](screenshots/step-12-01-settings-roles-denied.png)

![step 12 02 settings members denied](screenshots/step-12-02-settings-members-denied.png)

![step 12 03 billing denied](screenshots/step-12-03-billing-denied.png)

![step 12 04 settings products denied](screenshots/step-12-04-settings-products-denied.png)

**Video recording:**

[▶ Watch step recording](videos/step-12-cross-role-access.webm)

---

### 13. Step 13: Sales Rep blocked at HTTP layer by direct API calls — ✅ PASS

**What this step proves:**

The Sales Rep issues direct HTTP GET requests to restricted SvelteKit routes using page.request.get (which bypasses client-side navigation and UI redirects). Each response is asserted to be a 401, 403, or a 3xx redirect to /login — any 2xx would indicate the backend permitted the request, which is the failure mode this step is designed to catch. The exact status code and Location header for each URL are written to step-13-api-enforcement.json alongside the report so a reviewer can cite the wire-level response. This proves that permission enforcement is server-side and cannot be bypassed by a user who avoids the UI.

**Screenshots:**

![step 13 api enforcement](screenshots/step-13-api-enforcement.png)

**Video recording:**

[▶ Watch step recording](videos/step-13-api-enforcement.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.

### User-role assignments match test configuration — ✅ PASS

**Assertion:** Bob=Sales Rep, Ryan=Employee, Dan=StellarTech Admin

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

| email | name | role_name | role_id |
| --- | --- | --- | --- |
| bob.kauffman@stellartech.com | Bob Kauffman | Sales Representative | d2e3f4a5-b6c7-8901-def0-123456789abc |
| dan.distributor@stellartech.com | Dan Distributor | StellarTech Admin | 40e1f2a3-b4c5-6789-4567-890123456789 |
| ryan.delauintana@stellartech.com | Ryan Delauintana | Employee | f4a5b6c7-d8e9-0123-f012-3456789abcde |

### Permission counts follow role hierarchy — ✅ PASS

**Assertion:** Sales Rep (9) < Employee (16) < Admin (96)

```sql
SELECT r.name as role_name, r.id as role_id, COUNT(p.permission) as permission_count
      FROM roles r
      LEFT JOIN permissions p ON p.actor_id = r.id
      WHERE r.id IN ($1, $2, $3)
      GROUP BY r.name, r.id
      ORDER BY permission_count ASC
```

| role_name | role_id | permission_count |
| --- | --- | --- |
| Sales Representative | d2e3f4a5-b6c7-8901-def0-123456789abc | 9 |
| Employee | f4a5b6c7-d8e9-0123-f012-3456789abcde | 16 |
| StellarTech Admin | 40e1f2a3-b4c5-6789-4567-890123456789 | 96 |

### Admin has settings/billing permissions that Sales Rep lacks — ✅ PASS

**Assertion:** Admin should have org:manage_roles, billing:view, etc. while Sales Rep should not

```sql
SELECT r.name as role_name, r.id as role_id, p.permission
      FROM roles r
      JOIN permissions p ON p.actor_id = r.id
      WHERE r.id IN ($1, $2)
        AND p.permission IN (
          'org:manage_roles',
          'org:manage_users',
          'org:manage_organization_settings',
          'billing:view',
          'billing:create',
          'forms:manage'
        )
      ORDER BY r.name, p.permission
```

| role_name | role_id | permission |
| --- | --- | --- |
| StellarTech Admin | 40e1f2a3-b4c5-6789-4567-890123456789 | billing:create |
| StellarTech Admin | 40e1f2a3-b4c5-6789-4567-890123456789 | billing:view |
| StellarTech Admin | 40e1f2a3-b4c5-6789-4567-890123456789 | forms:manage |
| StellarTech Admin | 40e1f2a3-b4c5-6789-4567-890123456789 | org:manage_organization_settings |
| StellarTech Admin | 40e1f2a3-b4c5-6789-4567-890123456789 | org:manage_roles |
| StellarTech Admin | 40e1f2a3-b4c5-6789-4567-890123456789 | org:manage_users |

### All test users scoped to same organization — ✅ PASS

**Assertion:** All three test users should belong to StellarTech Medical Solutions

```sql
SELECT u.email, o.name as org_name, ur.organization_id
      FROM user_roles ur
      JOIN users u ON u.id = ur.user_id
      JOIN organizations o ON ur.organization_id = o.id
      WHERE ur.user_id IN ($1, $2, $3)
        AND ur.organization_id = $4
      ORDER BY u.email
```

| email | org_name | organization_id |
| --- | --- | --- |
| bob.kauffman@stellartech.com | StellarTech Medical Solutions | b2c3d4e5-f6a7-8901-bcde-f12345678901 |
| dan.distributor@stellartech.com | StellarTech Medical Solutions | b2c3d4e5-f6a7-8901-bcde-f12345678901 |
| ryan.delauintana@stellartech.com | StellarTech Medical Solutions | b2c3d4e5-f6a7-8901-bcde-f12345678901 |

### No orphaned permissions in StellarTech org — ✅ PASS

**Assertion:** All permissions should reference valid roles

```sql
SELECT p.actor_id, p.permission, p.organization_id
      FROM permissions p
      WHERE p.organization_id = $1
        AND NOT EXISTS (
          SELECT 1 FROM roles r WHERE r.id = p.actor_id
        )
      LIMIT 10
```

*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: Sales Rep login and navigation menu | `user_log:user:login` | ✅ |
| Step 5: Employee login and navigation menu | `user_log:user:login` | ✅ |
| Step 8: Admin login and navigation menu | `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:33:40.173Z

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

12 event(s) captured:

| Time | Type | Action | User | Org | Object ID | Performed | Reason |
|------|------|--------|------|-----|-----------|-----------|--------|
| 2026-04-23 03:33:49Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:33:56Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:34:04Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:34:12Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:34:21Z | user_log | user:login | ryan.delauintana@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:34:28Z | user_log | user:login | ryan.delauintana@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:34:36Z | user_log | user:login | ryan.delauintana@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:34:43Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:34:51Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:34:59Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:35:12Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
| 2026-04-23 03:35:26Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — |  |
