Skip to content

URS-063 · Distributor Onboarding Workflow with Roles

Title: Distributor Onboarding Workflow with Roles Date: 2026-04-23T03:45:07.127Z Duration: 91.4s Overall Status: ✅ PASS

The system shall support onboarding and role assignment of distributors.

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

Status: ✅ PASS

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: Login as manufacturer admin — ✅ PASS

Section titled “1. Step 1: Login as manufacturer admin — ✅ PASS”

What this step proves:

Proves that Mark (ZuriMED manufacturer admin) can authenticate successfully. Establishes the administrative context required to manage distributor relationships and member invitations in all subsequent steps. This step also opens the single browser context re-used by steps 2–11 so the audit log records exactly one user:login event for the manufacturer session (not one per step).

Screenshots:

step 01 manufacturer logged in

Video recording:


2. Step 2: Navigate to Distributor Agencies — ✅ PASS

Section titled “2. Step 2: Navigate to Distributor Agencies — ✅ PASS”

What this step proves:

Navigates to the Organization Relationships settings page where distributor agency relationships are managed. Confirms the page is accessible to manufacturer admins and displays the correct heading.

Screenshots:

step 02 org relationships page

Video recording:


3. Step 3: Existing distributors — ✅ PASS

Section titled “3. Step 3: Existing distributors — ✅ PASS”

What this step proves:

Verifies that existing downstream distributor relationships (StellarTech Medical Solutions) are displayed in the Downstream Organizations section, and that the “Create New Distributor” action is available to the admin.

Screenshots:

step 03 existing distributors

step 03 create button visible

Video recording:


4. Step 4: Create distributor — ✅ PASS

Section titled “4. Step 4: Create distributor — ✅ PASS”

What this step proves:

Fills out and submits the new distributor form with an organization name, invite email, invitee name, the “Add user as a representative” option, and the Rep ID and Trunk ID inputs. Confirms the system creates the distributor relationship and redirects back to the org-relationships page on success. The submitted Rep ID / Trunk ID values are asserted in DB validation to prove they were persisted.

Audit events generated by this step:

(Evidence scoped to step execution window: 2026-04-23T03:45:28.772Z → 2026-04-23T03:45:36.082Z)

TimeTypeActionUserOrgPerformed
2026-04-23 03:45:34Zuser_logrep_onboarding_request_approvedtest-distributor@example.comNew Medical Supplies Inc.
2026-04-23 03:45:34Ztransactional_emailrep_createdNew Medical Supplies Inc.
2026-04-23 03:45:35Ztransactional_emailverify_emailZuriMED

Emails triggered by this step:

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

Email 1: Representative Account Approved - ZuriMED

Template: Representative_Account_Approved_-_ZuriMED

Representative Account Approved - ZuriMED

Email 2: Verify your DeviceFlow account

Template: Verify_your_DeviceFlow_account

Verify your DeviceFlow account

Email 3: Verify your DeviceFlow account

Template: Verify_your_DeviceFlow_account

Verify your DeviceFlow account

Screenshots:

step 04 create distributor form empty

step 04 form filled with ids

step 04 distributor created

Video recording:


5. Step 5: Duplicate name rejected — ✅ PASS

Section titled “5. Step 5: Duplicate name rejected — ✅ PASS”

What this step proves:

Re-submits the new-distributor form with the same organization name and asserts the server rejects it with the inline message “An organization with this name already exists”. Proves the case-insensitive ilike duplicate-name guard in new-child.remote.ts is active end-to-end — not just at the form schema level.

Screenshots:

step 05 duplicate form filled

step 05 duplicate error visible

Video recording:


6. Step 6: New distributor in list — ✅ PASS

Section titled “6. Step 6: New distributor in list — ✅ PASS”

What this step proves:

After creation, the new distributor organization (“New Medical Supplies Inc.”) appears alongside the existing StellarTech in the downstream organizations list, confirming the relationship was persisted correctly.

Screenshots:

step 06 new distributor in list

Video recording:


What this step proves:

Navigates to the Members settings page and confirms it loads with an existing member table and the “Invite Member” button visible. Proves the admin has the manage_users permission required to send invitations.

Screenshots:

step 07 members page

Video recording:


What this step proves:

Opens the Invite Member form, fills in the new member’s name and email, and explicitly selects the “ZuriMED Admin” role from the role dropdown. Submits the invitation and verifies the form resets on success. The specific role picked here is asserted in DB check 8 so a silent regression (e.g. hardcoding the role on the server) is caught.

