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

User detail

Bối cảnh​

GET /api/v1/users là route "token này của ai?" tổng quát của auth service. Nó được viết từ trước khi migrate, và không API Shukah nào ánh xạ tới nó. Với x-auth-from: SHUKAH nó kiểm tra một token và trả về hồ sơ của client.

Nó quan trọng với việc migrate vì các backend khác dùng nó. order-v2 và point service gọi nó để biến token nhận được thành một client. Token đó có thể là token Shukah hoặc JWT của Locate, nên route này quyết định các route point của order-v2 chấp nhận token nào.

Tính năng​

Gửi token trong Authorization và nói backend nào verify nó trong x-auth-from. Các caller gửi SHUKAH.

  • order-v2: profile guard của nó, bảo vệ nhiều route client như orders và gift cards, gọi route này với x-auth-from: SHUKAH.
  • Point service: client middleware của nó gọi route này để biết người gọi là ai. Nó gửi x-auth-from từ setting AUTH_VERIFY_APPLICATION của chính nó (mặc định SHUKAH), đọc client id từ câu trả lời, và trả 401 cho caller của nó khi route này không trả lời bằng 2xx.
  • Các caller khác: Chưa được tài liệu hóa.

Bản thân app không gọi route này: snapshot app ngày 2026-02-26 không có lời gọi nào tới nó. App không cần gửi x-auth-from tới các route point của order-v2, vì order-v2 và point service tự set nó khi gọi route này.

Token nào chạy được phụ thuộc vào client setting auth_source (shukah hoặc locate), do locate-go sở hữu. Nếu service không đọc được setting, nó dùng locate.

Tokenauth_source không phải locateauth_source là locate
Token ShukahChạy được. Service nhờ Shukah kiểm tra (GET /maeda/api/verify-token) và trả nguyên câu trả lời của Shukah.Chạy được khi token là một trong các token active đã lưu của service. Chưa capture.
JWT của LocateChỉ chạy nếu Shukah biết JWT đó, vì service vẫn hỏi Shukah.Không bao giờ chạy ở code đã ghim: luôn nhận 401. Đây là một defect.

Trên dev, vào 2026-10-01, một token Shukah và một JWT Locate đều nhận 200 với cùng body. Vào 2026-10-02 điều đó đã đổi. auth_source của dev là shukah (đọc từ client settings công khai), nên route này chuyển tiếp token sang Shukah dev. Các route point của order-v2, vốn gọi route này, trả 401 cho một JWT Locate và 200 cho một token Shukah: Shukah dev không còn chấp nhận JWT (đây là suy luận; bản thân route này không được gọi với x-auth-from vào ngày đó). Nếu auth_source đặt là locate thì JWT cũng sẽ fail, vì defect trong bảng. Vậy trên dev hiện nay chỉ có token Shukah chạy ở đây, và không có setting nào một mình làm JWT Locate chạy được.

GET /api/v1/users​

Endpoint mới — không có endpoint tương đương trên Shukah.

Request​

FieldVị tríKiểuBắt buộcRàng buộcMô tả
Authorizationheaderstringcó, trừ MERCHANTBearer <token>. Phần thứ hai (ngăn cách bằng dấu cách) là token. Thiếu cho 401.Token cần kiểm tra. Trên dev hiện nay chỉ token Shukah qua được (2026-10-02).
x-auth-fromheaderstringcóMột trong SHUKAH, LOCATE_V2, ADMIN_SHUKAH, ADMIN_LOCATE hoặc MERCHANT. Phân biệt hoa thường: khi có Authorization, shukah cho 422. Các caller dùng SHUKAH, và phần còn lại của trang này nói về nó.Backend nào verify token.
access-token, client, uidheaderstringchỉ MERCHANTCả ba đều bắt buộc với MERCHANT.Một phiên merchant.

Response​

Với x-auth-from: SHUKAH, 200 kèm hồ sơ của client là một object trần. Body phụ thuộc vào cách service kiểm tra token:

Cách kiểm tra tokenBody
Relay: auth_source không phải locate.Body verify-token của chính Shukah, không đổi. Trên dev nó có cùng 13 field như Verify token: status là active, sex là 0, 1 hoặc 2, và các flag là 0 hoặc 1.
Local, token Shukah: auth_source là locate.Một shape khác: status là ACTIVE thô, sex là MALE, FEMALE hoặc UNKNOWN, bốn flag là boolean, và odoo_id bị bỏ khi client không có. Chưa capture.
Local, JWT Locate: auth_source là locate.Không thành công: 401 mọi lần ở code đã ghim.
{
"client_id": 356259,
"odoo_id": "1342170",
"contact_phone": "+966500000000",
"status": "active",
"email_address": "user@example.com",
"first_name": "Test",
"last_name": "User",
"sex": 1,
"birth_date": "1990-01-01",
"receive_offers": 0,
"push_enabled": 0,
"is_food_truck_user": 1,
"is_cod_disabled": 0
}

