> ## Documentation Index
> Fetch the complete documentation index at: https://docs.logbrew.co/llms.txt
> Use this file to discover all available pages before exploring further.

# إرشادات إعداد التقاط الأحداث في Node.js

> أرسل أحداث منتج مصنَّفة مع مستخدمين وجلسات محددة النوع من Node.js. شغّل اختبار التقاط محليًا، ثم اقرأ النتائج باستخدام CLI.

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

لقواعد العدّ وأنواع التقارير، راجع
[تحليلات المنتج](/ar/concepts/product-analytics).

## جهّز الاختبار

استخدم تطبيق Node.js بالإصدار 18 أو أحدث، ومشروع LogBrew تستطيع قراءته. إذا
لم ترسل بيانات قياس عن بُعد من قبل، فابدأ من [البدء السريع](/ar/quickstart).
أبقِ هذا الاختبار منفصلًا عن نشاط العملاء.

ثبّت الحزم في مجلد التطبيق:

```bash theme={null}
npm install @logbrew/sdk@0.1.28 @logbrew/node@0.1.12
```

استخدم مفتاح استيعاب للخادم خاصًا بالمشروع. احفظه في `LOGBREW_SERVER_API_KEY`،
خارج نظام التحكم في المصدر. لا تضع أبدًا مفتاح خادم في حزمة المتصفح. رمز وصول
الحساب المميز يقرأ النتائج، ولا يضبط الـ SDK.

## حدّد معنى الحدث الواحد

ابدأ بسؤال عن المنتج. مثلًا: هل يرسل المستخدمون نموذج إتمام الشراء بعد أن يفتحوه؟
أعطِ كل حدث اسمًا ثابتًا ومحفّزًا محددًا تمامًا ومكانًا واحدًا في التطبيق يدوّنه.

| اسم الحدث | المحفّز |
| - | - |
| `checkout.opened` | يفتح التطبيق صفحة إتمام الشراء. هذا ليس شراءً. |
| `checkout.submitted` | يقبل التطبيق إجراء الإرسال. هذا ليس دفعًا ناجحًا. |
| `checkout.completed` | يؤكد التطبيق الإتمام. لا تدوّنه عند كل نقرة أو إعادة محاولة على الشبكة. |

أبقِ أسماء الأحداث ثابتة عبر الإصدارات واللغات. لا تبنِ الأسماء من عنوان بريد
إلكتروني أو رقم طلب أو URL أو نص يدخله المستخدم.

استخدم خصائص مخصصة بمجموعة صغيرة من القيم المعتمدة. مثلًا، يمكن أن تكون قيمة
`checkout_mode` هي `guest` أو `signed_in`. لا تضف اسم حدث جديدًا لكل قيمة.
لا ترسل محتويات النماذج.

دوّن كل إجراء تجاري في مكان واحد فقط. إذا دوّن المتصفح والخادم الإجراء نفسه،
فستتضاعف المجاميع.

## استخدم نوع النشاط الصحيح

| النوع | المعنى | طريقة الالتقاط |
| - | - | - |
| `interaction` | إجراء منتج يحدده التطبيق. | `createProductActionAttributes`، كما هو موضح أدناه. |
| `page_view` | مشاهدة صفحة في المتصفح. | التقاط مشاهدات الصفحات في SDK المتصفح. |
| `screen_view` | مشاهدة شاشة في التطبيق. | دالة مساعدة لمشاهدات الشاشات على الهاتف المحمول. |

تضبط `createProductActionAttributes` القيمتين `analyticsSchemaVersion: 1`
و`analyticsKind: "interaction"` في البيانات الوصفية للحدث. ويضبط قالب المسار
أو اسم الشاشة فيها `analyticsSurface`. استخدم قالب مسار، مثل
`/orders/:id`، لا URL فعليًا.

اسم الحدث لا يحدد النوع. التفاعل المسمى `page_view` يبقى تفاعلًا. السجلات
والمشكلات والـ Spans ليست أحداث منتج. لبيئات التشغيل الأخرى، راجع
[دمج SDK](/ar/guides/sdk-ingestion).

## <span id="set-users-and-sessions-on-each-event">اضبط المستخدم والجلسة في كل حدث</span>

* للمستخدم الذي سجّل الدخول، اضبط `context.subject` على معرّف ثابت مع
  `kind: "user"`.
* للزائر المجهول الهوية، استخدم معرّفًا منفصلًا مع `kind: "anonymous"`.
* ضع معرّف الجلسة الخاص بالتطبيق في `context.session.id`. وأعد استخدامه طوال
  الجلسة.

