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

Address book

Bối cảnh​

Trên Shukah, app quản lý các địa chỉ giao hàng đã lưu của client bằng năm lời gọi trên /maeda/address-book (path không có phần /api/): list, get, create, update và delete. Auth service có cùng năm route đó, nhưng không phải là swap drop-in. Có bốn điều cần chú ý: id của địa chỉ là chuỗi 24 ký tự thay vì integer, câu trả lời của list và create dùng shape khác với câu trả lời của get và update, create trả lời bên trong wrapper {status, address}, và lời gọi create không tự điền street, city và các phần địa chỉ khác mà Shukah tự suy ra.

Tính năng​

App cho phép một client đã đăng nhập lưu nhiều địa chỉ và chọn một địa chỉ làm mặc định. Trong snapshot app ngày 2026-02-26 các lời gọi xảy ra ở đây:

Lời gọiỞ đâu trong app
ListKhi một client đã đăng nhập mở màn hình hiển thị các địa chỉ đã lưu (location drawer và thanh user-location) và danh sách chưa được tải, khi app thiết lập địa chỉ giao hàng mặc định sau khi đăng nhập, khi pull-to-refresh trong danh sách địa chỉ đã lưu, và lại sau mỗi lần create, update hoặc delete.
GetKhi client mở màn hình Edit address.
CreateKhi client lưu một vị trí từ bản đồ với "save for later" bật. Nếu đã có một địa chỉ đã lưu cùng tên, app xóa nó trước rồi mới tạo địa chỉ mới.
UpdateKhi client lưu màn hình Edit address. App gửi location_name, area, is_default và image_urls.
DeleteKhi client xóa một địa chỉ trên màn hình Edit address.

Cả năm lời gọi đều cần JWT Locate (xem "Lấy test token" ở trang tổng quan module). Các quy tắc áp dụng cho tất cả:

  • Id. Mọi response đưa id dưới dạng Mongo ObjectId: một chuỗi hex 24 ký tự. Trong path của get, update và delete, một giá trị chỉ gồm chữ số trước tiên được thử như id địa chỉ Shukah cũ, rồi mới như ObjectId. Mọi giá trị khác chỉ được thử như ObjectId. Chỉ những địa chỉ đến từ address book của Shukah mới mang Shukah id, và không response nào hiển thị nó.
  • Hai shape response. List và create dùng list shape: is_default là boolean, lat và lng là số, field text bị thiếu là null, và có các key source, created_at và updated_at. Get và update dùng detail shape: is_default là 0 hoặc 1, lat và lng là chuỗi, field text bị thiếu là "", và ba key đó vắng mặt.
  • Giá trị trống. Khi create và update, một field text được trim, và giá trị trống được lưu là null. lat hoặc lng trống hoặc không phải số được lưu là null. Không có gì được validate: một body rỗng tạo ra một địa chỉ với mọi field rỗng, và không có giới hạn số lượng địa chỉ.
  • Update một phần. Update chỉ thay đổi các key có trong body. Một key có mặt với null, "" hoặc chỉ khoảng trắng sẽ xóa field (image_urls thành []). source, Shukah id và created_at không bao giờ đổi.
  • Chỉ địa chỉ của chính mình. Id chỉ được tra trong các địa chỉ của người gọi. Một id thuộc về người khác, hoặc không thuộc về ai, cho 404 với Address not found.
  • Một mặc định. Service giữ một địa chỉ mặc định khi app create, update hoặc delete:
Lời gọiQuy tắc
Createis_default true xóa flag trên mọi địa chỉ khác. Nếu không, địa chỉ mới là mặc định chỉ khi sổ trống hoặc chưa có mặc định.
UpdateChỉ khi body có is_default. Đặt true: mọi địa chỉ khác mất flag. Đặt false khi không có địa chỉ nào khác là mặc định: địa chỉ khác đầu tiên trở thành mặc định. Nếu nó là địa chỉ duy nhất, nó vẫn là mặc định.
DeleteNếu không còn mặc định nào và sổ không trống, địa chỉ đầu tiên theo thứ tự lưu trữ trở thành mặc định. Danh sách được sắp theo ngày, nên đó không phải lúc nào cũng là địa chỉ đầu tiên mà app thấy.

Đảm bảo này chỉ đúng cho ba lời gọi này. Các địa chỉ copy từ Shukah không được kiểm tra, và trên dev cả 10 địa chỉ trong danh sách đã capture đều là mặc định (xem khối list).

GET /api/v1/clients/address-book​

Thay thế ShukahGET /maeda/address-book✅ Đã thay thế
Cần sửa app2 breaking · 5 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).
  • 🔴 Địa chỉ tạo trên Locate có formatted_address/street/city là null; app gửi formatted_address làm c_address.
  • 🟡 id là chuỗi 24 ký tự hex (Shukah là số nguyên); id Shukah đã lưu không còn khớp (initLocation.ts:78).
  • 🟡 is_default là boolean, true ở 28 trên 30 (Shukah: 0 ở cả 15); initLocation lấy mục đầu tiên có giá trị true.
  • 🟡 30 địa chỉ so với 15 trên Shukah: thao tác xóa trên Shukah không tới Locate, và "Saihat" xuất hiện 3 lần.
  • 🟡 image_urls là [] trên Locate cho cả 4 địa chỉ Shukah có ảnh (Shukah trả về URL).
  • 🟡 Locate xếp created_at mới nhất trước; Shukah xếp theo position (0..14), nên danh sách có thể đổi thứ tự.

Locate trả is_default dạng boolean và id dạng chuỗi 24 ký tự hex, trong khi Shukah trả 0 hoặc 1 và id là số nguyên (lat và lng là số ở cả hai phía); phần kiểm tra mặc định của app chấp nhận boolean, nhưng mọi chỗ coi id là số đều phải sửa.

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.
Bất kỳ query key hoặc header nào khácquery, header—khôngĐược chấp nhận và bỏ qua, ví dụ language.—

Không có phân trang, không có filter và không có tùy chọn sắp xếp.