Emails triggered by this step:

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

Email 1: Verify your DeviceFlow account

Template: Verify_your_DeviceFlow_account

Verify your DeviceFlow account

Email 2: Verify your DeviceFlow account

Template: Verify_your_DeviceFlow_account

Verify your DeviceFlow account

Screenshots:

step 08 invite form open

step 08 role assigned

step 08 invite submitted

Video recording:


What this step proves:

After invitation, the new member (“Jane Doe”) appears in the members list with their email address visible, confirming the invitation was recorded and the member is searchable from the admin interface.

Screenshots:

step 09 member in list

Video recording:


What this step proves:

Opens the member detail page for the invited user and verifies the Roles section is present. Confirms that role assignments made during invitation are accessible and visible to administrators.

Screenshots:

step 10 member details page

step 10 member roles

Video recording:


What this step proves:

Final admin view showing both the full distributor list (StellarTech + new distributor) and the complete member roster. Provides end-to-end evidence that the entire distributor onboarding workflow — from agency creation through member invitation and role assignment — is operational.

Screenshots:

step 11 all distributors

step 11 all members

Video recording:


12. Step 12: Distributor first login — ✅ PASS

Section titled “12. Step 12: Distributor first login — ✅ PASS”

What this step proves:

Switches to the distributor invitee’s perspective in a fresh browser context. Reads the verification email captured during step 4, extracts the /verify-email?requestId=…&code=… link, and navigates to it. The server auto-verifies the code and redirects through the password-reset flow, where the invitee sets an initial password and lands on the app home page. Proves the invitation link is functional from the recipient’s point of view, not just from the admin’s.

Screenshots:

step 12 password form

step 12 landing page

Video recording:


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.

New distributor organization created — ✅ PASS

Section titled “New distributor organization created — ✅ PASS”

Assertion: Organization “New Medical Supplies Inc.” should exist in the organizations table

SELECT id, name, created_at
FROM organizations
WHERE name = $1
idnamecreated_at
019db871-6ad0-78b9-88d0-1a0a769394fdNew Medical Supplies Inc.2026-04-23T03:45:33.904Z

Distributor relationship established — ✅ PASS

Section titled “Distributor relationship established — ✅ PASS”

Assertion: A distributor relationship should exist between ZuriMED and New Medical Supplies Inc.

SELECT
r.parent_organization_id,
r.child_organization_id,
r.relationship_type,
p.name as parent_name,
c.name as child_name
FROM organization_relationships r
JOIN organizations p ON p.id = r.parent_organization_id
JOIN organizations c ON c.id = r.child_organization_id
WHERE r.parent_organization_id = $1
AND c.name = $2
parent_organization_idchild_organization_idrelationship_typeparent_namechild_name
a1b2c3d4-e5f6-7890-abcd-ef1234567890019db871-6ad0-78b9-88d0-1a0a769394fddistributorZuriMEDNew Medical Supplies Inc.

Invited distributor user created — ✅ PASS

Section titled “Invited distributor user created — ✅ PASS”

Assertion: User with email test-distributor@example.com should exist in the users table

SELECT id, email, name, created_at
FROM users
WHERE email = $1
idemailnamecreated_at
019db871-6ace-7c25-ac42-eda8884f37d1test-distributor@example.comJohn Smith2026-04-23T03:45:33.902Z

Distributor user has expected role assigned — ✅ PASS

Section titled “Distributor user has expected role assigned — ✅ PASS”

Assertion: User test-distributor@example.com should have role “Administrator (preset)” in New Medical Supplies Inc. (hardcoded at new-child.remote.ts as globalOrgAdminRoleId)

SELECT
ur.user_id,
ur.role_id,
ur.organization_id,
r.name as role_name,
u.email,
o.name as org_name
FROM user_roles ur
JOIN users u ON u.id = ur.user_id
JOIN roles r ON r.id = ur.role_id
JOIN organizations o ON o.id = ur.organization_id
WHERE u.email = $1
AND o.name = $2
user_idrole_idorganization_idrole_nameemailorg_name
019db871-6ace-7c25-ac42-eda8884f37d124ee9b94-92a6-4bd4-89e6-48d4f19cfdbe019db871-6ad0-78b9-88d0-1a0a769394fdAdministrator (preset)test-distributor@example.comNew Medical Supplies Inc.

User is member of distributor org — ✅ PASS