Capture trên dev, 2026-10-01 (client 356259), một lần với token Shukah và một lần với JWT Locate: cả hai lời gọi trả body này. Các field cá nhân đã được thay thế. Vào 2026-10-02 một JWT Locate nhận 401 từ các route point gọi route này, nên body này là thứ một token Shukah nhận hiện nay.

Lỗi​

HTTPBodyKhi nào
401{"status":401,"message":"Unauthorization"}Không có header Authorization (trừ MERCHANT). Shukah từ chối token, hoặc token không nằm trong các token đã lưu. Bất kỳ exception nào khi kiểm tra token. auth_source là locate và token là JWT Locate.
422{"status":422,"message":"Your application is not support"}Có Authorization, nhưng x-auth-from thiếu hoặc không phải một trong năm giá trị.
404{"status":404,"message":"User not found"}Chỉ với x-auth-from: LOCATE_V2, khi legacy user không tồn tại.
500{"status":500,"message":"Internal server errors"}Handler throw, hoặc upstream MERCHANT lỗi với bất cứ mã nào ngoài 401.

Body 401 được capture trên dev vào 2026-10-01 khi không có token. Body 422 Your application is not support được capture trên dev vào 2026-10-02, với một JWT Locate và không có x-auth-from. Các body còn lại lấy từ code.

Thử ngay​

export AUTH_BASE_URL=https://dev.authentication.locate.sa
export SHUKAH_TOKEN='<shukah-token>' # a Locate JWT is expected to get 401 here on dev today (inference); see Feature
curl -s "$AUTH_BASE_URL/api/v1/users" -H "Authorization: Bearer $SHUKAH_TOKEN" -H "x-auth-from: SHUKAH"

Kỳ vọng trên dev (2026-10-02, suy luận: hôm đó route này không được gọi với x-auth-from, chỉ các route điểm gọi tới nó được gọi): 200 và hồ sơ như ở mục Response với một token Shukah, và 401 với một JWT Locate, vì dev chuyển tiếp nó sang Shukah, nơi không còn chấp nhận nó. Vào 2026-10-01 cả hai token đều nhận 200. Không có x-auth-from bạn nhận 422 như ở mục Lỗi.

Lưu ý​

  • JWT Locate được dự đoán sẽ nhận 401 ở đây trên dev hiện nay (suy luận từ các route điểm, 2026-10-02), và ở code đã ghim nó luôn như vậy khi auth_source đặt là locate, nên đừng hứa hỗ trợ JWT Locate trên route này.
  • x-auth-from phân biệt hoa thường: SHUKAH chạy, shukah nhận 422. Một tài liệu của service viết nó bằng chữ thường.
  • Ở chế độ relay mỗi lời gọi cũng đi tới Shukah và cập nhật một bản ghi legacy user, và JWT Locate chỉ chạy nếu Shukah biết nó.

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.

Các caller​

  • Point service: clientAuthMiddleware cần Authorization: Bearer <token>, rồi gọi GET {AUTH_SERVICE_URL}/api/v1/users với header đó, x-auth-from đặt bằng AUTH_VERIFY_APPLICATION (mặc định SHUKAH) và Accept: application/json. Câu trả lời không phải 2xx thành 401. Client id là giá trị non-null đầu tiên trong client_id, user_id và id của câu trả lời, và nó phải là số nguyên dương. x-auth-from của chính caller không bao giờ được forward.
  • order-v2: UserProfileGuard thực hiện cùng lời gọi với header Authorization nó nhận được và x-auth-from: SHUKAH. Nó được áp dụng bằng @UseGuards(UserProfileGuard) trên nhiều controller client, ví dụ orders và gift cards.

Năm giá trị x-auth-from​

Thứ tự kiểm tra: MERCHANT trước, rồi Authorization thiếu (401), rồi giá trị của x-auth-from (422), rồi một switch. Phép so sánh phân biệt hoa thường (src/middlewares/user.js:13-44, src/shared/constant/auth.js:1-7).