Response​

200 với một mảng theo list shape. Nó là [] khi client không có địa chỉ nào. created_at mới nhất đứng đầu, và các địa chỉ không có created_at đứng cuối.

FieldKiểuNullableĐịnh dạng / ràng buộcMô tả
idstringkhôngObjectId hex 24 ký tự. Không bao giờ là integer id của Shukah.Id địa chỉ cho get, update và delete.
sourcestringcómt_client_inline, mt_address_book hoặc locate.Địa chỉ đến từ đâu: locate cho địa chỉ tạo qua API này.
is_defaultbooleankhôngtrue hoặc false. Có thể có nhiều hơn một địa chỉ true.Địa chỉ mặc định.
location_name, street, area, area_name, city, state, zipcode, country, country_code, formatted_addressstringcónull khi thiếu. Chuỗi rỗng đã được lưu vẫn là "" (capture có state: "").Các phần của địa chỉ.
lat, lngnumbercóSố JSON. Không kiểm tra phạm vi.Tọa độ.
image_urlsarray of stringkhôngLuôn là mảng, có thể rỗng.URL ảnh.
created_at, updated_atstringcóISO 8601 theo UTC, ví dụ 2026-09-29T17:01:10.000Z.Khi địa chỉ được tạo và thay đổi lần cuối.
[
{
"id": "6abbeed8a492ed4862500b74",
"source": "mt_address_book",
"is_default": true,
"location_name": "Saihat",
"street": "King Fahd Rd",
"area": "Eastern Province",
"area_name": "A12345",
"city": "Saihat",
"state": "Al-Qatif",
"zipcode": "32461",
"country": "Saudi Arabia",
"country_code": "SA",
"lat": 24.7136,
"lng": 46.6753,
"formatted_address": "King Fahd Rd, Al Olaya, Riyadh 12211",
"image_urls": [],
"created_at": "2026-09-29T17:01:10.000Z",
"updated_at": "2026-09-29T17:01:10.000Z"
}
]

Capture trên dev, 2026-10-01 (client 356259): mục đầu tiên trong 28 mục, với các field cá nhân và tọa độ đã được thay thế.

Lỗi​

HTTPBodyKhi nào
401{"status":401,"message":"Unauthorization"}Không có token, token không phải JWT Locate, hoặc client thiếu hay không active. Cùng guard với Verify token.
401Cùng body.Token hợp lệ nhưng không tải được bản ghi client.
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).

Body 401 được capture trên dev vào 2026-10-01 khi không có token.

Thử ngay​

export AUTH_BASE_URL=https://dev.authentication.locate.sa
export TOKEN='<locate-jwt>' # see "Getting a test token" on the module overview
curl -s "$AUTH_BASE_URL/api/v1/clients/address-book" -H "Authorization: Bearer $TOKEN"

Kỳ vọng: 200 và một mảng như ở mục Response. Không có token bạn nhận 401 như ở mục Lỗi.

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

Khía cạnhShukahLocateTác động lên app
URLGET $SHUKAH_BASE_URL/maeda/address-bookGET $AUTH_BASE_URL/api/v1/clients/address-bookĐổ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.
idMột integer, ví dụ 162115 (capture trên dev, 2026-10-01).Một chuỗi 24 ký tự, ví dụ 6abbeed8a492ed4862500b74.Mọi chỗ lưu hoặc so sánh id dạng số đều phải đổi. App khai báo kiểu của nó là number.
is_default0 hoặc 1 (capture trên dev, 2026-10-01).true hoặc false.App tìm mặc định bằng phép thử truthiness, chạy được với cả hai. Một phép so sánh strict với 1 thì không.
Key thêmposition (một integer).source, created_at, updated_at; không có position.Không có: type địa chỉ của app không có key nào trong bốn key này.
image_urlsMột mảng hoặc null. Bốn trong 15 địa chỉ của client có URL ảnh (capture trên dev, 2026-10-02).Luôn là mảng. Bản copy trên Locate của bốn địa chỉ đó có [].Ảnh của các địa chỉ copy từ Shukah bị mất. Nguyên nhân: Chưa được tài liệu hóa.
Thứ tựTheo position, từ 0 đến 14, trong khi các id không theo thứ tự (162115, 161996, 162101, …) (capture trên dev, 2026-10-02).created_at mới nhất trước.Nếu app hiển thị danh sách theo thứ tự của server, thứ tự sẽ đổi.
Số lượng cho client 35625915 địa chỉ (capture trên dev, 2026-10-02; 13 vào 2026-10-01).30 địa chỉ, cùng client, cùng ngày (28 vào 2026-10-01).Các địa chỉ đã xóa trên Shukah vẫn còn trên Locate, và một địa chỉ xuất hiện ba lần trên Locate. Hãy kiểm tra trùng lặp trước khi chuyển.
Địa chỉ mặc địnhis_default là 0 ở cả 15 địa chỉ (capture trên dev, 2026-10-02).true ở 28 trong 30 địa chỉ.App lấy mặc định đầu tiên nó thấy, nên địa chỉ mặc định được chọn có thể khác.

GET /api/v1/clients/address-book/:id​

Thay thế ShukahGET /maeda/address-book/:id✅ Đã thay thế
Cần sửa app1 breaking · 5 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).
  • 🟡 id là chuỗi 24 ký tự hex; id số của Shukah (162115) vẫn được xử lý trong path.
  • 🟡 lat/lng là chuỗi (Shukah trả số); app dùng Number() (locationPresetToSelectedAddress.ts:14).
  • 🟡 Cùng một địa chỉ: is_default là 1 trên Locate so với 0 trên Shukah, và image_urls là [] so với một URL ảnh (162115).
  • 🟡 id của người khác: Locate trả 404 "Address not found"; Shukah trả 403 "You can only view address that belong to you."
  • 🟡 Body 404 của Locate có kèm stack của server (get.js:39:17) trên dev.

Request​

