التجارة السعودية · معمارية الأحداث

سلات سلة المتروكة: ابنِ مسار استعادة يعرف متى يتوقف

تصميم إنتاجي لاستعادة السلات المتروكة في سلة باستخدام Webhooks موقعة وقراءة الحالة الحالية والإيقاف الدائم والمطابقة ومزودي إرسال خارجيين.

المسار المرتبطهندسة التجارة الإلكترونية
رسم تصوري أصلي لحدث سلة تسوق يمر عبر صندوق وارد دائم وفحص حالة وبوابة إيقاف قبل مزود رسائل خارجي؛ وليس واجهة حقيقية من سلة.
تصوّر بصري للفكرة — يتبعه شرح ومخطط تنفيذي داخل المقال.

تبدو رسالة استعادة السلة المتروكة نشاطًا تسويقيًا بسيطًا، لكنها هندسيًا نظام موزع صغير. قد تتغير السلة بعد الحدث الأول، وقد يُعاد إرسال الـWebhook أو يصل بترتيب مختلف، وقد يشتري العميل من جهاز آخر، وقد يتوقف مزود الرسائل بعد قبول الطلب. أسوأ عطل ليس فقد رسالة، بل إرسالها بعد الدفع أو إرسالها مرتين.

توفر وثائق مطوري سلة الحالية العناصر اللازمة لبناء مسار أكثر أمانًا. تقدم واجهات السلات المتروكة Endpoint للقائمة وآخر لتفاصيل السلة ضمن صلاحية `carts.read`. وتوثق نماذج Webhook للسلة إنشاء السلة المتروكة وتحديثها وتغير حالتها وحدث الشراء الذي تصبح فيه الحالة `purchased`. كما يسجل سجل التغييرات إضافة حقل `status` إلى تفاصيل السلة ونموذجي `abandoned.cart.status.changed` و`abandoned.cart.purchased`.

هذا شرح مبني على الوثائق الحالية، وليس خبرًا عن ميزة أطلقت اليوم. جرى التحقق من الوثائق في 28 سبتمبر 2026. ويجب رسم حد مهم: هذه الواجهات والأحداث تكشف حالة السلة، لكنها لا تثبت وحدها أن رسالة استعادة أُرسلت أو وصلت. يبقى البريد أو SMS أو WhatsApp مسؤولية منتج اتصالات موثق، أو تطبيق مثبت، أو تكامل مخصص مع مزود خارجي.

حدّد الملكية قبل كتابة الـWorker

قسّم النظام إلى ثلاث مسؤوليات. سلة هي مصدر حالة التجارة: هوية السلة ومحتوياتها وحالتها وانتقالها إلى الشراء. يملك تطبيقك حالة سير العمل: أي حدث وصل، وهل السلة مؤهلة، ومتى يجوز تشغيل التذكير، ولماذا أُوقف. ويملك مزود الإرسال محاولة النقل ودليلها.

لا تختصر هذه الحالات في Boolean اسمه `sent`. يجب أن يميز السجل الدائم على الأقل بين: `observed` و`verified_abandoned` و`eligible` و`scheduled` و`dispatched` و`delivered` و`converted` و`suppressed` و`expired` و`review_required`. انتهاء مهلة المزود بعد الإرسال نتيجة مجهولة، وليس إذنًا لإرسال رسالة ثانية. والسلة التي اشتراها العميل لاحقًا تصبح محولة أو موقوفة حتى لو بقيت محاولة قديمة في سجل المزود.

ضع مفتاح المتجر أو المستأجر في كل سجل. معرف السلة وحده ليس حد عزل آمنًا لعدة متاجر. اربط تفويض سلة ومعرف المتجر والسلة ومرجع العميل وحساب مزود الإرسال في طبقة التطبيق، وطبّق الربط في استعلامات قاعدة البيانات والمهام الخلفية.

استجب للـWebhook بعد الحفظ الدائم

تنص وثائق أمان Webhooks على ترويسة `X-Salla-Signature` مبنية بـSHA-256 من النص الخام للطلب والسر، وتوصي بمقارنة ثابتة الزمن. تحقق من التوقيع قبل تحليل الحمولة أو تنفيذ أي فعل، واحتفظ بالبايتات الخام لأن إعادة تسلسل JSON قد تغير القيمة الموقعة.

