7.2 KiB
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.
// 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)
{
"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:
{
"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:
// 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:
- Backend deploys. (Nothing changes for the app — username login is untouched.)
- Back office adds a mobile number to every existing till account through the console. New accounts already require one.
- 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, includingtoken,expires_at,can_manage_staff,locations[]andstaff[] POST /pos/login/pin- Token format, TTL (30 days) and the
PosAuthguard POST /pos/orders,/pos/customers,/pos/health,GET /pos/cataloguePOS_AUTH_REQUIREDstill defaults to off
8. Verify after deploy
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"