FieldVị tríKiểuBắt buộcRàng buộcMô tả
AuthorizationheaderstringcóBearer <locate-jwt>.JWT của Locate.
idpathstringcóGiá trị chỉ gồm chữ số được thử trước như id địa chỉ Shukah, rồi như ObjectId. Mọi giá trị khác chỉ thử như ObjectId.Id địa chỉ.
Bất kỳ query key hoặc header nào khácquery, header—khôngĐược chấp nhận và bỏ qua.—

Response​

200 với một địa chỉ theo detail shape, không có wrapper:

FieldKiểuNullableĐịnh dạng / ràng buộcMô tả
idstringkhôngObjectId, kể cả khi dùng id số của Shukah trong path.Id địa chỉ.
location_name, formatted_address, area_name, street, city, area, state, zipcode, country, country_codestringkhông"" khi thiếu, không bao giờ là null.Các phần của địa chỉ.
is_defaultintegerkhông0 hoặc 1.Địa chỉ mặc định.
lat, lngstringkhôngSố dưới dạng text, ví dụ "24.7136". "" khi thiếu.Tọa độ.
image_urlsarray of stringkhôngCó thể rỗng.URL ảnh.

Không có source, created_at hay updated_at.

{
"id": "6abe570b9ac75c8c65a5fa1a",
"location_name": "Docs capture",
"is_default": 0,
"formatted_address": "King Fahd Rd, Al Olaya, Riyadh 12211",
"area_name": "Olaya",
"street": "King Fahd Rd",
"city": "Riyadh",
"area": "Al Olaya",
"state": "",
"zipcode": "12211",
"country": "Saudi Arabia",
"country_code": "SA",
"lat": "24.7136",
"lng": "46.6753",
"image_urls": []
}

Capture trên dev, 2026-10-01 (client 356259): địa chỉ được tạo bởi sample create-address bên dưới, đọc ngay sau khi tạo và bị xóa ở cuối lần chạy. Text địa chỉ vốn đã là minh họa.

Cùng địa chỉ đó trả về từ create với state: null, và ở đây với state: "": đó là khác biệt giữa hai shape.

Lỗi​

HTTPBodyKhi nào
401{"status":401,"message":"Unauthorization"}Không có token, token không phải JWT Locate, client không active, hoặc không tải được bản ghi client.
404{"status":404,"message":"Address not found"}Không địa chỉ nào của client này khớp với id. Bao gồm địa chỉ đã bị xóa, và id thuộc về client khác.

404 được capture trên dev vào 2026-10-01 bằng cách đọc địa chỉ mẫu sau khi nó bị xóa, và vào 2026-10-02 với một ObjectId không tồn tại. Một id thuộc về client khác nhận cùng câu trả lời vì lookup chỉ tìm trong các địa chỉ của người gọi (đọc code; id của người khác chưa được thử live trên Locate). Shukah trả lời id của người khác bằng 403 (capture trên dev, 2026-10-02; xem Khác biệt so với Shukah). Trên dev các body lỗi cũng mang field stack với một stack trace của server dạng text. Các sample trên trang này bỏ nó đi.

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 ADDRESS_ID='<id-from-the-list>'
curl -s "$AUTH_BASE_URL/api/v1/clients/address-book/$ADDRESS_ID" -H "Authorization: Bearer $TOKEN"

Kỳ vọng: 200 và địa chỉ theo detail shape. Một id không tồn tại cho 404 như ở mục Lỗi.

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

Khía cạnhShukahLocateTác động lên app
URLGET $SHUKAH_BASE_URL/maeda/address-book/{id}GET $AUTH_BASE_URL/api/v1/clients/address-book/{id}Đổi base URL và path.
idMột integer (capture trên dev, 2026-10-01).Một chuỗi 24 ký tự. Id số của Shukah vẫn chạy trong path với các địa chỉ đến từ address book của Shukah.List giờ trả ObjectId. App so sánh id địa chỉ chọn lần cuối đã lưu với các id trong list dưới dạng chuỗi, nên một integer Shukah đã lưu không còn khớp và lựa chọn bị bỏ.
lat, lngSố JSON, ví dụ 24.7136 (capture trên dev, 2026-10-01).Chuỗi, ví dụ "24.7136".Không có: app chấp nhận cả hai và chuyển bằng Number() trước khi dùng.
is_default0 hoặc 1. Địa chỉ 162115 là 0 (capture trên dev, 2026-10-02).0 hoặc 1. Cùng địa chỉ đó đọc qua Shukah id của nó là 1 (capture trên dev, 2026-10-02).Type giống nhau, giá trị thì không: địa chỉ mặc định mà app hiển thị có thể đổi.
image_urlsMột mảng hoặc null. Địa chỉ 162115 có một URL ảnh (capture trên dev, 2026-10-02).Luôn là mảng. Cùng địa chỉ đó có [].Ảnh của một địa chỉ copy từ Shukah bị mất.
Key thêmposition.Không có.Không có: app không đọc nó.
Địa chỉ của người khác403 {"name":"Forbidden","message":"You can only view address that belong to you.","code":0,"status":403,"type":"Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException"} (capture trên dev, 2026-10-02, id 1).404 Address not found, giống một id không tồn tại (đọc code).Status và text mà app hiển thị sẽ đổi.
Body 404{"name":"Not Found","message":"Object not found: 162119","code":0,"status":404,"type":"Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException"} (capture trên dev, 2026-10-01).{"status":404,"message":"Address not found"}App hiển thị message, nên text hiển thị sẽ đổi.

POST /api/v1/clients/address-book​

Thay thế ShukahPOST /maeda/address-book✅ Đã thay thế
Cần sửa app3 breaking · 2 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).
  • 🔴 Response là {status,address:{...}}; app dựng preset từ cấp cao nhất nên id và lat/lng là NaN.
  • 🔴 Không geocode: street, city, area, state, zipcode, country, formatted_address là null (Shukah điền các giá trị này).
  • 🟡 address.is_default là boolean (Shukah là 0); lat/lng là số ở đây nhưng là chuỗi ở get và update.
  • 🟡 Địa chỉ tạo trên Locate không bao giờ xuất hiện trên Shukah (push gọi /maeda/api/address-book, trả 404).

