Chuyển tới nội dung chính

Client lookup

Bối cảnh​

Trên Shukah, app tìm một client theo số điện thoại bằng GET /maeda/client?contact_phone=…. Auth service có cùng lookup đó tại GET /api/v1/clients. Nó trả về cùng bốn field, nhưng cần JWT của Locate và che last name.

Tính năng​

Gửi một số điện thoại và nhận lại ai đang giữ số đó: id, phone, first name của client và last name đã được che. Câu trả lời là một mảng có một dòng, hoặc mảng rỗng khi không có client active nào có phone đó.

Trong snapshot app ngày 2026-02-26, app chỉ dùng nó để tìm người nhận của một quà tặng điểm, từ form tặng quà và lần nữa ở bước checkout quà tặng. Nó chỉ đọc dòng đầu tiên, và mảng rỗng trở thành lỗi "User not found" trong app.

Lời gọi cần một phiên đã đăng nhập, nhưng số điện thoại bạn tra không nhất thiết phải là của bạn. Token chỉ xác định người gọi. Phone trong query quyết định ai được trả về.

GET /api/v1/clients​

Thay thế ShukahGET /maeda/client✅ Đã thay thế
Cần sửa app1 breaking · 3 cần lưu ý
  • 🔴 Token Shukah nhận 401 "Unauthorization"; hãy gửi JWT của Locate (lấy từ exchange-token; giữ lại token Shukah).
  • 🟡 Locate che last_name ("User" thành "U**r"); chưa rõ Shukah có che không (bản capture đã được làm sạch).
  • 🟡 Số điện thoại chưa tồn tại trả 200 [] trên Locate (theo code); app biến [] thành "User not found" (user.service.ts:49-51).
  • 🟡 Body 401 của Locate là {status,message}, không phải body Laravel; app chỉ đọc message.

Request​

FieldVị tríKiểuBắt buộcRàng buộcMô tả
AuthorizationheaderstringcóBearer <locate-jwt>, token của người gọi. Token Shukah bị từ chối với 401.Phiên của người gọi.
contact_phonequerystringcóKhoảng trắng bị bỏ. Nó được so khớp với phone đã lưu có hoặc không có dấu + ở đầu. Trống hoặc thiếu cho 400. Một dấu + nguyên văn trong URL bị đọc thành khoảng trắng và bị bỏ, nên +966… không encode vẫn khớp.Số điện thoại cần tra. Có thể thuộc về bất kỳ ai, không chỉ người gọi.
key, language và mọi query key khácquerystringkhôngĐược chấp nhận và bỏ qua.Giữ lại để query string Shukah cũ vẫn chạy.

Response​

200 với một mảng gồm không hoặc một dòng:

FieldKiểuNullableĐịnh dạng / ràng buộcMô tả
client_idintegerkhông—Id của client tìm được.
contact_phonestringcóPhone như đã lưu, không bị che.Số điện thoại của client.
first_namestringcóĐã trim. Trống thành null. Không bị che.Tên.
last_namestringcóBị che: giữ ký tự đầu và cuối và mọi ký tự giữa chúng thành * (User thành U**r). Tên một hoặc hai ký tự được trả nguyên. Trống thành null.Họ, đã che.

Khi không có client active, chưa bị xóa nào có phone đó, câu trả lời là 200 với []. Client đang suspended, blocked, pending hoặc expired cũng nhận [].

[
{
"client_id": 356259,
"contact_phone": "+966500000000",
"first_name": "Test",
"last_name": "User"
}
]

Capture trên dev, 2026-10-01 (client 356259); các field cá nhân đã được thay thế. Capture đã thay last_name bằng User, nên dạng đã che của giá trị thật không hiển thị ở đây. Quy tắc che đến từ code và unit test của nó: User sẽ thành U**r.

Lỗi​

HTTPBodyKhi nào
400{"name":"Bad Request","message":"Phone number cannot be blank.","code":0,"status":400,"type":"yii\\web\\BadRequestHttpException"}contact_phone thiếu hoặc trống.
401{"status":401,"message":"Unauthorization"}Token thiếu, sai định dạng hoặc không phải JWT của Locate, client của người gọi không tồn tại, hoặc client của người gọi không active.

