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

Profile and settings

Bối cảnh​

Trên Shukah, app thay đổi hồ sơ và công tắc push-notification bằng một lời gọi, PUT /maeda/client/{client_id}, và báo cho Shukah về phone bằng POST /maeda/client/add-device-id. Auth service có ba route cho việc này: một cho hồ sơ, một cho công tắc push, và một route device-id. Có ba điều cần chú ý: công tắc push cần một lời gọi riêng vì route hồ sơ bỏ qua push_enabled, route hồ sơ từ chối phone bị đổi, và route device-id là stub không lưu gì cả.

Tính năng​

Cả ba lời gọi đều là một phần của các màn hình tài khoản của client đã đăng nhập. Trong snapshot app ngày 2026-02-26 chúng xảy ra ở đây:

Lời gọiỞ đâu trong app
Update profileTrên màn hình Personal info, khi client bấm lưu. Một lời gọi mang client_id, contact_phone, first_name, last_name, email_address, sex, receive_offers và birth_date (dạng YYYY-MM-DD). Field phone được hiển thị nhưng bị vô hiệu hóa, và giá trị của nó là phone mà app đã tải cùng hồ sơ, nên app gửi lại đúng phone nó đã nhận.
Update settingTrên màn hình Settings, khi client bật/tắt công tắc push-notification. App gửi client_id và push_enabled (0 hoặc 1). Trên Shukah việc này đi qua cùng route với hồ sơ.
Add device idKhi app khởi động, ngay sau bước kiểm tra hồ sơ (verify-token), khi client đã đăng nhập và lời gọi chưa được thực hiện trên bản cài này. Nó gửi id duy nhất của thiết bị một lần. Sau câu trả lời 200 app ghi lại rằng đã gửi và không bao giờ gửi lại.

Hai lời gọi đầu cần JWT Locate (xem "Lấy test token" ở trang tổng quan module) và trả về hồ sơ của client, cùng 13 field như Verify token, sau thay đổi. Lời gọi device-id không cần token.

PUT /api/v1/clients/:client_id​

Thay thế ShukahPUT /maeda/client/:client_id✅ Đã thay thế
Cần sửa app1 breaking · 4 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).
  • 🟡 push_enabled bị bỏ qua trên route này (app vẫn gửi ở đây: user.dto.ts:100-101); xem update-setting.
  • 🟡 contact_phone phải bằng số điện thoại đã lưu, kèm "+", nếu không trả 400; quy tắc đổi số của Shukah chưa được kiểm tra.
  • 🟡 Dữ liệu sai trả 400 {status,message,stack} trên Locate, 422 [{field,message}] trên Shukah; app mất field.
  • 🟡 Chỉnh sửa chỉ nằm ở Locate và không được đẩy sang Shukah (update-profile/index.js không có bước push).

Request​

Cập nhật một phần: chỉ các key có trong body mới thay đổi. Service trả về vấn đề đầu tiên nó tìm thấy và kiểm tra theo thứ tự: client_id, contact_phone, first_name, last_name, email_address, birth_date.