Request​

Mọi field của body đều tùy chọn và không có gì được validate. Các key không được liệt kê bị bỏ qua. Server đặt source là locate và các timestamp là bây giờ, nên body không thể set chúng.

FieldVị tríKiểuBắt buộcRàng buộcMô tả
AuthorizationheaderstringcóBearer <locate-jwt>.JWT của Locate.
location_name, street, area, area_name, city, state, zipcode, country, country_code, formatted_addressbodystringkhôngĐược trim. Trống hoặc null được lưu là null. Không giới hạn độ dài.Các phần của địa chỉ.
lat, lngbodynumber hoặc numeric stringkhôngnull, "" và giá trị không phải số được lưu là null. Không kiểm tra phạm vi.Tọa độ.
image_urlsbodyarray of stringkhôngCác chuỗi được trim và chuỗi trống bị bỏ. null cho []. Một chuỗi JSON-array hoặc chuỗi ngăn cách bằng dấu phẩy cũng được chấp nhận.URL ảnh.
is_defaultbodyboolean, 0 hoặc 1khôngChỉ 1, "1" và true nghĩa là mặc định. Mọi giá trị khác, kể cả "true" và 2, nghĩa là không mặc định.Đặt địa chỉ này làm mặc định.

Những gì app gửi trong snapshot ngày 2026-02-26 chỉ là location_name, area_name, lat và lng (cả hai dạng chuỗi), is_default (0 hoặc 1) và image_urls (một mảng hoặc null).

Một request dùng cho capture bên dưới:

{
"location_name": "Docs capture",
"street": "King Fahd Rd",
"area": "Al Olaya",
"area_name": "Olaya",
"city": "Riyadh",
"zipcode": "12211",
"country": "Saudi Arabia",
"country_code": "SA",
"lat": 24.7136,
"lng": 46.6753,
"formatted_address": "King Fahd Rd, Al Olaya, Riyadh 12211",
"image_urls": [],
"is_default": false
}

Response​

200 với một wrapper chứa địa chỉ mới theo list shape:

FieldKiểuNullableĐịnh dạng / ràng buộcMô tả
statusintegerkhôngLuôn là 200.Echo status.
addressobjectkhôngList shape, với các field được liệt kê ở khối list. source là locate. is_default là true khi request yêu cầu hoặc khi client chưa có mặc định.Địa chỉ đã được tạo.
{
"status": 200,
"address": {
"id": "6abe570b9ac75c8c65a5fa1a",
"source": "locate",
"is_default": false,
"location_name": "Docs capture",
"street": "King Fahd Rd",
"area": "Al Olaya",
"area_name": "Olaya",
"city": "Riyadh",
"state": null,
"zipcode": "12211",
"country": "Saudi Arabia",
"country_code": "SA",
"lat": 24.7136,
"lng": 46.6753,
"formatted_address": "King Fahd Rd, Al Olaya, Riyadh 12211",
"image_urls": [],
"created_at": "2026-10-01T12:50:19.661Z",
"updated_at": "2026-10-01T12:50:19.661Z"
}
}

Capture trên dev, 2026-10-01 (client 356259, Task 9 live write). Địa chỉ bị xóa ở cuối lần chạy. Text địa chỉ vốn đã là minh họa. is_default là false vì client đã có các địa chỉ mặc định.

Lỗi​

HTTPBodyKhi nào
401{"status":401,"message":"Unauthorization"}Không có token, token không phải JWT Locate, client không active, hoặc không tải được bản ghi client.
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, ví dụ một lần save xung đột với một bản copy dữ liệu của client từ Shukah đến cùng lúc. 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).

Không có 400: giá trị xấu được làm sạch hoặc lưu là null. Body 401 được capture trên dev vào 2026-10-01 khi không có token.

Thử ngay​

Lời gọi này tạo một địa chỉ thật trên dev. Hãy xóa nó sau đó bằng lời gọi delete bên dưới.

export AUTH_BASE_URL=https://dev.authentication.locate.sa
export TOKEN='<locate-jwt>' # see "Getting a test token" on the module overview
curl -s -X POST "$AUTH_BASE_URL/api/v1/clients/address-book" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"location_name":"Docs test","area_name":"Olaya","lat":"24.7136","lng":"46.6753","is_default":0,"image_urls":[]}'

Kỳ vọng: 200 và {"status":200,"address":{...}}. Body này là cái app gửi, nên street, city, area, state, zipcode, country, country_code và formatted_address trả về là null (capture trên dev, 2026-10-02, với đúng body này). Giữ address.id cho các lời gọi khác.

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

Khía cạnhShukahLocateTác động lên app
URLPOST $SHUKAH_BASE_URL/maeda/address-bookPOST $AUTH_BASE_URL/api/v1/clients/address-bookĐổi base URL và path.
ResponseChính object địa chỉ, phẳng, với id integer và key position (capture trên dev, 2026-10-01).{"status":200,"address":{...}} với id 24 ký tự.App đọc id, lat, lng và phần còn lại từ cấp cao nhất của câu trả lời. Với wrapper, tất cả đều thiếu, và tọa độ nó dựng cho địa chỉ được chọn thành NaN. Hãy đọc address thay vào đó.
Các phần địa chỉ bị thiếuMột request chỉ có lat, lng, area_name, location_name, is_default và image_urls trả về với street, area, state, zipcode, country, country_code và formatted_address đã được điền (capture trên dev, 2026-10-01, và lại vào 2026-10-02 với position 15). Shukah suy ra chúng bằng cách nào: Chưa được tài liệu hóa.Chỉ lưu những gì được gửi. Cái gì không gửi là null: cùng request đó trả về cả tám giá trị là null (capture trên dev, 2026-10-02).Một địa chỉ tạo bằng body hiện tại của app không có street, city hay formatted address. Màn hình bản đồ có các giá trị này, nên app có thể gửi chúng, hoặc backend phải điền. Có kế hoạch như vậy hay không: Chưa được tài liệu hóa.
Địa chỉ cùng tênApp xóa một địa chỉ hiện có cùng tên trước khi tạo địa chỉ mới.Hai lời gọi đó vẫn chạy. Delete dùng id từ list, là một chuỗi.Không có ở bước này. Xem khối delete cho lần xóa tường minh.
Địa chỉ được lưu ở đâuTrong Shukah.Trong Locate, sau đó là một bản copy best-effort sang Shukah.Trên dev bản copy không tới được Shukah: list của Shukah vẫn có 13 địa chỉ sau create, update và delete ngày 2026-10-01, và vào 2026-10-02 địa chỉ tạo qua Locate cũng không bao giờ xuất hiện trên Shukah. Delete không bao giờ được copy. Không thể giả định một địa chỉ tạo qua Locate tồn tại trên Shukah.

