feat: interim customer PIN auth (login/set-pin/verify-pin), mirrors miler flow

No SMS/OTP gateway is live yet, so customers sign in with a self-set PIN like
milers do. The OTP endpoints stay in place — the app switches back once a
gateway is plugged in.

- POST /customer/auth/login  {phone} -> {registered, pin_set, name}: routes the
  app to register / set-PIN / enter-PIN.
- POST /customer/auth/set-pin {phone, new_pin, name?}: first-time PIN. Creates
  the account (name required) or sets the first PIN on an account with none;
  refuses to overwrite an existing PIN (409); logs in on success.
- POST /customer/auth/verify-pin {phone, pin}: returning login; same generic
  message for unknown phone and wrong PIN so it can't enumerate accounts.

All three reuse issueCxSession (access + refresh + customer) and the /customer
Cx* response envelope. Build + vet clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WRaFH5hMRqmUQvVPQsyjZD
This commit is contained in:
2026-09-21 16:25:03 +05:30
parent e714e1de73
commit f1dbf7edc9
3 changed files with 167 additions and 0 deletions

View File

@@ -20,6 +20,9 @@ const (
CxErrInvalid = "invalid"
CxErrInvalidName = "invalid_name"
CxErrInvalidOtp = "invalid_otp"
CxErrInvalidPin = "invalid_pin"
CxErrPinNotSet = "pin_not_set"
CxErrPinAlreadySet = "pin_already_set"
CxErrUnauthorized = "unauthorized"
CxErrForbidden = "forbidden"
CxErrNotFound = "not_found"