FieldVị tríKiểuBắt buộcRàng buộcMô tả
AuthorizationheaderstringcóBearer <locate-jwt>. Token Shukah nhận 401.JWT của Locate.
client_idpathintegercóPhải bằng client id trong token, nếu không 400 client_id does not match the authenticated client.Id của chính người gọi.
client_idbodyinteger hoặc numeric stringkhôngNếu gửi, nó cũng phải bằng client id của token, với cùng 400. null thì lỗi.Lại là id của chính người gọi, như app gửi.
contact_phonebodystringkhôngKhông thể đổi. Nếu gửi, giá trị đã bỏ khoảng trắng phải bằng đúng phone đã lưu, kể cả dấu + ở đầu (966500000000 không khớp +966500000000), nếu không 400 contact_phone cannot be changed. Nó không bao giờ được ghi.Phone của client.
first_name, last_namebodystring hoặc nullkhôngnull hoặc một chuỗi tối đa 100 ký tự sau khi trim, nếu không 400 first_name is invalid hoặc last_name is invalid. Lưu đã trim. null xóa nó, và "" được lưu là "".Tên.
email_addressbodystring hoặc nullkhôngMọi chuỗi hoặc null: không kiểm tra định dạng và không giới hạn độ dài, nếu không 400 email_address is invalid. Lưu đã trim.Email.
birth_datebodystring hoặc nullkhôngMột giá trị mà new Date() của JavaScript đọc được, lưu dưới dạng ngày UTC YYYY-MM-DD. null xóa nó. Giá trị không đọc được, kể cả "", cho 400 birth_date is invalid.Ngày sinh. App gửi YYYY-MM-DD.
sexbodyintegerkhôngKhông validate. 1 là nam và 2 là nữ. Mọi giá trị khác, kể cả 0, 9 và null, được lưu là không rõ và đọc lại là 0.Giới tính.
receive_offersbody0, 1 hoặc booleankhôngKhông validate. Chỉ 1, "1" và true nghĩa là bật. Mọi giá trị khác nghĩa là tắt.Client có nhận ưu đãi hay không.
push_enabled và mọi key khácbody—khôngBị bỏ qua. Công tắc push có route riêng.—

Một request dùng cho capture bên dưới, ghi lại đúng giá trị hiện tại của client:

{
"client_id": 356259,
"receive_offers": 0
}

Response​

200 kèm hồ sơ 13 field sau khi cập nhật, không có wrapper. Các field và quy tắc của chúng là bảng ở Verify token.

{
"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, Task 9 live write, giá trị hiện tại được ghi lại); các field cá nhân đã được thay thế.

Lỗi​

HTTPBodyKhi nào
400{"status":400,"message":"birth_date is invalid"}birth_date không đọc được thành ngày. Các message của các field khác có cùng shape: client_id does not match the authenticated client, contact_phone cannot be changed, first_name is invalid, last_name is invalid, email_address is invalid. Chỉ message lỗi đầu tiên được trả về. Trên dev body cũng có field stack (xem bên dưới).
401{"status":401,"message":"Unauthorization"}Không có token, token không phải JWT Locate, hoặc client không active. Điều này xảy ra trước mọi kiểm tra body.
500Trên dev: {"status":500,"message":"<raw error text>","stack":"<stack trace>"}. Trên production: {"status":500,"message":"Internal server error"}.Lỗi không mong đợi. Chưa capture. Trên dev message là text lỗi gốc và có thêm field stack; Internal server error chỉ xuất hiện trên production (UAT và production: Chưa được tài liệu hóa).

400 của birth_date được capture trên dev vào 2026-10-01, và lại vào 2026-10-02 với "birth_date":"not-a-date". Các message 400 khác lấy từ code và tài liệu service, và chưa được capture. Body 401 được capture trên dev vào 2026-10-01 khi không có token. Trên dev mọi body 400 cũng mang field stack với một stack trace của server dạng text, ví dụ {"status":400,"message":"birth_date is invalid","stack":"<stack trace>"} (capture 2026-10-02). Các sample trong bảng bỏ nó đi.

Thử ngay​

Lời gọi đầu ghi vào dev, nên hãy gửi giá trị hiện tại của client, như capture đã làm. Lời gọi thứ hai bị từ chối và không ghi gì.

export AUTH_BASE_URL=https://dev.authentication.locate.sa
export TOKEN='<locate-jwt>' # see "Getting a test token" on the module overview
export CLIENT_ID='<client-id-in-the-token>'
curl -s -X PUT "$AUTH_BASE_URL/api/v1/clients/$CLIENT_ID" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "{\"client_id\":$CLIENT_ID,\"receive_offers\":0}"
curl -s -X PUT "$AUTH_BASE_URL/api/v1/clients/$CLIENT_ID" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"birth_date":"not-a-date"}'

Kỳ vọng: lời gọi đầu cho 200 và hồ sơ như ở mục Response. Lời gọi thứ hai cho 400 với birth_date is invalid.

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