PUT /api/v1/clients/address-book/:id​

Thay thế ShukahPUT /maeda/address-book/:id✅ Đã thay thế
Cần sửa app1 breaking · 5 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).
  • 🟡 id là chuỗi 24 ký tự hex và lat/lng là chuỗi; app đọc cùng các key nên không cần thay đổi.
  • 🟡 Các phần địa chỉ chưa đặt trả về "" trên Locate (city, area, state ...); Shukah trả giá trị đã geocode.
  • 🟡 Chỉnh sửa trên Shukah không bao giờ tới Locate ("S (edited)" vẫn là "Parity test S" ở đó).
  • 🟡 Locate luôn giữ đúng một địa chỉ mặc định khi update; Shukah luôn trả is_default là 0.
  • 🟡 Body 404 có kèm stack của server trên dev.

Body phẳng theo kiểu Shukah; id có thể là id 24 ký tự hex hoặc id số của Shukah.

Request​

Cập nhật một phần: chỉ các key có trong body mới thay đổi.

FieldVị tríKiểuBắt buộcRàng buộcMô tả
AuthorizationheaderstringcóBearer <locate-jwt>.JWT của Locate.
idpathstringcóChỉ chữ số: id địa chỉ Shukah trước, rồi ObjectId. Mọi giá trị khác: chỉ ObjectId.Địa chỉ cần đổi.
location_name, street, area, area_name, city, state, zipcode, country, country_code, formatted_addressbodystring hoặc nullkhôngLàm sạch giống create. Một key có mặt với null, "" hoặc khoảng trắng đặt field là null.Các phần của địa chỉ.
lat, lngbodynumber, numeric string hoặc nullkhôngLàm sạch giống create.Tọa độ.
image_urlsbodyarray of string hoặc nullkhôngLàm sạch giống create. null cho [].URL ảnh.
is_defaultbodyboolean, 0 hoặc 1khôngChỉ 1, "1" và true nghĩa là mặc định. Xem các quy tắc mặc định ở mục Tính năng.Đặt địa chỉ này làm mặc định, hoặc không.
source, created_at, bất kỳ key nào khácbody—khôngBị bỏ qua.—

Những gì app gửi trong snapshot ngày 2026-02-26: location_name, area, is_default (0 hoặc 1) và image_urls.

{
"location_name": "Docs capture (edited)"
}

Response​

200 với địa chỉ theo detail shape, giống như get: không có wrapper, is_default là 0 hoặc 1, lat và lng là chuỗi.

{
"id": "6abe570b9ac75c8c65a5fa1a",
"location_name": "Docs capture (edited)",
"is_default": 0,
"formatted_address": "King Fahd Rd, Al Olaya, Riyadh 12211",
"area_name": "Olaya",
"street": "King Fahd Rd",
"city": "Riyadh",
"area": "Al Olaya",
"state": "",
"zipcode": "12211",
"country": "Saudi Arabia",
"country_code": "SA",
"lat": "24.7136",
"lng": "46.6753",
"image_urls": []
}

Capture trên dev, 2026-10-01 (client 356259, Task 9 live write): request ở trên, gửi tới địa chỉ từ sample create. Text địa chỉ vốn đã là minh họa.

Lỗi​

HTTPBodyKhi nào
401{"status":401,"message":"Unauthorization"}Không có token, token không phải JWT Locate, client không active, hoặc không tải được bản ghi client.
404{"status":404,"message":"Address not found"}Không địa chỉ nào của client này khớp với id, kể cả id thuộc về client khác.
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, như với create. 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).

Không có 400. Body 401 được capture trên dev vào 2026-10-01 khi không có token. Body 404 là cái đã capture cho get-address.

Thử ngay​

Lời gọi này thay đổi một địa chỉ trên dev. Hãy dùng một địa chỉ bạn đã tạo cho bài test.

export AUTH_BASE_URL=https://dev.authentication.locate.sa
export TOKEN='<locate-jwt>' # see "Getting a test token" on the module overview
export ADDRESS_ID='<id-from-the-create-call>'
curl -s -X PUT "$AUTH_BASE_URL/api/v1/clients/address-book/$ADDRESS_ID" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"location_name":"Office"}'

Kỳ vọng: 200 và địa chỉ theo detail shape với location_name mới.

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

Khía cạnhShukahLocateTác động lên app
URLPUT $SHUKAH_BASE_URL/maeda/address-book/{id}PUT $AUTH_BASE_URL/api/v1/clients/address-book/{id}Đổi base URL và path.
ResponseĐịa chỉ, phẳng, với id integer, số cho lat và lng, và key position (capture trên dev, 2026-10-01 và 2026-10-02).Địa chỉ, phẳng, với id 24 ký tự, chuỗi cho lat và lng, và không có position. Các phần địa chỉ chưa bao giờ được set trả về "" (capture trên dev, 2026-10-02).Không có với các key app đọc (đã xác nhận vào 2026-10-02). App dựng địa chỉ đã lưu của nó từ các key cấp cao nhất, đều có mặt.
Quy tắc mặc địnhChưa được tài liệu hóa.Các quy tắc ở mục Tính năng.Nếu app dựa vào cách chọn mặc định của Shukah, hãy so sánh trước khi chuyển.
Copy sang ShukahKhông áp dụng.Một bản copy best-effort của địa chỉ đã sửa được gửi sang Shukah. Khi địa chỉ không có Shukah id, bản copy tạo một địa chỉ mới ở đó, có thể gây trùng lặp.Trên dev bản copy không xuất hiện trong list của Shukah vào 2026-10-01 và cả vào 2026-10-02 (xem create). Một lần sửa làm trên Shukah cũng không tới được Locate (2026-10-02).

