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.
| ID | Title | Priority | Automation |
|---|---|---|---|
| E2E-IAM-001 | Sign up with e-mail and verify with the code | P1 | Automated (API, partial) |
| E2E-IAM-002 | Unverified user can only use the Account page | P1 | Automated (API, partial) |
| E2E-IAM-003 | Signing in unverified sends a new code | P2 | Automated (API, partial) |
| E2E-IAM-004 | Wrong code, then too many wrong codes | P2 | Automated (API, partial) |
| E2E-IAM-005 | Code expires after 2 minutes | P2 | Automated (API, partial) |
| E2E-IAM-006 | Resend is possible only after 30 seconds and replaces the old code | P2 | Automated (API, partial) |
| E2E-IAM-007 | Sign-up form validation and duplicates | P2 | Automated (API, partial) |
| E2E-IAM-008 | Sign in and wrong credentials | P1 | Automated (API, partial) |
| E2E-IAM-009 | Sign out ends the session | P1 | Automated (API, partial) |
| E2E-IAM-010 | Session survives a reload and an expired access token | P2 | Automated (API, partial) |
| E2E-IAM-011 | Reset a forgotten password | P1 | Automated (API, partial) |
| E2E-IAM-012 | Password reset does not reveal whether a user exists | P2 | Automated (API, partial) |
| E2E-IAM-013 | Password reset: mismatch and expired reset session | P3 | Automated (API, partial) |
| E2E-IAM-014 | Sign up with Google | P1 | Manual only |
| E2E-IAM-015 | Google sign-in on an existing e-mail user | P2 | Manual only |
| E2E-IAM-016 | Google sign-in cancelled or blocked | P3 | Manual only |
| E2E-IAM-017 | Password reset for a Google-only user | P3 | Manual only |
| E2E-IAM-018 | Interface and e-mail language | P1 | Automated (API, partial) |
| E2E-IAM-019 | Edit own profile | P2 | Automated (API, partial) |
| E2E-IAM-020 | Platform admin uses the admin web; others are denied; the owner web has no admin pages | P1 | Automated (API, partial) |
| E2E-IAM-021 | Adding a platform admin through configuration | P2 | Manual only |
| E2E-IAM-022 | Turn on MFA with an authenticator app and sign in with the code | P1 | Automated (API, partial) |
| E2E-IAM-023 | A recovery code signs in once | P1 | Automated (API, partial) |
| E2E-IAM-024 | Five wrong codes lock the second step | P1 | Automated (API, partial) |
| E2E-IAM-025 | Regenerate the recovery codes and turn MFA off | P2 | Automated (API, partial) |
| E2E-IAM-026 | Enrolment rules: wrong code, code used once, enrol twice, Google-only user | P2 | Automated (API, partial) |
| E2E-IAM-027 | Google sign-in never asks for the second factor | P2 | Automated (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
- Open the owner web and choose Create one on the sign-in page.
- Enter the full name, e-mail, phone and password, then press Create user.
- In Mailpit, open the newest e-mail to
[email protected]and copy the 6-digit code. - Enter the code on the verification page and press Verify.
- 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
- Sign in as
[email protected]. Do not enter the code. - Type these addresses into the browser one after the other:
/garages,/staff,/customers,/subscription. - Open
/user. - Change the full name to
QA Unverified User Editedand 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
- Sign in as
[email protected]. - In Mailpit, open the newest e-mail to
[email protected]. - 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
- Sign up with the test data. The verification page opens.
- Enter
000000and press Verify. - Repeat step 2 four more times (five wrong codes in total).
- 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
- Sign up with the test data and copy the code from Mailpit, but do not enter it.
- Wait until the countdown “Code expires in …” reaches zero (2 minutes).
- Enter the copied code.
- 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
- Sign up with the test data. Note code 1 from Mailpit.
- Look at the Resend code button right away.
- When the button becomes available (after 30 seconds), press it. Note code 2 from the newest e-mail.
- Enter code 1.
- 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:
| Case | Full name | Phone | Password | |
|---|---|---|---|---|
| a. Short password | QA Signup IAM007 | [email protected] | — | Qa@1234 (7 characters) |
| b. Invalid e-mail | QA Signup IAM007 | signup.iam007@vietgara | — | Qa@123456 |
| c. E-mail taken, other letter case | QA Signup IAM007 | [email protected] | — | Qa@123456 |
| d. Phone taken | QA Signup IAM007 | [email protected] | 0900000101 (OWNER_A) | Qa@123456 |
| e. Empty full name | (empty) | [email protected] | — | Qa@123456 |
Steps
- 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
- Sign in as
[email protected]with passwordWrong@123. - Sign in as
[email protected]with passwordTest#2026-local. - Sign in as
[email protected]with passwordTest#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
- Open Customers. Copy the page address.
- Press Sign out in the header.
- Press the browser’s Back button.
- 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
- Sign in as
[email protected]and open Customers. - Reload the page.
- 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
- In the first browser, signed out, choose Forgot password?.
- Enter
[email protected]and press Send code. - Enter the code from Mailpit and press Confirm code.
- Enter
Qa@654321twice and press Reset password. - Sign in with the old password
Qa@123456, then withQa@654321. - 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
- Choose Forgot password?, enter
[email protected]and press Send code. - Enter
123456and 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
- Start a reset for
[email protected]and confirm the code from Mailpit. - Enter
Qa@111111as new password andQa@222222as the repeat, then press Reset password. - Wait 11 minutes on the new-password step, then enter
Qa@111111twice 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
- On the sign-in page, press Continue with Google.
- In the Google window, choose GOOGLE_QA and agree.
- 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
- Sign out. Press Continue with Google and choose GOOGLE_QA.
- 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
- Press Continue with Google and close the Google window without choosing a user.
- 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
- Signed out, choose Forgot password? and enter the GOOGLE_QA e-mail.
- 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
- Signed out, switch the language on the sign-in page to English.
- Sign in as
[email protected]. - Use the header language switcher to choose English. Reload the page.
- Sign out and sign in again in another browser.
- Signed out, request a password reset for
[email protected]and open the e-mail in Mailpit. (Stop there; the password is not changed.) - 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
- Sign in as
[email protected]and open Account. - Change the full name to
QA Freelancer Editedand the phone to0900000302. Save. - Change the phone to
0900000112. Save. - Restore the name
QA Freelancerand phone0900000301.
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
- In the admin web, sign in as
[email protected]. Open Plans and Subscriptions from the sidebar. - In the admin web, sign in as
[email protected]. - Repeat step 2 as
[email protected]. - In the owner web, sign in as
[email protected]: look at the sidebar, then type/admin/plansand/admin/subscriptionsinto 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
- Set
[email protected],[email protected],[email protected]and restart the backend. - Sign in as
[email protected](sign out first if already signed in). - Sign up and verify
[email protected](nameQA Late Admin). - Restart the backend again. Sign out and sign in as
[email protected]. - Remove
[email protected]from the list, restart, and sign in as FREELANCER again. - 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
- Open Account → Security. It says two-step verification is off.
- Press Turn on. Scan the QR code with the authenticator app (or type the shown key), enter the 6-digit code, and press Confirm.
- Write down the 10 recovery codes and close the dialog.
- Sign out and sign in with the e-mail and password.
- On the code page, enter the current code from the app.
- 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
- Sign out. Sign in with the password, then enter the first recovery code on the code page (letter case does not matter).
- Sign out. Sign in again and enter the same recovery code.
- Sign out. Sign in again and enter the second recovery code.
- 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
- Sign in with the password. On the code page enter
000000four times. - Enter
000000a fifth time. - Enter the correct code from the app.
- 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
- In Account → Security press New recovery codes and enter an old recovery code.
- Press New recovery codes again and enter the current code from the app.
- Sign out and sign in with the password; enter an old recovery code.
- Sign in again; enter a new recovery code.
- In Account → Security press Turn off and enter the current code (or a recovery code).
- 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
- Start the enrolment and enter
000000as the confirming code. - Enter the correct code and confirm.
- Sign out, sign in with the password, and enter the code that was used to confirm.
- Try to start the enrolment again while signed in.
- 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
- 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.