دفتر العناوين
الخلفية
على Shukah يحتفظ التطبيق بعناوين التوصيل المحفوظة للعميل عبر خمسة استدعاءات على
/maeda/address-book (المسار لا يحتوي الجزء /api/): list وget وcreate وupdate وdelete. وفي خدمة
المصادقة الـ routes الخمسة نفسها، لكنها ليست بديلًا مباشرًا (drop-in). وأربعة أمور تستحق العناية: أن id
العنوان سلسلة من 24 حرفًا بدل عدد صحيح، وأن إجابتَي list وcreate لهما شكل مختلف عن إجابتَي
get وupdate، وأن create يجيب داخل غلاف {status, address}، وأن
استدعاء create لا يملأ الشارع والمدينة وسائر أجزاء العنوان التي تشتقها Shukah بنفسها.
الميزة
يتيح التطبيق للعميل المسجَّل الدخول أن يحتفظ بعدة عناوين محفوظة ويختار أحدها عنوانًا افتراضيًا. وفي نسخة التطبيق اللحظية بتاريخ 2026-02-26 تحدث الاستدعاءات في هذه الأماكن:
| الاستدعاء | أين في التطبيق |
|---|---|
| List | عندما يفتح عميل مسجَّل الدخول شاشة تعرض العناوين المحفوظة (درج المواقع وشريط موقع المستخدم) ولم تُحمَّل القائمة بعد، وعندما يهيّئ التطبيق عنوان التوصيل الافتراضي بعد تسجيل الدخول، وعند السحب للتحديث (pull-to-refresh) في قائمة العناوين المحفوظة، ومرة أخرى بعد كل create أو update أو delete. |
| Get | عندما يفتح العميل شاشة تعديل العنوان. |
| Create | عندما يحفظ العميل موقعًا من الخريطة مع تفعيل «حفظ لوقت لاحق». وإذا وُجد عنوان محفوظ بالاسم نفسه، يحذفه التطبيق أولًا ثم ينشئ العنوان الجديد. |
| Update | عندما يحفظ العميل شاشة تعديل العنوان. يرسل التطبيق location_name وarea وis_default وimage_urls. |
| Delete | عندما يحذف العميل عنوانًا في شاشة تعديل العنوان. |
تحتاج الاستدعاءات الخمسة كلها إلى JWT من Locate (انظر «الحصول على token تجريبي» في النظرة العامة للوحدة). وهذه القواعد تنطبق عليها جميعًا:
- المعرّفات (Ids). كل استجابة تعطي المعرّف بوصفه Mongo ObjectId: سلسلة hex من 24 حرفًا. وفي مسار get وupdate وdelete، تُجرَّب القيمة المكوَّنة من أرقام فقط أولًا بوصفها معرّف عنوان Shukah القديم، ثم بوصفها ObjectId. وأي قيمة أخرى تُجرَّب بوصفها ObjectId فقط. ولا يحمل معرّف Shukah إلا العناوين التي جاءت من دفتر عناوين Shukah، ولا تُظهره أي استجابة أبدًا.
- شكلان للاستجابة. يستخدم List وcreate شكل القائمة (list shape): فـ
is_defaultقيمة منطقية (boolean)، وlatوlngأرقام، والحقل النصي المفقودnull، وتوجد مفاتيحsourceوcreated_atوupdated_at. ويستخدم Get وupdate شكل التفصيل (detail shape): فـis_defaultهو0أو1، وlatوlngسلاسل نصية، والحقل النصي المفقود""، وهذه المفاتيح الثلاثة غائبة. - القيم الفارغة. في create وupdate يُحذف الفراغ الزائد من الحقل النصي، وتُخزَّن القيمة الفارغة
null. وتُخزَّنlatأوlngالفارغة أو غير الرقميةnull. ولا يُتحقق من أي شيء: فالـ body الفارغ ينشئ عنوانًا بكل حقوله فارغة، ولا حد لعدد العناوين. - التحديث الجزئي. يغيّر Update المفاتيح الموجودة في الـ body فقط. والمفتاح الموجود بالقيمة
nullأو""أو مسافات فقط يمسح الحقل (وتصبحimage_urls[]). أماsourceومعرّف Shukah وcreated_atفلا تتغير أبدًا. - عناوينه هو فقط. يُبحث عن المعرّف بين عناوين المستدعي فقط. والمعرّف الذي يخص شخصًا آخر،
أو لا يخص أحدًا، يعطي
404معAddress not found. - عنوان افتراضي واحد. تُبقي الخدمة عنوانًا افتراضيًا واحدًا عندما ينشئ التطبيق أو يحدّث أو يحذف:
| الاستدعاء | القاعدة |
|---|---|
| Create | is_default بقيمة true تمسح العلامة عن كل عنوان آخر. وإلا يصبح العنوان الجديد هو الافتراضي فقط عندما يكون الدفتر فارغًا أو بلا عنوان افتراضي. |
| Update | فقط عندما يحتوي الـ body على is_default. عند ضبطها true: يفقد كل عنوان آخر العلامة. وعند ضبطها false بينما لا يوجد عنوان آخر افتراضي: يصبح أول عنوان آخر هو الافتراضي. وإذا كان العنوان هو الوحيد، يبقى هو الافتراضي. |
| Delete | إذا لم يبقَ عنوان افتراضي والدفتر غير فارغ، يصبح أول عنوان بترتيب التخزين هو الافتراضي. والقائمة مرتبة بالتاريخ، لذا ليس هذا دائمًا أول عنوان يراه التطبيق. |
هذا الضمان يسري على هذه الاستدعاءات الثلاثة فقط. فالعناوين المنسوخة من Shukah لا تُفحص، وعلى dev كانت جميع العناوين العشرة في القائمة الملتقطة افتراضية (انظر كتلة list).
GET /api/v1/clients/address-book
GET /maeda/address-book✅ تم الاستبدال- 🔴 يحصل token من Shukah على 401 "Unauthorization"؛ أرسل JWT من Locate (من exchange-token؛ واحتفظ بـ token من Shukah).
- 🔴 العناوين التي تُنشأ على Locate قيم formatted_address وstreet وcity فيها null؛ ويرسل التطبيق formatted_address كـ c_address.
- 🟡 id سلسلة hex من 24 حرفًا (وهو عدد صحيح في Shukah)؛ ولم يعد معرّف Shukah المحفوظ يطابق (initLocation.ts:78).
- 🟡 is_default من نوع boolean وقيمته true في 28 من 30 (في Shukah القيمة 0 في كل الـ 15)؛ ويأخذ initLocation أول عنصر قيمته true.
- 🟡 30 عنوانًا مقابل 15 على Shukah: لا تصل عمليات الحذف في Shukah إلى Locate، ويظهر "Saihat" 3 مرات.
- 🟡 قيمة image_urls هي [] على Locate لكل عناوين Shukah الأربعة التي لها صورة (وتُرجع Shukah الرابط).
- 🟡 ترتّب Locate بحسب created_at الأحدث أولًا؛ وترتّب Shukah بحسب position (0..14)، لذا قد يتغير ترتيب القائمة.
تُرجع Locate القيمة is_default كـ boolean والمعرّف id كسلسلة hex من 24 حرفًا، بينما تُرجع Shukah القيمة 0 أو 1 ومعرّف id عددًا صحيحًا (و lat وlng أرقام على الجانبين)؛ ويقبل فحص الافتراضي في التطبيق الـ boolean، لكن أي شيء يعامل المعرّف كرقم يجب تغييره.
الطلب (Request)
| الحقل | الموضع | النوع | مطلوب | القيود | الوصف |
|---|---|---|---|---|---|
Authorization | header | string | نعم | Bearer <locate-jwt>. وtoken من Shukah يحصل على 401. | الـ JWT من Locate. |
| أي مفتاح query أو header آخر | query، header | — | لا | يُقبل ويُتجاهل، مثل language. | — |
لا ترقيم للصفحات (paging) ولا مرشّح ولا خيار ترتيب.
الاستجابة (Response)
200 مع مصفوفة بشكل القائمة. وهي [] عندما لا يكون للعميل عنوان. ويأتي أحدث
created_at أولًا، وتأتي العناوين التي بلا created_at أخيرًا.
| الحقل | النوع | يقبل null | الصيغة / القيود | الوصف |
|---|---|---|---|---|
id | string | لا | ObjectId من 24 حرف hex. وليس أبدًا معرّف Shukah العددي. | معرّف العنوان لـ get وupdate وdelete. |
source | string | نعم | mt_client_inline أو mt_address_book أو locate. | مصدر العنوان: locate لعنوان أُنشئ عبر هذا الـ API. |
is_default | boolean | لا | true أو false. ويمكن أن يكون أكثر من عنوان true. | العنوان الافتراضي. |
location_name وstreet وarea وarea_name وcity وstate وzipcode وcountry وcountry_code وformatted_address | string | نعم | null عند الغياب. والسلسلة الفارغة المخزَّنة بالفعل تبقى "" (في الالتقاط state: ""). | أجزاء العنوان. |
lat وlng | number | نعم | أرقام JSON. لا فحص للمدى. | الإحداثيات. |
image_urls | array of string | لا | مصفوفة دائمًا، وقد تكون فارغة. | عناوين URL للصور. |
created_at وupdated_at | string | نعم | ISO 8601 بتوقيت UTC، مثل 2026-09-29T17:01:10.000Z. | وقت إنشاء العنوان وآخر تغيير له. |
[
{
"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"
}
]
التُقط على dev، 2026-10-01 (العميل 356259): أول عنصر من 28 عنصرًا، واستُبدلت الحقول الشخصية والإحداثيات.
الأخطاء
| HTTP | Body | متى |
|---|---|---|
401 | {"status":401,"message":"Unauthorization"} | لا يوجد token، أو الـ token ليس JWT من Locate، أو العميل مفقود أو غير نشط. الحارس نفسه الخاص بـ التحقق من الـ token. |
401 | الـ body نفسه. | الـ token صالح لكن تعذّر تحميل سجل العميل. |
500 | على dev: {"status":500,"message":"<raw error text>","stack":"<stack trace>"}. وفي production: {"status":500,"message":"Internal server error"}. | فشل غير متوقع. لم يُلتقط. وعلى dev تكون الرسالة نص الخطأ الخام ويُضاف حقل stack؛ ولا تظهر Internal server error إلا في production (UAT وproduction: غير موثّق بعد). |
التُقط body الخاص بـ 401 على dev في 2026-10-01 دون token.
جرّبه
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"
المتوقع: 200 ومصفوفة مثل المبيّنة تحت «الاستجابة». وبلا token تحصل على 401 المبيّن
تحت «الأخطاء».
الفروق عن Shukah
| الجانب | Shukah | Locate | الأثر على التطبيق |
|---|---|---|---|
| URL | GET $SHUKAH_BASE_URL/maeda/address-book | GET $AUTH_BASE_URL/api/v1/clients/address-book | غيّر base URL والمسار. |
| الـ Token | token معتم (opaque) من Shukah. | JWT من Locate فقط. | احصل على الـ JWT عبر exchange-token أولًا، واحتفظ بـ token Shukah لـ order-v2. ولا تنقل تسجيل الدخول إلى Locate بعد. |
id | عدد صحيح، مثل 162115 (التُقط على dev، 2026-10-01). | سلسلة من 24 حرفًا، مثل 6abbeed8a492ed4862500b74. | يجب تغيير أي شيء يخزّن المعرّف أو يقارنه بوصفه رقمًا. والتطبيق يعرّفه كرقم. |
is_default | 0 أو 1 (التُقط على dev، 2026-10-01). | true أو false. | يجد التطبيق العنوان الافتراضي باختبار truthiness، وهو يعمل مع الاثنين. لكن المقارنة الصارمة مع 1 لن تعمل. |
| مفاتيح إضافية | position (عدد صحيح). | source وcreated_at وupdated_at؛ ولا position. | لا شيء: فنوع العنوان في التطبيق لا يحتوي أيًّا من هذه المفاتيح الأربعة. |
image_urls | مصفوفة أو null. أربعة من 15 عنوانًا للعميل لها URL صورة (التُقط على dev، 2026-10-02). | مصفوفة دائمًا. والنسخ على Locate من هذه العناوين الأربعة فيها []. | تضيع صور العناوين المنسوخة من Shukah. السبب: غير موثّق بعد. |
| الترتيب | حسب position، من 0 إلى 14، بينما المعرّفات ليست مرتبة (162115 و161996 و162101 و…) (التُقط على dev، 2026-10-02). | الأحدث created_at أولًا. | إذا كان التطبيق يعرض القائمة بترتيب الخادم، فسيتغير الترتيب. |
| العدد للعميل 356259 | 15 عنوانًا (التُقط على dev، 2026-10-02؛ و13 في 2026-10-01). | 30 عنوانًا، للعميل نفسه واليوم نفسه (و28 في 2026-10-01). | العناوين المحذوفة على Shukah تبقى على Locate، ويظهر عنوان واحد ثلاث مرات على Locate. افحص التكرارات قبل التحوّل. |
| العناوين الافتراضية | is_default يساوي 0 في العناوين الـ15 كلها (التُقط على dev، 2026-10-02). | true في 28 من 30. | يأخذ التطبيق أول عنوان افتراضي يجده، لذا قد يختلف العنوان الافتراضي المحدَّد. |
GET /api/v1/clients/address-book/:id
GET /maeda/address-book/:id✅ تم الاستبدال- 🔴 يحصل token من Shukah على 401 "Unauthorization"؛ أرسل JWT من Locate (من exchange-token؛ واحتفظ بـ token من Shukah).
- 🟡 id سلسلة hex من 24 حرفًا؛ ولا يزال معرّف Shukah العددي (162115) يُحلّ في المسار.
- 🟡 lat وlng سلسلتان نصيتان (أرقام في Shukah)؛ ويستخدم التطبيق Number() (locationPresetToSelectedAddress.ts:14).
- 🟡 العنوان نفسه: is_default يساوي 1 على Locate مقابل 0 على Shukah، وimage_urls هي [] مقابل رابط صورة (162115).
- 🟡 معرّف يخص شخصًا آخر: Locate تعطي 404 "Address not found"؛ وShukah تعطي 403 "You can only view address that belong to you."
- 🟡 يحمل body الـ 404 في Locate قيمة stack من الخادم (get.js:39:17) على dev.
الطلب (Request)
| الحقل | الموضع | النوع | مطلوب | القيود | الوصف |
|---|---|---|---|---|---|
Authorization | header | string | نعم | Bearer <locate-jwt>. | الـ JWT من Locate. |
id | path | string | نعم | القيمة المكوَّنة من أرقام فقط تُجرَّب أولًا بوصفها معرّف عنوان Shukah، ثم بوصفها ObjectId. وأي شيء آخر يُجرَّب بوصفه ObjectId فقط. | معرّف العنوان. |
| أي مفتاح query أو header آخر | query، header | — | لا | يُقبل ويُتجاهل. | — |
الاستجابة (Response)
200 مع عنوان واحد بشكل التفصيل، دون غلاف:
| الحقل | النوع | يقبل null | الصيغة / القيود | الوصف |
|---|---|---|---|---|
id | string | لا | الـ ObjectId، حتى لو استُخدم معرّف Shukah العددي في المسار. | معرّف العنوان. |
location_name وformatted_address وarea_name وstreet وcity وarea وstate وzipcode وcountry وcountry_code | string | لا | "" عند الغياب، وليس null أبدًا. | أجزاء العنوان. |
is_default | integer | لا | 0 أو 1. | العنوان الافتراضي. |
lat وlng | string | لا | الرقم كنص، مثل "24.7136". و"" عند الغياب. | الإحداثيات. |
image_urls | array of string | لا | قد تكون فارغة. | عناوين URL للصور. |
لا يوجد source ولا created_at ولا 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": []
}
التُقط على dev، 2026-10-01 (العميل 356259): العنوان الذي أنشأته عينة create-address أدناه، وقُرئ مباشرة بعد إنشائه، وحُذف في نهاية الجولة. وكان نص العنوان توضيحيًا أصلًا.
عاد العنوان نفسه من create مع state: null، وهنا مع state: "": وهذا هو
الفرق بين الشكلين.
الأخطاء
| HTTP | Body | متى |
|---|---|---|
401 | {"status":401,"message":"Unauthorization"} | لا token، أو token ليس JWT من Locate، أو عميل غير نشط، أو سجل عميل تعذّر تحميله. |
404 | {"status":404,"message":"Address not found"} | لا يوجد عنوان لهذا العميل يطابق المعرّف. ويشمل ذلك عنوانًا حُذف، ومعرّفًا يخص عميلًا آخر. |
التُقط 404 على dev في 2026-10-01 بقراءة عنوان العينة بعد حذفه، وفي 2026-10-02 لـ ObjectId
غير معروف. والمعرّف الذي يخص عميلًا آخر يحصل على الإجابة نفسها لأن البحث لا يفتش إلا في عناوين
المستدعي (قراءة شيفرة؛ ولم يُجرَّب معرّف غريب مباشرة على Locate). وتجيب Shukah على معرّف شخص آخر
بـ 403 بدلًا من ذلك (التُقط على dev، 2026-10-02؛ انظر الفروق عن Shukah). وعلى dev تحمل أجسام
الأخطاء أيضًا حقل stack فيه stack trace للخادم كنص. وتتركه العينات في هذه الصفحة.
جرّبه
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"
المتوقع: 200 والعنوان بشكل التفصيل. والمعرّف المجهول يعطي 404 المبيّن تحت «الأخطاء».
الفروق عن Shukah
| الجانب | Shukah | Locate | الأثر على التطبيق |
|---|---|---|---|
| URL | GET $SHUKAH_BASE_URL/maeda/address-book/{id} | GET $AUTH_BASE_URL/api/v1/clients/address-book/{id} | غيّر base URL والمسار. |
id | عدد صحيح (التُقط على dev، 2026-10-01). | سلسلة من 24 حرفًا. ومعرّف Shukah العددي ما زال يعمل في المسار للعناوين التي جاءت من دفتر عناوين Shukah. | تُرجع القائمة الآن ObjectIds. ويقارن التطبيق معرّف آخر عنوان محدَّد مخزَّنًا لديه مع معرّفات القائمة كسلاسل، لذا فالعدد الصحيح المحفوظ من Shukah لم يعد يطابق ويُسقَط التحديد. |
lat وlng | أرقام JSON، مثل 24.7136 (التُقط على dev، 2026-10-01). | سلاسل نصية، مثل "24.7136". | لا شيء: فالتطبيق يقبل الاثنين ويحوّل بـ Number() قبل الاستخدام. |
is_default | 0 أو 1. العنوان 162115 يساوي 0 (التُقط على dev، 2026-10-02). | 0 أو 1. والعنوان نفسه مقروءًا بمعرّفه في Shukah يساوي 1 (التُقط على dev، 2026-10-02). | النوع واحد، والقيمة ليست كذلك: فقد يتغير العنوان الافتراضي الذي يعرضه التطبيق. |
image_urls | مصفوفة أو null. للعنوان 162115 رابط صورة واحد (التُقط على dev، 2026-10-02). | مصفوفة دائمًا. وللعنوان نفسه []. | تضيع صورة عنوان منسوخ من Shukah. |
| مفتاح إضافي | position. | لا شيء. | لا شيء: فالتطبيق لا يقرؤه. |
| عنوان شخص آخر | 403 {"name":"Forbidden","message":"You can only view address that belong to you.","code":0,"status":403,"type":"Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException"} (التُقط على dev، 2026-10-02، المعرّف 1). | 404 Address not found، مثل المعرّف المجهول (قراءة شيفرة). | يتغير الـ status والنص الذي يعرضه التطبيق. |
body الخاص بـ 404 | {"name":"Not Found","message":"Object not found: 162119","code":0,"status":404,"type":"Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException"} (التُقط على dev، 2026-10-01). | {"status":404,"message":"Address not found"} | يعرض التطبيق message، فيتغير النص الذي يعرضه. |
POST /api/v1/clients/address-book
POST /maeda/address-book✅ تم الاستبدال- 🔴 يحصل token من Shukah على 401 "Unauthorization"؛ أرسل JWT من Locate (من exchange-token؛ واحتفظ بـ token من Shukah).
- 🔴 الاستجابة هي {status,address:{...}}؛ ويبني التطبيق الإعداد المسبق من المستوى الأعلى فتصبح id وlat/lng قيمة NaN.
- 🔴 لا يوجد geocoding: تكون street وcity وarea وstate وzipcode وcountry وformatted_address قيمتها null (وتملؤها Shukah).
- 🟡 قيمة address.is_default من نوع boolean (وفي Shukah 0)؛ وlat وlng أرقام هنا لكنهما سلسلتان نصيتان في get وupdate.
- 🟡 لم يظهر العنوان المُنشأ على Locate في Shukah أبدًا (يستهدف الدفع /maeda/api/address-book الذي يعطي 404).
الطلب (Request)
كل حقول الـ body اختيارية ولا يُتحقق من شيء. والمفاتيح غير المدرجة تُتجاهل. ويضبط
الخادم source على locate والطوابع الزمنية على الآن، فلا يستطيع الـ body ضبطها.
| الحقل | الموضع | النوع | مطلوب | القيود | الوصف |
|---|---|---|---|---|---|
Authorization | header | string | نعم | Bearer <locate-jwt>. | الـ JWT من Locate. |
location_name وstreet وarea وarea_name وcity وstate وzipcode وcountry وcountry_code وformatted_address | body | string | لا | تُحذف المسافات الزائدة. والفارغ أو null يُخزَّن null. ولا حد للطول. | أجزاء العنوان. |
lat وlng | body | number أو سلسلة رقمية | لا | null و"" والقيم غير الرقمية تُخزَّن null. لا فحص للمدى. | الإحداثيات. |
image_urls | body | array of string | لا | تُحذف المسافات الزائدة من السلاسل وتُسقَط الفارغة. وnull تعطي []. وتُقبل أيضًا سلسلة مصفوفة JSON أو سلسلة مفصولة بفواصل. | عناوين URL للصور. |
is_default | body | boolean أو 0 أو 1 | لا | فقط 1 و"1" وtrue تعني افتراضيًا. وكل قيمة أخرى، بما فيها "true" و2، تعني غير افتراضي. | جعل هذا العنوان هو الافتراضي. |
ما يرسله التطبيق في نسخة 2026-02-26 هو فقط location_name وarea_name وlat و
lng (كلاهما سلسلة)، وis_default (0 أو 1) وimage_urls (مصفوفة أو null).
طلب استُخدم للالتقاط أدناه:
{
"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 مع غلاف يحمل العنوان الجديد بشكل القائمة:
| الحقل | النوع | يقبل null | الصيغة / القيود | الوصف |
|---|---|---|---|---|
status | integer | لا | دائمًا 200. | صدى الحالة. |
address | object | لا | شكل القائمة، بالحقول المدرجة تحت كتلة list. وsource هو locate. وis_default هو true عندما طلبه الطلب أو عندما لم يكن للعميل عنوان افتراضي. | العنوان الذي أُنشئ. |
{
"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"
}
}
التُقط على dev، 2026-10-01 (العميل 356259، كتابة مباشرة في Task 9). حُذف العنوان في نهاية
الجولة. وكان نص العنوان توضيحيًا أصلًا. وis_default هو false لأن العميل
كان لديه عناوين افتراضية بالفعل.
الأخطاء
| HTTP | Body | متى |
|---|---|---|
401 | {"status":401,"message":"Unauthorization"} | لا token، أو token ليس JWT من Locate، أو عميل غير نشط، أو سجل عميل تعذّر تحميله. |
500 | على dev: {"status":500,"message":"<raw error text>","stack":"<stack trace>"}. وفي production: {"status":500,"message":"Internal server error"}. | فشل غير متوقع، مثل حفظ يتعارض مع نسخة من بيانات العميل من Shukah تصل في اللحظة نفسها. لم يُلتقط. وعلى dev تكون الرسالة نص الخطأ الخام ويُضاف حقل stack؛ ولا تظهر Internal server error إلا في production (UAT وproduction: غير موثّق بعد). |
لا يوجد 400: فالقيم السيئة تُنظَّف أو تُخزَّن null. والتُقط body الخاص بـ 401 على dev في
2026-10-01 دون token.
جرّبه
ينشئ هذا الاستدعاء عنوانًا حقيقيًا على dev. احذفه بعد ذلك باستدعاء delete أدناه.
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":[]}'
المتوقع: 200 و{"status":200,"address":{...}}. وهذا الـ body هو ما يرسله التطبيق، لذا تعود street
وcity وarea وstate وzipcode وcountry وcountry_code وformatted_address بالقيمة
null (التُقط على dev، 2026-10-02، بهذا الـ body تحديدًا). احتفظ بـ address.id للاستدعاءات الأخرى.
الفروق عن Shukah
| الجانب | Shukah | Locate | الأثر على التطبيق |
|---|---|---|---|
| URL | POST $SHUKAH_BASE_URL/maeda/address-book | POST $AUTH_BASE_URL/api/v1/clients/address-book | غيّر base URL والمسار. |
| الاستجابة | كائن العنوان نفسه، مسطّح (flat)، مع id عدد صحيح ومفتاح position (التُقط على dev، 2026-10-01). | {"status":200,"address":{...}} مع id من 24 حرفًا. | يقرأ التطبيق id وlat وlng وغيرها من المستوى الأعلى للإجابة. ومع الغلاف تكون كلها مفقودة، وتصبح الإحداثيات التي يبنيها للعنوان المحدَّد NaN. اقرأ address بدلًا من ذلك. |
| أجزاء العنوان المفقودة | طلب فيه فقط lat وlng وarea_name وlocation_name وis_default وimage_urls عاد مع street وarea وstate وzipcode وcountry وcountry_code وformatted_address معبَّأة (التُقط على dev، 2026-10-01، ومرة أخرى في 2026-10-02 مع position 15). وكيف تشتقها Shukah: غير موثّق بعد. | يخزّن فقط ما أُرسل. وأي شيء لم يُرسل هو null: فقد عاد الطلب نفسه والقيم الثماني كلها null (التُقط على dev، 2026-10-02). | العنوان المنشأ بـ body التطبيق الحالي لا شارع ولا مدينة ولا عنوان منسَّق (formatted address) له. وشاشة الخريطة تملك هذه القيم، لذا يستطيع التطبيق إرسالها، أو يجب على الـ backend ملأها. وهل هذا مخطَّط له: غير موثّق بعد. |
| عنوان بالاسم نفسه | يحذف التطبيق عنوانًا موجودًا بالاسم نفسه قبل أن ينشئ الجديد. | يعمل الاستدعاءان نفسهما. ويستخدم delete المعرّف من القائمة، وهو سلسلة. | لا شيء في هذه الخطوة. انظر كتلة delete لعملية الحذف الصريحة. |
| مكان تخزين العنوان | في Shukah. | في Locate، ثم نسخة بذل أقصى جهد (best-effort) إلى Shukah. | على dev لم تصل النسخة إلى Shukah: فقد ظلت قائمة Shukah تحتوي 13 عنوانًا بعد create وupdate وdelete في 2026-10-01، وفي 2026-10-02 لم يظهر العنوان المنشأ عبر Locate على Shukah أيضًا. ولا يُنسخ delete أبدًا. فلا يمكن افتراض أن عنوانًا أُنشئ عبر Locate موجود على Shukah. |
PUT /api/v1/clients/address-book/:id
PUT /maeda/address-book/:id✅ تم الاستبدال- 🔴 يحصل token من Shukah على 401 "Unauthorization"؛ أرسل JWT من Locate (من exchange-token؛ واحتفظ بـ token من Shukah).
- 🟡 id سلسلة hex من 24 حرفًا وlat وlng سلسلتان نصيتان؛ ويقرأ التطبيق المفاتيح نفسها فلا حاجة إلى تغيير.
- 🟡 الأجزاء غير المعيّنة من العنوان تعود "" على Locate (city وarea وstate ...)؛ وتُرجع Shukah القيم المحدَّدة جغرافيًا.
- 🟡 لا يصل التعديل الذي يُجرى على Shukah إلى Locate أبدًا ("S (edited)" بقي "Parity test S" هناك).
- 🟡 تُبقي Locate عنوانًا افتراضيًا واحدًا بالضبط عند update؛ وأرجعت Shukah is_default بقيمة 0 دائمًا.
- 🟡 يحمل body الـ 404 قيمة stack من الخادم على dev.
body مسطّح بنمط Shukah؛ ويمكن أن يكون المعرّف معرّف hex من 24 حرفًا أو معرّف Shukah العددي.
الطلب (Request)
تحديث جزئي: لا يتغير سوى المفاتيح الموجودة في الـ body.
| الحقل | الموضع | النوع | مطلوب | القيود | الوصف |
|---|---|---|---|---|---|
Authorization | header | string | نعم | Bearer <locate-jwt>. | الـ JWT من Locate. |
id | path | string | نعم | أرقام فقط: معرّف عنوان Shukah أولًا، ثم ObjectId. وأي شيء آخر: ObjectId فقط. | العنوان المراد تغييره. |
location_name وstreet وarea وarea_name وcity وstate وzipcode وcountry وcountry_code وformatted_address | body | string أو null | لا | التنظيف نفسه كما في create. والمفتاح الموجود بالقيمة null أو "" أو مسافات يضبط الحقل على null. | أجزاء العنوان. |
lat وlng | body | number أو سلسلة رقمية أو null | لا | التنظيف نفسه كما في create. | الإحداثيات. |
image_urls | body | array of string أو null | لا | التنظيف نفسه كما في create. وnull تعطي []. | عناوين URL للصور. |
is_default | body | boolean أو 0 أو 1 | لا | فقط 1 و"1" وtrue تعني افتراضيًا. انظر قواعد الافتراضي تحت «الميزة». | جعل هذا العنوان هو الافتراضي أو عدمه. |
source وcreated_at وأي مفتاح آخر | body | — | لا | يُتجاهل. | — |
ما يرسله التطبيق في نسخة 2026-02-26: location_name وarea وis_default (0 أو 1)
وimage_urls.
{
"location_name": "Docs capture (edited)"
}
الاستجابة (Response)
200 مع العنوان بشكل التفصيل، كما في get: دون غلاف، وis_default
0 أو 1، وlat وlng سلسلتان نصيتان.
{
"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": []
}
التُقط على dev، 2026-10-01 (العميل 356259، كتابة مباشرة في Task 9): الطلب أعلاه، أُرسل إلى عنوان عينة create. وكان نص العنوان توضيحيًا أصلًا.
الأخطاء
| HTTP | Body | متى |
|---|---|---|
401 | {"status":401,"message":"Unauthorization"} | لا token، أو token ليس JWT من Locate، أو عميل غير نشط، أو سجل عميل تعذّر تحميله. |
404 | {"status":404,"message":"Address not found"} | لا يوجد عنوان لهذا العميل يطابق المعرّف، بما في ذلك معرّف يخص عميلًا آخر. |
500 | على dev: {"status":500,"message":"<raw error text>","stack":"<stack trace>"}. وفي production: {"status":500,"message":"Internal server error"}. | فشل غير متوقع، كما في create. لم يُلتقط. وعلى dev تكون الرسالة نص الخطأ الخام ويُضاف حقل stack؛ ولا تظهر Internal server error إلا في production (UAT وproduction: غير موثّق بعد). |
لا يوجد 400. والتُقط body الخاص بـ 401 على dev في 2026-10-01 دون token. وbody الخاص بـ 404 هو
الذي التُقط لـ get-address.
جرّبه
يغيّر هذا الاستدعاء عنوانًا على dev. استخدم عنوانًا أنشأته للاختبار.
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"}'
المتوقع: 200 والعنوان بشكل التفصيل مع location_name الجديد.
الفروق عن Shukah
| الجانب | Shukah | Locate | الأثر على التطبيق |
|---|---|---|---|
| URL | PUT $SHUKAH_BASE_URL/maeda/address-book/{id} | PUT $AUTH_BASE_URL/api/v1/clients/address-book/{id} | غيّر base URL والمسار. |
| الاستجابة | العنوان، مسطّح، مع id عدد صحيح، وأرقام لـ lat وlng، ومفتاح position (التُقط على dev، 2026-10-01 و2026-10-02). | العنوان، مسطّح، مع id من 24 حرفًا، وسلاسل نصية لـ lat وlng، ودون position. وأجزاء العنوان التي لم تُضبط قط تعود "" (التُقط على dev، 2026-10-02). | لا شيء بالنسبة إلى المفاتيح التي يقرؤها التطبيق (تأكّد في 2026-10-02). فالتطبيق يبني عنوانه المحفوظ من مفاتيح المستوى الأعلى، وكلها موجودة. |
| قواعد الافتراضي | غير موثّق بعد. | القواعد الواردة تحت «الميزة». | إذا كان التطبيق يعتمد على طريقة Shukah في اختيار العنوان الافتراضي، فقارن قبل التحوّل. |
| النسخ إلى Shukah | لا ينطبق. | تذهب نسخة بذل أقصى جهد من العنوان المعدَّل إلى Shukah. وعندما لا يكون للعنوان معرّف في Shukah، تنشئ النسخة عنوانًا جديدًا هناك، وقد يكرره. | على dev لم تظهر النسخة في قائمة Shukah في 2026-10-01 ولا في 2026-10-02 (انظر create). وتعديل أُجري على Shukah لم يصل إلى Locate أيضًا (2026-10-02). |
DELETE /api/v1/clients/address-book/:id
DELETE /maeda/address-book/:id✅ تم الاستبدال- 🔴 يحصل token من Shukah على 401 "Unauthorization"؛ أرسل JWT من Locate (من exchange-token؛ واحتفظ بـ token من Shukah).
- 🔴 يرسل التطبيق +id، فيصبح المعرّف hex ذو 24 حرفًا NaN ويجيب الحذف بـ 404؛ وتقارن الـ slice أيضًا بـ +id.
- 🟡 الاستجابة 200 {"status":200}؛ وتعطي Shukah 204 بلا body؛ ويتجاهل التطبيق الـ body.
- 🟡 لا يُدفع الحذف في Locate إلى Shukah، ولا يصل الحذف في Shukah إلى Locate (عناوين شبحية).
الطلب (Request)
| الحقل | الموضع | النوع | مطلوب | القيود | الوصف |
|---|---|---|---|---|---|
Authorization | header | string | نعم | Bearer <locate-jwt>. | الـ JWT من Locate. |
id | path | string | نعم | أرقام فقط: معرّف عنوان Shukah أولًا، ثم ObjectId. وأي شيء آخر: ObjectId فقط. | العنوان المراد حذفه. |
لا يوجد body.
الاستجابة (Response)
200 مع مفتاح واحد:
| الحقل | النوع | يقبل null | الصيغة / القيود | الوصف |
|---|---|---|---|---|
status | integer | لا | دائمًا 200. ولا مفاتيح أخرى. | صدى الحالة. |
{
"status": 200
}
التُقط على dev، 2026-10-01 (العميل 356259، كتابة مباشرة في Task 9): حذف عنوان العينة.
الحذف نهائي. وإذا كان العنوان المحذوف هو الافتراضي وبقيت عناوين أخرى، يصبح أول عنوان بترتيب التخزين هو الافتراضي.
الأخطاء
| HTTP | Body | متى |
|---|---|---|
401 | {"status":401,"message":"Unauthorization"} | لا token، أو token ليس JWT من Locate، أو عميل غير نشط، أو سجل عميل تعذّر تحميله. |
404 | {"status":404,"message":"Address not found"} | لا يوجد عنوان لهذا العميل يطابق المعرّف. وحذف ثانٍ للمعرّف نفسه يحصل على هذا أيضًا، فالاستدعاء ليس idempotent. |
500 | على dev: {"status":500,"message":"<raw error text>","stack":"<stack trace>"}. وفي production: {"status":500,"message":"Internal server error"}. | فشل غير متوقع. لم يُلتقط. وعلى dev تكون الرسالة نص الخطأ الخام ويُضاف حقل stack؛ ولا تظهر Internal server error إلا في production (UAT وproduction: غير موثّق بعد). |
التُقط body الخاص بـ 401 على dev في 2026-10-01 دون token. وbody الخاص بـ 404 هو الذي التُقط
لـ get-address بعد هذا الحذف.
جرّبه
يحذف هذا الاستدعاء عنوانًا على dev. استخدم عنوانًا أنشأته للاختبار.
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"
المتوقع: 200 و{"status":200}. وتشغيله مجددًا يعطي 404 المبيّن تحت «الأخطاء».
الفروق عن Shukah
| الجانب | Shukah | Locate | الأثر على التطبيق |
|---|---|---|---|
| URL | DELETE $SHUKAH_BASE_URL/maeda/address-book/{id} | DELETE $AUTH_BASE_URL/api/v1/clients/address-book/{id} | غيّر base URL والمسار. |
| إجابة النجاح | 204 مع body فارغ (التُقط على dev، 2026-10-01). | 200 مع {"status":200}. | لا شيء: فالتطبيق لا يقرأ الـ body. |
| المعرّف الذي يرسله التطبيق | يحوّل التطبيق المعرّف إلى رقم بعلامة الجمع الأحادية (unary plus) قبل الاستدعاء. وهذا يعمل مع الأعداد الصحيحة في Shukah. | يصبح المعرّف المكوَّن من 24 حرفًا NaN، فيستدعي التطبيق .../address-book/NaN. وهذا ليس أرقامًا فقط، فتبحث الخدمة عن ObjectId هو NaN وتجيب 404 Address not found (قراءة شيفرة، لم يُجرَّب مباشرة). | يفشل الحذف الصريح في شاشة تعديل العنوان إلى أن يتوقف التطبيق عن تحويل المعرّف. أما حذف عنوان بالاسم نفسه داخل create فلا يحوّله. |
body الخاص بـ 404 | {"name":"Not Found","message":"Object not found: 162119",...} (التُقط على dev، 2026-10-01). | {"status":404,"message":"Address not found"} | يعرض التطبيق message، فيتغير النص الذي يعرضه. |
| النسخ إلى Shukah | لا ينطبق. | لا يُنسخ الحذف إلى Shukah أبدًا. | العنوان الذي أُنشئ أو عُدّل عبر Locate ثم حُذف عبر Locate قد يبقى على Shukah. |
تنبيه
- يحوّل التطبيق معرّف العنوان إلى رقم قبل أن يحذف، فيصبح معرّف Locate (24 حرف hex)
NaNويفشل الحذف بـ404. - يجيب Create بـ
{status, address}بدل العنوان نفسه، ولا يملأ الشارع أو المدينة أو العنوان المنسَّق من الإحداثيات كما تفعل Shukah. - يُرجع List وcreate قيمًا منطقية وأرقامًا، ويُرجع get وupdate
0/1وإحداثيات نصية، وقد تحتوي القائمة عدة عناوين افتراضية.
التفاصيل (للـ backend)
فُحص dev فقط: الـ host https://dev.authentication.locate.sa والبادئة /api/v1. أما الـ host والبادئة في UAT
وproduction: غير موثّق بعد. تحمل أجسام الأخطاء على dev حقل stack (التُقط
في 2026-10-01 على 404 الخاص بـ get-address وعلى 400 الخاصة بـ profile وsetting)، لذا فإن dev لا
يعمل بـ NODE_ENV=production؛ والـ handler لا يضيف stack إلا خارج production
(src/middlewares/error-handler.js:12-35). ويجعل الـ handler نفسه 500 غير المتوقع يحمل نص الخطأ الخام وstack على dev، وInternal server error في production فقط (src/middlewares/error-handler.js:28-33).
البحث عن المعرّف
تحوّل findAddressIndexByApiId معرّف المسار إلى نص. فإذا طابق ^\d+$ بحثت عن عنوان
قيمة shukah_address_id فيه تساوي ذلك العدد، وإن لم يطابق أي عنوان رجعت إلى _id في الوثيقة الفرعية
(src/controllers/client/address-book/lookup.js:13-25). ويستخدمها get وupdate وdelete جميعًا.
ويجري البحث على مصفوفة addresses الخاصة بالمستدعي، ولهذا يعطي معرّف عميل آخر 404
(src/controllers/client/address-book/get.js:11-14؛ وتسرد وثيقة الخدمة 404 نفسه لمعرّف
ليس للمستخدم الحالي، docs/api/client-auth-and-address-book.md:259-263). ويُنسخ معرّف Shukah من
mt_address_book.id للعناوين التي جاءت من دفتر عناوين Shukah، وهو null للعناوين المنشأة عبر الـ API
وللعنوان المضمَّن (inline) المبني من صف العميل
(src/models/client.js:19، src/sync/mappers/client-mapper.js:32-47,50-53).
قواعد الكتابة
- يقرأ Create المفاتيح الواردة في جدول طلبه فقط، لذا تُتجاهل المفاتيح المجهولة و
sourceوshukah_address_idوالطوابع الزمنية في الـ body. ويضبطsource: 'locate'وshukah_address_id: nullوالطابعين الزمنيين على الآن (src/controllers/client/address-book/parse-payload.js:4-21،src/controllers/client/address-book/create.js:13,18). - دوال التحويل (casts): تحذف
toStrالمسافات الزائدة وتحوّل الفارغ أوnullإلىnull؛ وتعطيtoNumالقيمةnullلـnullو""والأعداد غير المنتهية (non-finite)؛ وtoBoolتعطي true فقط لـ1و"1"وtrue؛ وتقبلtoImageUrlsمصفوفة أو سلسلة مصفوفة JSON أو سلسلة مفصولة بفواصل، وتحذف المسافات الزائدة وتُسقط الفارغ (src/sync/lib/casts.js:1,56-81). - يطبّق Update المفتاح فقط عندما يحتويه الـ body (
hasOwnProperty)، لذا فإنnullالموجودة تمسح الحقل (src/controllers/client/address-book/parse-payload.js:39-57). ولا يشغّل قاعدة الافتراضي إلا عندما يحتوي الـ body علىis_default(src/controllers/client/address-book/update.js:22-24،src/controllers/client/address-book/parse-payload.js:60-75). - قاعدة الافتراضي في Create موجودة في
resolveDefaultOnCreate(src/controllers/client/address-book/parse-payload.js:24-37)، وقاعدة Delete فيresolveDefaultOnDelete، التي ترقّيaddresses[0](parse-payload.js:78-82،src/controllers/client/address-book/remove.js:15-17). - تعيد الـ handlers تحميل العميل دون query cache، لذا لا تستخدم أي قراءة أو كتابة النسخة المخزَّنة
مؤقتًا لمدة 300 ثانية (
src/controllers/client/address-book/load-fresh-client.js:7-8). - قد يفشل حفظ يتسابق مع تغيير وارد من Shukah بـ
VersionErrorمن Mongoose ويعطي500(قراءة شيفرة؛ فالدفع الوارد يرفع إصدار الوثيقة عن قصد،docs/plans/2026-07-13-shukah-address-push-api.md:58-59).
الأشكال (Shapes)
تأتي إجابتا list وcreate من formatAddressForResponse، التي تستخدم ?? null للنصوص و
Boolean(is_default) (src/controllers/client/address-book/mapper.js:4-28). وتأتي إجابتا get وupdate من
formatAddressDetailForResponse، التي تحوّل كل نص مفقود إلى "" وis_default إلى 0 أو
1 وlat وlng إلى نص (src/controllers/client/address-book/mapper.js:30-51). والقائمة
مرتبة بـ created_at الأحدث أولًا، والعناوين التي بلا تاريخ أخيرًا
(src/controllers/client/address-book/handler.js:9-15).
العناوين الافتراضية في البيانات
قاعدة «عنوان افتراضي واحد» تُفرض فقط عبر هذه الاستدعاءات الثلاثة من التطبيق. فيختار الـ ETL عنوانًا افتراضيًا واحدًا لكل
عميل عندما يبني الوثيقة (src/sync/mappers/client-mapper.js:80-87)، لكن الدفع الوارد
للعناوين من Shukah إلى Locate لا يجري أي انتخاب (src/controllers/admin/client-addresses/handler.js:67-68).
وهكذا قد تكون كل العناصر العشرة الملتقطة في القائمة افتراضية (2026-10-01)، وكذلك 28 من 30 (2026-10-02).
وفي 2026-10-02 وصلت نسخة عنوان أُنشئ على Shukah وفيها is_default بقيمة true، مع أن Shukah أرسلت 0
(السبب: غير موثّق بعد). ولا تزال وثيقة الخدمة تقول إن الخادم يُبقي دائمًا
عنوانًا افتراضيًا واحدًا بالضبط (docs/api/client-auth-and-address-book.md:291).
الدفع إلى Shukah
بعد الحفظ المحلي، يدفع create وupdate العنوان إلى Shukah، بذل أقصى جهد ويُنتظر إتمامه. ويخزّن
Create المعرّف المُرجَع بوصفه shukah_address_id. ويدفع Update إلى {shukah_address_id} عندما يكون للعنوان
واحد، وإلا يرجع إلى دفع create. ولا يُدفع Delete
(src/services/shukah-sync.js:238-415؛ docs/plans/2026-09-22-shukah-address-outbound-push.md:106-110,149-151).
ولا يفعل الدفع شيئًا عندما تكون المزامنة معطّلة أو لا يكون الـ host أو token المسؤول مضبوطًا. وهل هو مفعّل على
dev: غير موثّق بعد. وتوحي التقاطات 2026-10-01 بأنه لم يكن يعمل لهذا العميل: فبعد
create وupdate وdelete في Locate، ظلت قائمة Shukah تحتوي 13 عنوانًا، بينما كان create منسوخ
دون delete منسوخ سيترك 14.
وفي 2026-10-02 وُجد السبب في الشيفرة: يرسل دفع create إلى /maeda/api/address-book
(src/services/shukah-sync.js:310)، وتجيب عليه Shukah على dev بـ 404؛ بينما تخدم Shukah
/maeda/address-book. ويُبتلع الفشل ولا يُكتب إلا في sync_logs (:335). أما دفع update
فيستخدم /maeda/address-book/{id} (:356) لكن فقط لعنوان له معرّف في Shukah بالفعل؛
وغيره يرجع إلى create المعطوب. والاتجاه الآخر معطوب أيضًا: فقد وصل create من Shukah إلى
Locate خلال ثوانٍ، لكن update وdelete من Shukah لم يصلا أبدًا. ولدى Locate المستقبِلات
(src/routes/admin.js:52-54)، فنسخة Laravel من Shukah لا تستدعيها (استنتاج). كما فقدت Locate
روابط الصور للعناوين الأربعة من Shukah التي لها صورة؛ ويعالج toImageUrls المصفوفات وسلاسل JSON
(src/sync/lib/casts.js:67-81)، فالفقد يحدث قبله في المصدر. السبب: غير موثّق بعد.
حيث تختلف الوثائق عن الشيفرة (القول للشيفرة)
- تقول وثيقة الخدمة إن
sourceالعنوان هو"locate"أو"shukah"(docs/api/client-auth-and-address-book.md:224). ويسمح النموذج بـmt_client_inlineوmt_address_bookوlocate(src/models/client.js:18)، ويُظهر الالتقاطmt_address_book. - تقول وثيقة الخدمة إن الخادم يضمن عنوانًا افتراضيًا واحدًا بالضبط
(
docs/api/client-auth-and-address-book.md:291). وهذا يصح على استدعاءات التطبيق فقط، كما سبق. - تقول وثيقة تصميم مبكرة إن get يُرجع
{status, address}(docs/plans/2026-07-07-shukah-address-book-api-local.md:13-14)، ثم تصححه إلى كائن مسطّح في الأسطر 23-24. والشيفرة تُرجع الكائن المسطّح. - تكتب وثائق التصميم مسارات Shukah بالشكل
/maeda/api/address-book(docs/plans/2026-07-07-shukah-address-book-api-local.md:49). أما التطبيق فيستدعي/maeda/address-book، وتجيب Shukah على dev بـ404للصيغة ذات/api/، لذا تستخدم الصفحات مسار التطبيق. - تُظهر الالتقاطات المنقَّحة أن Shukah تُرجع
latوlngكأرقام، بينما يعلن نوع التطبيق نفسه أنهما سلسلتان (src/entities/location/model/types/location.server.ts:3-19). - 2026-10-02: أعطت هذه الصفحة 13 عنوانًا على Shukah و28 على Locate، ولا عنوان افتراضيًا على Shukah وكل العناصر
العشرة افتراضية على Locate، وترتيبًا غير معروف على Shukah. وتُظهر التقاطات 2026-10-02 العددين 15 و30، وقيمة
0على Shukah في الـ15 كلها، وقيمةtrueعلى Locate في 28 من 30، وترتيب Shukah حسبposition. - 2026-10-02: توقعت هذه الصفحة ألا يكون هناك فرق في
image_urlsفي list وget. وقد فقدت Locate روابط الصور للعناوين الأربعة من Shukah التي لها صورة. - 2026-10-02: ذكرت هذه الصفحة أن
is_defaultفي get واحد على الجانبين. والعنوان نفسه يساوي0على Shukah و1على Locate. - 2026-10-02: قالت هذه الصفحة إن المعرّف الغريب يحصل على الإجابة نفسها على الجانبين. تجيب Shukah بـ
403؛ وتجيب Locate بـ404(قراءة شيفرة). - 2026-10-02: قالت هذه الصفحة إن أجزاء العنوان
nullفي create كانت قراءة شيفرة. وقد التُقطت الآن. - 2026-10-02: «النسخة بذل أقصى جهد إلى Shukah» في create وupdate موجودة في الشيفرة
(
src/controllers/client/address-book/create.js:23،src/controllers/client/address-book/update.js:31)، لكن لم تصل أي نسخة إلى Shukah على dev في 2026-10-02 أيضًا (انظر الدفع إلى 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- وثائق
locate-authentication-service@6757aa4:docs/api/client-auth-and-address-book.md§4 إلى §8 (الأسطر 187-370، 224، 259-263، 291؛ آخر تغيير 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 - نسخة الجوال اللحظية
mobile/locate-client@e960c3a(الفرعdevelopment، 2026-02-26؛ شيفرة التطبيق نفسه، وليست من 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، الدفع والمزامنة:src/services/shukah-sync.js:310,335,356،src/routes/admin.js:52-54،src/sync/lib/casts.js:67-81- التقاطات 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 - التقاطات 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