الإشعارات

كل إشعار ينطلق من حدث يُكتب في صندوق الصادر (outbox) داخل معاملة قاعدة البيانات نفسها التي تُجري التغيير. لا يستدعي كود الطلبات أو الدفع أو التوصيل خدمة الإشعارات مباشرة، فلا يستطيع خادم بريد بطيء التراجع عن طلب مدفوع، ولا يضيع بريد طلبٍ تم حفظه بسبب تعطل مفاجئ.

القنوات ومزوّدو الخدمة

القناةالمزوّد
البريد الإلكترونيSMTP
الإشعارات الفوريةFirebase Cloud Messaging (رموز الأجهزة تسجلها التطبيقات)
الرسائل النصيةTwilio — وتحمل أيضًا رموز الدخول ورموز التسليم
داخل التطبيقبلا مزوّد: الإشعار المحفوظ هو نفسه التسليم، ويظهر في قائمة إشعارات الحساب.

القناة التي لا مزوّد مضبوطًا لها تُبقي إشعاراتها في الانتظار بدل إسقاطها. يوجد مزوّد «طرفية» للتطوير ويُرفض عند التشغيل في بيئة الإنتاج.

قواعد تحكم الإرسال

  • ساعات الهدوء. تؤجَّل الإشعارات الروتينية إلى صباح المستلم — تأخير لا إسقاط. أما العاجلة (فشل دفع، مهمة السائق التالية، استرجاع بنكي) فتُرسل في كل الأحوال.
  • التجميع. تُجمع التدفقات الكثيفة: البائع الذي لديه أربعون طلبًا يتلقى «40 طلبًا جديدًا» وليس أربعين إشعارًا.
  • اللغة. كل قالب متوفر بالعربية والإنجليزية. تُحدَّد اللغة من الجهاز، ثم من ملف المستخدم، ثم الإنجليزية.
  • التفضيلات. يستطيع المشتري تشغيل الإشعارات أو إيقافها لكل حدث وقناة.
  • القوالب. يستطيع المسؤول تعديل نص أي قالب من لوحة الإدارة (قوالب الرسائل).

ما يُرسل اليوم

يضم الكتالوج (المولَّد في docs/notifications.md) ‏33 قاعدة لـ32 حدثًا عبر ست فئات. رموز الدخول وإعادة تعيين كلمة المرور تُرسل بالبريد أيضًا.

المشتري

الحدثالقنواتساعات الهدوءتجميعالرسالة
order.placedEMAIL · IN_APPتُرسل دائمًافرديةتأكيد الطلب
order.paidEMAIL · IN_APPتُرسل دائمًافرديةاستلام الدفع
order.payment_failedPUSH · EMAIL · IN_APPتُرسل دائمًافرديةمشكلة في الدفع
order.shippedPUSH · EMAIL · IN_APPتؤجَّل للصباحمجمّعةالطلب في الطريق
delivery.out_for_deliveryPUSH · IN_APPتُرسل دائمًافرديةالوصول قريبًا مع الوقت المتوقع
delivery.otp_issuedSMS · IN_APPتُرسل دائمًافرديةرمز التسليم الخاص بك
delivery.completedPUSH · IN_APPتؤجَّل للصباحمجمّعةتم التسليم
delivery.failedPUSH · SMS · IN_APPتُرسل دائمًافرديةتعذّر التسليم
order.cancelledEMAIL · IN_APPتؤجَّل للصباحفرديةأُلغي الطلب
refund.settledEMAIL · IN_APPتؤجَّل للصباحفرديةأُرسل المبلغ المسترد
ticket.repliedPUSH · EMAIL · IN_APPتؤجَّل للصباحفرديةردّ الدعم

البائع

الحدثالقنواتساعات الهدوءتجميعالرسالة
order.group_placedPUSH · EMAIL · IN_APPتُرسل دائمًامجمّعةطلب جديد
order.accept_deadline_missedPUSH · EMAIL · IN_APPتُرسل دائمًافرديةطلب تجاوز مهلة القبول
payout.paidEMAIL · IN_APPتؤجَّل للصباحفرديةأُرسلت الدفعة
review.publishedIN_APPتؤجَّل للصباحمجمّعةتقييم جديد
catalog.product_rejectedEMAIL · IN_APPتؤجَّل للصباحمجمّعةلم يُعتمد المنتج

السائق

الحدثالقنواتساعات الهدوءتجميعالرسالة
delivery.task_assignedPUSHتُرسل دائمًافرديةمهمة جديدة
delivery.task_reassignedPUSH · IN_APPتُرسل دائمًافرديةأُعيد إسناد المهمة
driver.earning_recordedIN_APPتؤجَّل للصباحمجمّعةسُجّل لك ربح

الإدارة والمالية والدعم

الحدثالقنواتساعات الهدوءتجميعالرسالة
order.accept_deadline_missedEMAIL · IN_APPتُرسل دائمًامجمّعةطلب بلا رد
payment.chargeback_openedEMAIL · IN_APPتُرسل دائمًافرديةفُتح استرجاع بنكي
seller.application_submittedIN_APPتؤجَّل للصباحمجمّعةبائعون بانتظار الاعتماد
review.flaggedIN_APPتؤجَّل للصباحمجمّعةتقييمات تحتاج مراجعة
cod.settlement_discrepancyEMAIL · IN_APPتُرسل دائمًامجمّعةعجز في تسوية الدفع عند الاستلام
ticket.sla_breachedEMAIL · IN_APPتُرسل دائمًافرديةتجاوز مهلة الدعم
مُدرجة في الكتالوج ولم تُفعَّل بعد

لهذه الأحداث قوالب، لكن لا شيء في الكود يطلقها حتى الآن، فلا تُرسل أبدًا: inventory.low_stock وmessage.received وticket.opened وorder.accept_deadline_near وledger.reconciliation_failed وdelivery.cash_limit_near.

التتبع المباشر

قناة فورية (Socket.IO على المسار /realtime) تتيح للمشتري الاشتراك في طلبه وتلقي تحديثات موقع السائق، وتتيح للمرسِلين الاشتراك في الأسطول. وتُرجع GET /tracking/orders/{orderNumber} آخر موقع معروف ووقت الوصول المتوقع. لا يرسل تطبيق السائق إشارات الموقع بعد، لذا لا تتدفق المواقع فعليًا حاليًا.