تذكر الوثائق نفسها أن سلة تنتظر قرابة 30 ثانية، وتعيد المحاولة ثلاث مرات بفواصل تقارب خمس دقائق عند الفشل. لذلك يجب أن يكون الـEndpoint حد استقبال، لا مكانًا لاستدعاء مزود الرسائل. بعد التحقق، أدخل الحدث وبصمة حمولته في صندوق وارد دائم، نفذ Commit، ثم أعد نجاحًا سريعًا. يستطيع Worker لاحقًا قراءة الحالة وجدولة العمل خارج طلب الـWebhook.

لا يعد النموذج المنشور بمعرف حدث عالمي يصلح لكل استراتيجية منع تكرار. لذلك صمّم المنع في التطبيق: ابنِ مفتاحًا ثابتًا من المتجر ونوع الحدث ومعرف السلة والحقول الثابتة المتاحة، واحتفظ ببصمة الحمولة للتدقيق، واجعل انتقال الحالة نفسه Idempotent. وصول الحدث نفسه مرتين يجب أن ينتج الحالة نفسها، لا رسالتين مجدولتين.

قبل الاشتراك، استخدم List Webhook Events لمعرفة الأحداث المتاحة فعليًا للتطبيق المفوض. ثم استخدم Register Webhook بأصغر مجموعة لازمة. توثق واجهة التسجيل أن الإصدار 2 هو الافتراضي، وأن تسجيل الرابط نفسه يحدث الاشتراك الموجود أو يعيده. ضع مطابقة التسجيل ضمن النشر كي يصبح حذف الاشتراك أو تغييره حالة مرصودة.

اقرأ الحالة الحالية ولا تثق بعمر الحدث

يقول الـWebhook إن شيئًا حدث، لكنه لا يضمن أن صورة الحمولة ما زالت الأحدث حين يعمل الـWorker. اقرأ تفاصيل السلة المتروكة قبل نقلها من `observed` إلى `eligible`. سجّل الحالة التي قرأتها ووقت القراءة والحدث الذي سبّب الفحص.

يجب أن تكون قواعد الأهلية صريحة ومؤرشفة بإصدار: أقل عمر للسلة، وجود وسيلة تواصل، موافقة القناة، حد التكرار، محاولات الاستعادة السابقة، ساعات هدوء المتجر، قيمة السلة أو استثناءات التاجر. خزّن إصدار السياسة مع القرار كي يستطيع المشغل تفسير سبب إرسال الرسالة بعد تغير القواعد.

استخدم تأخيرًا بدل الإرسال عند أول حدث. يمتص التأخير التصفح الطبيعي، لكنه يخلق نافذة سباق. مباشرة قبل الإرسال، أعد قراءة السلة أو استخدم سجل حالة يضمن معالجة كل أحداث الشراء وتغير الحالة. إذا كانت السلة مشتراة أو مفقودة أو منتهية أو لم تعد مسموحة، فألغ عنصر الـOutbox. فحص الإيقاف الأخير أهم خطوة في المسار.

يجب أن يقود حدثا `abandoned.cart.purchased` وتغير الحالة إلى الإيقاف، لا إلى فرع تسويقي جديد. عند وصول أي منهما، ألغ كل إرسال معلق لذلك المتجر والسلة، وأغلق المحاولات المجدولة، واحفظ سببًا للتدقيق. يجب أن يكون إيقاف العمل بديمومة جدولة العمل نفسها.

استخدم الـWebhook كإشارة إيقاظ، ثم اقرأ حالة السلة الحالية وطبّق بوابة إيقاف أخيرة مباشرة قبل إرسال أي رسالة خارجية.
استخدم الـWebhook كإشارة إيقاظ، ثم اقرأ حالة السلة الحالية وطبّق بوابة إيقاف أخيرة مباشرة قبل إرسال أي رسالة خارجية. اضغط لعرض أكبر

أضف مطابقة للأحداث التي لم تصل

تقلل Webhooks التأخير، لكنها لا تلغي المطابقة. استخدم List Abandoned Carts كحلقة إصلاح دورية. تدعم الواجهة الصفحات وفلتر `keyword` الموثق. ويوثق دليل Pagination وسيط `per_page` بحد عام أقصى 60، لذا احفظ Cursor أو Checkpoint وعالج صفحات محدودة بدل مسح كل السلات في كل تشغيل.

يجب أن تكشف المطابقة أربع حالات: سلة متروكة لا وجود لها في مسارك، وسلة محلية تغيرت حالتها في المنصة، وإرسال مجدول بلا تحقق حديث، وسلة محلية لم تعد تظهر حيث تتوقع. أصلح الحالة ولا تعِد الإرسال تلقائيًا. إذا بقي الدليل ملتبسًا، انقل السجل إلى `review_required`.

