CU-02: Auth lifecycle: register, email verification, login, forgot/reset password, delete account

Priority: P0 Accounts/sessions: Fresh throwaway account created during the run via the plus-alias ravikantguptaofficial+auth-<RUNID>@gmail.com. The agent must ALSO already be signed into Gmail in the browser as ravikantguptaofficial@gmail.com (plus-aliases deliver to that single inbox) so it can read the verification and reset emails. No other Calendo session is required — this suite creates and tears down its own account. Parallel-safe: Yes — runs against a brand-new throwaway account scoped by RUNID; touches no shared host data, event types, or availability. Exclusive (rewrites global host availability?): No. Estimated time: ~22 minutes. L3 reality checks: Yes — (1) the real email-verification email arriving in Gmail and its link working; (2) the real password-reset email arriving in Gmail and its link working. No calendar L3 in this suite.

Goal

This suite proves the complete email/password identity lifecycle that every self-serve Calendo user depends on: a new person can register with email + password, is gated until they verify their email via a real email they receive, can log in and is correctly rejected on a wrong password, can recover access through a real "forgot password" email and set a new password (with old sessions/passwords invalidated), and can finally delete their account and lose access. If any link in this chain is broken, users either cannot get in, cannot get back in, or cannot leave — all of which are launch-blocking. Because Calendo is a public SaaS where anyone signs up, this is the highest-trust path in the product.

Preconditions

Test data