Khía cạnhShukahLocateTác động lên app
URLPUT $SHUKAH_BASE_URL/maeda/client/{client_id}PUT $AUTH_BASE_URL/api/v1/clients/{client_id}Đổi base URL và path.
TokenToken opaque của Shukah.Chỉ JWT của Locate.Lấy JWT bằng exchange-token trước, và giữ token Shukah cho order-v2. Chưa chuyển đăng nhập sang Locate.
push_enabledCùng route này cũng nhận push_enabled, và app gửi nó ở đây cho công tắc push.Bị bỏ qua. Lời gọi vẫn trả 200 với hồ sơ không đổi.Chuyển công tắc push sang lời gọi setting bên dưới, nếu không nó lặng lẽ không làm gì (đọc code, chưa capture).
contact_phoneShukah có chấp nhận phone bị đổi hay không: Chưa được tài liệu hóa.Phải bằng đúng phone đã lưu, nếu không 400.Không có, miễn là app gửi lại đúng phone đã tải từ Locate. Đừng định dạng lại nó.
Validation và lỗi422 với một mảng lỗi theo field: [{"field":"birth_date","message":"The birth date field must match the format Y-m-d."}] cho "birth_date":"not-a-date" (capture trên dev, 2026-10-02). Các quy tắc khác của Shukah: Chưa được tài liệu hóa.400 với {"status":400,"message":"..."} (cộng stack trên dev), các quy tắc trong bảng Request.Status đổi từ 422 sang 400, và tên field không còn. App hiển thị message. Hãy kiểm tra cách diễn đạt trên màn hình Personal info.
Body thành côngHồ sơ 13 field (capture trên dev, 2026-10-02, với request ở trên).Hồ sơ 13 field (capture trên dev, 2026-10-01 và 2026-10-02).Không có: cùng 13 key, type và giá trị cho client 356259 vào 2026-10-02.
sexType của app cho phép 9 là "not applicable".9 được lưu là không rõ và đọc lại là 0.Client có hồ sơ Shukah mang 9 sẽ đọc là không rõ sau khi chuyển. Form Personal info chỉ có nam và nữ.
Copy sang ShukahKhông áp dụng.Chỉnh sửa ở lại Locate và không được copy sang Shukah.Mọi thứ vẫn đọc hồ sơ từ Shukah sẽ giữ giá trị cũ.

PUT /api/v1/clients/setting​

Thay thế ShukahPUT /maeda/client/:client_id✅ Đã thay thế
Cần sửa app2 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).
  • 🔴 App bật/tắt push qua PUT client/:id; Locate bỏ qua push_enabled ở đó, nên hãy gọi PUT /clients/setting.
  • 🟡 client_id bắt buộc trong body và phải bằng client_id của token; thiếu push_enabled trả 400.
  • 🟡 Thay đổi chỉ nằm ở Locate và không được đẩy sang Shukah.
  • 🟡 Cặp lệnh gọi ghi đúng giá trị hiện tại (push_enabled 0), nên chưa chứng minh được Shukah áp dụng push_enabled ở route này.

Request​

FieldVị tríKiểuBắt buộcRàng buộcMô tả
AuthorizationheaderstringcóBearer <locate-jwt>. Token Shukah nhận 401.JWT của Locate.
client_idbodyinteger hoặc numeric stringcóPhải bằng client id trong token. Thiếu hoặc khác cho 400 client_id does not match the authenticated client.Id của chính người gọi. Không có id trong path.
push_enabledbody0, 1 hoặc booleancóKey phải có mặt, nếu không 400 push_enabled is required. Chỉ 1, "1" và true bật nó. Mọi thứ khác tắt nó, kể cả null, "true" và 2.Bật hoặc tắt push notification.

client_id được kiểm tra trước. Hiện nay route này chỉ hỗ trợ push_enabled.

Một request dùng cho capture bên dưới, ghi lại giá trị hiện tại:

{
"client_id": 356259,
"push_enabled": 0
}

Response​

200 kèm hồ sơ 13 field sau khi cập nhật, không có wrapper, giống như ở Verify token. push_enabled hiển thị giá trị mới.

