تخطّ إلى المحتوى الرئيسي

تدفق البيانات

يوجّه تدفق البيانات الأحداث من Joryio إلى وجهات خارجية في وقت شبه حقيقي. يربط كل تدفق وجهةً بمجموعة من الأحداث، وتسلّم Joryio الأحداث المطابقة إلى تلك الوجهة على دفعات.

انتقل إلى البيانات → تدفق البيانات لإدارة تدفقاتك.

الوجهات​

الوجهةالنوعوظيفتها
Webhookنقطة نهاية HTTPأرسل كل حدث بطريقة POST كـ JSON إلى أي عنوان HTTPS
Snowflakeمستودع بياناتحمّل الأحداث باستمرار إلى جدول Snowflake
BigQueryمستودع بياناتابث الأحداث إلى مجموعة بيانات BigQuery
Amazon Redshiftمستودع بياناتحمّل الأحداث إلى عنقود Amazon Redshift
Amazon S3تخزين كائناتاكتب ملفات JSON / NDJSON مجمعة إلى حاوية
Kafkaتدفق أحداثانشر الأحداث إلى موضوع Kafka
Mixpanelتحليلات المنتجوجّه الأحداث إلى مشروع Mixpanel
Amplitudeتحليلات المنتجوجّه الأحداث إلى مشروع Amplitude

حقول الاتصال​

تطلب كل وجهة تفاصيل اتصالها الخاصة. تُشفّر الأسرار (كلمات المرور والمفاتيح والرموز المميزة وJSON حساب الخدمة وقيم ترويسات Webhook) أثناء التخزين ولا تُعرض مرة أخرى أبدًا - راجع بيانات اعتماد بأقل الصلاحيات.

  • Webhook - عنوان URL وسر التوقيع (اختياري) وترويسات إضافية (اختيارية، كائن JSON مثل {"Authorization": "Bearer <token>"}؛ تُعامَل قيمها كأسرار)
  • Snowflake - الحساب واسم المستخدم وكلمة المرور والدور (اختياري - الدور الذي تُنفَّذ به الاستعلامات؛ إذا كان فارغًا يُطبَّق الدور الافتراضي للمستخدم) وWarehouse وقاعدة البيانات وSchema والجدول
  • BigQuery - معرّف المشروع ومعرّف مجموعة البيانات ومعرّف الجدول وJSON حساب الخدمة
  • Amazon Redshift - المضيف والمنفذ وقاعدة البيانات والمستخدم وكلمة المرور وSchema والجدول
  • Amazon S3 - الحاوية والبادئة والمنطقة ونقطة النهاية (اختيارية، للتخزين المتوافق مع S3) ومعرّف مفتاح الوصول ومفتاح الوصول السري
  • Kafka - الوسطاء والموضوع واسم مستخدم/كلمة مرور SASL وSSL
  • Mixpanel - رمز المشروع والمنطقة (US / EU / India)
  • Amplitude - مفتاح API والمنطقة (US / EU)

بيانات اعتماد بأقل الصلاحيات​

امنح كل تدفق بيانات اعتماد خاصة به لا تستطيع إلا أمرًا واحدًا: الكتابة إلى الجدول أو مسار الحاوية أو الموضوع الذي يسلّم إليه التدفق. إذا تسرّبت بيانات الاعتماد يومًا، فهذا كل ما يمكن فعله بها - لا يمكنها قراءة بياناتك ولا المساس بأي شيء آخر. تستخدم الأمثلة أدناه أسماء توضيحية (example-bucket وanalytics.joryio_events وjoryio-events)؛ استبدلها بأسمائك.

كيف يتعامل Joryio مع بيانات الاعتماد المخزّنة​

  • مشفّرة. تُشفَّر كلمات المرور والمفاتيح والرموز المميزة وJSON حساب الخدمة وقيم ترويسات Webhook قبل تخزينها.
  • لا تُعرض مرة أخرى أبدًا. يعرض المحرر وواجهة API السر المخزّن على شكل ********. لا يستطيع أحد - بما في ذلك أنت وفريق Joryio - قراءته مجددًا في لوحة التحكم أو عبر API.
  • تبقى عند تعديل حقول أخرى. حقل السر الذي تتركه فارغًا (أو ********) يحتفظ بالقيمة المخزّنة؛ ولا يستبدلها إلا قيمة تكتبها. إعادة تسمية التدفق أو تغيير أحداثه لا تمس بيانات اعتماده أبدًا.
  • تُحذف مع التدفق. يؤدي حذف التدفق إلى حذف بيانات اعتماده المخزّنة. وعند حذف الحساب، تُمحى مع بقية بيانات الحساب.