Steps

  1. Action: Open a fresh browser tab and navigate to the registration page (https://calendo.dev/auth/register.html). Expect: The "Create your account" card renders with a Full name field (#name), Email field (#email), Password field (#password), a "Create account" button (#submitBtn), and OAuth buttons "Sign up with Google" (.oauth-google) and "Sign up with Microsoft" (.oauth-microsoft). [L1]
  1. Action: Confirm the OAuth buttons are present (.oauth-google, .oauth-microsoft) and that the "or" divider (.divider) is visible — this verifies OAuth is configured in production. Do NOT click them. Expect: Both OAuth buttons visible. [L1] Capture screenshot: cu02-01-register-form
  1. Action: Type the name Auth Test <RUNID> into Full name (#name), ravikantguptaofficial+auth-<RUNID>@gmail.com into Email (#email), and AuthInit-<RUNID>!9 into Password (#password). Expect: Fields hold the typed values; no inline validation error. [L1]
  1. Action: Click "Create account" (#submitBtn). Expect: No red error box (#error) appears. The card content is REPLACED in place with a verification gate that reads "Before continuing, we need to verify your email address.", "Please check your inbox for a confirmation link.", the email address ...+auth-<RUNID>@gmail.com shown in bold, and a "resend it to you" link (#resendLink). (Per public/auth/register.html, on success the page does NOT redirect to the dashboard — it swaps in this gate. A session cookie IS set behind the scenes.) [L1]
    • If instead a red #error appears containing "already": the RUNID collided with an existing account — STOP, pick a new RUNID, restart at Step 1. Capture screenshot: cu02-02-verify-gate
  1. Action: Confirm the new account's session is active by opening https://calendo.dev/dashboard/ in the same tab. Expect: Because the email is not yet verified, the dashboard's init guard force-redirects to the standalone verification page https://calendo.dev/auth/verify.html (per dashboard init() at if (!currentUser.email_verified) → /auth/verify.html). That page shows the heading "Before continuing, we need to verify your email address.", the account email in bold (#userEmail), a "resend it to you" link (#resendLink), and a status line "Checking for verification…" (#pollStatus) that polls every 3 seconds. This confirms (a) the session exists and (b) unverified users are correctly gated. [L1][L2] Capture screenshot: cu02-03-verify-page-gated
  1. Action: On https://calendo.dev/auth/verify.html, click the "resend it to you" link (#resendLink). Expect: A confirmation message appears (#resendMsg) reading "Verification email resent! Check your inbox." in green. (This calls POST /api/auth/resend-verification.) [L1]
  1. Action: L3 — verify the email actually arrived and the link works. See L3 reality checks → Verification email below for the exact Gmail search and link-click sub-steps. Expect: After clicking the verification link, the browser lands on the worker-rendered "Email Verified" page (a checkmark, heading "Email Verified", text "Your email address has been verified successfully. You're all set!", a "Continue Setup" button to /onboarding/, and "Redirecting in 2 seconds…"), then auto-redirects to https://calendo.dev/onboarding/. [L3] Capture screenshot: cu02-04-email-verified
  1. Action: Return to https://calendo.dev/dashboard/ (if onboarding appears, you may dismiss/skip it; the focus here is auth). Expect: The dashboard now loads fully (it no longer bounces to verify.html), the welcome header (#welcomeHeader) shows the name Auth Test <RUNID>, and the amber email-verification banner (#emailVerificationBanner, text "Please verify your email address to get the most out of Calendo.") is NOT displayed. This proves verification persisted server-side. [L2] Capture screenshot: cu02-05-dashboard-verified-no-banner
  1. Action: Capture the throwaway account's host slug for the cleanup/records: on the dashboard, read the booking-link value element (#bookingLinkValue) and note the portion after user=. Expect: A non-empty slug string. Record it. [L2]
  1. Action: Log out. Click the logout control (#logoutBtn) in the dashboard. Expect: The browser redirects to the login page https://calendo.dev/auth/login.html. [L1]
  1. Action: Confirm the session is truly cleared by navigating directly to https://calendo.dev/dashboard/. Expect: You are redirected back to https://calendo.dev/auth/login.html (no dashboard content). [L2]
  1. Action: Log back in with the correct credentials. On https://calendo.dev/auth/login.html, type ravikantguptaofficial+auth-<RUNID>@gmail.com into Email (#email) and AuthInit-<RUNID>!9 into Password (#password), then click "Sign in" (#submitBtn). Expect: No error box (#error); the browser navigates to https://calendo.dev/dashboard/ and the welcome header (#welcomeHeader) shows Auth Test <RUNID>. [L1] Capture screenshot: cu02-06-login-success
  1. Action: Log out again (#logoutBtn) to return to a clean login state for the negative test. Expect: Redirected to https://calendo.dev/auth/login.html. [L1]
  1. Action: Attempt a login with the WRONG password. On https://calendo.dev/auth/login.html, type the correct email ravikantguptaofficial+auth-<RUNID>@gmail.com (#email) and a deliberately wrong password WrongPass-<RUNID>!9 (#password), then click "Sign in" (#submitBtn). Expect: A red error box (#error) becomes visible and non-empty (the message is the generic "Invalid email or password"), and the URL stays on /auth/login.html — you are NOT logged in. [L1] Capture screenshot: cu02-07-wrong-password-error
  1. Action: Start the forgot-password flow. Navigate to https://calendo.dev/auth/reset-password.html (or click "Forgot your password?" on the login page, which links there). Expect: The "Forgot your password?" card shows with an Email field (#email) and a "Send reset link" button (#forgotBtn). [L1]
  1. Action: Type the account email ravikantguptaofficial+auth-<RUNID>@gmail.com into Email (#email) and click "Send reset link" (#forgotBtn). Expect: A green success message (#success) appears (text contains "reset link" / "Check your email for a reset link.") and the request form is hidden. (Note: per anti-enumeration design, the same success shows even for non-existent emails, so this UI message alone is NOT proof the email went out — the L3 check below is.) [L1] Capture screenshot: cu02-08-reset-requested
  1. Action: L3 — verify the reset email actually arrived and open its link. See L3 reality checks → Reset email below for the exact Gmail search and link-click sub-steps. After clicking the reset link you should land on https://calendo.dev/auth/reset-password.html?token=... showing the "Set a new password" form. Expect: The reset form renders with "New password" (#password) and "Confirm new password" (#confirmPassword) fields and a "Reset password" button (#resetBtn). [L3]
  1. Action: In the "Set a new password" form, type AuthReset-<RUNID>!9 into both "New password" (#password) and "Confirm new password" (#confirmPassword), then click "Reset password" (#resetBtn). Expect: A green success message (#success) appears (text contains "reset successfully"), the form hides, and after ~2.5 seconds the page auto-redirects to https://calendo.dev/auth/login.html. [L1] Capture screenshot: cu02-09-password-reset-success
  1. Action: Confirm the OLD password no longer works. On https://calendo.dev/auth/login.html, enter the account email (#email) and the OLD password AuthInit-<RUNID>!9 (#password), click "Sign in" (#submitBtn). Expect: Red error box (#error) "Invalid email or password"; URL stays on /auth/login.html; not logged in. This proves the password was actually changed. [L2] Capture screenshot: cu02-10-old-password-rejected
  1. Action: Confirm the NEW password works. On https://calendo.dev/auth/login.html, enter the account email (#email) and the NEW password AuthReset-<RUNID>!9 (#password), click "Sign in" (#submitBtn). Expect: No error; navigates to https://calendo.dev/dashboard/; welcome header (#welcomeHeader) shows Auth Test <RUNID>. [L2] Capture screenshot: cu02-11-new-password-login
  1. Action: (Session-invalidation check — best-effort, observable.) The password-reset endpoint invalidates all prior sessions for the user. We already proved logout cleared the session before reset, so to observe invalidation directly is not strictly available in a single browser. Record an explicit note in the results report that this property is covered by tests/unit/worker/password-reset.test.js ("should invalidate all sessions after password reset") and that the in-browser behavior consistent with it is: the OLD-password login failing (Step 19) and a NEW login being required (Step 20). Expect: Note recorded; no separate UI assertion. [L2]
  1. Action: Now delete the account. From the dashboard, open Settings — click the sidebar Settings tab (.sidebar-nav a[data-tab="settings"]). Scroll to the "Danger Zone" card (.settings-danger-card, red, titled "Danger Zone"). Expect: A red "Delete My Account" button (#deleteAccountBtn) is visible. [L1] Capture screenshot: cu02-12-danger-zone
  1. Action: Click "Delete My Account" (#deleteAccountBtn). Expect: A first confirmation dialog appears titled "Delete Account" warning that this permanently deletes the account, event types, bookings, availability, calendar connections, and booking pages, with a confirm button labeled "Delete Everything". [L1]
  1. Action: Confirm the first dialog ("Delete Everything"). Expect: A second confirmation dialog appears titled "Are you absolutely sure?" whose body shows "Type your email to confirm: ravikantguptaofficial+auth-<RUNID>@gmail.com" with a confirm button "Yes, Delete My Account". (Per the current implementation this second dialog is a confirm prompt, not a free-text email-entry field — there is no text input to type into; clicking the confirm button proceeds.) [L1] Capture screenshot: cu02-13-delete-confirm
  1. Action: Click "Yes, Delete My Account". Expect: The browser navigates to https://calendo.dev/auth/login.html?deleted=1 (the ?deleted=1 query indicates the deletion succeeded). The account session is gone. [L1] Capture screenshot: cu02-14-deleted-redirect
  1. Action: Confirm the deleted account can no longer log in. On https://calendo.dev/auth/login.html, enter the account email (#email) and the NEW password AuthReset-<RUNID>!9 (#password), click "Sign in" (#submitBtn). Expect: Red error box (#error) "Invalid email or password"; URL stays on /auth/login.html. The account is truly gone. [L2] Capture screenshot: cu02-15-deleted-login-fails
  1. Action: Confirm the deleted account's dashboard is inaccessible by navigating directly to https://calendo.dev/dashboard/. Expect: Redirected to https://calendo.dev/auth/login.html (no dashboard). [L2]

L3 reality checks

Verification email (used in Step 7)

  1. Open a new tab to https://mail.google.com (already logged in as ravikantguptaofficial@gmail.com).
  2. In the Gmail search box, search exactly: subject:(Verify your Calendo email address) to:(+auth-<RUNID>) — or more simply auth-<RUNID> to find any Calendo mail for this run.
  3. Confirm: An email arrives (allow up to ~3 minutes; refresh) from Calendo with subject "Verify your Calendo email address", addressed to ravikantguptaofficial+auth-<RUNID>@gmail.com, containing a "Verify Email" button/link pointing to https://calendo.dev/api/auth/verify-email?token=.... Capture screenshot: cu02-L3a-verification-email
  4. Click the "Verify Email" link in the email. Confirm: It opens the "Email Verified" success page on calendo.dev (Step 7 expectation) and redirects to /onboarding/. If two verification emails exist (one from registration, one from the resend in Step 6), use the most recent one; an older link may report "already used"/"Invalid" if the newer was clicked first — that is acceptable as long as one link verifies the account.

Reset email (used in Step 17)

  1. In Gmail (ravikantguptaofficial@gmail.com), search exactly: subject:(Reset your Calendo password) to:(+auth-<RUNID>) — or auth-<RUNID> and pick the password reset message.
  2. Confirm: An email arrives (allow up to ~3 minutes) from Calendo with subject "Reset your Calendo password", addressed to ravikantguptaofficial+auth-<RUNID>@gmail.com, containing a "Reset Password" link pointing to https://calendo.dev/auth/reset-password.html?token=.... Capture screenshot: cu02-L3b-reset-email
  3. Click the "Reset Password" link. Confirm: It opens https://calendo.dev/auth/reset-password.html with a token= query param and the "Set a new password" form (Step 17 expectation).

Cleanup

Pass/Fail criteria

The run PASSES only if ALL of the following are true:

The run FAILS if any L3 email does not arrive, any link is broken, a wrong password is ever accepted, the old password still works after reset, the deleted account can still log in, or any step's Expect is not met.

Evidence to capture

Manual residue / cannot-verify

Manual residue

None beyond the "Manual residue / cannot-verify" section above.