pos login edited with phone number
This commit is contained in:
208
docs/POS_PHONE_LOGIN_HANDOVER.md
Normal file
208
docs/POS_PHONE_LOGIN_HANDOVER.md
Normal file
@@ -0,0 +1,208 @@
|
||||
# POS sign-in by mobile number, and shift assignment — handover to the terminal team
|
||||
|
||||
Backend is done and builds clean. **Nothing about this breaks the current app** —
|
||||
username sign-in keeps working exactly as it does today. Read §5 before you ship
|
||||
anything, because the switch has one ordering rule that will lock out every
|
||||
cashier if it is done in the wrong order.
|
||||
|
||||
---
|
||||
|
||||
## 1. What changed, in one line
|
||||
|
||||
`POST /pos/login` now accepts a **mobile number** as well as a username, only
|
||||
till accounts are candidates, and a till account can carry a **shift**.
|
||||
|
||||
---
|
||||
|
||||
## 2. Endpoints — what was edited and how
|
||||
|
||||
### `POST /live/api/v1/pos/login` — CHANGED (backwards compatible)
|
||||
|
||||
The request body already had both fields. **Nothing in the contract changed.**
|
||||
What changed is behaviour behind it.
|
||||
|
||||
```jsonc
|
||||
// Sign in by mobile — the new way
|
||||
{ "contactno": "9876543210", "password": "xHegDaH55ccWic" }
|
||||
|
||||
// Sign in by username — still works, unchanged
|
||||
{ "authname": "cashier.1135@pos.nearle.in", "password": "xHegDaH55ccWic" }
|
||||
```
|
||||
|
||||
`authname` wins if both are sent. The response is unchanged.
|
||||
|
||||
**Behavioural change:** the account lookup is now restricted to till roles
|
||||
(Supervisor `7`, Cashier `8`).
|
||||
|
||||
*Why it matters to you:* previously a number shared with a back-office account
|
||||
returned two candidates and the login was refused outright. On live data **34
|
||||
numbers are shared by 104 accounts** — one by eleven — so without this,
|
||||
sign-in by phone would simply have failed for a large number of people. Now a
|
||||
number only has to be unique among till accounts.
|
||||
|
||||
A back-office user who types their own password at a till still gets the
|
||||
specific `403 "this account is not set up for the till"` rather than a vague
|
||||
rejection. That did not change.
|
||||
|
||||
### `POST /live/api/v1/web/tenants/createposuser` — CHANGED (two new fields)
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"tenantid": 1087,
|
||||
"locationid": 1135,
|
||||
"full_name": "Priya Raman",
|
||||
"role": "cashier",
|
||||
"pin": "4731",
|
||||
"contactno": "9876543210", // NEW — the sign-in number
|
||||
"shift_id": 3 // NEW — optional, 0/omitted = unassigned
|
||||
}
|
||||
```
|
||||
|
||||
The response gains `shift_id`, and `contactno` now comes back **normalised to
|
||||
ten digits**.
|
||||
|
||||
### `PUT /live/api/v1/web/tenants/updateposuser` — CHANGED (two new fields)
|
||||
|
||||
Accepts `contactno` and `shift_id`. Every field stays optional; only what is
|
||||
sent is written.
|
||||
|
||||
### `GET /live/api/v1/web/tenants/getposusers` — CHANGED (four new fields)
|
||||
|
||||
Each user in `details.users[]` now also carries:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"contactno": "9876543210",
|
||||
"shift_id": 3,
|
||||
"shift_name": "Morning",
|
||||
"shift_start": "07:00",
|
||||
"shift_end": "15:00"
|
||||
}
|
||||
```
|
||||
|
||||
Blank on accounts created before shifts existed. **`shift_*` also appears on
|
||||
`staff[]` in the `/pos/login` session**, so the terminal gets it for free.
|
||||
|
||||
### `GET/POST/PUT /live/api/v1/web/tenants/{getstaffshifts,createstaffshift,updatestaffshift}` — NEW
|
||||
|
||||
Console-only. The terminal does not need to call these; shifts arrive with the
|
||||
session. Documented for completeness:
|
||||
|
||||
```jsonc
|
||||
// POST createstaffshift
|
||||
{ "tenantid": 1087, "locationid": 1135,
|
||||
"name": "Morning", "start_time": "07:00", "end_time": "15:00",
|
||||
"weekdays": "1111100" } // 7 chars from Monday; empty = every day
|
||||
```
|
||||
|
||||
Also mirrored under `/v1/mob/tenants/*`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Number format — the one thing to get exactly right
|
||||
|
||||
The server reduces every number to **ten digits** before storing or matching:
|
||||
non-digits are stripped, then a leading `91` or `0` is dropped once. Anything
|
||||
that is not ten digits afterwards is **rejected**, not stored.
|
||||
|
||||
So all of these are the same account:
|
||||
|
||||
```
|
||||
"+91 98765 43210" → 9876543210
|
||||
"098765-43210" → 9876543210
|
||||
"9876543210" → 9876543210
|
||||
```
|
||||
|
||||
**What you should send:** the ten digits, or anything in the list above — the
|
||||
server normalises either way. **Do not** send a country code the user did not
|
||||
type, and do not reject `+91` locally; let it through and let the server reduce
|
||||
it. What matters is that you never send something that normalises to a
|
||||
*different* number than what the console stored.
|
||||
|
||||
---
|
||||
|
||||
## 4. Shift is informational
|
||||
|
||||
`shift_id` / `shift_name` / `shift_start` / `shift_end` are for **display**.
|
||||
Nothing on the server refuses a bill rung outside a shift window, and you should
|
||||
not add that check on the device either. A cashier locked out mid-queue by a
|
||||
clock is a worse failure than a bill filed against the wrong window. Show whose
|
||||
shift it is; do not gate on it.
|
||||
|
||||
Times are 24-hour `HH:MM`. A shift may legitimately wrap midnight (`22:00`
|
||||
→ `06:00`) — do not assume `end > start`.
|
||||
|
||||
---
|
||||
|
||||
## 5. 🔴 Sequencing — read this before shipping
|
||||
|
||||
**Every existing POS account has no mobile number.** All 12 live accounts have
|
||||
`contactno = ""`:
|
||||
|
||||
```
|
||||
supervisor.1135@pos.nearle.in phone=""
|
||||
cashier.1135@pos.nearle.in phone=""
|
||||
… 12 of 12
|
||||
```
|
||||
|
||||
If the app ships sign-in-by-phone **only**, every cashier in every shop is
|
||||
locked out on the next app update.
|
||||
|
||||
**Required order:**
|
||||
|
||||
1. Backend deploys. *(Nothing changes for the app — username login is untouched.)*
|
||||
2. Back office adds a mobile number to every existing till account through the
|
||||
console. New accounts already require one.
|
||||
3. **Only then** the app makes mobile the primary sign-in field.
|
||||
|
||||
**Recommendation for the app:** keep both. One field labelled *"Mobile number or
|
||||
username"* — if the value is all digits send it as `contactno`, otherwise as
|
||||
`authname`. That is a handful of lines, works before and after the backfill, and
|
||||
means a shop with one un-backfilled account is not stranded.
|
||||
|
||||
---
|
||||
|
||||
## 6. Errors you should handle
|
||||
|
||||
| Message | Meaning | What the app should do |
|
||||
|---|---|---|
|
||||
| generic 401 rejection | wrong number/username or wrong password | "Check your details" — do **not** say which was wrong |
|
||||
| `this account is not set up for the till…` | a back-office login was used | Show it verbatim; it names the fix |
|
||||
| `more than one account uses these sign-in details…` | ambiguous match | Show verbatim; it needs the back office |
|
||||
| `this account has no password set…` | provisioned without a password | Show verbatim |
|
||||
| `another till account in this business already signs in with 9876543210` | console-side only | Not seen by the app |
|
||||
|
||||
---
|
||||
|
||||
## 7. What did **not** change
|
||||
|
||||
- The response shape of `/pos/login`, including `token`, `expires_at`,
|
||||
`can_manage_staff`, `locations[]` and `staff[]`
|
||||
- `POST /pos/login/pin`
|
||||
- Token format, TTL (30 days) and the `PosAuth` guard
|
||||
- `POST /pos/orders`, `/pos/customers`, `/pos/health`, `GET /pos/catalogue`
|
||||
- `POS_AUTH_REQUIRED` still defaults to off
|
||||
|
||||
---
|
||||
|
||||
## 8. Verify after deploy
|
||||
|
||||
```bash
|
||||
B=https://fiesta.nearle.app/live/api/v1
|
||||
|
||||
# username sign-in still works (regression check — run this first)
|
||||
curl -s -X POST "$B/pos/login" -H 'Content-Type: application/json' \
|
||||
-d '{"authname":"supervisor.1135@pos.nearle.in","password":"…"}' \
|
||||
| grep -o '"can_manage_staff":[a-z]*'
|
||||
# expect: "can_manage_staff":true
|
||||
|
||||
# after a number is set on that account, the same account by phone
|
||||
curl -s -X POST "$B/pos/login" -H 'Content-Type: application/json' \
|
||||
-d '{"contactno":"9876543210","password":"…"}' \
|
||||
| grep -o '"can_manage_staff":[a-z]*'
|
||||
|
||||
# a back-office account is still refused with the specific message
|
||||
curl -s -X POST "$B/pos/login" -H 'Content-Type: application/json' \
|
||||
-d '{"authname":"rmart@gmail.com","password":"rmart@123"}'
|
||||
# expect: 403 "this account is not set up for the till"
|
||||
```
|
||||
Reference in New Issue
Block a user