Skip to content

feat(auth): PIN quick user switch with user picker (PIN for all roles, approvals stay owner/manager) #1338

Open

Description

@khaira777

Parent: #830 (S3a). Verified against main @ 8e39053. Related: per-user shifts issue (see #830).

Problem

An owner and a cashier sharing one till have to fully log out and back in with email and password (+1-829, 21 Sep).

Current behavior (verified)

  • The frontend keeps one session: frontend/src/store/auth.ts (~L48-53, L149-150) stores a single token and tenant. There is no lock or switch-user flow.
  • PINs are owner/manager only today. main/routes/staff.ts ~L314 rejects a PIN for operational roles ("PINs are only permitted for owner and manager roles"). PINs are 4-6 digits, bcrypt pin_hash.
  • Approval paths only accept active owner/manager approvers with a matching pin_hash (approvers directory staff.ts ~L214-216; docs/architecture/authentication-and-authorization.md ~L140-152).

Decisions (made by maintainer, 23 Oct)

  • Reuse the existing per-user PIN and allow it for every role. It doubles as the sign-in PIN. Only owner and manager PINs approve actions, so a cashier, server or chef PIN must never satisfy an approval check.
  • Quick switch with a user picker: when the POS is locked or logged out, show active users (name and role) as tiles. Tap a user, then enter that user's PIN. The PIN is checked only against the selected user, never by scanning all users, so two users may share the same PIN.
  • Only one user is signed in on a device at a time. Switching replaces the token.
  • Email and password sign-in stays available.

Small decisions (taken during grooming)

  • A "Lock" action in the topbar, plus an optional idle auto-lock setting (off by default).
  • A user without a PIN does not get a quick-switch tile and uses email and password.
  • Reuse the install-wide login rate limiting (fix(auth): enforce install-wide login attempt rate limiting across servers #1199) per user, and audit each PIN sign-in.
  • The open cash shift is not touched by switching. With per-user shifts on, the payment follows the signed-in user (see that issue).

Scope

  • Backend: lift the operational-role PIN restriction in staff.ts (create and update). Add POST /api/auth/pin-login taking { user_id, pin }, which returns the same token shape as /login. Add a public, minimal list of active users with a PIN (id, name, role only) for the lock screen.
  • Hardening (must do): audit every approval path (refund, item void, discount, order-status and kitchen-delivery overrides, charge waiver, payment-method correction) to confirm it enforces the owner/manager role, not just a matching PIN. Add a regression test that a cashier with a PIN is rejected on each.
  • Frontend: lock screen with user tiles and a PIN pad (auth/login/page.tsx or a new lock route), a Lock action, and store/auth.ts switch flow.
  • Wording: rename the user-facing PIN strings so there is one term ("PIN") for staff and "Staff Approval PIN" only where approval is meant. Fix kitchenDeliveryOverridePrompt, which still says "Manager PIN". Update all locales.
  • Docs: docs/architecture/authentication-and-authorization.md and docs/reference/roles-and-permissions.md.

Acceptance criteria

  • Cashier can set a PIN, and quick-switch in with the user tile and PIN.
  • Two users with an identical PIN can each sign in as themselves.
  • A cashier PIN is rejected on every approval prompt (tests).
  • Wrong PIN attempts are rate-limited and audited.
  • Logout and lock clear the previous token.

Verification

  • New tests/pin-quick-switch.test.ts and approval-path role tests, plus an e2e lock, switch and payment flow.
  • npm run lint && npm test && npm run test:e2e:browser

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:backendBackend (Express/SQLite)area:frontendFrontend (React/Next.js)enhancementNew feature or requeststate:readyScoped and ready for implementationtype:featureNew capability or enhancement request

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions