Repository navigation
feat(auth): PIN quick user switch with user picker (PIN for all roles, approvals stay owner/manager) #1338
Copy link
Copy link
Open
Labels
area:backendBackend (Express/SQLite)Backend (Express/SQLite)area:frontendFrontend (React/Next.js)Frontend (React/Next.js)enhancementNew feature or requestNew feature or requeststate:readyScoped and ready for implementationScoped and ready for implementationtype:featureNew capability or enhancement requestNew capability or enhancement request
Description
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 singletokenandtenant. 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, bcryptpin_hash. - Approval paths only accept active owner/manager approvers with a matching
pin_hash(approvers directorystaff.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). AddPOST /api/auth/pin-logintaking{ 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.tsxor a new lock route), a Lock action, andstore/auth.tsswitch 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.mdanddocs/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.tsand approval-path role tests, plus an e2e lock, switch and payment flow. npm run lint && npm test && npm run test:e2e:browser
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:backendBackend (Express/SQLite)Backend (Express/SQLite)area:frontendFrontend (React/Next.js)Frontend (React/Next.js)enhancementNew feature or requestNew feature or requeststate:readyScoped and ready for implementationScoped and ready for implementationtype:featureNew capability or enhancement requestNew capability or enhancement request
Activity