Files
lunarfront-app/packages/shared/src/schemas/auth.schema.ts
ryan cf299ac1d2 feat: POS PIN unlock with employee number + PIN auth
- Add employeeNumber and pinHash fields to users table
- POST /auth/pin-login: takes combined code (4-digit employee# + 4-digit PIN)
- POST /auth/set-pin: employee sets their own PIN (requires full auth)
- DELETE /auth/pin: remove PIN
- Lock screen with numpad, auto-submits on 8 digits, visual dot separator
- POS uses its own auth token separate from admin session
- Admin "POS" link clears admin session before navigating
- /pos route has no auth guard — lock screen is the auth
- API client uses POS token when available, admin token otherwise
- Auto-lock timer reads pos_lock_timeout from app_config (default 15 min)
- Lock button in POS top bar, shows current cashier name

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:05:19 +00:00

30 lines
963 B
TypeScript

import { z } from 'zod'
export const UserRole = z.enum(['admin', 'manager', 'staff', 'technician', 'instructor'])
export type UserRole = z.infer<typeof UserRole>
export const RegisterSchema = z.object({
email: z.string().email(),
password: z.string().min(12).max(128),
firstName: z.string().min(1).max(100),
lastName: z.string().min(1).max(100),
role: UserRole.default('staff'),
})
export type RegisterInput = z.infer<typeof RegisterSchema>
export const LoginSchema = z.object({
email: z.string().email(),
password: z.string().min(1),
})
export type LoginInput = z.infer<typeof LoginSchema>
export const PinLoginSchema = z.object({
code: z.string().min(8).max(10).regex(/^\d+$/, 'Code must be digits only'),
})
export type PinLoginInput = z.infer<typeof PinLoginSchema>
export const SetPinSchema = z.object({
pin: z.string().min(4).max(6).regex(/^\d+$/, 'PIN must be digits only'),
})
export type SetPinInput = z.infer<typeof SetPinSchema>