Section titled “User is member of distributor org — ✅ PASS”

Assertion: User test-distributor@example.com should be a member of New Medical Supplies Inc.

SELECT
om.user_id,
om.organization_id,
om.active,
u.email,
o.name as org_name
FROM organization_members om
JOIN users u ON u.id = om.user_id
JOIN organizations o ON o.id = om.organization_id
WHERE u.email = $1
AND o.name = $2
user_idorganization_idactiveemailorg_name
019db871-6ace-7c25-ac42-eda8884f37d1019db871-6ad0-78b9-88d0-1a0a769394fdtruetest-distributor@example.comNew Medical Supplies Inc.

Representation relationship created — ✅ PASS

Section titled “Representation relationship created — ✅ PASS”

Assertion: A representation relationship should exist for test-distributor@example.com (created via “Add as representative” checkbox)

SELECT
orr.id,
orr.user_id,
orr.approving_organization_id,
orr.requesting_organization_id,
orr.status,
orr.representative_type,
u.email,
ao.name as approving_org,
ro.name as requesting_org
FROM organization_representation_relationships orr
JOIN users u ON u.id = orr.user_id
JOIN organizations ao ON ao.id = orr.approving_organization_id
JOIN organizations ro ON ro.id = orr.requesting_organization_id
WHERE u.email = $1
iduser_idapproving_organization_idrequesting_organization_idstatusrepresentative_typeemailapproving_orgrequesting_org
019db871-6af3-7bc1-83e2-9b20e8b3232e019db871-6ace-7c25-ac42-eda8884f37d1a1b2c3d4-e5f6-7890-abcd-ef1234567890019db871-6ad0-78b9-88d0-1a0a769394fdactivesalespersontest-distributor@example.comZuriMEDNew Medical Supplies Inc.

Submitted Rep ID persisted for invited user — ✅ PASS

Section titled “Submitted Rep ID persisted for invited user — ✅ PASS”

Assertion: Rep ID “TEST-REP-063” submitted through the new-distributor form should be stored in real_world_contact_ids for test-distributor@example.com scoped to New Medical Supplies Inc.

SELECT
rwci.id,
rwci.organization_id,
rwci.contact_id,
rwci.id_type,
rwci.value,
u.email,
o.name as org_name
FROM real_world_contact_ids rwci
JOIN contacts c ON c.id = rwci.contact_id
JOIN users u ON u.id = c.user_id
JOIN organizations o ON o.id = rwci.organization_id
WHERE u.email = $1
AND o.name = $2
idorganization_idcontact_idid_typevalueemailorg_name
019db871-6af1-7d68-94e0-a15bd635c0bd019db871-6ad0-78b9-88d0-1a0a769394fd019db871-6ad3-7057-bf8f-1361ee09c9dczurimed_rep_idTEST-REP-063test-distributor@example.comNew Medical Supplies Inc.

Submitted Trunk ID persisted for invited user — ✅ PASS

Section titled “Submitted Trunk ID persisted for invited user — ✅ PASS”

Assertion: Trunk ID “TEST-TRUNK-063” submitted through the new-distributor form should be stored in real_world_location_ids scoped to the manufacturer org (ZuriMED)

SELECT
rwli.id,
rwli.organization_id,
rwli.location_id,
rwli.id_type,
rwli.value,
u.email,
o.name as org_name
FROM real_world_location_ids rwli
JOIN real_world_locations rwl ON rwl.id = rwli.location_id
JOIN contacts c ON c.default_location_id = rwl.id
JOIN users u ON u.id = c.user_id
JOIN organizations o ON o.id = rwli.organization_id
WHERE u.email = $1
AND o.id = $2
idorganization_idlocation_idid_typevalueemailorg_name
019db871-6af2-708c-9ab1-ae40de821be0a1b2c3d4-e5f6-7890-abcd-ef1234567890019db871-6ae3-7fd5-a11e-994d6fb5b94bTRUNK_LOCATION_IDTEST-TRUNK-063test-distributor@example.comZuriMED

Invited member exists in ZuriMED org — ✅ PASS

Section titled “Invited member exists in ZuriMED org — ✅ PASS”

Assertion: User jane.doe.test@zurimed.com should be a member of ZuriMED

SELECT
u.id, u.email, u.name,
om.active,
o.name as org_name
FROM users u
JOIN organization_members om ON om.user_id = u.id
JOIN organizations o ON o.id = om.organization_id
WHERE u.email = $1
AND om.organization_id = $2
idemailnameactiveorg_name
019db871-e1ce-7006-aaf8-b2cafb26bdf5jane.doe.test@zurimed.comJane DoetrueZuriMED

