پرش به محتوا
مستندات
EN
ورود به پنل
شروع
  • نقشهٔ مستندات
  • راه‌اندازی سریع
  • مفهوم‌ها
جمع‌آوری داده
  • تعریف رویداد
  • فرهنگ‌نامهٔ رویدادها
  • گذاشتن رویداد
  • ادغام هویت
  • SDK وب
  • SDK اندروید
  • ثبت دستگاه
  • سرور به سرور
  • کاتالوگ محصولات
  • وب‌هوک
مخاطب و پیام‌رسانی
  • سگمنت
  • سناریو
  • پیام تراکنشی
  • رضایت و سقف
  • پیام درون‌برنامه‌ای
تحلیل و خروجی
  • گزارش و خروجی
مرجع توسعه‌دهنده
  • مرجع API
    • نقاط ورود داده
    • API مدیریتی
  • کدهای خطا
  • سقف‌ها
  • OpenAPI
ابزارهای توسعه
  • سرور MCP
  • کار با عامل
حریم خصوصی و تغییرات
  • داده‌های شخصی
  • نسخه و تغییرها

تعریف رویداد: چه چیزی بفرستیم و با چه نامی

قاعده نام‌گذاری، انتخاب ویژگی‌ها و ساخت یک tracking plan پایدار برای گزارش و سگمنت.

رویداد چیزی است که یک نفر انجام داد. اسم دارد، لحظه دارد، و چند ویژگی دارد که همان لحظه درست بودند. تمام تصمیم‌های بعدی شما، هر سگمنت، هر کمپین، هر قیف، روی همین سه چیز سوار می‌شود؛ و بعضی از این تصمیم‌ها را نمی‌شود پس گرفت. این صفحه دقیقا می‌گوید کد چه کاری با آنچه می‌فرستید می‌کند. اگر دنبال دستور کار عملی هستید، یعنی اینکه فراخوانی را کجای کد خودتان بگذارید و چطور بررسی کنید که رسیده، گذاشتن رویداد همان صفحه است.

EVENT PRODUCERS
Web SDKBrowser behavior
Mobile SDKApp behavior
Server SDKTrusted events
SEGMENTICEvent pipelineValidate, normalize and resolve identity
LIVE CUSTOMER STATE
ProfilesTraits and history
SegmentsLive membership
Journey triggersReal-time entry
مسیر رویداد از SDK وب، موبایل و سرور تا پرونده، سگمنت و شروع سناریو

#رویداد چیست و چه چیزی نیست

رویداد وضعیت نیست. «موجودی کیف پول این کاربر ۱۲۰۰۰ تومان است» رویداد نیست، ویژگی پرونده است و با identify فرستاده می‌شود. «کاربر کیف پولش را ۱۲۰۰۰ تومان شارژ کرد» رویداد است. فرق این دو در بخش ویژگی رویداد یا ویژگی پرونده کامل باز شده، چون بیشترین اشتباه همان‌جا اتفاق می‌افتد.

رویداد بعد از نوشته‌شدن عوض نمی‌شود. هیچ endpointی برای ویرایش یا حذف یک رویداد وجود ندارد. سه چیز سطر را از جدول برمی‌دارد: سیاست نگهداری تنانت شما، TTL چهارصدروزه خود جدول رویدادها، و پاک‌سازی یک شخص شناسایی‌شده. یعنی هر تصمیمی که این صفحه از شما می‌خواهد، روی داده‌ای اثر دارد که از این لحظه به بعد می‌آید، نه روی چیزی که دیروز آمده است.

ترافیک ربات دور ریخته نمی‌شود. ذخیره می‌شود و ستون is_bot روی آن یک می‌شود، و گزارش‌ها به‌صورت پیش‌فرض کنارش می‌گذارند. اگر عددی را دور ریخته بودیم، بعدا هیچ‌کس نمی‌توانست ثابت کند که آن روز واقعا چه اتفاقی افتاده است.

یک رویداد باید دست‌کم یکی از user_id یا anonymous_id را داشته باشد، وگرنه با کد missing_identity رد می‌شود. هر دو حداکثر ۲۵۶ بایت‌اند.

#پنج نوع پیام

پنج نوع پیام وجود دارد و هرکدام مسیر خودش را دارد. نام رویدادی که ذخیره می‌شود، همیشه از خود شما نمی‌آید:

مسیرنوعنامی که ذخیره می‌شود
POST /v1/tracktrackهمان event که فرستاده‌اید. اجباری است
POST /v1/pagepageهمان event، و اگر خالی باشد page_viewed
POST /v1/screenscreenهمان event، و اگر خالی باشد screen_viewed
POST /v1/identifyidentifyهمیشه identify. هرچه در event بفرستید دور ریخته می‌شود
POST /v1/aliasaliasهمیشه alias. مثل بالا
POST /v1/batchهر پنج‌تاهر آیتم type خودش را دارد

روی پنج مسیر تک‌رویدادی، مسیر تعیین‌کننده است و فیلد type داخل بدنه نادیده گرفته می‌شود. اگر {"type":"identify"} را به /v1/track بفرستید، یک رویداد track ذخیره می‌شود. این عمدی است: در غیر این صورت یک بار اشتباه تایپ کردن در کد شما باعث می‌شد بار identify بی‌سروصدا به‌عنوان رویداد پذیرفته شود.

داخل /v1/batch قضیه برعکس است، چون مسیر یکی است و آیتم‌ها فرق دارند: type هر آیتم خوانده می‌شود و اگر ناشناخته باشد فقط همان آیتم با کد unknown_type رد می‌شود، نه کل دسته.

ویژگی‌های identify (که به آن‌ها «ویژگی» یا trait می‌گوییم) روی جدول رویدادها ذخیره نمی‌شوند. رویداد identify با ویژگی‌های خالی در جدول می‌نشیند و مقدار ویژگی‌ها فقط به پرونده کاربر می‌رود. اگر می‌خواهید در گزارش رویدادی ببینید که چه چیزی عوض شد، آن را به‌عنوان یک track جدا هم بفرستید.

یک رویداد کامل
curl -X POST https://in.segmentic.net/v1/track \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer wk_seg_..." \
  -d '{
    "message_id": "9f1c2b70-3a4d-4f2e-9a1b-0c7d8e5f6a21",
    "user_id": "u_88123",
    "event": "order_completed",
    "timestamp": "2026-08-07T09:14:22.310Z",
    "properties": {
      "order_id": "A-100294",
      "revenue": 2450000,
      "currency": "IRR",
      "item_count": 3,
      "payment_method": "gateway"
    },
    "context": {
      "locale": "fa-IR",
      "timezone": "Asia/Tehran",
      "library": { "name": "segmentic-js", "version": "1.0.0" }
    }
  }'