{
"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, Task 9 live write, giá trị hiện tại được ghi lại); các field cá nhân đã được thay thế.

Lỗi​

HTTPBodyKhi nào
400{"status":400,"message":"client_id does not match the authenticated client"}client_id thiếu hoặc không phải client của token. Điều này bao gồm một request không có JSON body, mà service đọc là {}. Đã capture với client_id đặt là 1.
400{"status":400,"message":"push_enabled is required"}Key push_enabled vắng mặt và client_id đúng. Chưa capture.
401{"status":401,"message":"Unauthorization"}Không có token, token không phải JWT Locate, hoặc client không active.
500Trên dev: {"status":500,"message":"<raw error text>","stack":"<stack trace>"}. Trên production: {"status":500,"message":"Internal server error"}.Lỗi không mong đợi. Chưa capture. Trên dev message là text lỗi gốc và có thêm field stack; Internal server error chỉ xuất hiện trên production (UAT và production: Chưa được tài liệu hóa).

400 của client_id và 401 được capture trên dev vào 2026-10-01 (401 khi không có token). 400 của push_enabled lấy từ code và tài liệu service. Trên dev body 400 cũng mang field stack, mà trang này bỏ đi.

Thử ngay​

Lời gọi đầu ghi vào dev, nên hãy gửi giá trị hiện tại của client. Lời gọi thứ hai bị từ chối và không ghi gì.

export AUTH_BASE_URL=https://dev.authentication.locate.sa
export TOKEN='<locate-jwt>' # see "Getting a test token" on the module overview
export CLIENT_ID='<client-id-in-the-token>'
curl -s -X PUT "$AUTH_BASE_URL/api/v1/clients/setting" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "{\"client_id\":$CLIENT_ID,\"push_enabled\":0}"
curl -s -X PUT "$AUTH_BASE_URL/api/v1/clients/setting" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"client_id":1,"push_enabled":0}'

Kỳ vọng: lời gọi đầu cho 200 và hồ sơ. Lời gọi thứ hai cho 400 với client_id does not match the authenticated client.

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

Khía cạnhShukahLocateTác động lên app
URLPUT $SHUKAH_BASE_URL/maeda/client/{client_id}, cùng route với cập nhật hồ sơ. Body là {client_id, push_enabled}.PUT $AUTH_BASE_URL/api/v1/clients/setting, không có id trong path.Công tắc push của app hiện gọi cập nhật hồ sơ. Hãy trỏ nó sang route này, nếu không Locate bỏ qua thay đổi.
TokenToken opaque của Shukah.Chỉ JWT của Locate.Lấy JWT bằng exchange-token trước, và giữ token Shukah cho order-v2. Chưa chuyển đăng nhập sang Locate.
client_idGửi trong path và body. Shukah có kiểm tra nó với token hay không: Chưa được tài liệu hóa.Phải có trong body và phải bằng client của token.Không có: app đã gửi client_id trong body.
Validation và lỗiChưa được tài liệu hóa.400 với {"status":400,"message":"..."} cho client_id sai hoặc thiếu push_enabled.App đã gửi cả hai key, nên các lỗi này không nên xảy ra.
Body thành côngHồ sơ 13 field với push_enabled là 0 (capture trên dev, 2026-10-02, body {"client_id":356259,"push_enabled":0}, giá trị hiện tại được ghi lại).Cùng hồ sơ 13 field đó (capture trên dev, 2026-10-02).App đọc push_enabled từ câu trả lời để đặt công tắc. Capture ghi giá trị hiện tại, nên nó không chứng minh rằng Shukah áp dụng thay đổi trên route này.
Copy sang ShukahKhông áp dụng.Thay đổi ở lại Locate và không được copy sang Shukah.Shukah giữ giá trị cũ.

POST /api/v1/clients/add-device-id​

Thay thế ShukahPOST /maeda/client/add-device-id✅ Đã thay thế
Thay thẳng0 breaking · 3 cần lưu ý
  • 🟡 Locate không lưu gì; Shukah lưu một dòng thiết bị (id 1074); app vẫn đánh dấu id là đã gửi.
  • 🟡 Locate trả lại id cố định 920 và client_id 356315 cho mọi người; Shukah trả client_id của người gọi.
  • 🟡 Locate không cần token (không có guard, routes/client.js:23); app có thể tiếp tục gửi token.