اضبط الاستدعاءات لكل متجر واقرأ ترويسات الحد الفعلية. تذكر وثائق Rate Limits أن الحدود تختلف حسب باقة المتجر، وتعرض `X-RateLimit-Limit` و`X-RateLimit-Remaining` و`Retry-After` و`X-RateLimit-Reset`. يجب أن يبطئ المجدول قبل استنفاد حصة التاجر، ويحترم `Retry-After`، ويعطي أولوية لفحص الحالة قبل الإرسال على المسح التاريخي الأقل قيمة.

افصل الإرسال واجعله مقاومًا للتكرار وواعيًا بالموافقة

ضع Transactional Outbox بين مسار السلة ومزود الإرسال الخارجي. في معاملة قاعدة البيانات نفسها التي تنقل السلة إلى `scheduled`، أضف صفًا واحدًا بمفتاح Idempotency ثابت يتضمن المتجر والسلة وإصدار الحملة ورقم المحاولة. يحجز الـDispatcher الصف، ويستدعي المزود، ويحفظ معرف طلبه. إذا تعطل بعد الاستدعاء، فطابق بمعرف الطلب أو مفتاح Idempotency بدل إعادة الإرسال عميانيًا.

توفر القناة لا يعني وجود موافقة تسويقية. احفظ دليل الموافقة وغرض القناة ومصدرها والإلغاء بصورة مستقلة، وقلل نسخ البيانات الشخصية، واشفر بيانات اعتماد المزود. يثبت سر الـWebhook أن الطلب من سلة؛ لكنه لا يأذن برسالة ترويجية إلى العميل. طبّق سياسة التاجر والمتطلبات القانونية والتعاقدية للقناة المختارة.

ولا تقل في القالب إن المنتجات محجوزة إلا إذا كان المتجر يطبق الحجز فعلًا. قد تتغير الأسعار والمخزون والخصومات. الرسالة الأكثر أمانًا تعيد العميل إلى السلة الحية، وتترك Checkout يعيد حساب التوفر والإجمالي.

اختبر مسار الإيقاف وقِس الضرر

المسار السعيد سهل. اختبر Webhooks مكررة وتوقيعًا خاطئًا وإعادة محاولة بعد ضياع استجابتك وأحداثًا بترتيب مختلف وشراءً أثناء تأخير الرسالة وشراءً بين القراءة الأخيرة واستدعاء المزود وانتهاء مهلة المزود بعد القبول وانتهاء بيانات الاعتماد وحدود الطلبات وWorkerين يحجزان السلة نفسها. وأسقط حدثًا عمدًا ثم شغل المطابقة.

راقب أكثر من التحويل. تشمل المقاييس المفيدة: فشل التوقيع، وتأخير صندوق الوارد إلى الـWorker، والأحداث المكررة الممنوعة، وفشل قراءة حالة السلة، والرسائل الملغاة بسبب الشراء، ومعدل الرسائل القديمة، والنتائج المجهولة لدى المزود، وعمق Dead Letter، وعدد القراءات لكل سلة مستعادة، والشكاوى أو إلغاء الاشتراك. التحويل بلا حارس يمنع الرسالة القديمة مقياس نجاح ناقص.

ابدأ بمرحلة Shadow: استقبل الأحداث، واقرأ السلات، واحسب الأهلية من دون إرسال. قارن الأفعال المتوقعة بنتائج السلات لاحقًا. ثم فعّل متجرًا واحدًا أو مجموعة صغيرة، وحدد المحاولات لكل سلة، واحتفظ بمفتاح إيقاف يعطل الإرسال من دون تعطيل جمع الحالة. التصميم الموثوق محافظ عمدًا: أحداث سلة توقظ المسار، وحالة السلة الحالية تقرر، وبوابة إيقاف دائمة تملك الكلمة الأخيرة.

المراجع الرسمية

تدعم هذه المراجع سلوك الأدوات المذكورة. الأمثلة وقرارات التصميم توضيحية، ويجب تكييفها مع متطلبات المشروع وإصداراته.

إعداد: Noor Yasser

من القرار إلى التنفيذ

تعمل على تحدٍ تقني مشابه؟

أساعد الفرق على تحويل القرار المعماري إلى نطاق واضح وتنفيذ يمكن تشغيله ومراجعته بثقة.

احجز لقاءً لمدة ٣٠ دقيقةالخدمة المرتبطةهندسة الأنظمة الخلفية وتكاملات APIمشروع من الأعمالمنصة اللوجستيات