URS-003 · Audit Log Tracking of All User Actions
Title: Audit Log Tracking of All User Actions Date: 2026-04-23T03:33:42.355Z Duration: 51.9s Overall Status: ✅ PASS
User Requirement
Section titled “User Requirement”The system shall record user actions related to data creation and modification.
Source: User_Requirement_Specifications_ZuriMED_DeviceFlow.xlsx — the run below proves the system meets this requirement.
Environment
Section titled “Environment”- Inbox URL: http://localhost:61673
- Database: localhost:61674/cc_repinbox_dev
Status: ✅ PASS
Test Steps
Section titled “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
Section titled “1. Step 1: Rep login — ✅ PASS”What this step proves:
The sales representative (Bob Kauffman) 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-04-23 03:33:47Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:33:52Z | 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:30Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |
Screenshots:
![]()
Video recording:
2. Step 2: Create order — ✅ PASS
Section titled “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-04-23T03:34:00.791Z → 2026-04-23T03:34:09.793Z)
| Time | Type | Action | User | Org | Performed |
|---|---|---|---|---|---|
| 2026-04-23 03:34:06Z | decision | order_request_created | bob.kauffman@stellartech.com | ZuriMED | yes |
Screenshots:
![]()
![]()
![]()
![]()
Video recording:
3. Step 3: Edit order item — ✅ PASS
Section titled “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-04-23T03:34:18.783Z → 2026-04-23T03:34:27.866Z)
| Time | Type | Action | User | Org | Performed |
|---|---|---|---|---|---|
| 2026-04-23 03:34:22Z | decision | reevaluate_order_request_issues | bob.kauffman@stellartech.com | ZuriMED | no |
| 2026-04-23 03:34:22Z | decision | update_order_request_item | bob.kauffman@stellartech.com | ZuriMED | yes |
Screenshots:
![]()
![]()
![]()
Video recording:
4. Step 4: Admin login — ✅ PASS
Section titled “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-04-23 03:33:47Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — |
| 2026-04-23 03:33:52Z | 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:30Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — |
Screenshots:
![]()
Video recording:
Database Validations
Section titled “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
Section titled “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
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 (Bob) — ✅ PASS
Section titled “rep login was audited (Bob) — ✅ PASS”Assertion: Bob logging in should produce at least one user_log row with action=user:login.
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 |
|---|---|---|---|---|---|---|
| 019db866-a1e2-73ee-bf1e-5bfc0b686ebb | user:login | user_log | 17b8c9d0-e1f2-3456-1234-567890123456 | b2c3d4e5-f6a7-8901-bcde-f12345678901 | {"email":"bob.kauffman@stellartech.com"} | 2026-04-23T03:33:47.125Z |
| 019db866-b84a-7f91-812b-12bc026210a4 | user:login | user_log | 17b8c9d0-e1f2-3456-1234-567890123456 | b2c3d4e5-f6a7-8901-bcde-f12345678901 | {"email":"bob.kauffman@stellartech.com"} | 2026-04-23T03:33:52.868Z |
| 019db867-063a-74c5-bcd5-b130710b67df | user:login | user_log | 17b8c9d0-e1f2-3456-1234-567890123456 | b2c3d4e5-f6a7-8901-bcde-f12345678901 | {"email":"bob.kauffman@stellartech.com"} | 2026-04-23T03:34:12.860Z |
admin login was audited (Dan) — ✅ PASS
Section titled “admin login was audited (Dan) — ✅ PASS”Assertion: Dan logging in should produce at least one user_log row with action=user:login.
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 |
|---|---|---|---|---|---|---|
| 019db867-4bb5-7c84-90d3-9b92568a3a0c | user:login | user_log | c3d4e5f6-a7b8-9012-cdef-123456789012 | b2c3d4e5-f6a7-8901-bcde-f12345678901 | {"email":"dan.distributor@stellartech.com"} | 2026-04-23T03:34:30.584Z |
order_request_created decision was audited for Bob — ✅ PASS
Section titled “order_request_created decision was audited for Bob — ✅ PASS”Assertion: Creating an order request should produce a decision audit_events row with action=order_request_created for the acting user.
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 |
|---|---|---|---|---|---|---|
| 019db866-ec10-70ce-9fbb-9d8adb4fd3c8 | order_request_created | decision | 17b8c9d0-e1f2-3456-1234-567890123456 | 019db866-ec0e-7dfd-a59c-a8ac170acf9a | {"reason":"Order request OR-1 created (importSource=manual)","priority":"normal","itemCount":1,"orderType":"consignment","performed":true,"entityType":"order_request","importSource":"manual","requestNumber":"OR-1","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-04-23T03:34:06.055Z |
update_order_request_item decision was audited for Bob — ✅ PASS
Section titled “update_order_request_item decision was audited for Bob — ✅ PASS”Assertion: Editing an order item should produce a decision audit_events row with action=update_order_request_item for the acting user.
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 |
|---|---|---|---|---|---|---|
| 019db867-2a9e-76ae-b9d4-6cda90b3cdb1 | update_order_request_item | decision | 17b8c9d0-e1f2-3456-1234-567890123456 | 019db866-ec0e-7dfd-a59c-a8ac170acf9a | {"reason":"Item quantity or notes updated during the submission grace period","performed":true,"entityType":"order_request"} | 2026-04-23T03:34:22.008Z |
audit rows for Bob have required fields populated — ✅ PASS
Section titled “audit rows for Bob have required fields populated — ✅ PASS”Assertion: Every audit_events row for Bob during the run should have non-null event_type and organization_id. (created_at is NOT NULL by schema constraint.)
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
Section titled “no audit rows leaked to other organizations (test actors only) — ✅ PASS”Assertion: Audit rows written during the run by the test actors (Bob, Dan, Ryan) must belong to one of the demo organizations (ZuriMED or StellarTech).
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
Section titled “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
Section titled “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
Section titled “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.539Z
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 ASC7 event(s) captured:
| Time | Type | Action | User | Org | Object ID | Performed | Reason |
|---|---|---|---|---|---|---|---|
| 2026-04-23 03:33:47Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — | |
| 2026-04-23 03:33:52Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — | |
| 2026-04-23 03:34:06Z | decision | order_request_created | bob.kauffman@stellartech.com | ZuriMED | 019db866-ec0e-7dfd-a59c-a8ac170acf9a | yes | Order request OR-1 created (importSource=manual) |
| 2026-04-23 03:34:12Z | user_log | user:login | bob.kauffman@stellartech.com | StellarTech Medical Solutions | — | — | |
| 2026-04-23 03:34:22Z | decision | reevaluate_order_request_issues | bob.kauffman@stellartech.com | ZuriMED | 019db866-ec0e-7dfd-a59c-a8ac170acf9a | no | Order request issues were unchanged after an edit |
| 2026-04-23 03:34:22Z | decision | update_order_request_item | bob.kauffman@stellartech.com | ZuriMED | 019db866-ec0e-7dfd-a59c-a8ac170acf9a | yes | Item quantity or notes updated during the submission grace period |
| 2026-04-23 03:34:30Z | user_log | user:login | dan.distributor@stellartech.com | StellarTech Medical Solutions | — | — |