Request​

Không cần token: token hay bất kỳ header nào khác đều bị bỏ qua.

FieldVị tríKiểuBắt buộcRàng buộcMô tả
device_idbodystringkhôngKhông validate. Nó được echo lại khi có.Id duy nhất của thiết bị.
Bất kỳ body key, query key hoặc header nào khácbody, query, header—khôngBị bỏ qua, ví dụ language.—
{
"device_id": "00000000-0000-4000-8000-000000000000"
}

Response​

200 kèm một bản ghi thiết bị. Nó là stub, nên hai trong ba giá trị là cố định:

FieldKiểuNullableĐịnh dạng / ràng buộcMô tả
idintegerkhôngLuôn là 920, cho mọi caller.Một id bản ghi thiết bị giả.
client_idintegerkhôngLuôn là 356315, cho mọi caller. Nó không phải id của người gọi.Một client id giả.
device_idstringkhôngdevice_id từ request. Khi request không có, là một id mẫu cố định 46AE56EF-29BA-40AE-B436-AF22B119FE1E.Device id, được echo lại.
{
"id": 920,
"client_id": 356315,
"device_id": "00000000-0000-4000-8000-000000000000"
}

Capture trên dev, 2026-10-01 (lời gọi live của Task 9, không token; request là cái ở trên). Lời gọi này không lưu gì.

Lỗi​

Không có lỗi nào được định nghĩa. Không có 401, vì route không kiểm tra token. Một request không có JSON body được đọc là body rỗng và vẫn trả 200 (lời gọi body rỗng được capture vào 2026-10-01).

Thử ngay​

export AUTH_BASE_URL=https://dev.authentication.locate.sa
curl -s -X POST "$AUTH_BASE_URL/api/v1/clients/add-device-id" -H "Content-Type: application/json" -d '{"device_id":"00000000-0000-4000-8000-000000000000"}'

Kỳ vọng: 200 và bản ghi như ở mục Response. Gọi an toàn: nó không ghi gì.

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

Khía cạnhShukahLocateTác động lên app
URLPOST $SHUKAH_BASE_URL/maeda/client/add-device-idPOST $AUTH_BASE_URL/api/v1/clients/add-device-idĐổi base URL và path.
Nó làm gìLưu một dòng thiết bị mới cho người gọi ở mỗi lời gọi (capture trên dev, 2026-10-02: dòng 1074). Không có API nào xóa nó.Không gì cả: không lưu, không liên kết với client, không kiểm tra token.Sau khi chuyển, không thiết bị nào được đăng ký bởi lời gọi này. Nếu có thứ gì trên Shukah phụ thuộc vào bản ghi thiết bị, nó sẽ ngừng: Chưa được tài liệu hóa.
Câu trả lời{"id":1074,"client_id":356259,"device_id":"<the id sent>"}: id của dòng mới và id của người gọi (capture trên dev, 2026-10-02). App bỏ qua câu trả lời.{id: 920, client_id: 356315, device_id} cho mọi người.Không có tác động với app.
TokenApp gửi token Shukah của nó. Shukah có yêu cầu nó hay không: Chưa được tài liệu hóa.Không cần, không kiểm tra.Không có.
Thử lạiApp ghi lại rằng đã gửi id sau câu trả lời 200.Stub luôn trả 200.App sẽ đánh dấu thiết bị là đã gửi và không bao giờ thử lại, dù không có gì được lưu.

Lưu ý​

  • Route hồ sơ bỏ qua push_enabled và vẫn trả 200 với giá trị cũ, nên công tắc push phải gọi PUT /api/v1/clients/setting thay vào đó.
  • contact_phone phải bằng đúng phone đã lưu, kể cả dấu + ở đầu, nếu không lời gọi lỗi với 400.
  • add-device-id luôn trả 200 và không lưu gì, nên app đánh dấu thiết bị là đã gửi dù không có thiết bị nào được đăng ký.

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. Body lỗi trên dev mang field stack (capture 2026-10-01 trên các 400 của profile và setting), nên dev không chạy với NODE_ENV=production; handler chỉ thêm stack ngoài production (src/middlewares/error-handler.js:12-35). Cùng handler đó làm cho một 500 không mong đợi mang text lỗi gốc và một stack trên dev, và Internal server error chỉ trên production (src/middlewares/error-handler.js:28-33).