پاسخ
{"status":"ok","accepted":1}

کلید نوشتن را می‌توانید با هدر Authorization: Bearer wk_seg_...، یا هدر X-Segmentic-Key، یا پارامتر ?write_key= بدهید. سومی فقط برای sendBeacon و بیکن تصویری وجود دارد که نمی‌توانند هدر بگذارند.

اگر message_id نفرستید، سرور یکی می‌سازد و یک هشدار برمی‌گرداند:

پاسخ وقتی message_id نفرستاده‌اید
{"status":"ok","accepted":1,"warnings":[{"code":"generated_message_id","field":"message_id","note":"no message_id sent; retries of this event cannot be de-duplicated"}]}

آن هشدار جدی است. message_id تنها چیزی است که تکرار را بی‌خطر می‌کند: SDK روی شبکه موبایل ایران دوباره می‌فرستد، و بدون شناسه ثابت، شمارش خرید مشتری بی‌صدا دو برابر می‌شود. حذف تکراری per-tenant است و دو تنانت می‌توانند از یک message_id استفاده کنند.

#قاعده نام‌گذاری

این کل قاعده است، و کوتاه‌تر از چیزی است که انتظار دارید. نام رویداد TrimSpace می‌شود، از نرمال‌سازی فارسی می‌گذرد (بخش متن فارسی)، و بعد فقط دو چیز بررسی می‌شود:

قاعدهحدکد رد
طول بعد از نرمال‌سازی۱۲۸ بایتevent_name_too_long
کاراکتر کنترلی یونیکدهیچ‌کدام مجاز نیستevent_name_invalid_chars
وجود نام روی trackاجباریmissing_event_name

همین. بدون کوچک‌کردن حروف، بدون snake_case کردن، بدون هیچ فیلتری روی کاراکترها. یعنی فاصله، اسلش، علامت سؤال، حروف فارسی، ایموجی، حروف بزرگ و کوچک قاطی، و یک آدرس کامل، همه نام‌های قانونی رویداد هستند.

دو نتیجه که آدم‌ها با آن غافلگیر می‌شوند:

  • Order Completed و order_completed و order completed سه رویداد جدا هستند، برای همیشه. هیچ‌چیزی آن‌ها را بعدا یکی نمی‌کند.
  • حد ۱۲۸ بایت است، نه ۱۲۸ حرف. هر حرف فارسی در UTF-8 دو بایت است، پس یک نام فارسی حداکثر حدود ۶۴ حرف می‌تواند باشد.

قاعده‌ای که پیشنهاد می‌کنیم و بقیه مستندات با آن نوشته شده: حروف کوچک انگلیسی، snake_case، فعل در زمان گذشته، شیء قبل از فعل. order_completed نه completeOrder، product_viewed نه View Product. دلیلش زیبایی نیست: نام رویداد در پنل، در سگمنت‌ساز، در تریگر سناریو و در خروجی CSV عینا همان رشته‌ای است که فرستاده‌اید، و یک فهرست با سه شکل نوشتار قاطی، فهرستی است که کسی نمی‌تواند از آن انتخاب کند.

سرور هیچ محدودیتی روی تعداد نام‌های متمایز شما نمی‌گذارد. این را جدی بگیرید، چون بخش بعد درباره همان است.

اگر نام‌ها در یکپارچه‌سازی شما از قبل چیز دیگری است، chk_out_v2 یا SUB_RENEW، برای خوانا شدن پنل لازم نیست چیزی را که کدتان می‌فرستد عوض کنید. پنل برای هر رویداد یک نام نمایشی نگه می‌دارد که فقط از «مدیریت داده»، در دستهٔ «رویدادها» گذاشته می‌شود. فقط نام نمایشی است: آنچه SDK می‌فرستد، آنچه تعریف یک سگمنت به آن ارجاع می‌دهد و آنچه در خروجی می‌آید هیچ‌کدام عوض نمی‌شوند، پس تغییر نام نمی‌تواند سگمنت یا قیف ذخیره‌شده‌ای را خراب کند. گذاشتنش به مجوز settings.write نیاز دارد.

#وقتی نام رویداد یک آدرس است

نام رویداد را از یک متغیر نسازید. این جمله انتزاعی به نظر می‌رسد تا وقتی که ببینید چطور اتفاق می‌افتد.

متد page(name) در SDK وب، رویداد را دقیقا به همان رشته‌ای نام‌گذاری می‌کند که به آن داده‌اید. یکی از مشتری‌ها به آن pathname + search را داد. نتیجه: نام رویداد کل آدرس شد، و هر کد معرف و هر شناسه پروفایل یک نوع رویداد جدید ساخت. عددهای واقعی آن حساب:

  • ۱۶۹ نام متمایز آدرس‌شکل روی ۵۶۱۸ سطر.
  • فهرست رویدادها در یک روز به ۱۶۸ نام رسید: ۱۵۳ تای آن آدرس بود و ۱۵ تا رویداد واقعی.
  • «صفحه بازی‌ها را باز کرد» بین ۴۶ نام پخش شده بود: /games/ و /games/?ref=GPE9UHTV و /games/?utm_source=ecrm&utm_medium=inapp_banner و /u/69235/ و بقیه.
  • همه آن ۱۶۹ نام، وقتی به مسیر تبدیل شوند، ۲۳ تا می‌شوند.

چرا این فقط زشت نیست بلکه داده را از دست می‌دهد: فهرست رویدادها (GET /v1/schema/events) حداکثر ۵۰۰ نام برمی‌گرداند، مرتب‌شده بر اساس حجم نزولی، فقط از ۹۰ روز اخیر. تنانتی که در این وضعیت است، نام‌های واقعی‌اش از ته فهرست می‌افتند بیرون. بازاریاب نمی‌تواند سگمنت «خرید کرد» را بسازد چون نام رویدادش در فهرست نیست.

راه درست: صفحه را به نام مسیر بفرستید نه به نام آدرس، و آدرس را همان‌جا که جایش هست بگذارید. اگر autoContext روشن باشد، SDK وب خودش context.page.url و context.page.path و context.page.search را روی هر پیام می‌گذارد و کلکتور دو تای اول را در ستون‌های page_url و page_path ذخیره می‌کند. پس آدرس دقیق از دست نمی‌رود.