Body 401 được capture trên dev vào 2026-10-01 khi không có token. Body 400 có cùng shape với cái đã capture cho reset-otp (xem OTP login). Nó chưa được capture trên route này, vì lần chạy capture không có lời gọi lookup nào với token và phone rỗng.

Thử ngay​

export AUTH_BASE_URL=https://dev.authentication.locate.sa
export TOKEN='<locate-jwt>' # see "Getting a test token" on the module overview
export PHONE='<phone-to-look-up>' # the answer shows that client's first name and phone
curl -s -G "$AUTH_BASE_URL/api/v1/clients" --data-urlencode "contact_phone=$PHONE" -H "Authorization: Bearer $TOKEN"

Kỳ vọng: 200 và một mảng có một dòng, như ở mục Response. Phone không ai có cho [].

Khác biệt so với Shukah​

Body 200 có cùng bốn key ở cả hai phía: vào 2026-10-01 cả hai service trả client_id, contact_phone, first_name và last_name cho client 356259.

Khía cạnhShukahLocateTác động lên app
TokenToken Shukah (capture dùng một token như vậy).Chỉ JWT của Locate. Token Shukah nhận 401 ở cùng guard với verify-token.Exchange token Shukah lấy JWT trước khi chuyển, và giữ token Shukah cho order-v2.
URLGET $SHUKAH_BASE_URL/maeda/client?contact_phone=…&key=maeda&language=en-GB (lời gọi đã capture).GET $AUTH_BASE_URL/api/v1/clients?contact_phone=…. Locate bỏ qua key và language.Đổi base URL và path. App có thể tiếp tục gửi key và language.
last_nameChưa được tài liệu hóa: capture trên dev đã thay last_name, nên không thấy được việc che.Bị che: giữ ký tự đầu và cuối và phần giữa thành *.App copy last_name từ dòng đầu tiên, và Locate trả nó đã che. Hãy kiểm tra flow tặng quà dùng tên như thế nào.
Phone không tồn tạiChưa được tài liệu hóa.200 với [], cũng áp dụng cho client không active.App đã biến mảng rỗng thành "User not found", nên [] không cần đổi gì.
Body 401{"name":"Unauthorized","message":"Your request was made with invalid credentials.","code":0,"status":401,"type":"Illuminate\\Auth\\AuthenticationException"} (không token, capture trên dev, 2026-10-01).{"status":401,"message":"Unauthorization"} (không token, capture trên dev, 2026-10-01).Mọi chỗ so khớp theo text lỗi, name hay type đều phải đổi. status là 401 ở cả hai.

Lưu ý​

  • last_name trả về đã che (User thành U**r), nhưng first_name và contact_phone trả về đầy đủ.
  • Phone không tồn tại và client không active đều nhận 200 với [], mà app biến thành lỗi "User not found", nên không phân biệt được hai trường hợp.
  • Token và phone độc lập với nhau: bất kỳ người gọi đã đăng nhập nào cũng có thể tra bất kỳ phone nào và nhận first name và phone của client đó.

Chi tiết (cho backend)​

Chỉ kiểm tra dev: host https://dev.authentication.locate.sa, prefix /api/v1. Host và prefix của UAT và production: Chưa được tài liệu hóa.

Route và lookup​

  • GET /clients được đăng ký trước mọi route có tham số, phía sau middleware client, nên nó cần JWT Locate của một client active giống như verify-token (src/routes/client.js:14-16, src/middlewares/client.js:8-42).
  • Handler đọc contact_phone và trả 400 qua lỗi Yii khi nó trống (src/controllers/client/lookup/index.js:33-34).
  • Lookup là findClientByPhone, giống reset-otp: phone đã lưu với + tùy chọn, chưa bị xóa, status ACTIVE, client_id mới nhất trước, không cache (src/controllers/client/reset-otp/handler.js:24-30, src/shared/helpers/filter.js:1-4). Nó trả về một kết quả khớp tốt nhất, nên mảng có tối đa một dòng (src/controllers/client/lookup/index.js:36-40).
  • Một dấu + nguyên văn trong URL được decode thành khoảng trắng, và normalizePhone sau đó bỏ nó, nên +966… không encode vẫn khớp (src/sync/lib/casts.js:40-41; đọc code).
  • Design doc nêu các flow merchant giữ một JWT client của Locate làm use case (docs/plans/2026-08-04-client-lookup-by-phone-api-local.md:9-11). Snapshot app chỉ gọi nó để resolve người nhận quà (xem Sources).
  • Lời gọi chỉ đọc, không có cache riêng, không phân trang và không có side effect (docs/plans/2026-08-04-client-lookup-by-phone-api-local.md:25-28).