Thứ tự route và guard​

PUT /clients/setting được đăng ký trước PUT /clients/:client_id, nên setting không bao giờ bị đọc như một client id. Cả hai chạy guard client, nên các quy tắc token là của Verify token. Route device-id chỉ có async wrapper và không có guard (src/routes/client.js:23-26).

Cập nhật hồ sơ​

  • Các kiểm tra là các chuỗi express-validator chạy sau guard. Handler throw message đầu tiên, nên chỉ một message 400 được trả về (src/controllers/client/update-profile/validate.js:12-31, src/controllers/client/update-profile/index.js:12-15).
  • check('client_id') nhìn vào body, cookie, header, params và query, nên một client_id không khớp trong query string hay một header cũng lỗi với cùng message (kiểm tra offline, 2026-10-01: các chuỗi validator thật được chạy với khoảng 20 request tự tạo).
  • contact_phone được so sánh sau normalizePhone, chỉ bỏ khoảng trắng. Giá trị null lỗi, và giá trị không bao giờ được ghi (src/controllers/client/update-profile/validate.js:20-23, src/controllers/client/update-profile/parse-payload.js:8-9, src/sync/lib/casts.js:40-41).
  • Tên và email được lưu đã trim. null được lưu là null và "" là "" (src/controllers/client/update-profile/parse-payload.js:5,11-13).
  • birth_date qua được khi nó là null hoặc toBirthDateString cho ra một ngày. Hàm đó trả null cho giá trị rỗng và giá trị không đọc được, và ngày nó giữ là ngày UTC (src/sync/lib/casts.js:2-11, src/controllers/client/update-profile/validate.js:27-30, src/controllers/client/update-profile/parse-payload.js:14-16).
  • sex đi qua mapGender: 1 hoặc "1" là MALE, 2 hoặc "2" là FEMALE, mọi thứ khác là UNKNOWN, và response ánh xạ UNKNOWN thành 0. receive_offers đi qua toBool (src/sync/lib/casts.js:1,14-18, src/controllers/client/update-profile/parse-payload.js:17-18, src/controllers/client/setting/mapper.js:14-18,34).
  • Handler thay đổi client mà guard đã tải, set updated_at và save. Lần save xóa client đã cache (src/controllers/client/update-profile/index.js:17-20, src/models/client.js:158-161). Không có push sang Shukah (docs/plans/2026-07-16-shukah-update-profile-api-local.md:42,140).
  • Route hồ sơ không đọc push_enabled (docs/plans/2026-07-16-shukah-update-profile-api-local.md:39, src/controllers/client/update-profile/parse-payload.js:10-19).

Cập nhật setting​

Handler cần client_id bằng client của token, rồi push_enabled không được là undefined, set push_enabled bằng toBool và save. Nó không thay đổi gì khác và không push sang Shukah (src/controllers/client/setting/index.js:9-24, src/sync/lib/casts.js:1, docs/plans/2026-07-10-shukah-client-setting-api-local.md:100-106). Một request không có JSON body đến dưới dạng {}, cho message client_id trước.

Stub device id​