نام مسیر، نه نام آدرس
import { init, page } from "@segmentic/web";

init({
  writeKey: "wk_seg_...",
  apiHost: "https://in.segmentic.net",
  // Off, because the automatic page view fires on init and would land
  // beside the route-named one below.
  autoPageView: false,
});

function routeNameOf(pathname) {
  return pathname
    .replace(/\/$/, "")
    .replace(/\/u\/\d+/g, "/u/:id")
    .replace(/\/(\d+)(?=\/|$)/g, "/:id") || "/";
}

// On the first load, and again on every client-side navigation.
page(routeNameOf(location.pathname));

یک نکته درباره autoPageView که تایپ خود SDK آن را جور دیگری می‌گوید. توضیح تایپ می‌گوید «یک بازدید صفحه روی راه‌اندازی و روی جابه‌جایی در تاریخچه». کد فقط روی راه‌اندازی می‌فرستد. تنها شنونده‌هایی که SDK وب نصب می‌کند visibilitychange و pagehide و online هستند و هیچ‌جای سورس هیچ popstate یا وصله‌ای روی pushState وجود ندارد. یعنی یک اپ تک‌صفحه‌ای باید خودش روی هر جابه‌جایی page() را صدا بزند، وگرنه کل نشست کاربر یک بازدید صفحه ثبت می‌کند.

و اگر همین حالا در این وضعیت هستید: اسکریپت deploy/scripts/rename-url-event-names.sh روی برنچ chore/rename-the-url-shaped-event-names این کار را برای سطرهای موجود می‌کند. رشته پرس‌وجو را حذف می‌کند، اسلش انتهایی را حذف می‌کند، چند مسیر پویای نام‌برده را جایگزین می‌کند و بعد هر بخش عددی باقی‌مانده را به :id تبدیل می‌کند. به‌صورت پیش‌فرض فقط گزارش می‌دهد و با --apply اجرا می‌شود.

این برنچ در main مرج نشده است، پس اسکریپت روی نصب استاندارد در دسترس نیست. مهم‌تر: کاری که می‌کند یک ALTER TABLE ... UPDATE است و برگشت ندارد، چون مقدار قبلی جایی نگه داشته نمی‌شود. خود اسکریپت پیش از --apply می‌شمارد که چند سطر page_url خالی دارند و اگر حتی یکی باشد اجرا نمی‌شود، چون برای آن سطرها آدرس فقط در نام زندگی می‌کند.

#انتخاب ویژگی‌ها

روی رویداد آن چیزی را بگذارید که در همان لحظه درست بود. مبلغی که پرداخت شد، کدی که تخفیف داد، دسته‌ای که محصول در آن بود. اگر بعدا قیمت محصول عوض شود، رویداد دیروز هنوز قیمت دیروز را نشان می‌دهد، و این تنها راهی است که «درآمد ماه گذشته» معنی درستی داشته باشد.

سه چیز را روی رویداد نگذارید:

  • چیزی که کلاینت خودش می‌فرستد. context همین حالا دستگاه، سیستم‌عامل، نسخه اپ، صفحه، کمپین، زبان و منطقه زمانی را می‌آورد. ویژگی os_name روی رویداد فقط یک نسخه دوم و بدتر از ستونی است که وجود دارد.
  • توکن، رمز و شماره کارت. ویژگی‌ها در صفحه تایم‌لاین کاربر عینا به تیم پشتیبانی نشان داده می‌شوند و در خروجی CSV هم می‌آیند.
  • چیزی که فقط یک مقدار برای هر آدم دارد و تغییر می‌کند، مثل «سطح باشگاه مشتریان». آن ویژگی پرونده است.

کلید ویژگی هم نرمال می‌شود، و بدانید چطور، چون کلید چیزی است که بعدا در فیلتر تایپ می‌کنید:

ورودیکلید ذخیره‌شده
" spaced key "spaced_key
"dotted.key"dotted_key
"dashed-key"dashed_key
"multi space"multi_space
"_leading_"leading
"" یا " "حذف می‌شود

یعنی: فاصله و نقطه و خط تیره به یک _ تبدیل می‌شوند، _ ابتدا و انتها حذف می‌شود، کاراکتر کنترلی دور ریخته می‌شود و کلید در ۱۲۸ بایت بریده می‌شود. اما کلیدها کوچک نمی‌شوند و نرمال‌سازی فارسی روی آن‌ها اجرا نمی‌شود. Price و price دو ویژگی جدا هستند.

#یک ویژگی چه چیزی می‌تواند نگه دارد

ClickHouse نوع Map همگن دارد، پس هر ویژگی در یکی از دو نقشه یا هر دو نوشته می‌شود: props_str برای متن و props_num برای عدد. جدول کامل:

مقدار در JSONدر props_strدر props_num
nullنوشته نمی‌شودنوشته نمی‌شود
رشتهنرمال‌سازی فارسی، بریده در ۸۱۹۲ بایتنوشته نمی‌شود
true یا false"true" یا "false"1 یا 0
عددشکل متنی عددخود عدد
آرایه یا شیءهمان JSON به‌صورت رشته، بریده در ۸۱۹۲ بایتنوشته نمی‌شود
چیزی که JSON نمی‌شودنوشته نمی‌شودنوشته نمی‌شود، به‌علاوه هشدار unserialisable_property

null یعنی «تنظیم نشده»، و اگر آن را "" ذخیره می‌کردیم فیلتر «تنظیم نشده» غلط جواب می‌داد.

عدد صحیح، صفر اضافه نمی‌گیرد: 1234 به‌صورت رشته "1234" ذخیره می‌شود نه "1234.0". بدون این، شماره سفارشی که به‌صورت عدد JSON می‌آید، دیگر به سیستم خود مشتری join نمی‌شد.

آنچه می‌فرستید
{
  "type": "track",
  "user_id": "u_88123",
  "event": "order_completed",
  "properties": {
    "str": "hello",
    "num": 42.5,
    "int_like": 1234,
    "bool_t": true,
    "bool_f": false,
    "nil": null,
    "arr": [1, 2],
    "obj": { "a": 1 }
  }
}
آنچه ذخیره می‌شود
props_str = { str: "hello", num: "42.5", int_like: "1234",
              bool_t: "true", bool_f: "false",
              arr: "[1,2]", obj: "{\"a\":1}" }
props_num = { num: 42.5, int_like: 1234, bool_t: 1, bool_f: 0 }