لا تستخدم أبدًا الأسماء أو عناوين البريد الإلكتروني أو عناوين IP أو رموز الوصول
المميزة معرّفاتٍ. يربط المعرّف الثابت إجراءات المستخدم ببعضها، ولا يجعل البيانات
مجهولة الهوية.

لا تضبط مستخدمًا أو جلسة افتراضية على عميل خادم مشترك. مرّر الكيان والجلسة
الخاصين بالطلب الذي أنتج كل حدث. لا ينشئ الـ SDK هذه المعرّفات، ولا يكتشف
تسجيل الدخول أو تسجيل الخروج أو تبديل الحسابات. لا يدمج LogBrew الكيان مجهول
الهوية في المستخدم بعد تسجيل الدخول.

## شغّل المثال محليًا

احفظ هذا المثال باسم `product-events.mjs`. يدوّن 5 إجراءات تجريبية عبر زيارات
مجهولة الهوية وعمليات تسجيل دخول ومستخدمَين اثنين. لا يحمل العميل إلا سياق
الخدمة والنشر المشترك. التسليم التلقائي متوقف في هذا الاختبار.

```js theme={null}
import { randomUUID } from "node:crypto";
import { createProductActionAttributes, SdkError } from "@logbrew/sdk";
import { createLogBrewNodeClient } from "@logbrew/node";

try {
  const client = createLogBrewNodeClient({
    automaticDelivery: false,
    context: {
      schemaVersion: 1,
      resource: {
        service: { name: "analytics-check", version: "analytics@1" },
        deployment: { environment: "development", release: "analytics@1" }
      }
    }
  });
  const startedAt = new Date().toISOString();
  client.release(randomUUID(), startedAt, { version: "analytics@1" });
  client.environment(randomUUID(), startedAt, { name: "development" });

  function record(name, subject, sessionId) {
    client.action(randomUUID(), new Date().toISOString(), {
      ...createProductActionAttributes({
        name,
        routeTemplate: "/checkout",
        metadata: { checkout_mode: subject.kind === "user" ? "signed_in" : "guest" }
      }),
      context: { schemaVersion: 1, subject, session: { id: sessionId } }
    });
  }

  record("checkout.opened", { id: "anon_demo_a", kind: "anonymous" }, randomUUID());
  const userSession = randomUUID();
  record("checkout.submitted", { id: "user_demo_a", kind: "user" }, userSession);
  record("checkout.completed", { id: "user_demo_a", kind: "user" }, userSession);
  record("checkout.opened", { id: "anon_demo_b", kind: "anonymous" }, randomUUID());
  record("checkout.submitted", { id: "user_demo_b", kind: "user" }, randomUUID());

  if (process.argv.includes("--send")) {
    const response = await client.shutdown();
    console.log(JSON.stringify({
      mode: "sent",
      status_code: response.statusCode,
      attempts: response.attempts
    }));
  } else {
    const batch = JSON.parse(client.previewJson());
    const actions = batch.events.filter(event => event.type === "action");
    console.log(JSON.stringify({
      mode: "local_preview",
      actions: actions.length,
      kinds: [...new Set(actions.map(event => event.attributes.metadata.analyticsKind))],
      dropped: client.droppedEvents()
    }));
  }
} catch (error) {
  console.error(JSON.stringify({
    ok: false,
    error: error instanceof SdkError ? error.code : "capture_failed"
  }));
  process.exitCode = 1;
}
```

شغّل البرنامج النصي دون `--send`. لا يرسل هذا الأمر أي طلب:

```bash theme={null}
LOGBREW_SERVER_API_KEY=local-preview-only node product-events.mjs
```

المخرجات المتوقعة:

```json theme={null}
{"mode":"local_preview","actions":5,"kinds":["interaction"],"dropped":0}
```

علامتا الإصدار والبيئة ليستا إجراءات منتج. تعرض هذه النتيجة الطابور المحلي
فقط، ولا تثبت أن LogBrew استلم الأحداث. لا تطبع `previewJson()` في تطبيق فيه
سياق عملاء حقيقي.

## تعامل مع تسجيل الدخول وتسجيل الخروج

* قبل تسجيل الدخول، أرسل الكيان مجهول الهوية الحالي مع كل حدث.
* بعد تسجيل الدخول، أرسل المعرّف الثابت للمستخدم مع النوع `user`.
* عند تسجيل الخروج، توقف عن استخدام سياق ذلك المستخدم. وأنشئ كيانًا جديدًا
  مجهول الهوية وفق سياسة الخصوصية لديك.
