RFC-002: نظام الإشعارات
| الحقل | القيمة |
|---|---|
| الحالة | 📋 مسودة |
| المؤلف | فريق التطوير |
| تاريخ الإنشاء | 2025-01-01 |
| آخر تحديث | 2025-01-01 |
الملخص
إنشاء نظام إشعارات موحد وقابل للتوسع يدعم قنوات متعددة (Push, SMS, WhatsApp, Email) مع إمكانية التخصيص والجدولة.
الدافع
الوضع الحالي
الإشعارات موزعة في الكود:
- WhatsApp عبر Twilio (محدود)
- SMS للـ OTP فقط
- لا يوجد Push Notifications
- لا يوجد Email
المشاكل
-
التجزئة:
- منطق الإشعارات موزع
- صعوبة الصيانة
- تكرار الكود
-
القصور:
- لا تذكير بالرحلات
- لا إشعارات للتحديثات
- لا إشعارات للعروض
-
عدم التتبع:
- لا نعرف نسبة التسليم
- لا تحليلات للإشعارات
التصميم المقترح
البنية العامة
┌─────────────────────────────────────────────────────┐
│ Notification Service │
├─────────────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Template │ │ Scheduler│ │ Analytics│ │
│ │ Engine │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────┐ │
│ │ Push │ │ SMS │ │ WhatsApp │ │Email│ │
│ │ Provider │ │ Provider │ │ Provider │ │Prov.│ │
│ └──────────┘ └──────────┘ └──────────┘ └─────┘ │
└─────────────────────────────────────────────────────┘
نموذج البيانات
-- قوالب الإشعارات
CREATE TABLE notification_templates (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
code VARCHAR(100) UNIQUE NOT NULL,
name_ar VARCHAR(255) NOT NULL,
name_en VARCHAR(255),
channels notification_channel[] NOT NULL,
subject_ar TEXT,
subject_en TEXT,
body_ar TEXT NOT NULL,
body_en TEXT,
variables JSONB DEFAULT '[]',
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- القنوات المدعومة
CREATE TYPE notification_channel AS ENUM (
'push',
'sms',
'whatsapp',
'email'
);
-- سجل الإشعارات
CREATE TABLE notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
template_id UUID REFERENCES notification_templates(id),
recipient_type VARCHAR(50) NOT NULL, -- 'passenger', 'company_user', 'admin'
recipient_id UUID NOT NULL,
channel notification_channel NOT NULL,
status notification_status NOT NULL DEFAULT 'pending',
content JSONB NOT NULL,
scheduled_at TIMESTAMPTZ,
sent_at TIMESTAMPTZ,
delivered_at TIMESTAMPTZ,
read_at TIMESTAMPTZ,
failed_at TIMESTAMPTZ,
error_message TEXT,
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- حالات الإشعار
CREATE TYPE notification_status AS ENUM (
'pending', -- بانتظار الإرسال
'scheduled', -- مجدول
'sending', -- قيد الإرسال
'sent', -- تم الإرسال
'delivered', -- تم التسليم
'read', -- تم القراءة
'failed' -- فشل
);
-- تفضيلات المستخدم
CREATE TABLE notification_preferences (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_type VARCHAR(50) NOT NULL,
user_id UUID NOT NULL,
channel notification_channel NOT NULL,
enabled BOOLEAN DEFAULT true,
quiet_hours_start TIME,
quiet_hours_end TIME,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(user_type, user_id, channel)
);
-- اشتراكات Push
CREATE TABLE push_subscriptions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_type VARCHAR(50) NOT NULL,
user_id UUID NOT NULL,
platform VARCHAR(20) NOT NULL, -- 'web', 'ios', 'android'
token TEXT NOT NULL,
device_info JSONB,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
أنواع الإشعارات
| الكود | الوصف | القنوات |
|---|---|---|
booking_confirmed | تأكيد الحجز | Push, SMS, WhatsApp |
booking_cancelled | إلغاء الحجز | Push, SMS, WhatsApp |
trip_reminder_24h | تذكير قبل 24 ساعة | Push |
trip_reminder_2h | تذكير قبل ساعتين | Push, SMS |
trip_delayed | تأخير الرحلة | Push, SMS, WhatsApp |
trip_cancelled | إلغاء الرحلة | Push, SMS, WhatsApp |
payment_received | استلام الدفعة | Push |
promo_offer | عرض ترويجي | Push, Email |
API
// خدمة الإشعارات
interface NotificationService {
// إرسال إشعار
send(notification: SendNotificationRequest): Promise<Notification>;
// إرسال مجمع
sendBulk(notifications: SendNotificationRequest[]): Promise<Notification[]>;
// جدولة إشعار
schedule(notification: ScheduleNotificationRequest): Promise<Notification>;
// إلغاء إشعار مجدول
cancel(notificationId: string): Promise<void>;
}
interface SendNotificationRequest {
templateCode: string;
recipientType: "passenger" | "company_user" | "admin";
recipientId: string;
channels?: NotificationChannel[];
variables?: Record<string, any>;
metadata?: Record<string, any>;
}
محرك القوالب
// مثال قالب
const template = {
code: "booking_confirmed",
body_ar: `
تم تأكيد حجزك!
رقم الحجز: {{booking_code}}
من: {{origin_city}}
إلى: {{destination_city}}
التاريخ: {{departure_date}}
الوقت: {{departure_time}}
نتمنى لك رحلة سعيدة! 🚌
`,
variables: [
"booking_code",
"origin_city",
"destination_city",
"departure_date",
"departure_time",
],
};
// الاستخدام
await notificationService.send({
templateCode: "booking_confirmed",
recipientType: "passenger",
recipientId: passengerId,
variables: {
booking_code: "SB-123456",
origin_city: "دمشق",
destination_city: "حلب",
departure_date: "15/01/2025",
departure_time: "08:00",
},
});
الجدولة
// جدولة تذكير
await notificationService.schedule({
templateCode: 'trip_reminder_24h',
recipientType: 'passenger',
recipientId: passengerId,
scheduledAt: subHours(tripDeparture, 24),
variables: { ... }
});
البدائل المدروسة
1. خدمات جاهزة (OneSignal, Firebase)
الإيجابيات:
- جاهز للاستخدام
- Dashboard مدمج
- تحليلات متقدمة
السلبيات:
- تكلفة مرتفعة
- اعتماد على طرف ثالث
- قد لا تعمل بشكل جيد في سوريا
2. النظام الحالي المحسّن
الإيجابيات:
- لا تغييرات كبيرة
- أسرع للتنفيذ
السلبيات:
- لا قابلية للتوسع
- لا تتبع
- صعوبة الصيانة
3. نظام مخصص (القرار المتخذ)
الإيجابيات:
- تحكم كامل
- قابل للتوسع
- مخصص لاحتياجاتنا
السلبيات:
- وقت تطوير أطول
- صيانة مستمرة
التأثير
قاعدة البيانات
- جداول جديدة:
notification_templates,notifications,notification_preferences,push_subscriptions
API
- خدمة إشعارات مستقلة
- Endpoints للتفضيلات
التطبيقات
- Web: Service Worker للـ Push
- Mobile: Firebase Cloud Messaging
- تفضيلات: شاشة إعدادات الإشعارات
الأمان والخصوصية
احترام التفضيلات
- لا إرسال بدون موافقة
- ساعات الهدوء
- إلغاء الاشتراك السهل
Rate Limiting
const rateLimits = {
sms: { max: 5, window: "1h" },
whatsapp: { max: 10, window: "1h" },
push: { max: 50, window: "1h" },
email: { max: 20, window: "1h" },
};
خطة التنفيذ
المرحلة 1: البنية الأساسية (2 أسابيع)
- تصميم قاعدة البيانات
- خدمة الإشعارات الأساسية
- محرك القوالب
المرحلة 2: قنوات الإرسال (2 أسابيع)
- Push (Firebase)
- SMS (Twilio)
- WhatsApp (Twilio)
المرحلة 3: الجدولة والتفضيلات (1 أسبوع)
- نظام الجدولة
- شاشة التفضيلات
- ساعات الهدوء
المرحلة 4: التحليلات (1 أسبوع)
- تتبع التسليم
- Dashboard
- تقارير
المقاييس
| المقياس | الهدف |
|---|---|
| نسبة التسليم | > 95% |
| وقت الإرسال | < 5 ثوانٍ |
| نسبة القراءة (Push) | > 30% |
| نسبة إلغاء الاشتراك | < 5% |
الأسئلة المفتوحة
- هل نحتاج إشعارات داخل التطبيق (in-app)?
- ما الحد الأقصى للإشعارات اليومية للمستخدم؟
- كيف نتعامل مع الفشل المتكرر؟