nil در هیچ‌کدام نیست. arr و obj فقط متن‌اند، ولی با توابع JSON خود ClickHouse هنوز قابل فیلتر شدن‌اند. هیچ‌چیزی تخت نمی‌شود و هیچ عمقی از دست نمی‌رود.

مهم‌ترین نتیجه این جدول: رشته عددشکل هرگز عدد نمی‌شود. اگر "price": "2450000" بفرستید، props_num هیچ‌وقت price نمی‌گیرد و فیلتر «بیشتر از» روی آن هرگز چیزی پیدا نمی‌کند. این عمدی است، چون تجزیه‌کردن "01234" صفر ابتدایی کد پستی را دور می‌ریزد. اگر منظورتان عدد است، در JSON عدد بفرستید. همین قاعده برای رقم فارسی هم هست: "۲۴۵۰۰۰۰" یک رشته است و رشته می‌ماند.

هیچ ثبت نوعی وجود ندارد. هر رویداد مستقل نرمال می‌شود و هیچ‌جای مسیر ورودی حافظه‌ای از این ندارد که این کلید دفعه قبل چه نوعی بود. پس فرستادن price به‌صورت عدد و بعد به‌صورت متن، نه خطا می‌دهد نه هشدار. فقط بعضی سطرها در props_num هستند و بعضی نیستند.

#حدها و اینکه وقتی رد می‌شوید چه می‌شود

چیزحدوقتی رد شود
ویژگی در هر رویداد۲۵۶۲۵۶ تای اول نگه داشته می‌شود، بقیه دور ریخته، هشدار too_many_properties
طول کلید ویژگی۱۲۸ بایتبریده می‌شود
طول مقدار ویژگی۸۱۹۲ بایتبریده می‌شود، روی مرز حرف UTF-8
ویژگی پرونده در هر پیام۲۵۶حلقه متوقف می‌شود، هشدار too_many_traits
آیتم در هر batch۵۰۰کل درخواست با batch_too_large رد می‌شود
اندازه بدنه۵ مگابایتکد ۴۱۳
طول نام رویداد۱۲۸ بایترد با event_name_too_long
طول user_id و anonymous_id و message_id۲۵۶ بایترد با id_too_long
طول session_id۲۵۶ بایتبریده می‌شود، رد نمی‌شود
طول previous_id روی aliasحدی نداردهیچ بررسی طولی روی آن نیست؛ فقط سقف ۵ مگابایتی بدنه محدودش می‌کند
آدرس و مسیر و ارجاع صفحه۲۰۴۸ بایتبریده می‌شود
عمق تودرتوییحدی نداردآرایه و شیء یکجا به JSON تبدیل می‌شوند

دو ریزه‌کاری که فقط وقتی به آن‌ها برمی‌خورید که دیر شده است:

«۲۵۶ تای اول» ترتیب مشخصی ندارد. پیمایش نقشه در Go تصادفی است، پس اگر ۳۰۰ ویژگی بفرستید، اینکه کدام ۴۴ تا حذف می‌شوند در هر رویداد فرق می‌کند. نتیجه یک ستون نیمه‌پر است که در گزارش شبیه داده کم‌کیفیت به نظر می‌رسد نه شبیه یک باگ. متن هشدار عدد دقیق را می‌گوید: 300 properties sent, keeping 256.

یک ویژگی با مقدار null یکی از ۲۵۶ جا را می‌گیرد ولی چیزی ذخیره نمی‌کند. برای ویژگی‌های پرونده این‌طور نیست: آنجا مقدار خالی قبل از شمارش رد می‌شود.

بریدن هرگز وسط یک حرف اتفاق نمی‌افتد. اگر می‌افتاد، رشته UTF-8 نامعتبر می‌شد، ClickHouse کل دسته را رد می‌کرد، و یک رشته خراب کل یک پارتیشن را متوقف می‌کرد.

#درآمد، و اینکه چطور بی‌اجازه جمع می‌شود

اینجا یک رفتار هست که باید قبل از طراحی رویدادهایتان بدانید: درآمد از هر رویدادی استخراج می‌شود، نه فقط از سفارش.

استخراج به این ترتیب کار می‌کند، اولین مقدار غیرصفر برنده است:

  1. props_num["revenue"]
  2. props_num["total"]
  3. props_num["value"]
  4. و اگر هیچ‌کدام نبود: props_num["price"] × props_num["quantity"]، با quantity پیش‌فرض ۱ وقتی نیامده یا مثبت نیست.

ارز از props_str["currency"] می‌آید، بزرگ می‌شود و در ۸ بایت بریده می‌شود؛ پیش‌فرض IRR است. IRT هم یک مقدار شناخته‌شده است، اما هیچ تبدیلی بین ریال و تومان انجام نمی‌شود. هر عددی که بفرستید در همان واحدی می‌ماند که گفته‌اید و جمع‌ها فرض می‌کنند شما ثابت مانده‌اید.

حالا قسمت گران: پرونده کاربر درآمد را از هر رویدادی که آن را حمل کند جمع می‌کند.

نام رویداداثر روی پرونده
order_completedtotal_revenue زیاد می‌شود، order_count یکی بالا می‌رود، last_order_at جلو می‌رود
order_refunded و order_cancelledقدرمطلق مبلغ از total_revenue کم می‌شود (کف صفر) و order_count یکی پایین می‌آید (کف صفر)
هر نام دیگریمبلغ به total_revenue اضافه می‌شود

پس یک رویداد product_added_to_cart که price و quantity دارد، همین حالا به ارزش طول عمر آن کاربر اضافه می‌کند، بدون اینکه کسی سفارشی ثبت کرده باشد. سگمنت «مشتری وی‌آی‌پی» که روی total_revenue ساخته شده، پر می‌شود از آدم‌هایی که فقط سبد پر کرده‌اند.

کلیدهای revenue و total و value و همچنین جفت price با quantity را فقط روی رویدادی بگذارید که واقعا پول جابه‌جا شده است. برای بقیه اسم دیگری بگذارید: unit_price، cart_total، estimated_value. این کلیدها رزرو شده‌اند و کد به آن‌ها معنی می‌دهد.

order_id و product_id هم در فهرست کلیدهای رزرو اعلام شده‌اند، ولی هیچ کدی آن‌ها را نمی‌خواند. ویژگی معمولی‌اند.

#نام‌هایی که پلتفرم به آن‌ها معنی می‌دهد

