Skip to content

E2E SCENARIOS — IDENTITY & ACCESS

VietGara — Release 1.0–1.1 · Version 1.0 — September 28, 2026

Covers FR-IAM-01, 02, 04, 07, 08, 09 (optional MFA, Release 6.1) and FR-NOT-04 (verification and reset e-mails). Users and passwords are in 00_Test_Data.md; Mailpit and the environment are in README §3.

IDTitlePriorityAutomation
E2E-IAM-001Sign up with e-mail and verify with the codeP1Automated (API, partial)
E2E-IAM-002Unverified user can only use the Account pageP1Automated (API, partial)
E2E-IAM-003Signing in unverified sends a new codeP2Automated (API, partial)
E2E-IAM-004Wrong code, then too many wrong codesP2Automated (API, partial)
E2E-IAM-005Code expires after 2 minutesP2Automated (API, partial)
E2E-IAM-006Resend is possible only after 30 seconds and replaces the old codeP2Automated (API, partial)
E2E-IAM-007Sign-up form validation and duplicatesP2Automated (API, partial)
E2E-IAM-008Sign in and wrong credentialsP1Automated (API, partial)
E2E-IAM-009Sign out ends the sessionP1Automated (API, partial)
E2E-IAM-010Session survives a reload and an expired access tokenP2Automated (API, partial)
E2E-IAM-011Reset a forgotten passwordP1Automated (API, partial)
E2E-IAM-012Password reset does not reveal whether a user existsP2Automated (API, partial)
E2E-IAM-013Password reset: mismatch and expired reset sessionP3Automated (API, partial)
E2E-IAM-014Sign up with GoogleP1Manual only
E2E-IAM-015Google sign-in on an existing e-mail userP2Manual only
E2E-IAM-016Google sign-in cancelled or blockedP3Manual only
E2E-IAM-017Password reset for a Google-only userP3Manual only
E2E-IAM-018Interface and e-mail languageP1Automated (API, partial)
E2E-IAM-019Edit own profileP2Automated (API, partial)
E2E-IAM-020Platform admin uses the admin web; others are denied; the owner web has no admin pagesP1Automated (API, partial)
E2E-IAM-021Adding a platform admin through configurationP2Manual only
E2E-IAM-022Turn on MFA with an authenticator app and sign in with the codeP1Automated (API, partial)
E2E-IAM-023A recovery code signs in onceP1Automated (API, partial)
E2E-IAM-024Five wrong codes lock the second stepP1Automated (API, partial)
E2E-IAM-025Regenerate the recovery codes and turn MFA offP2Automated (API, partial)
E2E-IAM-026Enrolment rules: wrong code, code used once, enrol twice, Google-only userP2Automated (API, partial)
E2E-IAM-027Google sign-in never asks for the second factorP2Automated (API, partial)

E2E-IAM-001 · Sign up with e-mail and verify with the code

Priority: P1 · Covers: FR-IAM-01, FR-IAM-03, FR-LIC-01, FR-NOT-04 · Automation: Automated (API, partial)

Preconditions: no user uses [email protected]. Browser signed out.

Test data: full name QA Signup IAM001, e-mail [email protected], phone 0900000901, password Qa@123456.

Steps

  1. Open the owner web and choose Create one on the sign-in page.
  2. Enter the full name, e-mail, phone and password, then press Create user.
  3. In Mailpit, open the newest e-mail to [email protected] and copy the 6-digit code.
  4. Enter the code on the verification page and press Verify.
  5. Open Subscription, then Roles & groups.

Expected results

  • After step 2 the Verify your e-mail page opens and says a 6-digit code was sent to [email protected], valid for 2 minutes, with a countdown.
  • The e-mail is in Vietnamese (the default language), greets QA Signup IAM001 and contains a 6-digit code.
  • After step 4 the app opens the Garages page with the empty state “No garage yet. Create your first garage to get started.”
  • Subscription shows plan Free trial, status Trial, a trial end date 14 days from today, and the trial banner “14 days left in your free trial”.
  • Roles & groups lists the five default roles, each tagged Default: Manager, Accountant, Service Advisor, Technician, Inventory Staff (in Vietnamese: Quản lý, Kế toán, Cố vấn dịch vụ, Kỹ thuật viên, Nhân viên kho).