* عند تبديل الحساب، استخدم معرّف المستخدم الجديد.

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

## أرسل مرة واحدة واقرأ النتائج

اضبط مفتاح الخادم الخاص بمشروع الاختبار في بيئة العملية. شغّل هذا الأمر مرة
واحدة:

```bash theme={null}
node product-events.mjs --send
```

كل تشغيل ينشئ معرّفات أحداث جديدة، لذا يضيف التشغيل الثاني 5 أحداث أخرى. إذا
فشلت العملية، فستحتوي المخرجات على رمز خطأ الـ SDK. المفتاح المرفوض يعطي:

```json theme={null}
{"ok":false,"error":"unauthenticated"}
```

تأكد من أن مفتاح الاستيعاب نشط وأنه يتبع مشروع الاختبار. تسجيل الدخول إلى حسابك
لا يصلح مفتاح SDK. راجع [أخطاء API](/ar/reference/api-errors)
و[استكشاف الأخطاء وإصلاحها](/ar/guides/troubleshooting) لحالات الفشل الأخرى.

بعد أن يقبل LogBrew الدفعة، اعثر على الأحداث في لوحة التحكم:

1. افتح **التحليلات**.
2. ضمن **المشروع**، اختر مشروع الاختبار.
3. ضمن **النطاق الزمني**، اختر **24 ساعة**.
4. اعثر على أسماء الأحداث الثلاثة ضمن **أبرز الأحداث**، وعلى `/checkout` ضمن
   **أبرز الواجهات**.

أي نشاط آخر في المشروع يغيّر هذه المجاميع. للتحقق من الخدمة والإصدار والبيئة
بدقة، اقرأ النظرة العامة باستخدام [CLI](/ar/guides/cli) بعد تسجيل الدخول:

```bash theme={null}
logbrew analytics overview --project "<project_id>" --since 1h \
  --service analytics-check --release analytics@1 \
  --environment development --json
```

لتشغيل واحد في نطاق خالٍ من أي نشاط آخر، توقّع:

* 5 تفاعلات، كلها مع سياق جلسة، على الواجهة `/checkout`.
* 3 أحداث من مستخدمين وحدثين من كيانات مجهولة الهوية.
* مستخدمَين اثنين وكيانين مجهولي الهوية و4 جلسات.

أعداد المستخدمين والكيانات والجلسات الفريدة تقريبية. مجاميع الأحداث دقيقة
ضمن النطاق الزمني المحدد. لا يقيس هذا الاختبار التحويل أو الاحتفاظ
بالمستخدمين.

| النتيجة | الفحص التالي |
| - | - |
| لا يوجد نشاط للمنتج | افحص نتيجة التسليم والمشروع والنطاق الزمني والخدمة والإصدار والبيئة. |
| النشاط غير مصنَّف | استخدم `createProductActionAttributes`. اسم الحدث وحده لا يحدد النوع. |
| أعداد المستخدمين مختلفة | افحص `context.subject` في كل حدث. الكيانات مجهولة الهوية لا تُحسب مستخدمين. |
| أعداد الجلسات مختلفة | افحص `context.session.id` في كل حدث، وافحص قاعدة الجلسات لديك. |
| الأحداث أكثر من المتوقع | تحقّق من تكرار التشغيل ومن إجراءات مدوَّنة في مكانين. |

## اختبر الأحداث في تطبيقك

انقل استدعاءات الالتقاط إلى معالجات التطبيق. حافظ على معنى كل حدث ونوعه وقاعدة
هويته. اختبر بحسابات اصطناعية أولًا.

| اختبار التطبيق | الالتقاط المتوقع |
| - | - |
| افتح صفحة إتمام الشراء دون إرسال | `checkout.opened` فقط. |
| أرسل نموذجًا يفشل في التحقق | لا يوجد `checkout.submitted`. لا ترسل محتويات النموذج أبدًا. |
| اقبل إرسالًا، ثم اجعل الدفع يفشل | `checkout.submitted`، ولا يوجد `checkout.completed`. |
| أعد محاولة طلب بعد إتمام مؤكَّد | لا يوجد `checkout.completed` ثانٍ. |
| سجّل الخروج، ثم استخدم حسابًا آخر | تستخدم الأحداث اللاحقة الكيان والجلسة الجديدين. |

المعاينة المحلية تختبر الالتقاط. والدفعة المقبولة تختبر التسليم. ولا تثبت أيٌّ
منهما أن استدعاء الالتقاط يعمل في الموضع الصحيح من تطبيقك.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.