پلتفرم یازده نام استاندارد فروشگاهی را اعلام می‌کند. فقط سه‌تای آن‌ها رفتار دارند (بخش بالا) و بقیه نام معمولی‌اند که فقط در پنل برچسب فارسی می‌گیرند:

product_viewed و product_added_to_cart و product_removed_from_cart و cart_viewed و checkout_started و order_completed و order_refunded و order_cancelled و searched و signed_up و signed_in.

«فهرست پیش‌فرض» را بیش از آنچه هست حساب نکنید. سگمنت‌ساز تا وقتی اسکیمای واقعی تنانت بارگذاری نشده، ده نام ثابت را نشان می‌دهد و بس: order_completed و product_viewed و product_added_to_cart و checkout_started و order_refunded و searched و app_opened و signed_up و message_opened و message_clicked. بقیه نام‌های استاندارد، از جمله cart_viewed و product_removed_from_cart و signed_in و order_cancelled، در آن فهرست موقت نیستند. به‌محض اینکه اسکیما برسد، فهرست از رویدادهای واقعی خودتان ساخته می‌شود و این ده‌تا فقط برچسب می‌دهند.

چهار نام را خود سرور می‌سازد و شما نمی‌توانید عوضشان کنید: page_viewed و screen_viewed وقتی page یا screen بدون نام بیاید، و identify و alias که همیشه ثابت‌اند.

چند نام را هم ورکرهای خود سگمنتیک داخل جریان رویدادهای شما می‌نویسند، تا تعامل با کمپین دقیقا با همان ابزاری قابل پرس‌وجو باشد که رویدادهای اپ. این نام‌ها را خودتان نفرستید:

نامچه کسی می‌نویسد
message_sentفرستنده پیام، روی ارسال موفق
message_failedفرستنده پیام، روی شکست
message_withheldفرستنده پیام، فقط برای گروه کنترل
message_openedنقطه ردیابی باز شدن پیام

message_withheld توضیح خودش را می‌خواهد: کسی برای کمپین انتخاب شده و عمدا برایش پیامی نرفته است. سطر نوشته می‌شود تا سنجش اثر یک خط پایه داشته باشد، چون بدون سطری که بگوید «این آدم را انتخاب کردیم و ساکت ماندیم»، چیزی برای مقایسه با گروه درمان وجود ندارد. هر نوع دیگری از سرکوب پیام عمدا در جریان نمی‌آید، چون ثبت‌کردنشان به‌عنوان ارسال، دسترسی هر کمپین را دقیقا به اندازه آدم‌هایی که به آن‌ها نرسیده متورم می‌کند.

نام‌های message_delivered و message_bounced و unsubscribed به‌عنوان ثابت اعلام شده‌اند و هیچ جای دیگر بک‌اند از آن‌ها استفاده نمی‌کند: نه ورکری آن‌ها را می‌نویسد و نه چیزی آن‌ها را می‌خواند، پس گزارشی که روی message_delivered بسازید خالی برمی‌گردد. با این حال خود پنل رویداد تحویل می‌خواهد. قالب داشبورد «عملکرد پیام‌رسانی» و متریک‌های پایه «نرخ تحویل پیام» و «نرخ بازشدن پیام» و «نرخ کلیک پیام» هرکدام به یک رویداد تحویل نیاز دارند که از اسکیمای رویداد خودتان به آن‌ها وصل شود، و تا اسمی ندهید فعال‌سازی جلو نمی‌رود، پس اگر خودتان رویداد تحویل نفرستید، آن داشبورد و آن سه متریک هرگز ساخته نمی‌شوند.

آنچه کم است رویداد است، نه داده. گزارش کمپین شمار پیام‌های تحویل‌شده خودش را از رسیدهایی می‌گیرد که مسیر ارسال پس می‌فرستد، سرویس تحویل‌پذیری برگشتی‌ها را از مسیر بازگشت SMTP می‌خواند و روی فهرست مسدود می‌نویسد، و لغو اشتراک روی پرونده آن آدم در مرکز تنظیمات می‌نشیند و در ارسال بعدی به‌عنوان دلیل سرکوب برمی‌گردد. هیچ‌کدام این‌ها به‌شکل سطر وارد جریان رویداد شما نمی‌شود.

ورکر انتساب دقیقا چهار نام را می‌شناسد، message_sent و message_withheld و message_opened و message_clicked، و هر رویداد دیگری را که به دستش برسد نادیده می‌گیرد. message_clicked را هم ورکر نمی‌نویسد: SDK وب آن را وقتی می‌فرستد که بازدیدکننده روی لینکی با sg_mid وارد سایت شود، یک بار، تا وقتی شناسه پیام دیگری جایش را بگیرد. مقایسه با همان یک شناسه داخل حافظه است نه با تاریخچه‌ای از شناسه‌ها، پس بازدیدکننده‌ای که روی یک پیام بیاید، بعد روی پیام دوم، و بعد دوباره روی همان پیام اول، کلیک پیام اول را دو بار گزارش می‌کند.

شش نام app_installed و app_opened و app_updated و app_removed و session_started و session_ended در کد به‌عنوان «رویدادهای چرخه عمر که SDKها خودکار می‌فرستند» اعلام شده‌اند. هیچ SDKای آن‌ها را نمی‌فرستد. نه SDK وب، نه اندروید، نه iOS. جست‌وجو در هر سه، صفر فرستنده پیدا می‌کند. app_opened در فهرست پیش‌فرض رویدادهای پنل هم هست و برچسب فارسی دارد، که باعث می‌شود خودکار به نظر برسد. اگر این رویدادها را می‌خواهید، خودتان باید بفرستیدشان.

#ویژگی رویداد یا ویژگی پرونده

این جایی است که بیشترین اشتباه اتفاق می‌افتد، و اشتباهش تا ماه‌ها بعد خودش را نشان نمی‌دهد.

ویژگی رویدادویژگی پرونده
چطور فرستاده می‌شودproperties روی track یا page یا screentraits روی identify
کجا می‌نشیندروی همان یک سطر رویدادروی پرونده کاربر، یک مقدار برای هر آدم
تاریخچه داردبله، هر رویداد نسخه خودش را نگه می‌داردخیر، آخرین مقدار جای قبلی را می‌گیرد
با کاربر مهمان کار می‌کندبلهخیر، تا وقتی user_id نداشته باشید پرونده‌ای ساخته نمی‌شود
برای چه فیلتری خوب است«کسی که در ۳۰ روز گذشته سفارش بالای ۵۰۰ هزار داشت»«کسی که الان سطح طلایی است»