DELETE /api/v1/clients/address-book/:id​

Thay thế ShukahDELETE /maeda/address-book/:id✅ Đã thay thế
Cần sửa app2 breaking · 2 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 gửi +id, nên id 24 ký tự hex thành NaN và lệnh xóa trả 404; slice cũng so sánh bằng +id.
  • 🟡 Response là 200 {"status":200}; Shukah trả 204 không có body; app bỏ qua body.
  • 🟡 Xóa trên Locate không được đẩy sang Shukah, và xóa trên Shukah không tới Locate (địa chỉ "ma").

Request​

FieldVị tríKiểuBắt buộcRàng buộcMô tả
AuthorizationheaderstringcóBearer <locate-jwt>.JWT của Locate.
idpathstringcóChỉ chữ số: id địa chỉ Shukah trước, rồi ObjectId. Mọi giá trị khác: chỉ ObjectId.Địa chỉ cần xóa.

Không có body.

Response​

200 với một key:

FieldKiểuNullableĐịnh dạng / ràng buộcMô tả
statusintegerkhôngLuôn là 200. Không có key nào khác.Echo status.
{
"status": 200
}

Capture trên dev, 2026-10-01 (client 356259, Task 9 live write): lần xóa địa chỉ mẫu.

Việc xóa là vĩnh viễn. Nếu địa chỉ bị xóa là mặc định và vẫn còn địa chỉ khác, địa chỉ đầu tiên theo thứ tự lưu trữ trở thành mặc định.

Lỗi​

HTTPBodyKhi nào
401{"status":401,"message":"Unauthorization"}Không có token, token không phải JWT Locate, client không active, hoặc không tải được bản ghi client.
404{"status":404,"message":"Address not found"}Không địa chỉ nào của client này khớp với id. Lần delete thứ hai của cùng id cũng nhận cái này, nên lời gọi không idempotent.
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).

Body 401 được capture trên dev vào 2026-10-01 khi không có token. Body 404 là cái đã capture cho get-address sau lần delete này.

Thử ngay​

Lời gọi này xóa một địa chỉ trên dev. Hãy dùng một địa chỉ bạn đã tạo cho bài test.

export AUTH_BASE_URL=https://dev.authentication.locate.sa
export TOKEN='<locate-jwt>' # see "Getting a test token" on the module overview
export ADDRESS_ID='<id-from-the-create-call>'
curl -s -X DELETE "$AUTH_BASE_URL/api/v1/clients/address-book/$ADDRESS_ID" -H "Authorization: Bearer $TOKEN"

Kỳ vọng: 200 và {"status":200}. Chạy lại cho 404 như ở mục Lỗi.

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

Khía cạnhShukahLocateTác động lên app
URLDELETE $SHUKAH_BASE_URL/maeda/address-book/{id}DELETE $AUTH_BASE_URL/api/v1/clients/address-book/{id}Đổi base URL và path.
Câu trả lời thành công204 với body rỗng (capture trên dev, 2026-10-01).200 với {"status":200}.Không có: app không đọc body.
Id mà app gửiApp biến id thành số bằng toán tử unary plus trước lời gọi. Điều đó chạy với integer của Shukah.Một id 24 ký tự thành NaN, nên app gọi .../address-book/NaN. Đó không phải toàn chữ số, nên service tìm một ObjectId NaN và trả 404 Address not found (đọc code, chưa thử live).Lần xóa tường minh trên màn hình Edit address sẽ lỗi cho đến khi app ngừng chuyển đổi id. Việc xóa địa chỉ cùng tên bên trong create không chuyển đổi nó.
Body 404{"name":"Not Found","message":"Object not found: 162119",...} (capture trên dev, 2026-10-01).{"status":404,"message":"Address not found"}App hiển thị message, nên text hiển thị sẽ đổi.
Copy sang ShukahKhông áp dụng.Delete không bao giờ được copy sang Shukah.Một địa chỉ được tạo hoặc sửa qua Locate rồi xóa qua Locate có thể vẫn còn trên Shukah.

Lưu ý​

  • App biến id địa chỉ thành số trước khi xóa, nên id Locate (24 ký tự hex) thành NaN và lần xóa lỗi với 404.
  • Create trả {status, address} thay vì chính địa chỉ, và nó không tự điền street, city hay formatted address từ tọa độ như Shukah làm.
  • List và create trả boolean và số, get và update trả 0/1 và tọa độ dạng chuỗi, và list có thể chứa nhiều địa chỉ mặc định.

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 404 của get-address và 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).

Lookup id​

findAddressIndexByApiId biến id trong path thành text. Nếu nó khớp ^\d+$ thì tìm một địa chỉ có shukah_address_id bằng số đó, và nếu không có cái nào khớp thì fallback sang _id của sub-document (src/controllers/client/address-book/lookup.js:13-25). Get, update và delete đều dùng nó. Lookup chạy trên mảng addresses của chính người gọi, đó là lý do id của client khác cho 404 (src/controllers/client/address-book/get.js:11-14; tài liệu service liệt kê cùng 404 cho một id không phải của user hiện tại, docs/api/client-auth-and-address-book.md:259-263). Shukah id được copy từ mt_address_book.id cho các địa chỉ đến từ address book của Shukah, và là null cho các địa chỉ tạo qua API và cho địa chỉ inline dựng từ dòng client (src/models/client.js:19, src/sync/mappers/client-mapper.js:32-47,50-53).