E2E-IAM-002 · Unverified user can only use the Account page

Priority: P1 · Covers: FR-IAM-01 · Automation: Automated (API, partial)

Preconditions: baseline. [email protected] exists and is not verified.

Test data: UNVERIFIED ([email protected] / Test#2026-local).

Steps

  1. Sign in as [email protected]. Do not enter the code.
  2. Type these addresses into the browser one after the other: /garages, /staff, /customers, /subscription.
  3. Open /user.
  4. Change the full name to QA Unverified User Edited and save.

Expected results

  • Step 1 opens the verification page.
  • Every address in step 2 goes back to the verification page, which explains: “Verify your e-mail before managing garages, staff and data.”
  • The Account page opens, shows the e-mail as Not verified, and saving the new name shows “Changes saved.”

E2E-IAM-003 · Signing in unverified sends a new code

Priority: P2 · Covers: FR-IAM-01 · Automation: Automated (API, partial)

Preconditions: baseline. At least 30 seconds since the last code was sent to [email protected].

Test data: UNVERIFIED.

Steps

  1. Sign in as [email protected].
  2. In Mailpit, open the newest e-mail to [email protected].
  3. Enter that code and press Verify.

Expected results

  • A new verification e-mail arrives at the time of step 1.
  • The code verifies the user and the Garages page opens.
  • After this scenario, UNVERIFIED is verified. Create a new unverified user [email protected] if E2E-IAM-002 must run again.

E2E-IAM-004 · Wrong code, then too many wrong codes

Priority: P2 · Covers: FR-IAM-01 · Automation: Automated (API, partial)

Preconditions: none.

Test data: sign up [email protected] (name QA Signup IAM004, password Qa@123456). Wrong code 000000 (if the real code happens to be 000000, use 111111).

Steps

  1. Sign up with the test data. The verification page opens.
  2. Enter 000000 and press Verify.
  3. Repeat step 2 four more times (five wrong codes in total).
  4. Enter the correct code from Mailpit.

Expected results

  • Step 2 shows “Wrong code.” and the page stays open.
  • After the fifth wrong code, the message is “Too many wrong codes. Request a new one.”
  • Step 4 is refused as well: the code is no longer usable. After Resend code (available 30 seconds after the code was sent), the new code from Mailpit verifies the user.

E2E-IAM-005 · Code expires after 2 minutes

Priority: P2 · Covers: FR-IAM-01 · Automation: Automated (API, partial)

Preconditions: none.

Test data: sign up [email protected] (name QA Signup IAM005).

Steps

  1. Sign up with the test data and copy the code from Mailpit, but do not enter it.
  2. Wait until the countdown “Code expires in …” reaches zero (2 minutes).
  3. Enter the copied code.
  4. Press Resend code, and verify with the new code.

Expected results

  • At zero the page shows “The code expired. Request a new one.” and the Verify button is disabled.
  • A code entered after expiry is not accepted.
  • The new code verifies the user.

E2E-IAM-006 · Resend is possible only after 30 seconds and replaces the old code

Priority: P2 · Covers: FR-IAM-01 · Automation: Automated (API, partial)

Preconditions: none.

Test data: sign up [email protected] (name QA Signup IAM006). Call the first code code 1.

Steps

  1. Sign up with the test data. Note code 1 from Mailpit.
  2. Look at the Resend code button right away.
  3. When the button becomes available (after 30 seconds), press it. Note code 2 from the newest e-mail.
  4. Enter code 1.
  5. Enter code 2.

Expected results

  • In step 2 the button is disabled and shows “Resend in 30s”, counting down.
  • Step 3 shows “A new code was sent.” and a second e-mail arrives; the expiry countdown restarts at 2:00.
  • Code 1 is refused with “Wrong code.”
  • Code 2 verifies the user.

E2E-IAM-007 · Sign-up form validation and duplicates

Priority: P2 · Covers: FR-IAM-01 · Automation: Automated (API, partial)

Preconditions: baseline.

Test data:

CaseFull nameE-mailPhonePassword
a. Short passwordQA Signup IAM007[email protected]—Qa@1234 (7 characters)
b. Invalid e-mailQA Signup IAM007signup.iam007@vietgara—Qa@123456
c. E-mail taken, other letter caseQA Signup IAM007[email protected]—Qa@123456
d. Phone takenQA Signup IAM007[email protected]0900000101 (OWNER_A)Qa@123456
e. Empty full name(empty)[email protected]—Qa@123456

Steps

  1. For each case, open Create one, fill in the row and press Create user.

Expected results

  • a. Refused; the password field shows the rule “At least 8 characters.”
  • b. Refused; the e-mail field is marked invalid.
  • c. Refused with “This e-mail is already registered.” (e-mails are compared ignoring letter case).
  • d. Refused with “This phone number belongs to another user.”
  • e. Refused; the full-name field is marked as required.
  • No case sends an e-mail and no case creates [email protected] (check: it can still be used to sign up afterwards).

E2E-IAM-008 · Sign in and wrong credentials

Priority: P1 · Covers: FR-IAM-02 · Automation: Automated (API, partial)

Preconditions: baseline. Signed out.

Test data: OWNER_A ([email protected] / Test#2026-local); unknown e-mail [email protected].

Steps

  1. Sign in as [email protected] with password Wrong@123.
  2. Sign in as [email protected] with password Test#2026-local.
  3. Sign in as [email protected] with password Test#2026-local.

Expected results

  • Steps 1 and 2 show the same message, “Wrong e-mail or password.”, so it is not possible to tell whether the e-mail exists.
  • Step 3 signs in (e-mail letter case does not matter). The app opens with QA Gara A1 Quan 1 or QA Gara A2 Thu Duc as active garage and the owner’s name in the header.

E2E-IAM-009 · Sign out ends the session

Priority: P1 · Covers: FR-IAM-02 · Automation: Automated (API, partial)

Preconditions: baseline. Signed in as OWNER_A.

Test data: OWNER_A.

Steps

  1. Open Customers. Copy the page address.
  2. Press Sign out in the header.
  3. Press the browser’s Back button.
  4. Paste the copied address into the address bar.

Expected results

  • Step 2 opens the sign-in page.
  • Steps 3 and 4 do not show any customer data; they end on the sign-in page.

E2E-IAM-010 · Session survives a reload and an expired access token

Priority: P2 · Covers: FR-IAM-02 · Automation: Automated (API, partial)

Preconditions: baseline. JWT_ACCESS_TTL=20m (default).

Test data: ADVISOR_A1.

Steps

  1. Sign in as [email protected] and open Customers.
  2. Reload the page.
  3. Leave the tab idle for 25 minutes, then open Vehicles.

Expected results

  • After the reload, the user is still signed in and Customers loads again.
  • After 25 minutes, Vehicles loads without asking to sign in: the session was refreshed in the background.

E2E-IAM-011 · Reset a forgotten password

Priority: P1 · Covers: FR-IAM-04, FR-NOT-04 · Automation: Automated (API, partial)

Preconditions: [email protected] exists and is verified (sign it up with password Qa@123456, name QA Signup IAM011). It is signed in in a second browser (or a private window).

Test data: new password Qa@654321.

Steps

  1. In the first browser, signed out, choose Forgot password?.
  2. Enter [email protected] and press Send code.
  3. Enter the code from Mailpit and press Confirm code.
  4. Enter Qa@654321 twice and press Reset password.
  5. Sign in with the old password Qa@123456, then with Qa@654321.
  6. In the second browser, open any page.

Expected results

  • Step 2 moves to the code step, which says a code was sent if the address has a user.
  • The reset e-mail is in the user language and contains a 6-digit code valid for 2 minutes.
  • Step 4 shows “Password changed. Sign in again.” and returns to sign-in.
  • The old password is refused; the new one signs in.
  • The second browser is signed out: every session was revoked by the reset.

E2E-IAM-012 · Password reset does not reveal whether a user exists

Priority: P2 · Covers: FR-IAM-04 · Automation: Automated (API, partial)

Preconditions: signed out.

Test data: [email protected] (no user).

Steps

  1. Choose Forgot password?, enter [email protected] and press Send code.
  2. Enter 123456 and press Confirm code.

Expected results

  • Step 1 behaves exactly as for an existing user: the code step opens with the same wording.
  • Mailpit receives no e-mail to [email protected].
  • Step 2 is refused with a code error; nothing says the user does not exist.

E2E-IAM-013 · Password reset: mismatch and expired reset session

Priority: P3 · Covers: FR-IAM-04 · Automation: Automated (API, partial)

Preconditions: [email protected] exists (from E2E-IAM-011).

Test data: passwords Qa@111111 and Qa@222222.

Steps

  1. Start a reset for [email protected] and confirm the code from Mailpit.
  2. Enter Qa@111111 as new password and Qa@222222 as the repeat, then press Reset password.
  3. Wait 11 minutes on the new-password step, then enter Qa@111111 twice and press Reset password.

Expected results

  • Step 2 shows “The passwords do not match.” and nothing is sent.
  • Step 3 is refused with “The reset session expired. Start again.” (the reset session lasts 10 minutes). The password is unchanged.

E2E-IAM-014 · Sign up with Google

Priority: P1 · Covers: FR-IAM-01 · Automation: Manual only (real Google account)

Preconditions: Google sign-in is configured in the environment. GOOGLE_QA has no VietGara user yet. Pop-ups are allowed for the owner web.

Test data: GOOGLE_QA.

Steps

  1. On the sign-in page, press Continue with Google.
  2. In the Google window, choose GOOGLE_QA and agree.
  3. Open Account and Subscription.

Expected results

  • The Google window closes and the app opens directly on the Garages page, with no verification step.
  • Account shows the Google e-mail as Verified and the name from Google.
  • Subscription shows a Free trial, 14 days, as for an e-mail sign-up.

E2E-IAM-015 · Google sign-in on an existing e-mail user

Priority: P2 · Covers: FR-IAM-01, FR-IAM-02 · Automation: Manual only

Preconditions: a VietGara user was created with e-mail and password for the GOOGLE_QA address and is not verified (sign up with that e-mail, name QA Google Existing, password Qa@123456, and skip the code).

Test data: GOOGLE_QA.

Steps

  1. Sign out. Press Continue with Google and choose GOOGLE_QA.
  2. Sign out, then sign in with the GOOGLE_QA e-mail and Qa@123456.

Expected results

  • Step 1 signs in to the same user (name QA Google Existing, same garages): no second user is created.
  • The user is now Verified and has a trial subscription.
  • Step 2 works: the password still signs in.

E2E-IAM-016 · Google sign-in cancelled or blocked

Priority: P3 · Covers: FR-IAM-01 · Automation: Manual only

Preconditions: signed out.

Steps

  1. Press Continue with Google and close the Google window without choosing a user.
  2. Block pop-ups for the owner web in the browser settings, then press Continue with Google again.

Expected results

  • Step 1 stays on the sign-in page with “Google sign-in was cancelled.” (or no message). No user is created.
  • Step 2 shows “The browser blocked the Google sign-in window.”

E2E-IAM-017 · Password reset for a Google-only user

Priority: P3 · Covers: FR-IAM-04 · Automation: Manual only

Preconditions: the GOOGLE_QA user from E2E-IAM-014 (created by Google, never given a password).

Steps

  1. Signed out, choose Forgot password? and enter the GOOGLE_QA e-mail.
  2. Check Mailpit / the Google mailbox.

Expected results

  • The FRD says password reset is “not applicable to Google-only users”: the page answers as usual (it never reveals anything), but no reset code is sent and no password can be set.

Open question (September 28, 2026): the current backend sends a reset code to Google-only users, so they can set a password. If Product decides this is acceptable, change the expected result and the FRD; otherwise log a defect against FR-IAM-04.


E2E-IAM-018 · Interface and e-mail language

Priority: P1 · Covers: FR-IAM-07, FR-NOT-04 · Automation: Automated (API, partial)

Preconditions: baseline. [email protected] uses Vietnamese.

Test data: ADVISOR_A1.

Steps

  1. Signed out, switch the language on the sign-in page to English.
  2. Sign in as [email protected].
  3. Use the header language switcher to choose English. Reload the page.
  4. Sign out and sign in again in another browser.
  5. Signed out, request a password reset for [email protected] and open the e-mail in Mailpit. (Stop there; the password is not changed.)
  6. Switch back to Tiếng Việt in the header.

Expected results

  • Step 1 switches the sign-in page to English at once.
  • After step 3 all menus, buttons and messages are in English, and stay in English after the reload.
  • Step 4: the other browser opens in English: the choice is saved on the user, not only in the browser.
  • The reset e-mail in step 5 is in English.
  • After step 6 the interface is Vietnamese again, with no English text left in the sidebar, header or page.

E2E-IAM-019 · Edit own profile

Priority: P2 · Covers: FR-IAM-01, FR-TEN-04 · Automation: Automated (API, partial)

Preconditions: baseline.

Test data: FREELANCER. New phone 0900000302; taken phone 0900000112 (ADVISOR_A1).

Steps

  1. Sign in as [email protected] and open Account.
  2. Change the full name to QA Freelancer Edited and the phone to 0900000302. Save.
  3. Change the phone to 0900000112. Save.
  4. Restore the name QA Freelancer and phone 0900000301.

Expected results

  • Step 2 shows “Changes saved.”; the header shows the new name.
  • Step 3 is refused with “This phone number belongs to another user.”
  • The e-mail cannot be edited on this page.

E2E-IAM-020 · Platform admin uses the admin web; others are denied; the owner web has no admin pages

Priority: P1 · Covers: FR-IAM-08, FR-LIC-05 · Automation: Automated (API, partial)

Preconditions: baseline (ADMIN became platform admin in step B4). The admin web (vietgara-admin-web) is running next to the owner web.

Test data: ADMIN, OWNER_A, MANAGER_A1.

Steps

  1. In the admin web, sign in as [email protected]. Open Plans and Subscriptions from the sidebar.
  2. In the admin web, sign in as [email protected].
  3. Repeat step 2 as [email protected].
  4. In the owner web, sign in as [email protected]: look at the sidebar, then type /admin/plans and /admin/subscriptions into the address bar.

Expected results

  • Step 1: both pages load (plans table; subscription search).
  • Steps 2-3: OWNER_A and MANAGER_A1 can sign in but see only the Access denied page with a Sign out button; no admin data is shown or requested successfully (the backend refuses /api/v1/admin/*).
  • Step 4: the owner web has no Platform admin section; both addresses redirect to the default page.

E2E-IAM-021 · Adding a platform admin through configuration

Priority: P2 · Covers: FR-IAM-08 · Automation: Manual only (needs a backend restart)

Preconditions: baseline. Access to the backend .env and permission to restart it.

Test data: FREELANCER ([email protected]); [email protected] (no user yet).

Steps

  1. Set [email protected],[email protected],[email protected] and restart the backend.
  2. Sign in as [email protected] (sign out first if already signed in).
  3. Sign up and verify [email protected] (name QA Late Admin).
  4. Restart the backend again. Sign out and sign in as [email protected].
  5. Remove [email protected] from the list, restart, and sign in as FREELANCER again.
  6. Restore [email protected] and remove the extra rows: DELETE FROM platform_admins WHERE user_id IN (SELECT id FROM users WHERE email IN ('[email protected]', '[email protected]'));. Restart.

Expected results

  • Step 2: FREELANCER can use the admin web (sees Plans); more than one admin works at the same time as ADMIN.
  • Step 3: [email protected] is denied in the admin web: its user did not exist at the restart in step 1.
  • Step 4: after the second restart it does.
  • Step 5: FREELANCER still can use the admin web. Removing an e-mail from the list does not revoke admin rights (see the backend README, Platform admins); revoking needs step 6.

E2E-IAM-022 · Turn on MFA with an authenticator app and sign in with the code

Priority: P1 · Covers: FR-IAM-09, NFR-SE-04 · Automation: Automated (API, partial; the QR code and the screens are web and app E2E)

Preconditions: no user uses [email protected]. An authenticator app (or any TOTP tool) is available. The backend has MFA_ENCRYPTION_KEY set.

Test data: full name QA MFA IAM022, e-mail [email protected], password Qa@123456; sign up and verify the user as in E2E-IAM-001.

Steps

  1. Open Account → Security. It says two-step verification is off.
  2. Press Turn on. Scan the QR code with the authenticator app (or type the shown key), enter the 6-digit code, and press Confirm.
  3. Write down the 10 recovery codes and close the dialog.
  4. Sign out and sign in with the e-mail and password.
  5. On the code page, enter the current code from the app.
  6. Wait for the access token to expire, or reload the page.

Expected results

  • Step 1: the page offers Turn on; before step 2 completes, signing in still needs only the password.
  • Step 2: after the code is accepted the page lists 10 recovery codes (shown once) and the status reads On.
  • Step 4: the app opens the code page instead of the Garages page; no tokens are stored yet.
  • Step 5: the Garages page opens.
  • Step 6: the session continues without asking for a code again.

E2E-IAM-023 · A recovery code signs in once

Priority: P1 · Covers: FR-IAM-09 · Automation: Automated (API, partial)

Preconditions: the user of E2E-IAM-022 with MFA on and its recovery codes.

Steps

  1. Sign out. Sign in with the password, then enter the first recovery code on the code page (letter case does not matter).
  2. Sign out. Sign in again and enter the same recovery code.
  3. Sign out. Sign in again and enter the second recovery code.
  4. Open Account → Security.

Expected results

  • Step 1: signs in.
  • Step 2: refused with “the code is incorrect”.
  • Step 3: signs in; each code works once and the others are unaffected.
  • Step 4: shows 8 recovery codes left.

E2E-IAM-024 · Five wrong codes lock the second step

Priority: P1 · Covers: FR-IAM-09, NFR-SE-04 · Automation: Automated (API, partial)

Preconditions: a user with MFA on.

Steps

  1. Sign in with the password. On the code page enter 000000 four times.
  2. Enter 000000 a fifth time.
  3. Enter the correct code from the app.
  4. Go back, sign in with the password again, and enter the correct code.

Expected results

  • Step 1: each attempt says the code is incorrect.
  • Step 2: the page says there were too many wrong codes and to try again later.
  • Steps 3-4: still refused with the same message, even with the correct code, for 15 minutes (a new sign-in with the password itself still works). After 15 minutes the correct code signs in.

E2E-IAM-025 · Regenerate the recovery codes and turn MFA off

Priority: P2 · Covers: FR-IAM-09 · Automation: Automated (API, partial)

Preconditions: a user with MFA on, signed in, with the old recovery codes.

Steps

  1. In Account → Security press New recovery codes and enter an old recovery code.
  2. Press New recovery codes again and enter the current code from the app.
  3. Sign out and sign in with the password; enter an old recovery code.
  4. Sign in again; enter a new recovery code.
  5. In Account → Security press Turn off and enter the current code (or a recovery code).
  6. Sign out and sign in with the password.

Expected results

  • Step 1: refused; only the code from the app regenerates the codes.
  • Step 2: a new set of 10 codes is shown once.
  • Step 3: the old code is refused.
  • Step 4: the new code signs in.
  • Step 5: the status reads Off.
  • Step 6: signs in with the password alone.

E2E-IAM-026 · Enrolment rules: wrong code, code used once, enrol twice, Google-only user

Priority: P2 · Covers: FR-IAM-09 · Automation: Automated (API, partial)

Preconditions: a verified user with a password and MFA off; a user created by Google sign-in (E2E-IAM-014).

Steps

  1. Start the enrolment and enter 000000 as the confirming code.
  2. Enter the correct code and confirm.
  3. Sign out, sign in with the password, and enter the code that was used to confirm.
  4. Try to start the enrolment again while signed in.
  5. Sign in with Google as the Google-only user and open Account → Security.

Expected results

  • Step 1: refused; MFA stays off and the sign-in still needs only the password.
  • Step 2: MFA is on.
  • Step 3: refused: a code works once.
  • Step 4: refused: MFA is already on.
  • Step 5: the page does not offer MFA for a user without a password (the API answers MFA_NOT_AVAILABLE).

E2E-IAM-027 · Google sign-in never asks for the second factor

Priority: P2 · Covers: FR-IAM-09 · Automation: Automated (API, partial)

Preconditions: a user with a password and MFA on, whose e-mail is also a Google account.

Steps

  1. Sign out. Choose Sign in with Google with that account.

Expected results

  • Step 1: signs in as the same user without a code page; Google’s own 2-step verification protects this sign-in.