مثال دقیق: city به‌عنوان ویژگی روی order_completed یعنی «این سفارش به تهران رفت». همان city به‌عنوان ویژگی پرونده یعنی «این آدم الان در تهران زندگی می‌کند». اولی هرگز عوض نمی‌شود، دومی با هر identify عوض می‌شود و مقدار قبلی برای همیشه می‌رود.

سه چیز از این تفاوت درمی‌آید که در ساخت سگمنت به آن‌ها می‌خورید:

ویژگی‌های پرونده شناخته‌شده از نقشه ویژگی‌ها بیرون کشیده می‌شوند. email و phone و first_name و last_name و gender و birthday و national_id و city و region و country و language و timezone و push_opt_in و email_opt_in و sms_opt_in به ستون‌های واقعی پرونده می‌روند و در نقشه آزاد traits نمی‌مانند. پس در پاسخ GET /v1/schema/traits دیده نمی‌شوند. ویژگی email شما گم نشده است، فقط ستون است.

فیلتر عددی روی ویژگی پرونده، کسی را که آن ویژگی را ندارد انتخاب نمی‌کند. کامپایلر سگمنت شرط را با mapContains می‌پیچد. جهت خطا عمدی انتخاب شده است: مخاطبی که بی‌صدا خالی است یعنی کمپینی که نمی‌رود و کسی متوجه می‌شود؛ مخاطبی که بی‌صدا همه است یعنی کمپینی که برای همه رفته و پس گرفته نمی‌شود.

فیلتر عددی روی ویژگی رویداد این محافظ را ندارد. فیلتر روی props_num بدون mapContains کامپایل می‌شود، و نقشه در ClickHouse برای کلید غایب مقدار صفر می‌دهد. یعنی شرط «قیمت کمتر از ۱۰۰۰۰» رویدادهایی را هم می‌گیرد که اصلا price نفرستاده‌اند. اگر ویژگی را روی همه رویدادهای آن نام نمی‌فرستید، شرط «تنظیم شده» را هم کنارش بگذارید.

بررسی «تنظیم شده» برای ویژگی رویداد روی props_str انجام می‌شود، که مشکلی ندارد: هر مقدار عددی همیشه در هر دو نقشه نوشته می‌شود، پس props_str مجموعه بزرگ‌تر است.

#متن فارسی

هر رشته‌ای که کاربر می‌فرستد پیش از ذخیره از Normalize می‌گذرد. این‌ها جاهایی است که اجرا می‌شود:

  • نام رویداد
  • مقدار هر ویژگی رشته‌ای
  • مقدار هر ویژگی پرونده سفارشی
  • context.location.country و .region و .city
  • context.page.title

و این‌ها جاهایی است که اجرا نمی‌شود: کلید ویژگی، کلید ویژگی پرونده، user_id، anonymous_id، message_id، session_id، آدرس و مسیر و ارجاع صفحه، مقدارهای UTM. برای email فقط حروف کوچک می‌شود، phone جدا تجزیه می‌شود و national_id فقط رقم‌هایش به لاتین تبدیل می‌شود.

آنچه انجام می‌دهد:

ازبه
یای عربی ي، الف مقصوره ى، ےیای فارسی ی
کاف عربی ك، ڪکاف فارسی ک
ة، ۀه
ؤو
أ، إ، ٱا

به‌علاوه اعراب و کشیده و ZWJ به‌کلی حذف می‌شوند، و هر دنباله فاصله (شامل فاصله بدون‌شکست، فاصله‌های یونیکد، و BOM) به یک فاصله ساده تبدیل و از دو سر بریده می‌شود. کپی از Word و از ویرایشگرهای راست‌به‌چپ بیشتر این‌ها را با خودش می‌آورد.

آنچه عمدا دست‌نخورده می‌ماند:

  • نیم‌فاصله. می‌رود برای خواننده کلمه دیگری است غیر از میرود.
  • بزرگی و کوچکی حروف لاتین. Digikala همان Digikala می‌ماند.
  • رقم فارسی. ۱۴۰۵ همان ۱۴۰۵ می‌ماند و به لاتین تبدیل نمی‌شود.
  • فاصله با عرض صفر، الف با کلاه، ی با همزه، و همزه تنها.

نتیجه عملی: تهراني که با صفحه‌کلید عربی تایپ شده و تهرانی که با صفحه‌کلید فارسی تایپ شده، یک مقدار می‌شوند و در یک سگمنت می‌افتند. اما Tehran و tehran یکی نمی‌شوند، و ۱۲۳ هرگز 123 نمی‌شود.

#تلفن، کد ملی و جنسیت

چهار ویژگی پرونده رفتار مخصوص دارند، چون هویت آدم‌اند و ذخیره‌کردنشان به هر شکلی که رسیده، تضمین می‌کند برای یک انسان دو پرونده داشته باشید.

phone با ParsePhone تجزیه می‌شود و به شکل E.164 ذخیره می‌شود، به‌علاوه یک ویژگی مشتق به نام phone_operator. الگوریتم: رقم‌های فارسی و عربی به لاتین، بعد فقط رقم‌ها و یک + ابتدایی نگه داشته می‌شوند، بعد پیشوند کشور برداشته می‌شود، و آنچه می‌ماند باید دقیقا ده رقم باشد که با ۹ شروع می‌شود.

شکل‌هایی که همه یک نتیجه می‌دهند
09123456789     9123456789      +989123456789    00989123456789
989123456789    0912 345 6789   0912-345-6789    (0912) 345 6789
۰۹۱۲۳۴۵۶۷۸۹    ٠٩١٢٣٤٥٦٧٨٩

نتیجه:  phone = "+989123456789"   phone_operator = "mci"
شکل‌هایی که رد می‌شوند
""   "abc"   "0812345678"   "091234567"   "091234567890"
"+981234567890"   "12345"   "+1234567890"   "0000000000"

اگر تجزیه شکست بخورد، مقدار خام همان‌طور که آمده ذخیره می‌شود و هشدار invalid_phone برمی‌گردد؛ phone_operator نوشته نمی‌شود. دور نمی‌ریزیمش، چون یک شماره بدشکل هنوز تنها راه تماس با آن آدم است.

اپراتور از چهار رقم اول شکل داخلی شماره درمی‌آید، یعنی همان 09XX:

اپراتورپیشوندها
mci (همراه اول)۰۹۱۰ تا ۰۹۱۹، ۰۹۹۰ تا ۰۹۹۷، ۰۹۹۹
irancell (ایرانسل)۰۹۰۰ تا ۰۹۰۵، ۰۹۳۰، ۰۹۳۳، ۰۹۳۵ تا ۰۹۳۹، ۰۹۴۱
rightel (رایتل)۰۹۲۰ تا ۰۹۲۳
shatel (شاتل موبایل)۰۹۹۸
samantel (سامانتل)۰۹۳۱
unknownهر چیز دیگری، مثلا ۰۹۰۶ یا ۰۹۳۲ یا ۰۹۳۴

national_id با الگوریتم رقم کنترلی مبنای یازده بررسی می‌شود. طول باید بین ۸ تا ۱۰ باشد و کوتاه‌تر از ۱۰ از چپ با صفر پر می‌شود، چون صفر ابتدایی مرتب در فایل اکسل گم می‌شود. این پرکردن فقط برای حساب رقم کنترلی است. چیزی که ذخیره می‌شود همان مقداری است که فرستادید و فقط رقم‌هایش به لاتین تبدیل می‌شود، پس 12345679 هشت‌کاراکتری می‌ماند. کد ملی با رقم‌های یکسان مثل 1111111111 رد می‌شود، حتی وقتی از رقم کنترلی رد شود. اگر نامعتبر باشد، ویژگی کلا حذف می‌شود و هشدار invalid_national_id برمی‌گردد. تلفن نامعتبر همان‌طور که فرستادید نگه داشته می‌شود، ولی کد ملی نامعتبر اصلا نگه داشته نمی‌شود، چون مشتری‌های سازمانی CRM خودشان را روی این کلید می‌بندند و یک مقدار غلط، یک پرونده تقلبی می‌سازد.

email فقط TrimSpace و کوچک می‌شود. هیچ بررسی قالبی در ورودی انجام نمی‌شود.

gender به دقیقا یکی از سه مقدار male یا female یا other نگاشت می‌شود. male از m و male و man و مرد و اقا و پسر می‌آید؛ female از f و female و woman و زن و خانم و دختر؛ هر چیز دیگری other می‌شود. مقایسه از تابع Fold می‌گذرد، پس آقا هم به male می‌رسد.

بقیه ویژگی‌های پرونده، از جمله city و first_name و birthday و language و کلیدهای رضایت، فقط نرمال‌سازی فارسی و بریدن می‌گیرند.

#محافظ کاردینالیتی

سه چیز را باید از هم جدا نگه داشت، چون فقط یکی از آن‌ها واقعا محافظ دارد.

آنچه محافظت می‌شود: برچسب متریک‌ها. وقتی رویدادی رد می‌شود، آنچه به‌عنوان دلیل شمرده می‌شود یکی از کدهای ثابت است، نه متن کامل خطا. متن کامل خطا نوع رویداد یا زمان فرستاده‌شده توسط شما را در خودش دارد، و پیش‌تر همان متن مستقیم برچسب Prometheus می‌شد: یعنی هرکسی که یک کلید نوشتن داشت می‌توانست با فرستادن یک نام تصادفی در هر درخواست، به ازای هر درخواست یک سری زمانی جدید بسازد. این حافظه بی‌کران است و اول از همه سیستم پایش را از کار می‌اندازد، یعنی دقیقا همان چیزی که برای فهمیدن ماجرا لازم دارید. حالا ۳۰۰ نوع نامعتبر متمایز در یک دسته، به یک برچسب جمع می‌شوند. بدنه پاسخ همچنان متن کامل و مقدار مقصر را به شما می‌دهد.

آنچه محافظت نمی‌شود: تعداد نام‌های رویداد شما. هیچ شمارنده‌ای وجود ندارد و هیچ سقفی اعمال نمی‌شود. تنها اثری که می‌بینید این است که فهرست رویدادها در ۵۰۰ نام قطع می‌شود.

آنچه محافظت نمی‌شود: تعداد مقدارهای متمایز یک ویژگی. هیچ سقفی روی آن هم نیست. اگر شناسه جلسه یا شماره سفارش را به‌عنوان مقدار ویژگی بفرستید، این کار درست است و مشکلی ندارد. اگر همان را به‌عنوان نام رویداد بفرستید، بخش نام آدرس‌شکل را دوباره بخوانید.

#دیدن اینکه واقعا چه رسید

سه راه، و هر سه چیز متفاوتی به شما می‌گویند.

بدنه پاسخ. هشدارها همان لحظه برمی‌گردند. کل فهرست کدهای هشدار: generated_message_id، timestamp_in_future، timestamp_too_old، too_many_properties، unserialisable_property، too_many_traits، invalid_phone، invalid_national_id. در /v1/batch کلکتور وقتی از قبل ۵۰ هشدار جمع کرده باشد، دیگر هشداری اضافه نمی‌کند، و این بررسی را پیش از افزودن هشدارهای یک آیتم کامل انجام می‌دهد، پس پاسخ می‌تواند ۴۹ هشدار به‌علاوه هرچه آیتم بعدی ساخته را حمل کند. شمارش‌ها دقیق می‌مانند.

یک دسته که یک آیتمش بد بود
{"status":"ok","accepted":2,"rejected":1,"errors":[{"index":1,"reason":"missing_event_name"}]}

یک آیتم بد کل دسته را غرق نمی‌کند. آیتم‌های رد شده با شماره‌شان در آرایه گزارش می‌شوند. توجه کنید که accepted شامل تکراری‌ها هم هست، تا SDK دست از تلاش دوباره بردارد.

فهرست رویدادها. GET /v1/schema/events روی api.segmentic.net با کلید API و دسترسی event.read:

فهرست رویدادها
curl -H "Authorization: Bearer sk_seg_..." \
  https://api.segmentic.net/v1/schema/events
پاسخ
{
  "events": [
    { "name": "product_viewed", "volume": 88000000, "prop_keys": ["product_id","price"], "last_seen": "2026-08-06" },
    { "name": "order_completed", "volume": 4200000, "prop_keys": ["revenue","order_id"], "last_seen": "2026-08-07" }
  ]
}

last_seen مفیدترین ستون این جدول است: رویدادی با حجم بزرگ و آخرین مشاهده سه هفته پیش، یعنی یکپارچگی‌ای که شکسته است، و هیچ عدد دیگری این را نمی‌گوید چون حجم تا یک ماه بعد هنوز سالم به نظر می‌رسد. پنجره ۹۰ روز است، سقف ۵۰۰ نام مرتب بر اساس حجم، و prop_keys اتحاد کلیدهای دو نقشه است بدون هیچ اطلاعاتی از نوع. یعنی این endpoint نمی‌تواند به شما بگوید نوع یک ویژگی عوض شده است.