Quy tắc ghi​

  • Create chỉ đọc các key trong bảng request của nó, nên các key lạ, source, shukah_address_id và các timestamp trong body bị bỏ qua. Nó set source: 'locate', shukah_address_id: null và cả hai timestamp là bây giờ (src/controllers/client/address-book/parse-payload.js:4-21, src/controllers/client/address-book/create.js:13,18).
  • Các cast: toStr trim và biến trống hoặc null thành null; toNum cho null với null, "" và số không hữu hạn; toBool chỉ true với 1, "1" và true; toImageUrls chấp nhận một mảng, một chuỗi JSON-array hoặc một chuỗi ngăn cách bằng dấu phẩy, trim, và bỏ giá trị trống (src/sync/lib/casts.js:1,56-81).
  • Update chỉ áp dụng một key khi body có nó (hasOwnProperty), nên một null có mặt xóa field (src/controllers/client/address-book/parse-payload.js:39-57). Nó chỉ chạy quy tắc mặc định khi body có is_default (src/controllers/client/address-book/update.js:22-24, src/controllers/client/address-book/parse-payload.js:60-75).
  • Quy tắc mặc định của create nằm trong resolveDefaultOnCreate (src/controllers/client/address-book/parse-payload.js:24-37), và của delete trong resolveDefaultOnDelete, hàm promote addresses[0] (parse-payload.js:78-82, src/controllers/client/address-book/remove.js:15-17).
  • Các handler tải lại client mà không dùng query cache, nên một lần đọc hay ghi không bao giờ dùng bản cache 300 giây (src/controllers/client/address-book/load-fresh-client.js:7-8).
  • Một lần save chạy đua với một thay đổi inbound từ Shukah có thể lỗi với Mongoose VersionError và cho 500 (đọc code; inbound push cố ý tăng version của document, docs/plans/2026-07-13-shukah-address-push-api.md:58-59).

Shape​

Các câu trả lời list và create đến từ formatAddressForResponse, dùng ?? null cho text và Boolean(is_default) (src/controllers/client/address-book/mapper.js:4-28). Get và update đến từ formatAddressDetailForResponse, biến mọi text bị thiếu thành "", is_default thành 0 hoặc 1, và lat và lng thành text (src/controllers/client/address-book/mapper.js:30-51). List được sắp theo created_at, mới nhất trước, với các địa chỉ không có ngày ở cuối (src/controllers/client/address-book/handler.js:9-15).

Địa chỉ mặc định trong dữ liệu​

Quy tắc "một mặc định" chỉ được thực thi bởi ba lời gọi app này. ETL chọn một mặc định cho mỗi client khi nó dựng document (src/sync/mappers/client-mapper.js:80-87), nhưng inbound push địa chỉ từ Shukah sang Locate không bầu chọn gì (src/controllers/admin/client-addresses/handler.js:67-68). Đó là cách cả 10 mục trong list đã capture đều có thể là mặc định (2026-10-01), và 28 trong 30 (2026-10-02). Vào 2026-10-02 bản copy của một địa chỉ tạo trên Shukah đến nơi với is_default là true, dù Shukah gửi 0 (nguyên nhân: Chưa được tài liệu hóa). Tài liệu service vẫn nói server luôn giữ đúng một mặc định (docs/api/client-auth-and-address-book.md:291).

Push sang Shukah​

Sau một lần save cục bộ, create và update đẩy địa chỉ sang Shukah, best effort và được await. Create lưu id trả về làm shukah_address_id. Update đẩy tới {shukah_address_id} khi địa chỉ có, và nếu không thì fallback sang create push. Delete không được đẩy (src/services/shukah-sync.js:238-415; docs/plans/2026-09-22-shukah-address-outbound-push.md:106-110,149-151). Push không làm gì khi sync tắt hoặc host hay admin token chưa được set. Nó có được bật trên dev hay không: Chưa được tài liệu hóa. Các capture 2026-10-01 gợi ý nó không chạy với client này: sau create, update và delete trên Locate, list của Shukah vẫn có 13 địa chỉ, trong khi một create được copy mà không có delete được copy sẽ để lại 14.

Vào 2026-10-02 nguyên nhân đã được tìm thấy trong code: create push gửi tới /maeda/api/address-book (src/services/shukah-sync.js:310), mà Shukah dev trả lời bằng 404; Shukah phục vụ /maeda/address-book. Lỗi bị nuốt và chỉ được ghi vào sync_logs (:335). Update push dùng /maeda/address-book/{id} (:356) nhưng chỉ cho địa chỉ đã có Shukah id; các địa chỉ khác fallback sang create bị hỏng. Chiều ngược lại cũng hỏng: một create trên Shukah tới Locate trong vài giây, nhưng update và delete trên Shukah không bao giờ tới. Locate có các receiver (src/routes/admin.js:52-54), nên bản port Laravel của Shukah không gọi chúng (suy luận). Locate cũng mất URL ảnh của 4 địa chỉ Shukah có ảnh; toImageUrls xử lý được mảng và chuỗi JSON (src/sync/lib/casts.js:67-81), nên chỗ mất nằm ở upstream của nó. Nguyên nhân: Chưa được tài liệu hóa.

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

  • Tài liệu service nói source của địa chỉ là "locate" hoặc "shukah" (docs/api/client-auth-and-address-book.md:224). Model cho phép mt_client_inline, mt_address_book và locate (src/models/client.js:18), và capture cho thấy mt_address_book.
  • Tài liệu service nói server đảm bảo đúng một mặc định (docs/api/client-auth-and-address-book.md:291). Điều đó chỉ đúng cho các lời gọi của app, như ở trên.
  • Một design doc ban đầu nói get trả {status, address} (docs/plans/2026-07-07-shukah-address-book-api-local.md:13-14), và sửa thành object phẳng ở dòng 23-24. Code trả object phẳng.
  • Các design doc viết path Shukah là /maeda/api/address-book (docs/plans/2026-07-07-shukah-address-book-api-local.md:49). App gọi /maeda/address-book, và Shukah dev trả 404 cho dạng /api/, nên các trang dùng path của app.
  • Các capture đã làm sạch cho thấy Shukah trả lat và lng dạng số, trong khi type riêng của app khai báo là chuỗi (src/entities/location/model/types/location.server.ts:3-19).
  • 2026-10-02: trang này ghi 13 địa chỉ Shukah và 28 địa chỉ Locate, không có mặc định trên Shukah và cả 10 đều mặc định trên Locate, và thứ tự Shukah chưa rõ. Các capture 2026-10-02 cho thấy 15 và 30, Shukah 0 ở cả 15, Locate true ở 28 trong 30, và Shukah sắp theo position.
  • 2026-10-02: trang này kỳ vọng không có khác biệt image_urls ở list và get. Locate đã mất URL ảnh của 4 địa chỉ Shukah có ảnh.
  • 2026-10-02: trang này ghi is_default của get là giống nhau ở cả hai phía. Cùng một địa chỉ là 0 trên Shukah và 1 trên Locate.
  • 2026-10-02: trang này nói một id của người khác nhận cùng câu trả lời ở cả hai phía. Shukah trả 403; Locate trả 404 (đọc code).
  • 2026-10-02: trang này nói các phần địa chỉ null ở create là đọc code. Giờ chúng đã được capture.
  • 2026-10-02: "bản copy best-effort sang Shukah" của create và update có trong code (src/controllers/client/address-book/create.js:23, src/controllers/client/address-book/update.js:31), nhưng vào 2026-10-02 cũng không có bản copy nào tới Shukah dev (xem Push sang Shukah).