Map dòng và che dữ liệu​

toLookupRow dựng từng dòng (src/controllers/client/lookup/index.js:23-28):

  • client_id là client_id đã lưu. contact_phone là phone đã lưu, hoặc null.
  • first_name được trim, và trống thành null (src/controllers/client/lookup/index.js:17-21).
  • last_name đi qua maskLastName: trim, null hoặc trống cho null, độ dài hai trở xuống thì giữ nguyên, còn lại là ký tự đầu, length - 2 dấu sao và ký tự cuối (src/controllers/client/lookup/index.js:8-15). Unit test chốt User thành U**r (src/controllers/client/__tests__/lookup.test.js:32).
  • Việc che first_name hay contact_phone nằm ngoài phạm vi trong design doc (docs/plans/2026-08-04-client-lookup-by-phone-api-local.md:93). Vì vậy bất kỳ người gọi đã đăng nhập nào cũng nhận chúng đầy đủ cho bất kỳ phone nào, và lời gọi không phân biệt được phone không tồn tại với phone không active.

Chưa được tài liệu hóa​

  • Shukah có che last_name hay không: capture đã thay giá trị.
  • Shukah trả gì cho phone không tồn tại hoặc phone trống: cả hai đều chưa được capture.
  • Lookup của Shukah có nhận thêm các filter danh sách hay không. Design doc liệt kê "Pagination / status / page list filters from upstream" là ngoài phạm vi của Locate (docs/plans/2026-08-04-client-lookup-by-phone-api-local.md:91), và capture chỉ dùng contact_phone, key và language.
  • Có môi trường nào có route này hay không: origin/production tại 4f3bc96 (2026-09-21) không đăng ký nó (src/routes/client.js của nó không import lookup), và có thứ gì chạy từ ref đó hay không thì chưa rõ.

Khi tài liệu và code mâu thuẫn (code thắng)​

  • Ví dụ che trong design doc có 13 dấu sao (U*************) cho User (500…000)) (docs/plans/2026-08-04-client-lookup-by-phone-api-local.md:30). Code và unit test cho 12 (src/controllers/client/__tests__/lookup.test.js:33), vì quy tắc là length - 2. Khác biệt này chỉ là hình thức.

Sources​

  • locate-authentication-service@6757aa4: src/routes/client.js:14-16, src/middlewares/client.js:8-42, src/controllers/client/lookup/index.js:8-41, src/controllers/client/__tests__/lookup.test.js:32-33, src/controllers/client/reset-otp/handler.js:24-30, src/shared/helpers/filter.js:1-4, src/sync/lib/casts.js:40-41, src/shared/errors/yii-bad-request-error.js:12-23, src/middlewares/error-handler.js:10, src/shared/constant/error-message.js:59
  • Tài liệu của locate-authentication-service@6757aa4: docs/plans/2026-08-04-client-lookup-by-phone-api-local.md:9-11,25-30,56-59,90-93 (2026-08-04)
  • Snapshot mobile mobile/locate-client@e960c3a (branch development, 2026-02-26; code của chính app, không phải Locate): src/entities/user/model/api/services/user.service.ts:38-47,49-51,58-60, src/entities/user/model/api/dto/user.dto.ts:126-155, src/widgets/SendPointGiftForm/model/hooks/sendPointGiftForm.ts:64, src/widgets/PointGiftsCheckout/model/hooks/usePointGiftsCheckout.ts:376
  • Capture dev, 2026-10-01: locate-client-lookup, shukah-client-lookup, probe-locate-client-lookup, probe-shukah-client-lookup, probe-locate-reset-otp
  • Bằng chứng phụ, không phải sha đã ghim: locate-authentication-service origin/production tại 4f3bc96 (2026-09-21), src/routes/client.js