الملف الشخصي والإعدادات
الخلفية
على Shukah يغيّر التطبيق الملف الشخصي ومفتاح إشعارات push باستدعاء واحد،
PUT /maeda/client/{client_id}، ويُبلغ Shukah بالهاتف عبر
POST /maeda/client/add-device-id. وفي خدمة المصادقة ثلاثة routes لذلك: واحد للملف الشخصي،
وواحد لمفتاح push، وroute لمعرّف الجهاز (device-id). وثلاثة أمور تستحق العناية: يحتاج مفتاح push إلى استدعاء
خاص به لأن route الملف الشخصي يتجاهل push_enabled، ويرفض route الملف الشخصي هاتفًا تغيّر،
وroute الجهاز مجرد stub لا يخزّن شيئًا.
الميزة
الاستدعاءات الثلاثة كلها جزء من شاشات حساب العميل المسجَّل الدخول. وفي نسخة التطبيق اللحظية بتاريخ 2026-02-26 تحدث في هذه الأماكن:
| الاستدعاء | أين في التطبيق |
|---|---|
| تحديث الملف الشخصي | في شاشة المعلومات الشخصية، عندما ينقر العميل على «حفظ». يحمل استدعاء واحد client_id وcontact_phone وfirst_name وlast_name وemail_address وsex وreceive_offers وbirth_date (بالصيغة YYYY-MM-DD). حقل الهاتف ظاهر لكنه معطَّل، وقيمته هي الهاتف الذي حمّله التطبيق مع الملف الشخصي، لذا يعيد التطبيق إرسال الهاتف الذي استلمه. |
| تحديث الإعداد | في شاشة الإعدادات، عندما يقلب العميل مفتاح إشعارات push. يرسل التطبيق client_id وpush_enabled (0 أو 1). وعلى Shukah يمر هذا عبر route الملف الشخصي نفسه. |
| إضافة معرّف الجهاز | عند بدء التطبيق، بعد فحص الملف الشخصي (verify-token) مباشرة، عندما يكون العميل مسجَّل الدخول ولم يُجرَ الاستدعاء بعد على هذا التثبيت. يرسل المعرّف الفريد للجهاز مرة واحدة. وبعد إجابة 200 يسجّل التطبيق أنه أرسله ولا يرسله ثانية أبدًا. |
يحتاج أول استدعاءين إلى JWT من Locate (انظر «الحصول على token تجريبي» في النظرة العامة للوحدة) ويجيبان بالملف الشخصي للعميل، الحقول الـ 13 نفسها في التحقق من الـ token، بعد التغيير. أما استدعاء معرّف الجهاز فلا يحتاج إلى token.
PUT /api/v1/clients/:client_id
PUT /maeda/client/:client_id✅ تم الاستبدال- 🔴 يحصل token من Shukah على 401 "Unauthorization"؛ أرسل JWT من Locate (من exchange-token؛ واحتفظ بـ token من Shukah).
- 🟡 يُتجاهل push_enabled في هذا الـ route (ولا يزال التطبيق يرسله هنا: user.dto.ts:100-101)؛ راجع update-setting.
- 🟡 يجب أن يساوي contact_phone الهاتف المخزَّن مع "+" وإلا 400؛ وقاعدة تغيير الهاتف في Shukah لم تُختبر.
- 🟡 المدخلات الخاطئة تعطي 400 {status,message,stack} على Locate و422 [{field,message}] على Shukah؛ ويفقد التطبيق field.
- 🟡 يبقى التعديل في Locate ولا يُدفع إلى Shukah (لا يوجد دفع في update-profile/index.js).
الطلب (Request)
تحديث جزئي: لا يتغير سوى المفاتيح الموجودة في الـ body. وتُرجع الخدمة أول مشكلة
تجدها وتفحص بهذا الترتيب: client_id ثم contact_phone ثم first_name ثم last_name ثم
email_address ثم birth_date.
| الحقل | الموضع | النوع | مطلوب | القيود | الوصف |
|---|---|---|---|---|---|
Authorization | header | string | نعم | Bearer <locate-jwt>. وtoken من Shukah يحصل على 401. | الـ JWT من Locate. |
client_id | path | integer | نعم | يجب أن يساوي معرّف العميل في الـ token، وإلا 400 مع client_id does not match the authenticated client. | معرّف المستدعي نفسه. |
client_id | body | integer أو سلسلة رقمية | لا | إن أُرسل فيجب أن يساوي معرّف عميل الـ token أيضًا، مع 400 نفسه. وnull يفشل. | معرّف المستدعي نفسه مرة أخرى، كما يرسله التطبيق. |
contact_phone | body | string | لا | لا يمكن تغييره. إن أُرسل فيجب أن تساوي القيمة بعد حذف المسافات الهاتف المخزَّن تمامًا، بما فيها + في البداية (966500000000 لا تطابق +966500000000)، وإلا 400 مع contact_phone cannot be changed. ولا يُكتب أبدًا. | هاتف العميل. |
first_name وlast_name | body | string أو null | لا | null أو سلسلة بحد أقصى 100 حرف بعد حذف المسافات الزائدة، وإلا 400 مع first_name is invalid أو last_name is invalid. تُخزَّن بعد حذف المسافات الزائدة. وnull تمسحها، وتُخزَّن "" كما هي "". | الأسماء. |
email_address | body | string أو null | لا | أي سلسلة أو null: لا فحص للصيغة ولا حد للطول، وإلا 400 مع email_address is invalid. تُخزَّن بعد حذف المسافات الزائدة. | البريد الإلكتروني. |
birth_date | body | string أو null | لا | قيمة يستطيع new Date() في JavaScript قراءتها، وتُخزَّن بتاريخ UTC بالصيغة YYYY-MM-DD. وnull تمسحها. والقيمة غير المقروءة، بما فيها ""، تعطي 400 مع birth_date is invalid. | تاريخ الميلاد. ويرسل التطبيق YYYY-MM-DD. |
sex | body | integer | لا | لا يُتحقق منه. 1 ذكر و2 أنثى. وأي شيء آخر، بما فيه 0 و9 وnull، يُخزَّن «غير معروف» ويُقرأ لاحقًا 0. | الجنس. |
receive_offers | body | 0 أو 1 أو boolean | لا | لا يُتحقق منه. فقط 1 و"1" وtrue تعني التفعيل. وأي شيء آخر يعني التعطيل. | هل يتلقى العميل العروض. |
push_enabled وأي مفتاح آخر | body | — | لا | يُتجاهل. فلمفتاح push route خاص به. | — |
طلب استُخدم للالتقاط أدناه، ويكتب القيمة الحالية للعميل مرة أخرى:
{
"client_id": 356259,
"receive_offers": 0
}
الاستجابة (Response)
200 مع الملف الشخصي ذي الحقول الـ 13 بعد التحديث، دون غلاف. والحقول وقواعدها هي
الجدول الوارد تحت التحقق من الـ 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
}
التُقط على dev، 2026-10-01 (العميل 356259، كتابة مباشرة في Task 9، والقيمة الحالية أُعيدت كتابتها)؛ واستُبدلت الحقول الشخصية.
الأخطاء
| HTTP | Body | متى |
|---|---|---|
400 | {"status":400,"message":"birth_date is invalid"} | تعذّرت قراءة birth_date كتاريخ. ولرسائل الحقول الأخرى الشكل نفسه: 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. وتُرجَع أول رسالة فاشلة فقط. وعلى dev يحمل الـ body أيضًا حقل stack (انظر أدناه). |
401 | {"status":401,"message":"Unauthorization"} | لا token، أو token ليس JWT من Locate، أو عميل غير نشط. وهذا يأتي قبل أي فحص للـ body. |
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: غير موثّق بعد). |
التُقط 400 الخاص بـ birth_date على dev في 2026-10-01، ومرة أخرى في 2026-10-02 مع
"birth_date":"not-a-date". ورسائل 400 الأخرى مصدرها الشيفرة ووثيقة الخدمة، ولم تُلتقط.
والتُقط body الخاص بـ 401 على dev في 2026-10-01 دون token. وعلى dev يحمل كل body من نوع 400
أيضًا حقل stack فيه stack trace للخادم كنص، مثل
{"status":400,"message":"birth_date is invalid","stack":"<stack trace>"} (التُقط 2026-10-02).
وتتركه العينات في الجدول.
جرّبه
يكتب الاستدعاء الأول على dev، لذا أرسل القيمة الحالية للعميل، كما فعل الالتقاط. أما الاستدعاء الثاني فيُرفض ولا يكتب شيئًا.
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"}'
المتوقع: يعطي الاستدعاء الأول 200 والملف الشخصي المبيّن تحت «الاستجابة». ويعطي الثاني 400 مع
birth_date is invalid.
الفروق عن Shukah
| الجانب | Shukah | Locate | الأثر على التطبيق |
|---|---|---|---|
| URL | PUT $SHUKAH_BASE_URL/maeda/client/{client_id} | PUT $AUTH_BASE_URL/api/v1/clients/{client_id} | غيّر base URL والمسار. |
| الـ Token | token معتم (opaque) من Shukah. | JWT من Locate فقط. | احصل على الـ JWT عبر exchange-token أولًا، واحتفظ بـ token Shukah لـ order-v2. ولا تنقل تسجيل الدخول إلى Locate بعد. |
push_enabled | يقبل الـ route نفسه push_enabled أيضًا، ويرسله التطبيق هنا لمفتاح push. | يُتجاهل. ويظل الاستدعاء يجيب 200 مع الملف الشخصي دون تغيير. | انقل مفتاح push إلى استدعاء الإعداد أدناه، وإلا فلن يفعل شيئًا بصمت (قراءة شيفرة، لم يُلتقط). |
contact_phone | هل تقبل Shukah هاتفًا تغيّر: غير موثّق بعد. | يجب أن يساوي الهاتف المخزَّن تمامًا، وإلا 400. | لا شيء ما دام التطبيق يعيد إرسال الهاتف الذي حمّله من Locate. لا تعِد تنسيقه. |
| التحقق والأخطاء | 422 مع مصفوفة أخطاء حقول: [{"field":"birth_date","message":"The birth date field must match the format Y-m-d."}] لـ "birth_date":"not-a-date" (التُقط على dev، 2026-10-02). وقواعد Shukah الأخرى: غير موثّق بعد. | 400 مع {"status":400,"message":"..."} (مع stack على dev)، والقواعد الواردة في جدول الطلب. | يتغير الـ status من 422 إلى 400، ويختفي اسم الحقل. يعرض التطبيق message. افحص الصياغة في شاشة المعلومات الشخصية. |
| body النجاح | الملف الشخصي ذو الحقول الـ 13 (التُقط على dev، 2026-10-02، بالطلب أعلاه). | الملف الشخصي ذو الحقول الـ 13 (التُقط على dev، 2026-10-01 و2026-10-02). | لا شيء: المفاتيح الـ 13 نفسها والأنواع والقيم نفسها للعميل 356259 في 2026-10-02. |
sex | يسمح نوع التطبيق بـ 9 لـ «غير منطبق». | تُخزَّن 9 «غير معروف» وتُقرأ لاحقًا 0. | العميل الذي في ملفه على Shukah القيمة 9 يُقرأ «غير معروف» بعد التحوّل. ولا يعرض نموذج المعلومات الشخصية سوى ذكر وأنثى. |
| النسخ إلى Shukah | لا ينطبق. | يبقى التعديل في Locate ولا يُنسخ إلى Shukah. | أي شيء ما زال يقرأ الملف الشخصي من Shukah يحتفظ بالقيم القديمة. |
PUT /api/v1/clients/setting
PUT /maeda/client/:client_id✅ تم الاستبدال- 🔴 يحصل token من Shukah على 401 "Unauthorization"؛ أرسل JWT من Locate (من exchange-token؛ واحتفظ بـ token من Shukah).
- 🔴 يبدّل التطبيق push عبر PUT client/:id؛ وتتجاهل Locate push_enabled هناك، لذا استدعِ PUT /clients/setting.
- 🟡 client_id مطلوب في body ويجب أن يساوي client_id الخاص بالـ token؛ وغياب push_enabled يعطي 400.
- 🟡 يبقى التغيير في Locate ولا يُدفع إلى Shukah.
- 🟡 كتب الزوج القيمة الحالية (push_enabled 0)، لذا لم يثبت أن Shukah تطبّق push_enabled في هذا الـ route.
الطلب (Request)
| الحقل | الموضع | النوع | مطلوب | القيود | الوصف |
|---|---|---|---|---|---|
Authorization | header | string | نعم | Bearer <locate-jwt>. وtoken من Shukah يحصل على 401. | الـ JWT من Locate. |
client_id | body | integer أو سلسلة رقمية | نعم | يجب أن يساوي معرّف العميل في الـ token. والمفقود أو المختلف يعطي 400 مع client_id does not match the authenticated client. | معرّف المستدعي نفسه. ولا معرّف في المسار. |
push_enabled | body | 0 أو 1 أو boolean | نعم | يجب أن يكون المفتاح موجودًا، وإلا 400 مع push_enabled is required. فقط 1 و"1" وtrue تفعّله. وكل شيء آخر يعطّله، بما فيه null و"true" و2. | تشغيل إشعارات push أو إيقافها. |
يُفحص client_id أولًا. ولا يُدعم في هذا الـ route اليوم سوى push_enabled.
طلب استُخدم للالتقاط أدناه، ويكتب القيمة الحالية مرة أخرى:
{
"client_id": 356259,
"push_enabled": 0
}
الاستجابة (Response)
200 مع الملف الشخصي ذي الحقول الـ 13 بعد التحديث، دون غلاف، كما هو تحت
التحقق من الـ token. ويُظهر push_enabled القيمة الجديدة.
{
"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
}
التُقط على dev، 2026-10-01 (العميل 356259، كتابة مباشرة في Task 9، والقيمة الحالية أُعيدت كتابتها)؛ واستُبدلت الحقول الشخصية.
الأخطاء
| HTTP | Body | متى |
|---|---|---|
400 | {"status":400,"message":"client_id does not match the authenticated client"} | client_id مفقود أو ليس عميل الـ token. ويشمل ذلك طلبًا بلا JSON body، تقرؤه الخدمة كـ {}. التُقط مع ضبط client_id على 1. |
400 | {"status":400,"message":"push_enabled is required"} | مفتاح push_enabled غائب وclient_id صحيح. لم يُلتقط. |
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"}. | فشل غير متوقع. لم يُلتقط. وعلى dev تكون الرسالة نص الخطأ الخام ويُضاف حقل stack؛ ولا تظهر Internal server error إلا في production (UAT وproduction: غير موثّق بعد). |
التُقط 400 الخاص بـ client_id و401 على dev في 2026-10-01 (والـ 401 دون token).
أما 400 الخاص بـ push_enabled فمن الشيفرة ووثيقة الخدمة. وعلى dev يحمل body الخاص بـ 400 أيضًا
حقل stack، وتتركه هذه الصفحة.
جرّبه
يكتب الاستدعاء الأول على dev، لذا أرسل القيمة الحالية للعميل. أما الاستدعاء الثاني فيُرفض ولا يكتب شيئًا.
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}'
المتوقع: يعطي الاستدعاء الأول 200 والملف الشخصي. ويعطي الثاني 400 مع
client_id does not match the authenticated client.
الفروق عن Shukah
| الجانب | Shukah | Locate | الأثر على التطبيق |
|---|---|---|---|
| URL | PUT $SHUKAH_BASE_URL/maeda/client/{client_id}، وهو route تحديث الملف الشخصي نفسه. والـ body هو {client_id, push_enabled}. | PUT $AUTH_BASE_URL/api/v1/clients/setting، دون معرّف في المسار. | يستدعي مفتاح push في التطبيق اليوم تحديث الملف الشخصي. وجّهه إلى هذا الـ route، وإلا تتجاهل Locate التغيير. |
| الـ Token | token معتم (opaque) من Shukah. | JWT من Locate فقط. | احصل على الـ JWT عبر exchange-token أولًا، واحتفظ بـ token Shukah لـ order-v2. ولا تنقل تسجيل الدخول إلى Locate بعد. |
client_id | يُرسل في المسار والـ body. وهل تفحصه Shukah مقابل الـ token: غير موثّق بعد. | يجب أن يكون في الـ body وأن يساوي عميل الـ token. | لا شيء: فالتطبيق يرسل client_id في الـ body بالفعل. |
| التحقق والأخطاء | غير موثّق بعد. | 400 مع {"status":400,"message":"..."} لـ client_id خاطئ أو push_enabled مفقود. | يرسل التطبيق المفتاحين بالفعل، لذا لا ينبغي أن يحدث ذلك. |
| body النجاح | الملف الشخصي ذو الحقول الـ 13 مع push_enabled يساوي 0 (التُقط على dev، 2026-10-02، والـ body هو {"client_id":356259,"push_enabled":0}، أي أُعيدت كتابة القيمة الحالية). | الملف الشخصي نفسه ذو الحقول الـ 13 (التُقط على dev، 2026-10-02). | يقرأ التطبيق push_enabled من الإجابة ليضبط المفتاح. وقد كتب الالتقاط القيمة الحالية، فهو لا يثبت أن Shukah تطبّق التغيير على هذا الـ route. |
| النسخ إلى Shukah | لا ينطبق. | يبقى التغيير في Locate ولا يُنسخ إلى Shukah. | تحتفظ Shukah بالقيمة القديمة. |
POST /api/v1/clients/add-device-id
POST /maeda/client/add-device-id✅ تم الاستبدال- 🟡 لا تخزّن Locate شيئًا؛ وحفظت Shukah صف جهاز (id 1074)؛ ويعلّم التطبيق المعرّف بأنه أُرسل على أي حال.
- 🟡 تُعيد Locate القيمتين الثابتتين id 920 وclient_id 356315 للجميع؛ وتُرجع Shukah client_id الخاص بالمستدعي.
- 🟡 لا تحتاج Locate إلى token (لا يوجد guard، routes/client.js:23)؛ ويمكن للتطبيق مواصلة إرسال token.
الطلب (Request)
لا حاجة إلى token: فالـ token أو أي header آخر يُتجاهل.
| الحقل | الموضع | النوع | مطلوب | القيود | الوصف |
|---|---|---|---|---|---|
device_id | body | string | لا | لا يُتحقق منه. ويُعاد كما هو عند وجوده. | المعرّف الفريد للجهاز. |
| أي مفتاح body أو query أو header آخر | body، query، header | — | لا | يُتجاهل، مثل language. | — |
{
"device_id": "00000000-0000-4000-8000-000000000000"
}
الاستجابة (Response)
200 مع سجل جهاز. وهو stub، لذا فقيمتان من الثلاث ثابتتان:
| الحقل | النوع | يقبل null | الصيغة / القيود | الوصف |
|---|---|---|---|---|
id | integer | لا | دائمًا 920، لكل مستدعٍ. | معرّف سجل جهاز بديل (stand-in). |
client_id | integer | لا | دائمًا 356315، لكل مستدعٍ. وليس معرّف المستدعي. | معرّف عميل بديل (stand-in). |
device_id | string | لا | قيمة device_id من الطلب. وعندما لا يكون في الطلب واحد، معرّف نموذجي ثابت 46AE56EF-29BA-40AE-B436-AF22B119FE1E. | معرّف الجهاز، كما أُعيد. |
{
"id": 920,
"client_id": 356315,
"device_id": "00000000-0000-4000-8000-000000000000"
}
التُقط على dev، 2026-10-01 (استدعاء مباشر في Task 9، بلا token؛ والطلب هو الوارد أعلاه). لا شيء يُخزَّن بهذا الاستدعاء.
الأخطاء
لا شيء معرَّف. ولا يوجد 401، لأن الـ route لا يفحص الـ token. والطلب بلا
JSON body يُقرأ كـ body فارغ ويظل يجيب 200 (التُقط الاستدعاء بـ body فارغ في
2026-10-01).
جرّبه
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"}'
المتوقع: 200 والسجل المبيّن تحت «الاستجابة». ويمكن استدعاؤه بأمان: فهو لا يكتب شيئًا.
الفروق عن Shukah
| الجانب | Shukah | Locate | الأثر على التطبيق |
|---|---|---|---|
| URL | POST $SHUKAH_BASE_URL/maeda/client/add-device-id | POST $AUTH_BASE_URL/api/v1/clients/add-device-id | غيّر base URL والمسار. |
| ما يفعله | يخزّن سجل جهاز جديدًا للمستدعي في كل استدعاء (التُقط على dev، 2026-10-02: السجل 1074). ولا يوجد API يزيله. | لا شيء: لا تخزين، ولا ربط بالعميل، ولا فحص للـ token. | بعد التحوّل لا يُسجَّل أي جهاز بهذا الاستدعاء. وإن كان شيء على Shukah يعتمد على سجل الجهاز فسيتوقف: غير موثّق بعد. |
| الإجابة | {"id":1074,"client_id":356259,"device_id":"<the id sent>"}: معرّف السجل الجديد ومعرّف المستدعي (التُقط على dev، 2026-10-02). ويتجاهل التطبيق الإجابة. | {id: 920, client_id: 356315, device_id} للجميع. | لا شيء بالنسبة إلى التطبيق. |
| الـ Token | يرسل التطبيق token Shukah الخاص به. وهل تشترطه Shukah: غير موثّق بعد. | غير مطلوب، ولا يُفحص. | لا شيء. |
| إعادة المحاولة | يسجّل التطبيق أنه أرسل المعرّف بعد إجابة 200. | يجيب الـ stub دائمًا بـ 200. | سيعلّم التطبيق الجهاز بأنه أُرسل ولن يحاول مرة أخرى أبدًا، مع أن شيئًا لم يُخزَّن. |
تنبيه
- يتجاهل route الملف الشخصي
push_enabledويظل يجيب200مع القيمة القديمة، لذا يجب أن يستدعي مفتاح push المسارPUT /api/v1/clients/settingبدلًا منه. - يجب أن يساوي
contact_phoneالهاتف المخزَّن تمامًا، بما فيها+في البداية، وإلا يفشل الاستدعاء بـ400. - يجيب
add-device-idدائمًا بـ200ولا يخزّن شيئًا، فيعلّم التطبيق الجهاز بأنه أُرسل مع أنه لم يُسجَّل أي جهاز.
التفاصيل (للـ backend)
فُحص dev فقط: الـ host https://dev.authentication.locate.sa والبادئة /api/v1. أما الـ host والبادئة في UAT
وproduction: غير موثّق بعد. تحمل أجسام الأخطاء على dev حقل stack (التُقط
في 2026-10-01 على 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).
ترتيب الـ routes والحارس
يُسجَّل PUT /clients/setting قبل PUT /clients/:client_id، لذا لا يمكن قراءة setting أبدًا
كمعرّف عميل. ويشغّل كلاهما حارس client، فقواعد الـ token هي قواعد
التحقق من الـ token. أما route الجهاز (device-id) فلديه الغلاف async فقط ولا
حارس (src/routes/client.js:23-26).
تحديث الملف الشخصي
- الفحوص هي سلاسل express-validator تعمل بعد الحارس. ويُلقي الـ handler أول
رسالة، لذا لا تعود سوى رسالة
400واحدة (src/controllers/client/update-profile/validate.js:12-31،src/controllers/client/update-profile/index.js:12-15). - يبحث
check('client_id')في body وcookies وheaders وparams وquery، لذا فإنclient_idغير المطابق في سلسلة query أو في header يفشل بالرسالة نفسها أيضًا (فحص دون اتصال، 2026-10-01: شُغّلت سلاسل المدقّق الحقيقية على نحو 20 طلبًا مصطنعًا). - يُقارَن
contact_phoneبعدnormalizePhone، الذي يحذف المسافات فقط. والقيمةnullتفشل، ولا تُكتب القيمة أبدًا (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). - تُخزَّن الأسماء والبريد بعد حذف المسافات الزائدة. وتُخزَّن
nullكما هيnullو""كما هي""(src/controllers/client/update-profile/parse-payload.js:5,11-13). - يمر
birth_dateعندما يكونnullأو عندما تعطيtoBirthDateStringتاريخًا. وتُرجع تلك الدالةnullللقيمة الفارغة وللقيمة غير المقروءة، والتاريخ الذي تحتفظ به هو تاريخ 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عبرmapGender:1أو"1"هيMALE، و2أو"2"هيFEMALE، وكل شيء آخر هوUNKNOWN، وتحوّل الاستجابةUNKNOWNإلى0. ويمرreceive_offersعبر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 العميل الذي حمّله الحارس، ويضبط
updated_atويحفظ. ويمسح الحفظ العميل المخزَّن مؤقتًا (cache) (src/controllers/client/update-profile/index.js:17-20،src/models/client.js:158-161). ولا يوجد دفع (push) إلى Shukah (docs/plans/2026-07-16-shukah-update-profile-api-local.md:42,140). - لا يقرأ route الملف الشخصي
push_enabled(docs/plans/2026-07-16-shukah-update-profile-api-local.md:39،src/controllers/client/update-profile/parse-payload.js:10-19).
تحديث الإعداد
يشترط الـ handler أن يساوي client_id عميل الـ token، ثم ألا تكون push_enabled بقيمة undefined،
ثم يضبط push_enabled بـ toBool ويحفظ. ولا يغيّر شيئًا آخر ولا يدفع إلى 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). والطلب بلا JSON body
يصل كـ {}، فيعطي رسالة client_id أولًا.
Stub الخاص بمعرّف الجهاز
يُرجع الـ handler {id: 920, client_id: 356315, device_id: req.body?.device_id ?? '<sample uuid>'}
ولا يفعل شيئًا آخر. ويُتجاهل الـ query والـ headers
(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). ويثبّته اختبار وحدة
(src/controllers/client/__tests__/add-device-id.test.js:11-35).
حيث تختلف الوثائق عن الشيفرة (القول للشيفرة)
- تعطي وثيقة تصميم 2026-07-16 مسار تحديث Shukah بالشكل
PUT /api/v1/clients/{client_id}(docs/plans/2026-07-16-shukah-update-profile-api-local.md:14-19). أما التطبيق فيستدعيPUT /maeda/client/{client_id}. - يُظهر سجل routes خدمة المصادقة route لـ Shukah هو
PUT /maeda/api/settingاستبدلته خدمة Locate (commitd837492). ولا يستدعيه التطبيق أبدًا: فمفتاح push يمر عبر route الملف الشخصي. - سلوك
sexوreceive_offersوpush_enabledفي استدعاء الملف الشخصي على Shukah غير موجود في أي مستودع: غير موثّق بعد. - 2026-10-02: لم يكن في هذه الصفحة body نجاح من Shukah لـ update profile وupdate setting، ولا body خطأ من
Shukah. وقد التُقطت الآن: الملف الشخصي نفسه ذو الحقول الـ 13 على الجانبين، ومصفوفة أخطاء حقول
422على Shukah حيث تجيب Locate بـ400. - 2026-10-02: كتبت هذه الصفحة body
400في Locate بالشكل{"status":400,"message":"..."}. وعلى dev يحمل أيضًاstack، وهو stack trace للخادم (src/middlewares/error-handler.js:33، يُضاف كلما كانNODE_ENVليسproduction). - 2026-10-02: قالت هذه الصفحة إن ما تخزّنه Shukah لـ add-device-id غير موثّق، وإن إجابتها غير مؤكَّدة. تخزّن Shukah سجل جهاز جديدًا في كل استدعاء وتجيب بمعرّفه ومعرّف المستدعي.
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- وثائق
locate-authentication-service@6757aa4:docs/api/client-auth-and-address-book.md§10 و §11 (الأسطر 412-528؛ آخر تغيير 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 - نسخة الجوال اللحظية
mobile/locate-client@e960c3a(الفرعdevelopment، 2026-02-26؛ شيفرة التطبيق نفسه، وليست من 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 - التقاطات 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 - التقاطات 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