Sources​

  • locate-authentication-service@6757aa4: src/routes/client.js:17-21, src/controllers/client/address-book/handler.js:6-17, src/controllers/client/address-book/get.js:9-22, src/controllers/client/address-book/create.js:10-28, src/controllers/client/address-book/update.js:12-37, src/controllers/client/address-book/remove.js:8-21, src/controllers/client/address-book/lookup.js:13-25, src/controllers/client/address-book/load-fresh-client.js:7-8, src/controllers/client/address-book/mapper.js:4-51, src/controllers/client/address-book/parse-payload.js:4-82, src/sync/lib/casts.js:1,56-81, src/models/client.js:16-34, src/middlewares/error-handler.js:12-35, src/sync/mappers/client-mapper.js:32-87, src/controllers/admin/client-addresses/handler.js:67-68, src/services/shukah-sync.js:238-415
  • Tài liệu của locate-authentication-service@6757aa4: docs/api/client-auth-and-address-book.md §4 đến §8 (dòng 187-370, 224, 259-263, 291; thay đổi lần cuối 2026-07-27), docs/plans/2026-07-07-shukah-address-book-api-local.md:13-24,49,226, docs/plans/2026-07-13-shukah-address-push-api.md:58-59, docs/plans/2026-09-22-shukah-address-outbound-push.md:106-110,149-151
  • Snapshot mobile mobile/locate-client@e960c3a (branch development, 2026-02-26; code của chính app, không phải Locate): src/entities/location/model/api/services/location.service.ts:21-24,37-41,55-59,73-78,92-96, src/entities/location/model/api/controllers/location.controller.ts:38-110, src/entities/location/model/api/dto/location.dto.ts:38-86,105-126,144-199, src/entities/location/model/types/location.server.ts:3-19, src/entities/location/model/constants/location.ts:15-18, src/entities/location/model/helpers/locationPresetToSelectedAddress.ts:3-20, src/entities/location/model/services/fetchLocationPresets/fetchLocationPresets.ts:17, src/entities/location/model/services/fetchLocationPresetById/fetchLocationPresetById.ts:17-19, src/entities/location/model/services/createLocationPreset/createLocationPreset.ts:50-92, src/entities/location/model/services/updateLocationPreset/updateLocationPreset.ts:18-20, src/entities/location/model/services/deleteLocationPreset/deleteLocationPreset.ts:20-21, src/entities/location/model/services/initLocation/initLocation.ts:33-38,78, src/entities/location/model/slice/location.slice.ts:56-58, src/features/SavedLocationsList/ui/SavedLocationsList/SavedLocationsList.tsx:70, src/features/UserLocationInfo/ui/UserLocationInfo/UserLocationInfo.container.tsx:44-46, src/widgets/LocationDrawer/ui/LocationDrawer/LocationDrawer.tsx:42-44, src/features/MapDrawer/model/services/createLocationPreset/saveLocation.ts:69-80, src/widgets/Map/ui/Map/Map.tsx:105, src/features/EditSavedAddress/model/services/init.ts:13-17, src/features/EditSavedAddress/model/services/updatePreset.ts:62-70, src/features/EditSavedAddress/model/services/deletePreset.ts:19, src/shared/api/reqError.ts:52-62
  • locate-authentication-service@6757aa4, push và sync: src/services/shukah-sync.js:310,335,356, src/routes/admin.js:52-54, src/sync/lib/casts.js:67-81
  • Capture dev, 2026-10-02 (parity audit): addr-list-before--shukah, addr-list-before--locate-jwt, address-book-get--shukah, address-book-get--locate-jwt, address-book-get-shukahid--shukah, address-book-get-shukahid--locate-jwt, address-book-get-unknown--shukah, address-book-get-unknown--locate-jwt, address-create--shukah, address-create--locate-jwt, address-update--shukah, address-update--locate-jwt, address-delete--shukah, address-delete--locate-jwt, addr-list-after-create--shukah, addr-list-after-update--shukah, addr-list-after-delete--shukah, addr-list-after-delete--locate-jwt
  • Capture dev, 2026-10-01: locate-address-list, locate-address-get, locate-address-create, locate-address-get-created, locate-address-update, locate-address-delete, locate-address-get-deleted, locate-address-list-after-shukah-writes, shukah-address-list, shukah-address-get, shukah-address-create, shukah-address-update, shukah-address-delete, shukah-address-get-deleted, shukah-address-list-after-locate-writes, probe-locate-address-list, probe-locate-address-get, probe-locate-address-create, probe-locate-address-update, probe-locate-address-delete