Invited member has the role selected in the form — ✅ PASS

Section titled “Invited member has the role selected in the form — ✅ PASS”

Assertion: User jane.doe.test@zurimed.com should have role “ZuriMED Admin” in ZuriMED (this is the role the spec picks from the Invite Member dropdown)

SELECT
ur.user_id,
ur.role_id,
r.name as role_name,
u.email,
o.name as org_name
FROM user_roles ur
JOIN users u ON u.id = ur.user_id
JOIN roles r ON r.id = ur.role_id
JOIN organizations o ON o.id = ur.organization_id
WHERE u.email = $1
AND ur.organization_id = $2
user_idrole_idrole_nameemailorg_name
019db871-e1ce-7006-aaf8-b2cafb26bdf539d0e1f2-a3b4-5678-3456-789012345678ZuriMED Adminjane.doe.test@zurimed.comZuriMED

Distributor org has feature flags — ✅ PASS

Section titled “Distributor org has feature flags — ✅ PASS”

Assertion: New Medical Supplies Inc. should have feature flags propagated from parent org

SELECT
ff.id as flag_id,
ff.value,
o.name as org_name
FROM feature_flags ff
JOIN organizations o ON o.id = ff.organization_id
WHERE o.name = $1
ORDER BY ff.id
flag_idvalueorg_name
billingtrueNew Medical Supplies Inc.
home_screen_prototypetrueNew Medical Supplies Inc.
inbox_checklist_itemstrueNew Medical Supplies Inc.
inbox_ticketstrueNew Medical Supplies Inc.
inventory_snapshotstrueNew Medical Supplies Inc.
order_requeststrueNew Medical Supplies Inc.
org_type:distributortrueNew Medical Supplies Inc.
organization_representationtrueNew Medical Supplies Inc.
sales_accountstrueNew Medical Supplies Inc.
workflow_visualizationtrueNew Medical Supplies Inc.

manufacturer_can_create_distributors flag enabled — ✅ PASS

Section titled “manufacturer_can_create_distributors flag enabled — ✅ PASS”

Assertion: manufacturer_can_create_distributors feature flag should be enabled for ZuriMED

SELECT id, organization_id, value
FROM feature_flags
WHERE id = 'manufacturer_can_create_distributors'
AND organization_id = $1
idorganization_idvalue
manufacturer_can_create_distributorsa1b2c3d4-e5f6-7890-abcd-ef1234567890true

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.

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.

StepExpected Audit ActionFound
Step 4: Create distributoruser_log:rep_onboarding_request_approved

Each row asserts that a declared expectedEmailTemplates entry was matched (case-insensitive substring) by a captured email subject or template. A ❌ flips overall status to FAIL.

StepExpected TemplateFound
Step 4: Create distributorVerify your DeviceFlow
Step 4: Create distributorRepresentative Account Approved
Step 8: Invite memberVerify your DeviceFlow

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:45:05.195Z

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

5 event(s) captured:

TimeTypeActionUserOrgObject IDPerformedReason
2026-04-23 03:45:13Zuser_loguser:loginmark.manufacturer@zurimed.comZuriMED
2026-04-23 03:45:34Zuser_logrep_onboarding_request_approvedtest-distributor@example.comNew Medical Supplies Inc.019db871-6af3-7bc1-83e2-9b20e8b3232e
2026-04-23 03:45:34Ztransactional_emailrep_createdNew Medical Supplies Inc.019db871-6af3-7bc1-83e2-9b20e8b3232e
2026-04-23 03:45:35Ztransactional_emailverify_emailZuriMED019db871-6ace-7c25-ac42-eda8884f37d1
2026-04-23 03:46:06Ztransactional_emailverify_emailZuriMED019db871-e1ce-7006-aaf8-b2cafb26bdf5

3 notification email(s) were captured during this test run. Each email is rendered as a screenshot for compliance review.

1. Representative Account Approved - ZuriMED

Section titled “1. Representative Account Approved - ZuriMED”

Template: Representative_Account_Approved_-_ZuriMED

Representative Account Approved - ZuriMED

Template: Verify_your_DeviceFlow_account

Verify your DeviceFlow account

Template: Verify_your_DeviceFlow_account

Verify your DeviceFlow account