تازگی داده به چرخه نوشتن ingestor بند است: هر ۱۰۰۰۰ رویداد یا هر ۵ ثانیه، هرکدام زودتر رسید. کش و job جداگانه‌ای در کار نیست.

دیباگر زنده. در پنل، ضبط را روشن می‌کنید و ۳۰ دقیقه رویدادها را همان‌طور که می‌رسند می‌بینید، با هشدارهایشان. آخرین ۲۰۰ رویداد نگه داشته می‌شود. تا وقتی کسی دیباگر را باز نکرده باشد هیچ ضبطی انجام نمی‌شود.

دیباگر فقط مسیرهای تک‌رویدادی را ضبط می‌کند. POST /v1/batch هیچ‌چیزی به آن نمی‌دهد، و هر سه SDK دسته‌ای می‌فرستند. یعنی وقتی SDK را تازه نصب کرده‌اید و رویدادها هم دارند می‌رسند، دیباگر خالی می‌ماند و شما فکر می‌کنید کار نکرده است. برای تایید یک نصب SDK از صفحه «اتصال» در پنل استفاده کنید که فعالیت اپ را در ۲۴ ساعت گذشته می‌پرسد، یا موقتا با POST /v1/track یک رویداد تکی بفرستید.

جدول segmentic.ingest_warnings در اسکیما وجود دارد و توضیحش می‌گوید تاریخچه هشدارهای هر تنانت را نگه می‌دارد. هیچ‌چیزی در آن نمی‌نویسد. پس تاریخچه هشدار وجود ندارد: هشدار فقط در بدنه پاسخ و در دیباگر زنده دیده می‌شود. اگر می‌خواهید بدانید SDK اندروید شما از دیروز user_id نمی‌فرستد، باید خودتان پاسخ‌ها را لاگ کنید.

#تصمیم‌هایی که بعدا برگشت ندارند

هر ردیف این جدول، چیزی است که یک بار روی داده نوشته می‌شود و بعد فقط می‌شود از آن به بعد را درست کرد.

تصمیمچرا برگشت نداردبه‌جایش چه کنید
نام رویدادتغییر نام یعنی ALTER TABLE ... UPDATE روی سطرهای موجود، که مقدار قبلی را نگه نمی‌دارد. اسکریپتش هم در main نیستقبل از اولین ارسال، فهرست نام‌ها را روی کاغذ بنویسید. فهرست آماده در فرهنگ‌نامه رویدادها هست
ویژگی‌ای که نفرستادیدهیچ راهی برای افزودن ویژگی به سطرهای نوشته‌شده وجود نداردویژگی‌های زمینه‌ای را از روز اول بفرستید، حتی اگر هنوز به آن‌ها نیاز ندارید
عدد که به‌شکل رشته فرستاده شدرشته عددشکل هرگز تجزیه نمی‌شود، و رویدادهای بعدی سطرهای قبلی را درست نمی‌کننددر JSON عدد بفرستید. رقم فارسی هم رشته است
مهاجرت تاریخچه از POST /v1/eventsآن مسیر یک پنجره ثابت ۳۰ روزه دارد، هرچه قدیمی‌تر باشد به لبه پنجره چسبانده می‌شود، پاسخ ۲۰۲ است و هیچ هشداری در بدنه برنمی‌گردد. یک سال سفارش به‌صورت یک روز غول‌آسا می‌نشینداز مسیر واردکردن استفاده کنید که در حالت backfill رد می‌کند به‌جای اینکه جابه‌جا کند
ویژگی پرونده که نوعش عوض شدفرستادن "abc" بعد از 428 نیمه متنی را عوض می‌کند ولی نیمه عددی روی 428 می‌ماند، و از مسیر ورودی راهی برای پاک‌کردنش هم نیست: مقدار رشته خالی پیش از رسیدن به پرونده دور ریخته می‌شودنوع ویژگی پرونده را ثابت نگه دارید
رویداد اشتباهی که فرستاده شدendpointی برای حذف یک رویداد وجود نداردفقط سیاست نگهداری و TTL چهارصدروزه خود جدول و پاک‌سازی شخص، سطر را برمی‌دارند

دو ریزه‌کاری روی سطر مهاجرت. پنجره ۳۰ روزه فقط برای POST /v1/events است؛ کلکتور روی in.segmentic.net پنجره‌اش سیاست نگهداری خود تنانت است و اگر چیزی را بچسباند، هشدار timestamp_too_old را هم در بدنه پاسخ می‌دهد. و مسیر واردکردن (POST /v1/import/events) روی API عمومی ثبت نشده است: فقط از پنل در دسترس است، پس مهاجرت تاریخچه کاری است که یک نفر با مرورگر انجام می‌دهد نه یک اسکریپت با کلید مدیریتی.

و یک محدودیت که سیاست شما نیست، سقف پلتفرم است: جدول رویدادها یک TTL چهارصدروزه دارد. هیچ رویدادی بیشتر از ۴۰۰ روز نمی‌ماند، هر سیاست نگهداری‌ای که تنظیم کرده باشید. اگر به نگهداری بلندتر نیاز دارید، خروجی بگیرید.

قدم بعد: فرهنگ‌نامه رویدادها فهرست آماده برای شش نوع کسب‌وکار دارد، و هویت می‌گوید user_id و anonymous_id چطور به هم وصل می‌شوند.

قبلیمفهوم‌هابعدیفرهنگ‌نامهٔ رویدادها

در این صفحه

  • رویداد چیست و چه چیزی نیست
  • پنج نوع پیام
  • قاعده نام‌گذاری
  • وقتی نام رویداد یک آدرس است
  • انتخاب ویژگی‌ها
  • یک ویژگی چه چیزی می‌تواند نگه دارد
  • حدها و اینکه وقتی رد می‌شوید چه می‌شود
  • درآمد، و اینکه چطور بی‌اجازه جمع می‌شود
  • نام‌هایی که پلتفرم به آن‌ها معنی می‌دهد
  • ویژگی رویداد یا ویژگی پرونده
  • متن فارسی
  • تلفن، کد ملی و جنسیت
  • محافظ کاردینالیتی
  • دیدن اینکه واقعا چه رسید
  • تصمیم‌هایی که بعدا برگشت ندارند

سگمنتیک

این صفحه از روی کد نوشته شده است