عند حذف تدفق، ألغِ بيانات اعتماده أو غيّرها أيضًا لدى الوجهة: لم تعد لدى Joryio، لكن المفتاح نفسه يبقى صالحًا حتى تلغيه.

ترويسات Webhook أسرار أيضًا. أدخلها على شكل كائن JSON، مثل {"Authorization": "Bearer <token>"}. تبقى أسماء الترويسات ظاهرة؛ وتُشفَّر كل قيمة وتظهر على شكل ********. عند تعديل التدفق، اترك ******** للإبقاء على القيمة، أو اكتب قيمة جديدة لاستبدالها، أو أزل الترويسة لحذفها. استخدم رمزًا مميزًا صادرًا لـ Joryio وحده، حتى تتمكن من إلغائه دون التأثير في أي شيء آخر.

Amazon S3​

أنشئ مستخدم IAM (أو دورًا) لـ Joryio تكون صلاحيته الوحيدة s3:PutObject على حاوية التدفق وبادئته، واستخدم مفتاح الوصول الخاص به في التدفق. يكتب Joryio الكائنات تحت <prefix>/<date>/، لذا مع البادئة joryio-events:

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "JoryioWriteEvents",
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::example-bucket/joryio-events/*"
}
]
}

يتحقق اختبار الاتصال من وجود الحاوية، وهو ما لا يسمح به AWS إلا مع s3:ListBucket على الحاوية. تتيح هذه الصلاحية للمفتاح سرد أسماء الكائنات في الحاوية، لذا فهي اختيارية: بدونها يعمل التسليم ولا يُبلغ بالفشل إلا الاختبار. للسماح بالاختبار، أضف هذا البيان:

{
"Sid": "JoryioTestConnection",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example-bucket"
}

للتخزين المتوافق مع S3، أنشئ رمزًا مقيّدًا بالحاوية الواحدة مع صلاحية كتابة الكائنات فقط.

Amazon Redshift​

أنشئ مستخدم قاعدة بيانات مخصصًا لا يستطيع إلا الإدراج في جدول التدفق:

CREATE USER joryio_loader PASSWORD '<strong-password>';
GRANT USAGE ON SCHEMA analytics TO joryio_loader;
GRANT INSERT ON TABLE analytics.joryio_events TO joryio_loader;

أدخل joryio_loader في حقل المستخدم في التدفق.

Snowflake​

أنشئ دورًا لا يستطيع إلا الإدراج في جدول التدفق (إضافة إلى صلاحيات USAGE التي يحتاجها Snowflake للوصول إليه)، ومستخدمًا يملك هذا الدور:

CREATE ROLE JORYIO_WRITER;
GRANT USAGE ON WAREHOUSE LOAD_WH TO ROLE JORYIO_WRITER;
GRANT USAGE ON DATABASE ANALYTICS TO ROLE JORYIO_WRITER;
GRANT USAGE ON SCHEMA ANALYTICS.EVENTS TO ROLE JORYIO_WRITER;
GRANT INSERT ON TABLE ANALYTICS.EVENTS.JORYIO_EVENTS TO ROLE JORYIO_WRITER;

CREATE USER JORYIO_LOADER PASSWORD = '<strong-password>'
DEFAULT_ROLE = JORYIO_WRITER DEFAULT_WAREHOUSE = LOAD_WH;
GRANT ROLE JORYIO_WRITER TO USER JORYIO_LOADER;

أدخل JORYIO_LOADER في اسم المستخدم وJORYIO_WRITER في الدور. حقل الدور اختياري: عند تعيينه، ينفّذ Joryio كل استعلام بهذا الدور؛ وعندما يكون فارغًا، يُطبَّق الدور الافتراضي للمستخدم.

BigQuery​

أنشئ حساب خدمة لـ Joryio وامنحه BigQuery Data Editor (roles/bigquery.dataEditor) على مجموعة بيانات التدفق فقط - من إعدادات مشاركة مجموعة البيانات، لا على مستوى المشروع. ثم أنشئ له مفتاح JSON والصقه في JSON حساب الخدمة.

يرسل Joryio الصفوف عبر واجهة الإدراج في BigQuery ويقرأ البيانات الوصفية للجدول لاختبار الاتصال؛ ولا يشغّل أيٌّ منهما مهمة استعلام، لذا لا حاجة إلى BigQuery Job User. تتيح صلاحية Data Editor على مجموعة بيانات تعديل جداول أخرى فيها أيضًا، لذا ضع جدول التدفق في مجموعة بيانات خاصة به، أو امنح دورًا مخصصًا يقتصر على bigquery.tables.get وbigquery.tables.updateData على الجدول.

Kafka​

أنشئ مستخدم SASL لـ Joryio (يصادق Joryio باستخدام SASL/PLAIN) واسمح له فقط بـ WRITE وDESCRIBE على موضوع التدفق. أنشئ الموضوع بنفسك مسبقًا - لا يحتاج Joryio إلى صلاحية إنشاء المواضيع.

kafka-acls --bootstrap-server <broker:port> --command-config admin.properties \
--add --allow-principal User:joryio \
--operation Write --operation Describe \
--topic joryio-events

Mixpanel وAmplitude وWebhooks​

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

إنشاء تدفق​

  1. انتقل إلى البيانات → تدفق البيانات وانقر إنشاء تدفق.
  2. سمِّ التدفق (يظهر في قائمة التدفقات) واختر وجهة.
  3. املأ حقول الاتصال الخاصة بالوجهة.
  4. اختر تنسيق الحمولة: JSON (كائن واحد لكل حدث) أو NDJSON (سطر لكل حدث).
  5. حدد الأحداث التي تريد بثها (انظر أدناه).
  6. راجع شريط الملخص وانقر إنشاء تدفق.

اختيار الأحداث​

أنت تتحكم بدقة في الأحداث التي يستقبلها التدفق:

  • All events - فعّله لبث كل حدث حالي ومستقبلي. أوقفه لاختيار أحداث محددة.
  • الرسائل، حسب القناة - تُختار أحداث الرسائل لكل قناة على حدة (راجع الاختيار حسب القناة).
  • مجموعات أخرى - In-App والرحلات والحملات وبطاقات Wallet والتجارة الإلكترونية والهوية. حدد مجموعة كاملة أو أحداثًا منفردة.
  • الأحداث المخصصة - ضمن Custom Event، ابحث عن أحداثك أو اكتبها (تلك التي ترسلها باستخدام track()، مثل purchase أو page_view). تعرض القائمة الأحداث التي سجلتها مساحة العمل فعلًا؛ ويمكنك أيضًا كتابة حدث لم يُسجَّل بعد والنقر على Add.

الاختيار حسب القناة​

يعرض المحرر قسمًا لكل قناة - البريد الإلكتروني وSMS وWhatsApp والإشعارات وViber وWebhook - ولا يضم إلا الأحداث الموجودة في تلك القناة (لا يوجد "فتح SMS"). داخل كل قسم تُجمَّع الأحداث هكذا:

المجموعةالخيارات
التفاعلإرسال، تسليم، فتح (البريد الإلكتروني)، قراءة (WhatsApp)، نقرة
المشكلاتارتداد، تحديد كبريد عشوائي، فشل، لم تُرسل، تأجيل، رد تلقائي (البريد الإلكتروني)
الموافقةإلغاء الاشتراك، اشتراك
الواردةرسالة واردة (SMS و WhatsApp و Viber)

لكل قسم مربع تحديد الكل خاص به، ويحدد تحديد الكل في كل القنوات كل شيء دفعة واحدة. بجانب كل خيار يظهر الحجم الشهري التقديري - عدد هذه الأحداث التي سجلتها مساحة العمل في آخر 30 يومًا - لترى قبل الحفظ ما سيكلفه الاختيار لوجهتك.

يحمل الإرسال والتسليم والفتح علامة حجم كبير: كل منها صف واحد لكل رسالة. يبدأ التدفق الجديد بتحديد كل الخيارات الأخرى، وتُترك هذه الثلاثة لتضيفها بنفسك.

لا يتغير تنسيق البيانات. تحديد التسليم تحت SMS يبث الحدث المعتاد message.delivered الذي تكون خاصية channel فيه sms - وهو الاسم والقيم نفسها التي يستخدمها مخزن الأحداث و REST API وتكاملات Webhook. وتحتفظ الردود الواردة بأسمائها: sms.message.received و whatsapp.message.received و viber.message.received.

لا يزال بإمكان التدفق المُنشأ عبر الـ API اختيار حدث رسالة بالاسم ("events": ["message.delivered"]، مع إمكانية التضييق عبر "channels"). يستمر ذلك في العمل، ويعرضه المحرر كالحدث نفسه محددًا في كل قناة يغطيها.

تغيير حالة الاشتراك​

يحتوي قسم الاشتراكات على خيار واحد، تغيير حالة الاشتراك: كل اشتراك وإلغاء اشتراك في كل قناة وقائمة. يبث حدثي الموافقة اللذين تسجلهما Joryio بالفعل، فلا يُحتسب شيء مرتين:

  • message.subscribed - اشترك شخص في قناة أو قائمة. يوضح status و previousStatus التغيير، و scope هو channel أو list (مع listId)، و source يوضح كيف حدث ذلك (api و dashboard و preference_center و double_opt_in و keyword والاشتراك من متجر أو نموذج وغير ذلك).
  • message.unsubscribed - ألغى شخص اشتراكه. scope هو channel أو list أو global، و reason يوضح طريقة الوصول (link و keyword ...)، و unsubscribeSource يحدد المسار الدقيق (زر إلغاء الاشتراك في تطبيق البريد، زر الصفحة، مركز التفضيلات، رد STOP).

الارتدادات وشكاوى البريد العشوائي أحداث مستقلة (message.bounced و message.spamreport). استيراد جهات الاتصال ومزامنة مستودع البيانات والمزامنة الأولى للمتجر تكتب الموافقة بشكل جماعي ولا تُصدر هذه الأحداث.

إيصالات التسليم​

تقارير التسليم والارتدادات وشكاوى البريد العشوائي وإلغاء الاشتراك والرسائل التي لم ترسلها Joryio هي إيصالات (receipts). اخترها مثل أي حدث رسالة آخر، وتصل كالأحداث التالية:

الحدثالقنواتخصائص بارزة
message.deliveredالبريد الإلكتروني، SMS، Viber، الإشعارات، WhatsAppmessageId و campaignId و canvasId
message.bouncedالبريد الإلكترونيbounceType (hard أو soft) و bounceSubType و dsnStatus و reason
message.spamreportالبريد الإلكترونيmessageId و campaignId
message.failedكل القنواتerrorCode و errorReason
message.skippedكل القنواتreason - سبب عدم الإرسال (حظر، حد التكرار، الموافقة، ساعات الهدوء)
message.deferredالبريد الإلكترونيالمزوّد يعيد المحاولة بعد فشل مؤقت
message.auto_repliedالبريد الإلكترونيرد غياب تلقائي - تم تسليم البريد
message.unsubscribedكل القنواتراجع تغيير حالة الاشتراك
message.opened (القناة whatsapp)WhatsAppإيصال القراءة
sms.message.received و whatsapp.message.received و viber.message.receivedSMS و WhatsApp و Viberرد وارد؛ في SMS و Viber تكون keyword هي stop أو start أو help عندما يكون الرد كلمة امتثال

تصل الإيصالات إلى تدفق البيانات فقط. لا تبدأ أي رحلة ولا تُشغِّل أي حملة، تمامًا كما كان من قبل.

التدفقات المُنشأة قبل توفر الإيصالات

قد يحدد تدفق محفوظ قبل وجود الإيصالات بعضًا منها مسبقًا (مثل message.bounced). لم تصل هذه أبدًا، ولن تبدأ بالوصول من تلقاء نفسها: يعرض التدفق إيصالات التسليم متاحة الآن، وتبدأ بالتدفق بمجرد حفظ التدفق مرة أخرى. تستقبل التدفقات الجديدة الإيصالات منذ البداية.

ما يحتويه حدث الرسالة المبثوث​

  • يحمل كل حدث معرّف جهة الاتصال في Joryio (userId)، وتحمل أحداث الرسائل أيضًا externalId لجهة الاتصال عند وجوده.
  • تُضمَّن عناوين البريد الإلكتروني وأرقام الهواتف فقط عندما يملك آخر من حفظ التدفق صلاحية pii:view (يملكها Admin و Owner دائمًا). وإلا فإنها تُزال. حفظ التدفق مرة أخرى يطبق القاعدة على من يحفظه.
  • لا يُضمَّن محتوى الرسالة (النص، العنوان، HTML) في أي إيصال.
  • لا تُحذف عمليات الفتح والنقر التي تبدو آلية (ماسحات الأمان، خوادم خصوصية البريد)؛ بل تحمل $is_bot: true لتقرر أنت ما تفعله بها.

مجموعات الأحداث الأخرى​

المجموعةالأحداث
In-Appin_app.displayed و in_app.clicked و in_app.dismissed و in_app.converted
الرحلاتcanvas.experiment.entered و canvas.ai_decision.entered و canvas.step.entered و canvas.step.left
الحملاتcampaign.sent و campaign.abtest.winner_declared و campaign.ai_decision.entered
بطاقات Walletpass.issued و pass.installed و pass.updated و pass.update_pushed و pass.removed و pass.voided و pass.expired و pass.scanned
التجارة الإلكترونيةOrder Completed و Order Refunded و Order Cancelled
الهوية$identify و $alias

يمكنك أيضًا بث أي حدث مخصص ترسله باستخدام track().

التجميع في دفعات​

تُخزن الأحداث مؤقتًا وتُسلّم على دفعات. يمكنك ضبط:

  • حجم الدفعة - عدد الأحداث المتراكمة قبل الإرسال.
  • فاصل الإرسال - أطول مدة انتظار قبل إرسال دفعة جزئية.

تُسلّم الدفعة عند بلوغ حجم الدفعة أو انقضاء فاصل الإرسال، أيهما يحدث أولًا.

آلية العمل​

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

عندما يطابق حدث اختيار أحداث التدفق، يُوضع في الطابور ويُسلّم إلى الوجهة في الدفعة التالية. يتضمن كل تسليم اسم الحدث وخصائصه وطابعه الزمني ومعرّف المستخدم، وقناة المصدر لأحداث الرسائل. تحمّل وجهات مستودعات البيانات والتخزين الدفعة كصفوف/ملفات، وتوجّه وجهات تحليلات المنتج كل حدث عبر API الإدخال، وتتلقى Webhooks نص JSON أو NDJSON.

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

ضمانات التسليم والتكرارات​

التسليم مرة واحدة على الأقل (at-least-once). في حالات نادرة - إعادة محاولة بعد فشل شبكة، أو إعادة تشغيل عامل في منتصف دفعة - قد يُسلَّم الحدث نفسه إلى وجهتك أكثر من مرة.

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

كل حدث يحمل eventId ثابتًا. وهو القيمة نفسها في كل تسليم لذلك الحدث، فيمكنك استخدامه لإزالة التكرار:

الوجهةما نقوم به
Amplitudeيُرسل كـ insert_id - يزيل Amplitude التكرار تلقائيًا
Mixpanelيُرسل كـ $insert_id - يزيل Mixpanel التكرار تلقائيًا
S3الدفعة المُعاد تسليمها تُكتب على مفتاح الكائن نفسه، فتستبدل بدل أن تضيف ملفًا ثانيًا
BigQuery, Snowflake, Redshiftأزل التكرار حسب eventId عند التحميل، مثل ROW_NUMBER() OVER (PARTITION BY eventId)
Webhookتجاهل أي eventId سبق أن عالجته

بالنسبة لمستودعات البيانات والتخزين، التكرارات غير ضارة بعد إزالتها عند التحميل. أما webhooks التي تنفّذ إجراءً على كل حدث - إنشاء تذكرة، خصم مبلغ - فتحقق من eventId قبل التنفيذ.

المراقبة​

تعرض قائمة التدفقات مؤشرات الأداء والحالة لكل تدفق:

  • نشط - يُسلّم بصورة طبيعية
  • متوقف مؤقتًا - متوقف مؤقتًا (يمكن استئنافه في أي وقت)
  • خطأ - تفشل عمليات التسليم الأخيرة (تحقق من الاتصال)

يمكنك أيضًا رؤية إجمالي ما تم تسليمه وإجمالي ما فشل ومعدل التسليم ووقت آخر تسليم. افتح تدفقًا لعرض صفحة التفاصيل أو تعديله أو إيقافه/استئنافه أو حذفه.