كل إشعار يمر عبر دالة واحدة، notify() في src/lib/notify، وهي توزّعه على القنوات أدناه. كل قناة اختيارية: إن غابت مفاتيحها لا تفعل شيئاً وتستمر القنوات الأخرى. يبقى البريد عند من يستدعيها (site/booking/notify.ts) لأنها تملك قالبه.
| القناة | من يستلمها | ما تحتاجه |
|---|---|---|
| صندوق الإشعارات | الحسابات المسجّلة — الضيوف أصحاب الحسابات والفريق | لا شيء — مفعّلة دائماً |
| إشعار الهاتف (Web Push) | كل متصفح أو هاتف فعّله الشخص، والهواتف التي فعّلها الضيف من صفحة حجزه (دون حساب) | VAPID_PUBLIC_KEY وVAPID_PRIVATE_KEY وVAPID_SUBJECT |
| واتساب | رقم هاتف الحجز، وأعضاء الفريق الذين لهم رقم واتساب في حساباتهم | مفاتيح Meta Cloud API أو Evolution API (أدناه) |
| البريد | بريد الحجز، وكل مدير وكاشير نشط | RESEND_API_KEY |
ما الذي يرسل ماذا
| الحدث | الضيف | فريق الاستقبال (مدير + كاشير) | فريق المقهى (كل الفريق) |
|---|---|---|---|
| أُرسل الطلب · السعر جاهز · تأكّد الحجز · وصل التحويل · لم يُطابَق الدفع · أُلغي (من سبيس أو من الضيف) · انتهت مهلة الطلب · تغيّر الموعد | صندوق · هاتف · واتساب · بريد | — | — |
| تذكير قبل الموعد بيوم (مهمة كل ساعة، لا ترسل بين 22:00 و07:00، مرة لكل حجز) | صندوق · هاتف · واتساب · بريد | — | — |
| طلب جديد، حجز مؤكد فوراً، تحويل للمراجعة، إلغاء من الضيف | — | صندوق · هاتف · واتساب · بريد | — |
| طلب مقهى جديد عبر QR | — | — | صندوق · هاتف |
إشعارات الفريق بالعربية وتفتح الحجز في لوحة التحكم. إشعارات الضيف بلغة الحجز وتفتح صفحة حجزه.
الأسلوب. كل إشعار مكتوب كما تكتب Airbnb إشعاراتها: جملة واحدة واضحة تحمل الخبر كله — ماذا وأين ومتى — مثل «كل شيء جاهز: قاعة اجتماعات، الأحد، 11 أكتوبر، 10:00 ص – 12:00 م. نراك في سبيس!». هذه الجملة هي سطر الصندوق ونص إشعار الهاتف ومقدّمة البريد، ويتصدّر العنوان القصير («تأكّد حجزك») إشعار الهاتف والبريد. النصوص في booking.json ← email وnotifications.json ← cafe.
صندوق الإشعارات
يحاكي إشعارات Airbnb على الويب. لا جرس في الرأس: ما دام هناك غير مقروء، يحمل زر الحساب نقطة حمراء صغيرة (--alert، لون Airbnb)، وفي قائمة الحساب الإشعارات مع عدد أحمر. وزر القائمة على الهاتف يحمل النقطة نفسها. الصفحة — /notifications للضيوف و/dashboard/notifications للفريق (src/components/notifications/inbox.tsx) — عنوان ثم صف لكل إشعار: علامة سبيس الدائرية، والجملة (عريضة ما دامت غير مقروءة، رمادية بعد القراءة)، والتاريخ كاملاً تحتها، و✕ لإزالتها. فتح الصفحة يعلّم الكل مقروءاً، وحين تكون فارغة تقول «لا إشعارات بعد».
مخزن واحد (feed.ts) يقرأ /api/notifications لكل المؤشرات في الصفحة — كل دقيقة ما دامت ظاهرة، وعند كل تنقّل، ولحظة وصول إشعار. الزائر غير المسجّل يتلقى ردّ 401 واحداً لكل تنقّل دون تكرار، وتُظهر أيقونة التطبيق المثبّت عدد غير المقروء حيث يدعم الهاتف ذلك.
الإشعار على الهاتف
public/sw.jsيعرض الإشعار ويفتح رابطه عند الضغط. (ويحفظ أيضاً واجهة التطبيق لتعمل دون اتصال — راجعsrc/components/pwa.)- يشترك المتصفح بالمفتاح العام من
GET /api/push، ثم يحفظPOST /api/pushالاشتراك باسم الحساب المسجّل و/أو رمز الحجز. src/lib/notify/web-push.tsيوقّع VAPID ويشفّر المحتوى (RFC 8291) بـ WebCrypto فقط، فيعمل على Worker. الاشتراكات التي تعلن خدمة الإشعارات انتهاءها (404/410) تُحذف.- آيفون: يسمح سفاري بالإشعارات فقط بعد إضافة سبيس إلى الشاشة الرئيسية وفتحه منها. يشرح زر التفعيل ذلك للمستخدم.
- الهاتف الذي فعّل الإشعارات يتبع آخر صفحة حجز فتحها — فتح حجز جديد يحوّله إليه.
ولّد المفاتيح مرة لكل بيئة بالأمر pnpm push:keys. تغيير المفاتيح يُبطل كل الاشتراكات الحالية.
واتساب
المفعّل الآن: رقم سبيس نفسه، +249 909 199 383، كجهاز مرتبط (Evolution). الجسر هو عملية Evolution التي تعمل أصلاً داخل حاوية hogwarts (مشتركة منذ 2026-10-25، فلا يدفع سبيس ثمن حاوية خاصة به)، بلا رابط عام: يصل إليه Worker سبيس عبر ربط الخدمة WHATSAPP الموجَّه إلى المدخل الخاص WhatsappBridge في hogwarts. لسبيس نسخته الخاصة باسم space. جلسته محفوظة في قاعدة Neon لـ hogwarts باسم evolution، فإن أُعيد تشغيل الحاوية عاد الاتصال دون رمز جديد. اربط الهاتف أو أعد ربطه من الإدارة ← واتساب (للمدير): امسح الرمز من واتساب ← الأجهزة المرتبطة، أو اكتب الرمز المكوّن من 8 أحرف بعد «الربط برقم الهاتف بدلاً من ذلك». الصفحة نفسها ترسل رسالة تجريبية وتفك الربط. وأزرار واتساب في الموقع تفتح محادثة مع SPACE_WHATSAPP.
مزوّدان، وتُقدَّم Meta إن ضُبط الاثنان.
- Meta WhatsApp Cloud API (الرسمي):
WHATSAPP_TOKENوWHATSAPP_PHONE_NUMBER_IDوWHATSAPP_TEMPLATE(الافتراضيspace_notice). الرسائل التي يبدأها سبيس يجب أن تستخدم قالباً معتمداً من فئة Utility فيه متغيّر واحد، مثلسبيس: {{1}}، معتمداً بالعربية والإنجليزية. يحتاج نشاطاً تجارياً موثّقاً لدى Meta ورقماً مسجّلاً في منصة واتساب للأعمال. - Evolution API (مستضاف ذاتياً، يربط رقم واتساب عادياً بمسح QR كما في hogwarts):
EVOLUTION_API_URLوEVOLUTION_API_KEYوEVOLUTION_INSTANCE. يرسل نصاً حراً لكنه غير رسمي — قد يحظر واتساب الرقم.
تُحوَّل الأرقام إلى الصيغة الدولية، والسودان (+249) هو الافتراضي: 0912345678 تصبح 249912345678. يضبط أعضاء الفريق أرقامهم من الإدارة ← الفريق، أو من صفحة حسابهم.
البيانات
Notification (صف لكل مستلم، العنوان والنص بلغته) وPushSubscription (العنوان والمفاتيح، يملكه userId أو bookingId). يُحذفان مع الحساب أو الحجز.