x-auth-fromĐiều gì xảy raBody thành côngNguồn
SHUKAHToken được kiểm tra như ở bảng kế tiếp.Hồ sơ.src/middlewares/user.js:36-37,100-187
LOCATE_V2 (default case của switch)Token được tra trong collection users legacy. Một user legacy DEACTIVATE cho 401. Sau đó handler trả document user đã lưu, hoặc 404.Document legacy user.src/middlewares/user.js:42-43,201-228; src/controllers/users/detail/handler.js:26-36
ADMIN_SHUKAHToken phải bằng admin token đã cấu hình, nếu không 401.Một 200 rỗng.src/middlewares/user.js:38-39,189-199; src/controllers/users/detail/handler.js:15-17
ADMIN_LOCATEGET {LOCATE_GO_BASE_URL}/api/admin/api/v1/profile với Bearer token. Mọi lỗi cho 401.Hồ sơ từ upstream.src/middlewares/user.js:40-41,250-275
MERCHANTCần các header access-token, client và uid. Thiếu một cái cho 422 {"status":422,"message":"Unauthorization"}. Sau đó GET {MERCHANT_BASE_URL}/api/v1/users/profile. Upstream 401 cho 401, các lỗi khác cho 500.Hồ sơ từ upstream.src/middlewares/user.js:54-98
Thiếu hoặc bất kỳ giá trị nào khác, khi có Authorization422 {"status":422,"message":"Your application is not support"}.—src/middlewares/user.js:28-33; src/shared/constant/error-message.js:62

SHUKAH kiểm tra token như thế nào​

auth_sourceJWT Locate (đúng ba phần ngăn cách bằng dấu chấm)Token opaqueNguồn
locateverifyClientToken gọi ClientService.findByToken, và nó throw TypeError: Client.findByToken(...).cacheQuery is not a function. Static của model là async, nên nó trả một Promise, và một Promise không có cacheQuery. Catch biến nó thành 401, mọi lần. Kiểm tra offline với một JWT hợp lệ và middleware thật.Tìm một dòng token_bridge active theo token raw, rồi client. Không tìm thấy cho 401. Tìm thấy thì set hồ sơ từ toShukahClientProfile (kiểu raw).src/middlewares/user.js:104-130,230-248; src/services/client.js:12-35; src/models/client.js:163-175
Bất kỳ giá trị nào khác (thường là shukah)Relay: GET {SHUKAH_HOST}/maeda/api/verify-token với Authorization: Bearer <token>. Một 200 kèm body thành hồ sơ, đúng như Shukah gửi. Mọi lỗi cho 401.Cùng relay đó.src/middlewares/user.js:132-186

getAuthSource() resolve giá trị theo thứ tự: biến môi trường AUTH_SOURCE, rồi auth_source đã cache của key settings:client trong Redis, rồi GET {LOCATE_API_URL}/settings/client, rồi mặc định locate (src/services/setting.js:12-51, docs/plans/2026-08-25-point-ledger-shared-write-contract.md:408-421). Một message Kafka từ locate-go làm mới cache (src/events/settingConsumer.js:14-33, docs/plans/2026-07-28-settings-broker-consumer.md:43-68).

  • Cả hai nhánh locate đều không kiểm tra trạng thái tài khoản. ClientService.findOne chỉ lọc theo client_id, và Client.findByToken chỉ lọc theo is_deleted: false và phone của token. Vì vậy route này không ép chỉ-active như middleware client (đọc code, src/services/client.js:5-17, src/models/client.js:163-175).
  • Ở nhánh relay mọi lời gọi đều ghi vào collection users legacy: một upsert từ payload của Shukah. status active thành ACTIVE, mọi giá trị khác thành DEACTIVATE, và sex 0 thành MALE, mọi giá trị khác thành FEMALE. Quy tắc sex đó khác với cách mã hóa của chính hồ sơ (1 nam, 2 nữ) (src/middlewares/user.js:145-172).
  • Relay chỉ chấp nhận JWT Locate nếu Shukah biết nó. Điều đó phụ thuộc vào việc đẩy các JWT Locate mới sang Shukah (xem Exchange token), nên một client mà push thất bại hoặc bị bỏ qua (không có Shukah id) sẽ nhận 401 ở đây khi auth_source là shukah (đọc code).
  • Thời gian trên dev: 630 ms cho token Shukah và 1061 ms cho JWT Locate, so với 161 đến 331 ms cho các lời gọi nằm trong service. Điều đó khớp với một hop tới upstream.

Hai capture không giải thích được điều gì​

Cả hai lời gọi đã capture đều trả body định dạng Shukah (status chữ thường, sex số nguyên, flag 0 và 1) và đều chậm. Ở code đã ghim chỉ nhánh relay mới tạo ra body đó cho một JWT Locate. Vậy hoặc auth_source của dev không phải locate vào 2026-10-01, và Shukah chấp nhận JWT Locate (điều đó khớp với việc lời gọi exchange-token mint ra nó đã đẩy nó sang Shukah, nếu push được bật trên dev), hoặc dev không chạy 6757aa4. Cả code lẫn tài liệu đều không nói là cái nào: Chưa được tài liệu hóa. Đây là suy luận, không phải sự thật.

Để phân biệt, so sánh uptime của process từ route /health không cần xác thực (không có prefix) với lần merge 6757aa4 lúc 2026-10-01 11:57 +0700, và đọc auth_source từ client settings (src/routes/health.js:8, src/controllers/health/handler.js:11-19).

