Skip to content

Work / Scrvio / Wiki / Surfaces

login

Surfacecanonicalverified 2026-10-04

SURFACE.WEB.LOGIN

Summary

Email and password sign-in, with Google as the second way in.

Raw wireframe

  • .context/designs/web/auth/login.html
  • .context/designs/web/auth/login-error.html

Why it is drawn this way

The form sits in the shared auth shell. auth/layout.tsx wraps every /auth/* page in AuthLayout: the welcome title and six benefits on the left, a card on the right.

A wrong password is reported under Email. The server answers "Invalid email or password. Please try again." login-form.tsx puts any message containing email or user under the email field, so that is where it lands. The error state draws this. The same text also shows as a toast (use-auth.ts).

Some failures show no field error at all. A message with none of email, user, password in it — "Account is inactive", or the form's own fallback "Login failed. Please check your credentials." — is dropped by the form. Only the toast shows.

"Email is required" is unreachable in a browser. Both inputs are required, so the browser blocks an empty submit before handleSubmit runs. The strings exist in code and are not drawn.

Success goes to Home. router.push(redirect || "/"). The submit button links to Home. A visitor bounced from a guarded page returns to it through ?redirect=.

The Google button uses the Chrome icon. oauth-button.tsx imports lucide Chrome. It opens a popup, so it is a button here, not a link.

The benefits list a VIEWER role. benefits.ts says "OWNER, ADMIN, MEMBER, and VIEWER". The schema's OrgMemberRole has no VIEWER.

Related

Sources

  • apps/website/src/app/auth/login/page.tsx
  • apps/website/src/app/auth/layout.tsx
  • apps/website/src/app/auth/benefits.ts
  • packages/ui/src/components/auth/login-form.tsx
  • packages/ui/src/components/auth/auth-layout.tsx
  • packages/ui/src/hooks/use-auth.ts