URS-001 · Secure Login with Unique User Credentials
Title: Secure Login with Unique User Credentials Date: 2026-09-29T02:26:37.482Z Duration: 174.0s Overall Status: ✅ PASS
User Requirement
Section titled “User Requirement”The system shall provide secure login using unique user credentials.
Source: User_Requirement_Specifications_Vantis_DeviceFlow.xlsx — the run below proves the system meets this requirement.
Environment
Section titled “Environment”- Inbox URL: http://localhost:44709
- Database: localhost:36607/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: Login page loads correctly — ✅ PASS
Section titled “1. Step 1: Login page loads correctly — ✅ PASS”What this step proves:
The system presents a login form with email and password fields and a password reset link. This confirms the authentication entry point is functional and that all users are directed to credential-based login rather than any unauthenticated route.
Screenshots:

Video recording:
2. Step 2: Valid login - Distributor user — ✅ PASS
Section titled “2. Step 2: Valid login - Distributor user — ✅ PASS”What this step proves:
A distributor user authenticates successfully with correct credentials. The system validates the credentials, creates a session, and redirects the user to the authenticated application. This demonstrates that valid credentials grant access as required by URS-001.
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-09-29 02:27:49Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-09-29 02:27:55Z | user_log | user:login | mark.manufacturer@vantismedical.com | Vantis | — |
| 2026-09-29 02:28:32Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — |
| 2026-09-29 02:29:11Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — |
| 2026-09-29 02:29:17Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-09-29 02:29:18Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — |
| 2026-09-29 02:29:24Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — |
Screenshots:

Video recording:
3. Step 3: Valid login - Manufacturer user — ✅ PASS
Section titled “3. Step 3: Valid login - Manufacturer user — ✅ PASS”What this step proves:
A manufacturer-type user authenticates successfully, confirming that the secure credential flow handles multiple organization types uniformly. No special path exists for different org types.
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-09-29 02:27:49Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-09-29 02:27:55Z | user_log | user:login | mark.manufacturer@vantismedical.com | Vantis | — |
| 2026-09-29 02:28:32Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — |
| 2026-09-29 02:29:11Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — |
| 2026-09-29 02:29:17Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-09-29 02:29:18Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — |
| 2026-09-29 02:29:24Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — |
Screenshots:

Video recording:
4. Step 4: Valid login - Admin user — ✅ PASS
Section titled “4. Step 4: Valid login - Admin user — ✅ PASS”What this step proves:
An admin user authenticates successfully, confirming that all system roles use the same credential-based authentication mechanism.
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-09-29 02:27:49Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-09-29 02:27:55Z | user_log | user:login | mark.manufacturer@vantismedical.com | Vantis | — |
| 2026-09-29 02:28:32Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — |
| 2026-09-29 02:29:11Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — |
| 2026-09-29 02:29:17Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — |
| 2026-09-29 02:29:18Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — |
| 2026-09-29 02:29:24Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — |
Screenshots:

Video recording:
5. Step 5: Invalid credentials - Wrong password — ✅ PASS
Section titled “5. Step 5: Invalid credentials - Wrong password — ✅ PASS”What this step proves:
Attempting to log in with a valid registered email but an incorrect password is rejected. The system returns a generic error message and keeps the user on the login page. The exact error text is captured for comparison in Step 6 to verify protection against email enumeration.
Screenshots:

Video recording:
6. Step 6a: Invalid credentials - Non-existent email — ✅ PASS
Section titled “6. Step 6a: Invalid credentials - Non-existent email — ✅ PASS”What this step proves:
Attempting to log in with an email address that has never been registered returns the exact same error message as Step 5. Identical responses for wrong-password and unknown-email requests prevent attackers from determining whether a given email address exists in the system.
Screenshots:

Video recording:
7. Step 6b: Locked account - inactive user cannot login — ✅ PASS
Section titled “7. Step 6b: Locked account - inactive user cannot login — ✅ PASS”What this step proves:
A user whose organization membership has been deactivated is blocked from logging in even when submitting the correct credentials. This confirms that deactivating a user account takes effect immediately and that credential validity alone is insufficient for access.
Screenshots:

Video recording:
8. Step 7: Empty field validation — ✅ PASS
Section titled “8. Step 7: Empty field validation — ✅ PASS”What this step proves:
Submitting the login form with empty fields triggers validation errors before any server request is made, displaying field-level messages such as “Invalid email” and “Password is required”. This confirms that required-field enforcement provides clear feedback and prevents malformed requests.
Screenshots:


Video recording:
9. Step 8: Session security - Cookie verification — ✅ PASS
Section titled “9. Step 8: Session security - Cookie verification — ✅ PASS”What this step proves:
After successful login the session cookie attributes are inspected. The httpOnly flag confirms that JavaScript cannot read the token, mitigating XSS-based session theft. The SameSite=Lax setting blocks cross-site request forgery. Cookie evidence is written to session-cookie-evidence.json.
Screenshots:

Video recording:
10. Step 9: Session isolation - Multiple users — ✅ PASS
Section titled “10. Step 9: Session isolation - Multiple users — ✅ PASS”What this step proves:
Two users log in simultaneously in separate browser contexts (equivalent to separate incognito windows) and each receives a distinct, non-overlapping session token. This confirms that sessions are fully isolated and one user’s session cannot be used to access another user’s account.
Screenshots:


Video recording:
11. Step 10: Logout and session termination — ✅ PASS
Section titled “11. Step 10: Logout and session termination — ✅ PASS”What this step proves:
A logged-in user opens the sidebar user menu and clicks Logout. The server invalidates the session, clears the session cookie, and redirects the browser. A subsequent attempt to access /inbox confirms that the session can no longer authenticate: the user is redirected to login.
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.
Demo users exist — ✅ PASS
Section titled “Demo users exist — ✅ PASS”Assertion: All 4 demo users should exist in the users table
SELECT id, email, name, created_at FROM users WHERE email IN ( 'alex.admin@vantismedical.com', 'mark.manufacturer@vantismedical.com', 'dan.distributor@corvetasurgical.com', 'demo.user@vantismedical.com' ) ORDER BY email| id | name | created_at | |
|---|---|---|---|
| f6a7b8c9-d0e1-2345-f123-456789012345 | alex.admin@vantismedical.com | Alex Admin | 2026-09-29T02:23:23.011Z |
| c3d4e5f6-a7b8-9012-cdef-123456789012 | dan.distributor@corvetasurgical.com | Dan Distributor | 2026-09-29T02:23:23.011Z |
| e5f6a7b8-c9d0-1234-ef12-345678901234 | demo.user@vantismedical.com | Demo User | 2026-09-29T02:23:23.011Z |
| d4e5f6a7-b8c9-0123-def1-234567890123 | mark.manufacturer@vantismedical.com | Mark Manufacturer | 2026-09-29T02:23:23.011Z |
No duplicate emails — ✅ PASS
Section titled “No duplicate emails — ✅ PASS”Assertion: No email address should appear more than once in the users table
SELECT email, COUNT(*) as count FROM users GROUP BY email HAVING COUNT(*) > 1No rows returned
Passwords are hashed — ✅ PASS
Section titled “Passwords are hashed — ✅ PASS”Assertion: All password hashes should use Argon2id algorithm (not plaintext)
SELECT id, email, LEFT(password_hash, 10) as hash_prefix, password_hash LIKE '$argon2id$%' as is_argon2 FROM users WHERE email IN ( 'alex.admin@vantismedical.com', 'mark.manufacturer@vantismedical.com', 'dan.distributor@corvetasurgical.com', 'demo.user@vantismedical.com' ) ORDER BY email| id | hash_prefix | is_argon2 | |
|---|---|---|---|
| f6a7b8c9-d0e1-2345-f123-456789012345 | alex.admin@vantismedical.com | $argon2id$ | true |
| c3d4e5f6-a7b8-9012-cdef-123456789012 | dan.distributor@corvetasurgical.com | $argon2id$ | true |
| e5f6a7b8-c9d0-1234-ef12-345678901234 | demo.user@vantismedical.com | $argon2id$ | true |
| d4e5f6a7-b8c9-0123-def1-234567890123 | mark.manufacturer@vantismedical.com | $argon2id$ | true |
Recent sessions created — ✅ PASS
Section titled “Recent sessions created — ✅ PASS”Assertion: Sessions should have been created within the last 10 minutes for users who logged in during the test
SELECT s.id as session_id, u.email, s.created_at, s.expires_at FROM session s JOIN users u ON s.user_id = u.id WHERE u.email IN ( 'alex.admin@vantismedical.com', 'mark.manufacturer@vantismedical.com', 'dan.distributor@corvetasurgical.com' ) AND s.created_at > NOW() - INTERVAL '10 minutes' ORDER BY s.created_at DESC LIMIT 10| session_id | created_at | expires_at | |
|---|---|---|---|
| 274c4b8ebe5216c6206c5c1c694b06714034cc8886d1fc80e20bf358716cbd55 | alex.admin@vantismedical.com | 2026-09-29T02:29:18.840Z | 2026-10-06T02:29:18.838Z |
| d364894f19d4af6af240910917a7c3f50b7e83aa1f7bc372329a31f0badaf96b | dan.distributor@corvetasurgical.com | 2026-09-29T02:29:17.197Z | 2026-10-06T02:29:17.195Z |
| 93730bf5b17f1df95d6e260727958a6e907feda10bdd91f36bde56feb35e1325 | alex.admin@vantismedical.com | 2026-09-29T02:29:11.267Z | 2026-10-06T02:29:11.264Z |
| eb11510071ffd13a091af93aea0e4524d02350f9ea44f99d10ca2b875be3448e | alex.admin@vantismedical.com | 2026-09-29T02:28:32.253Z | 2026-10-06T02:28:32.250Z |
| 78f1c8635720f1f3666de77ee07215175368e267c55179289526ecfb98e19764 | mark.manufacturer@vantismedical.com | 2026-09-29T02:27:55.680Z | 2026-10-06T02:27:55.678Z |
| 6f7706f2500dfb663f1ad9246f082e3a85b54668a0b38cadd1216c0c32ab88a0 | dan.distributor@corvetasurgical.com | 2026-09-29T02:27:49.744Z | 2026-10-06T02:27:49.735Z |
Locked user is inactive — ✅ PASS
Section titled “Locked user is inactive — ✅ PASS”Assertion: demo.user@vantismedical.com should have inactive org membership (locked account)
SELECT u.email, om.active, om.organization_id FROM organization_members om JOIN users u ON om.user_id = u.id WHERE u.email = 'demo.user@vantismedical.com'| active | organization_id | |
|---|---|---|
| demo.user@vantismedical.com | false | a1b2c3d4-e5f6-7890-abcd-ef1234567890 |
| demo.user@vantismedical.com | false | b2c3d4e5-f6a7-8901-bcde-f12345678901 |
| demo.user@vantismedical.com | false | 6763fc17-7da1-47e3-851e-8f4fac570dc6 |
Global email uniqueness — ✅ PASS
Section titled “Global email uniqueness — ✅ PASS”Assertion: Every user should have a unique email address
SELECT COUNT(DISTINCT email) as unique_emails, COUNT(*) as total_users FROM users WHERE email IS NOT NULL| unique_emails | total_users |
|---|---|
| 20 | 20 |
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 2: Valid login - Distributor user | user_log:user:login | ✅ |
| Step 3: Valid login - Manufacturer user | user_log:user:login | ✅ |
| Step 4: Valid login - Admin user | 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-09-29T02:26:35.681Z
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 ASC8 event(s) captured:
| Time | Type | Action | User | Org | Object ID | Performed | Reason |
|---|---|---|---|---|---|---|---|
| 2026-09-29 02:27:49Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — | — | |
| 2026-09-29 02:27:55Z | user_log | user:login | mark.manufacturer@vantismedical.com | Vantis | — | — | |
| 2026-09-29 02:28:32Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — | — | |
| 2026-09-29 02:28:55Z | user_log | user:login_deactivated | demo.user@vantismedical.com | Vantis | — | — | |
| 2026-09-29 02:29:11Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — | — | |
| 2026-09-29 02:29:17Z | user_log | user:login | dan.distributor@corvetasurgical.com | Corveta Surgical Group | — | — | |
| 2026-09-29 02:29:18Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — | — | |
| 2026-09-29 02:29:24Z | user_log | user:login | alex.admin@vantismedical.com | Vantis | — | — |
Downloads
Section titled “Downloads”- audit-events.json
- report.md
- result.json
- screenshots-index.json
- session-cookie-evidence.json
- step-timings.json