Đã có câu trả lời vào 2026-10-02. Client settings công khai (GET https://dev.go.locate.sa/api/v1/settings/client, host nằm trong SETTINGS_BASE_URL của app) trả "auth_source":"shukah". Một biến môi trường AUTH_SOURCE sẽ ghi đè nó và không thể đọc từ bên ngoài, nên điều này rất có khả năng đúng, chưa được chứng minh. Uptime /health 90,815 s nghĩa là service khởi động khoảng 2026-10-01 06:43 UTC, 1 giờ 46 phút sau lần merge 6757aa4 (04:57 UTC), nên dev nhiều khả năng chạy 6757aa4 hoặc mới hơn. Vì vậy giải thích đầu tiên là giải thích có khả năng đúng: vào 2026-10-01 nhánh relay chạy và Shukah dev chấp nhận JWT Locate. Vào 2026-10-02 cùng relay đó từ chối nó, đó là lý do các route point của order-v2 trả cho JWT Locate 401 Invalid or expired token (locate-point-service: services/api/src/services/client-auth.service.ts:17,22-29). Vì sao Shukah dev ngừng chấp nhận JWT: Chưa được tài liệu hóa. Nguyên nhân có khả năng là việc push token từ Locate sang Shukah (src/config/envConfig.js:22-35) không tới được, hoặc không còn tồn tại trên bản port Laravel của Shukah dev (suy luận).

Defect locate + JWT cũng có trong origin/production tại 4f3bc96 (2026-09-21), có cùng src/services/client.js và src/models/client.js như 6757aa4. Có thứ gì chạy từ ref đó hay không, và có kế hoạch sửa trước khi auth_source chuyển hay không: Chưa được tài liệu hóa.

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

  • Một design doc viết giá trị header là x-auth-from: shukah (docs/plans/2026-08-25-point-ledger-shared-write-contract.md:418). Code so sánh với SHUKAH chính xác, và giá trị chữ thường nhận 422.
  • Một design doc nói JWT Locate "short-circuit to verifyClientToken … and were never broken" (docs/plans/2026-07-27-shukah-opaque-token-auth-fix.md:51-52). Điều đó đúng vào 2026-07-27 và đã lỗi thời từ commit 3396fd1 (2026-07-28): khi auth_source đặt là locate, nhánh JWT luôn cho 401.
  • 2026-10-02: trang này nói một token Shukah và một JWT Locate đều nhận 200 trên dev (2026-10-01), và mục Thử ngay của nó kỳ vọng 200 với cả hai token. Vào 2026-10-02 auth_source của dev là shukah và Shukah dev không còn chấp nhận JWT Locate, nên chỉ token Shukah chạy; với auth_source đặt là locate mọi JWT đều nhận 401 vì src/services/client.js:12-17 gọi .cacheQuery trên Promise do Client.findByToken kiểu async trả về (src/models/client.js:163).

Sources​

  • locate-authentication-service@6757aa4: src/routes/user.js:5-12, src/middlewares/user.js:13-275, src/controllers/users/detail/handler.js:9-45, src/services/client.js:5-35, src/models/client.js:163-175, src/services/setting.js:12-51, src/events/settingConsumer.js:14-33, src/shared/constant/auth.js:1-7, src/shared/constant/error-message.js:59,62,77, src/routes/health.js:8, src/controllers/health/handler.js:11-19
  • Tài liệu của locate-authentication-service@6757aa4: docs/plans/2026-08-25-point-ledger-shared-write-contract.md:408-421, docs/plans/2026-07-28-settings-broker-consumer.md:43-68, docs/plans/2026-07-27-shukah-opaque-token-auth-fix.md:51-52
  • locate-point-service@2c44ce3: services/api/src/middleware/client-auth.ts:7-18, services/api/src/services/client-auth.service.ts:15-37
  • locate-order-v2-api@d9e4e5f6: src/auth/guards/user-profile-auth.guard.ts:58-72, src/modules/client/orders/orders.controller.ts:84, src/modules/client/gift-card-code/gift-card-code.controller.ts:10, src/modules/client/point/point.controller.ts:17-45 (các route point không có guard và forward Authorization sang point service)
  • Snapshot mobile mobile/locate-client@e960c3a (branch development, 2026-02-26; code của chính app, không phải Locate): tìm toàn bộ cây thư mục với api/v1/users không thấy gì
  • locate-authentication-service@6757aa4: src/config/envConfig.js:22-35
  • Capture dev, 2026-10-02 (parity audit): user-detail--locate-jwt, points--locate-jwt, points--locate-st; client settings của dev và uptime /health của auth service, cả hai được đọc vào 2026-10-02
  • Capture dev, 2026-10-01: locate-users-shukah-token, locate-users-locate-token, probe-locate-users, shukah-verify-token