Handler trả {id: 920, client_id: 356315, device_id: req.body?.device_id ?? '<sample uuid>'} và không làm gì khác. Query và header bị bỏ qua (src/controllers/client/add-device-id/index.js:1-10, docs/plans/2026-07-15-shukah-add-device-id-api-local.md:15-16,65-69). Một unit test chốt nó (src/controllers/client/__tests__/add-device-id.test.js:11-35).

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

  • Design doc 2026-07-16 ghi path cập nhật của Shukah là PUT /api/v1/clients/{client_id} (docs/plans/2026-07-16-shukah-update-profile-api-local.md:14-19). App gọi PUT /maeda/client/{client_id}.
  • Lịch sử route của auth service cho thấy một route Shukah PUT /maeda/api/setting mà service Locate đã thay thế (commit d837492). App không bao giờ gọi nó: công tắc push đi qua route hồ sơ.
  • Hành vi sex, receive_offers và push_enabled của lời gọi hồ sơ trên Shukah không có trong repo nào: Chưa được tài liệu hóa.
  • 2026-10-02: trang này không có body thành công của Shukah cho update profile và update setting, và không có body lỗi của Shukah. Giờ chúng đã được capture: cùng hồ sơ 13 field ở cả hai phía, và một mảng lỗi theo field 422 trên Shukah trong khi Locate trả lời 400.
  • 2026-10-02: trang này ghi body 400 của Locate là {"status":400,"message":"..."}. Trên dev nó cũng mang stack, một stack trace của server (src/middlewares/error-handler.js:33, được thêm bất cứ khi nào NODE_ENV không phải production).
  • 2026-10-02: trang này nói Shukah lưu gì cho add-device-id là chưa được tài liệu hóa, và câu trả lời của nó chưa được xác nhận. Shukah lưu một dòng thiết bị mới cho mỗi lời gọi và trả lời bằng id của dòng đó và id của người gọi.

Sources​

  • locate-authentication-service@6757aa4: src/routes/client.js:23-26, src/controllers/client/update-profile/validate.js:4-31, src/controllers/client/update-profile/index.js:11-23, src/controllers/client/update-profile/parse-payload.js:5-19, src/controllers/client/setting/index.js:9-24, src/controllers/client/setting/mapper.js:14-38, src/controllers/client/add-device-id/index.js:1-10, src/controllers/client/__tests__/add-device-id.test.js:11-35, src/sync/lib/casts.js:1-18,40-41, src/models/client.js:158-161, src/middlewares/error-handler.js:12-35
  • Tài liệu của locate-authentication-service@6757aa4: docs/api/client-auth-and-address-book.md §10 và §11 (dòng 412-528; thay đổi lần cuối 2026-07-27), docs/plans/2026-07-16-shukah-update-profile-api-local.md:14-19,36-44,138-140, docs/plans/2026-07-10-shukah-client-setting-api-local.md:100-106, docs/plans/2026-07-15-shukah-add-device-id-api-local.md:12-18,63-69
  • 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:20-27,68-74, src/entities/user/model/api/dto/user.dto.ts:58-121,165-171, src/entities/user/model/types/user.server.ts:3-14, src/entities/user/model/constants/user.server.ts:1-6, src/entities/user/model/services/updateUser/updateUser.ts:13-42, src/features/UpdateProfileForm/model/services/updateProfile.ts:80-91, src/features/UpdateProfileForm/model/services/initUpdateProfileForm.ts:13-23, src/features/UpdateProfileForm/ui/UpdateProfileForm/UpdateProfileForm.tsx:42-45,73,155-160, platforms/mobile/products/locate/screens/home/PersonalInfo/ui/PersonalInfo/PersonalInfo.tsx:51, src/features/PushNotificationSettings/model/services/togglePushNotificationEnable.ts:22-26, src/features/PushNotificationSettings/ui/PushNotificationSettings/PushNotificationSettings.tsx:42-50, platforms/mobile/products/locate/screens/home/Settings/ui/Settings/Settings.tsx:37, src/entities/user/model/services/sendDeviceIdentificationData/sendDeviceIdentificationData.ts:18-30, src/entities/user/model/services/init/init.ts:21-23
  • Capture dev, 2026-10-02 (parity audit): update-profile--shukah, update-profile--locate-jwt, update-profile-bad--shukah, update-profile-bad--locate-jwt, update-setting--shukah, update-setting--locate-jwt, add-device-id--shukah, add-device-id--locate-jwt
  • Capture dev, 2026-10-01: locate-update-profile-unchanged, locate-update-profile-bad-birth-date, locate-setting-unchanged, locate-setting-mismatched-client, locate-add-device-id, probe-locate-update-profile, probe-locate-setting, probe-locate-add-device-id