Skip to content

Login (Cara Vault)

StatusShipped
LinearPIN-489 ↗
ModuleSettings & Admin ↗

The launch login was rebuilt as "Cara Vault": Cara-branded, workspace-scoped (Pinley Mechanical hardcoded), with inline error banners (not toasts) and a per-error message map. QA switches roles via the dev role switcher in the top bar (non-prod builds only).

Prerequisites

  • Credentials for at least one seeded account; on staging, confirm with Marko whether VITE_DEV_FEATURES is on (that decides whether the role switcher exists — see step 5).

1. The screen

/login shows: top classification strip (Cara · Construction Intelligence / Secure Access · Pinley Mechanical), the Cara lockup, promise line "A knowing friend.", headline Welcome back. with subtitle "— Sign in to continue", a Workspace block reading Pinley Mechanical, Email and Password fields (eye toggle), Forgot password? link, Sign in button (disabled until both fields are filled), footer © {year} Pinco Technologies Inc. · SOC 2 Type II · End-to-end encrypted.

2. Error states — inline banner, not toast

Wrong inputs swap the headline to Couldn't sign you in. (subtitle "— Please check and try again") and show a red inline banner. Message map to verify:

Trigger Banner text
Wrong password or unknown user Account not yet linked to this workspace. Ask your admin to grant access, then try again. — the backend deliberately returns one generic answer for both (anti-enumeration), so the frontend's "Email or password incorrect" string is currently unreachable. Verified live 2026-07-08.
Locked account Account locked. Contact your admin to unlock.
Rate-limited (hammer sign-in) Too many sign-in attempts. Please wait 15 minutes and try again.

The button flips to Try again. ⚠ UX side-effect worth a ticket: a user who merely typo'd their password is told their account "isn't linked to this workspace" — misleading. Either the copy or the backend mapping should change.

3. Password recovery

Forgot password? → email field → Send reset link → success screen "Check your email." then auto-redirect to /reset-password. Invite/activation lives at /verify-account. Run recovery once end-to-end with a mailbox you control.

4. Session expiry and post-login landing

  • Expired session: the next RPC bounces cleanly to /login (no white screen, no stuck spinner).
  • Post-login you land on your role's default page — deep links do not survive login (visiting /projects/… logged-out → login → role home, not back to the project). Known limitation, don't file as new.

5. Switching roles (the QA superpower)

In non-prod builds a role chip sits in the top bar (next to Search): click it → dropdown of all 14 roles → selecting one re-logs-in as that role's seeded account ({role}@codilas.com) and reloads. Permissions are real server-side grants, not mocks — this is the sanctioned way to run every per-role check in the other walkthroughs. If the chip is absent on staging, ask Marko for per-role logins instead.

⚠ The switcher uses the build-time VITE_DEV_PASSWORD. If it doesn't match the environment's seeded password, the switch fails silently (console error only, no UI feedback) — verified live 2026-07-08 on a local stand. If clicking a role does nothing, log in manually as {role}@codilas.com with the environment's password instead, and ask Marko to align the env var.

Verification Checklist

  • Sign in disabled until both fields are non-empty; eye toggle works
  • Each error trigger above shows its exact banner (and never a toast)
  • Rate limit engages after repeated failures
  • Recovery email flow completes and the new password works
  • Expired session bounces to /login; re-login lands on the role default page
  • Role switcher lists 14 roles and actually changes permissions (e.g. Field User loses the Bids nav)
  • No console errors on the auth screens

Known Issues / Current Gaps

  • The login is fully Cara-branded by design — no Pinley logo; "Pinley Mechanical" appears only as the workspace name. Not a bug.
  • ⚠ Deep links don't survive login (role default page instead) — known.

Updating this walkthrough

Run the full flow yourself end-to-end. If it passes, bump last_verified: in the frontmatter to today's date. If any step fails, fix the doc or the code in the same PR — drift is the enemy.