بازگشت به وبلاگ

مدیریت اشتراک های وب پوش نوتیفیکیشن

مدیریت اشتراک های وب پوش نوتیفیکیشن

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

چرخه عمر اشتراک وب پوش چیست؟

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

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

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

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

اصل کلیدی: مجوز اعلان، اشتراک مرورگر، رکورد پایگاه داده و تحویل موفق پیام چهار نشانه متفاوت‌اند. هیچ‌کدام را به‌تنهایی معادل «کاربر اعلان فعال دارد» در نظر نگیرید.

اشتراک وب پوش دقیقاً چه داده‌ای دارد؟

در Web Push، مرورگر شیئی به نام PushSubscription در اختیار برنامه وب می‌گذارد. این شیء معمولاً endpoint و کلیدهای رمزنگاری لازم برای ارسال پیام را شامل می‌شود. endpoint یک نشانی برای استفاده سرویس‌دهنده است، نه یک نشانی عمومی برای نمایش به کاربر و نه شناسه‌ای که بتوان آن را با نام یا ایمیل برابر دانست. کلیدهای موجود در اشتراک نیز برای سازوکار رمزنگاری پیام به کار می‌روند. برنامه سمت سرور باید کل شیء مورد نیاز را با قالب مناسب ثبت کند و هنگام ارسال از کتابخانه یا زیرساخت سازگار با Web Push بهره ببرد.

در بسیاری از پیاده‌سازی‌ها، خروجی JSON اشتراک فیلدهایی مانند endpoint و keys را دارد. مقدار endpoint ممکن است در طول زمان تغییر کند؛ ساختار یا دامنه آن را برای استخراج اطلاعات هویتی تحلیل نکنید. کلیدهای p256dh و auth نیز داده‌های حساس عملیاتی محسوب می‌شوند؛ هرچند رمز عبور حساب نیستند، نباید بی‌دلیل در لاگ‌های قابل‌مشاهده، ابزارهای تحلیل یا گزارش خطا چاپ شوند. در طراحی ذخیره‌سازی، داده را فقط به اجزایی محدود کنید که ارسال، حذف، ممیزی یا تشخیص تکرار را ممکن می‌کنند.

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

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

معماری پیشنهادی برای مدیریت اشتراک

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

در این معماری بهتر است API ثبت اشتراک یک عملیات تکرارپذیر و امن باشد. اگر همان Subscription دوباره فرستاده شود، سرور نباید رکورد تازه و تکراری بسازد. برای مثال، می‌توان یک شناسه داخلی پایدار از ترکیب یا هش امن داده‌های اشتراک ساخت و روی آن محدودیت یکتا گذاشت؛ اما هش‌کردن endpoint به‌تنهایی جای کنترل دسترسی، احراز هویت یا محافظت در برابر درخواست جعلی را نمی‌گیرد. در هر درخواست، سرور باید اعتبار نشست و مجوز اتصال به حساب را بررسی کند و اندازه و قالب داده را محدود سازد.

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

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

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

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

در وب، مجوز اعلان معمولاً از طریق Notification.permission قابل‌بررسی است و مقدار آن می‌تواند default، granted یا denied باشد. default یعنی هنوز تصمیمی ثبت نشده است؛ آن را به معنای موافقت تلقی نکنید. granted نیز تنها نشان می‌دهد مرورگر اجازه اعلان داده است و تضمین نمی‌کند Subscription فعال، سروری ثبت‌شده یا تحویل موفق وجود دارد. denied یعنی کاربر یا سیاست مرورگر اجازه نمی‌دهد؛ نمایش مکرر دکمه‌ای که هر بار همان پنجره را باز می‌کند مشکل را حل نمی‌کند. در این حالت باید راهنمایی غیرتحمیلی برای تنظیمات مرورگر ارائه شود، آن هم فقط اگر کاربر واقعاً بخواهد اعلان‌ها را فعال کند.

درخواست مجوز را به کلیک یا اقدام روشن کاربر گره بزنید و وضعیت را قبل و بعد از آن بررسی کنید. اگر کاربر درخواست را رد کرد، مسیر جایگزین تجربه سایت را مختل نکند. برای مثال، دسترسی به محتوای اصلی را به فعال‌کردن اعلان مشروط نکنید، مگر اینکه اعلان واقعاً جزء ضروری یک قابلیت جداگانه باشد و این محدودیت از پیش شفاف بیان شده باشد. زمان و بسامد نمایش دعوت به فعال‌سازی را نیز محدود کنید. نمایش دوباره همان پیام در هر بار بازدید می‌تواند حس اجبار ایجاد کند و اعتماد را کاهش دهد.

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

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

ثبت اشتراک در مرورگر و سرور

فرایند فنی را با بررسی پشتیبانی مرورگر از Service Worker، PushManager و اعلان آغاز کنید. این بررسی باید پیش از نمایش گزینه فعال‌سازی انجام شود تا کاربر با دکمه‌ای غیرقابل‌استفاده مواجه نشود. سپس سرویس‌ورکر را در مسیر و scope درست ثبت کنید و آماده‌شدن آن را منتظر بمانید. اگر ثبت سرویس‌ورکر خطا داد، علت را در رابط کاربری به شکل مناسب گزارش کنید و اطلاعات فنی لازم را بدون داده حساس در لاگ ثبت کنید. بهتر است خطای شبکه، مسدودشدن فایل سرویس‌ورکر و خطای مجوز، وضعیت‌های جدا باشند.

پس از رضایت کاربر، ابتدا از PushManager وضعیت اشتراک موجود را بخوانید. اگر اشتراک معتبر در مرورگر وجود دارد، آن را بی‌دلیل با unsubscribe و subscribe جایگزین نکنید؛ چنین کاری می‌تواند endpoint را تغییر دهد و ایجاد رکوردهای اضافی یا فاصله زمانی در دریافت پیام را به‌دنبال داشته باشد. اشتراک موجود را با سرور همگام کنید. اگر اشتراکی وجود ندارد، تابع subscribe با تنظیمات معتبر فراخوانی می‌شود. گزینه userVisibleOnly در بسیاری از پیاده‌سازی‌های وب پوش به کار می‌رود تا کاربرد اعلان با نمایش قابل‌مشاهده برای کاربر همسو باشد. کلید عمومی VAPID باید مطابق تنظیمات سرور و در قالب مورد انتظار مرورگر استفاده شود.

خروجی subscribe را به شکل JSON به API خود بفرستید و در سرور ارتباط آن را با نشست فعلی یا شناسه ناشناس مجاز بررسی کنید. درخواست باید از HTTPS ارسال شود و در سایت دارای نشست مبتنی بر کوکی، محافظت مناسب در برابر درخواست بین‌سایتی نیز رعایت شود. سرور فقط به این دلیل که درخواست شامل endpoint است نباید آن را به حساب دلخواه متصل کند. درخواست‌پذیری محدود، بررسی نوع محتوا، محدودیت اندازه بدنه، کنترل مجوز و ثبت نتیجه از اصول لازم‌اند.

ثبت در سرور را به شکل idempotent طراحی کنید؛ یعنی تکرار درخواست پس از قطع شبکه یا تلاش مجدد برنامه، یک نتیجه درست و قابل‌پیش‌بینی داشته باشد. اگر شبکه پس از ثبت سمت سرور قطع شود، مرورگر ممکن است درخواست را دوباره بفرستد. کلید یکتا و منطق upsert می‌تواند از رکوردهای تکراری جلوگیری کند. در پاسخ API، شناسه داخلی یا وضعیت ثبت را برگردانید، اما endpoint یا کلیدهای اشتراک را در پیام خطای قابل‌نمایش کاربر بازتاب ندهید.

برای جلوگیری از «وضعیت ظاهراً موفق»، نتیجه هر مرحله را مستقل بسنجید: آماده‌شدن سرویس‌ورکر، صدور مجوز، دریافت Subscription، پاسخ موفق API و تأیید ذخیره‌سازی. یک پیام موفق عمومی فقط زمانی نمایش داده شود که مرحله لازم برای محصول کامل شده باشد. اگر مرورگر اشتراک را ساخته اما API در دسترس نیست، می‌توان با حفظ حداقلی وضعیت در حافظه و تلاش مجدد کنترل‌شده همگام‌سازی را انجام داد؛ اما از ذخیره بلندمدت داده حساس در فضای ناامن یا ارسال بی‌وقفه درخواست‌ها پرهیز کنید.

مدل داده مناسب برای ذخیره اشتراک‌ها

مدل پایگاه داده باید تفاوت میان دستگاه یا مرورگر، اشتراک، حساب کاربری و ترجیحات پیام را بازتاب دهد. یک جدول فشرده می‌تواند شناسه داخلی، endpoint، کلیدهای لازم، تاریخ ثبت، زمان آخرین تأیید، وضعیت فعال، منبع رضایت، شناسه حساب nullable و داده‌های حداقلی محیط را نگه دارد. با این حال، لازم نیست همه مشخصات مرورگر یا دستگاه را با جزئیات تهاجمی جمع کنید. اگر برای پشتیبانی فقط خانواده مرورگر یا پلتفرم لازم است، همان را ذخیره کنید؛ اثرانگشت‌سازی دقیق دستگاه معمولاً برای مدیریت اشتراک ضرورت ندارد.

بهتر است زمان‌ها با منطقه زمانی یکسان و قالب استاندارد در پایگاه داده ذخیره شوند. فیلد created_at زمان نخستین ثبت را نشان می‌دهد؛ last_seen_at می‌تواند آخرین همگام‌سازی موفق مرورگر را نشان دهد؛ last_delivery_attempt_at زمان آخرین تلاش ارسال است؛ و invalidated_at زمان خارج‌کردن اشتراک از چرخه ارسال را ثبت می‌کند. یک فیلد عمومی updated_at برای همه این معناها کافی نیست، زیرا بعداً نمی‌توان فهمید رکورد واقعاً چه زمانی از مرورگر دیده شده یا آخرین پیام چه زمانی برایش فرستاده شده است.

وضعیت را با چند مقدار صریح تعریف کنید؛ برای مثال pending، active، invalid، unsubscribed یا suppressed. حالت suppressed می‌تواند برای توقف عملیاتی یا درخواست حذف بررسی‌نشده به کار رود، اما نباید با لغو رضایت کاربر مخلوط شود. دلیل غیرفعال‌شدن را نیز در محدوده لازم ثبت کنید: پاسخ endpoint نامعتبر، لغو از مرورگر، درخواست کاربر، خروج از حساب طبق سیاست محصول یا حذف مدیریتی. ثبت دلیل به پشتیبانی کمک می‌کند و از حذف کورکورانه داده جلوگیری می‌کند. دلیل‌ها باید کدهای کنترل‌شده باشند، نه متن آزاد پر از داده شخصی.

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

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

همگام‌سازی تغییرهای اشتراک

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

PushSubscription در بعضی مرورگرها رویداد pushsubscriptionchange دارد که می‌تواند درباره تغییر اشتراک اطلاع دهد. پشتیبانی و رفتار این رویداد در محیط‌های گوناگون یکسان و تضمین‌شده نیست؛ آن را تنها راه همگام‌سازی قرار ندهید. اگر رویداد در دسترس بود، می‌تواند نشانه‌ای برای خواندن اشتراک تازه و فرستادن آن به سرور باشد. با این حال، طراحی مقاوم باید با بررسی دوره‌ای کنترل‌شده و رسیدگی به خطاهای ارسال هم کار کند. از رویدادهای سرویس‌ورکر برای کارهایی استفاده کنید که واقعاً قابلیت اتکا در آن محیط دارند، نه برای ساخت تضمین مطلق.

اگر Subscription تازه‌ای در مرورگر وجود دارد اما سرور رکورد قبلی را دارد، از مقایسه ساده تعداد رکوردها برای تصمیم‌گیری استفاده نکنید. سامانه باید بفهمد رکورد جدید جایگزین همان ثبت مرورگر شده، روی پروفایل دیگری ایجاد شده یا دستگاه دیگری است. ممکن است داده‌های سمت کاربر پس از پاک‌کردن اطلاعات سایت تغییر کند. در چنین وضعی، endpoint تازه را ثبت و رکورد قبلی را طبق سیاست نگه‌داری غیرفعال کنید؛ حذف فوری رکورد قبلی فقط وقتی درست است که مطمئن باشید دیگر برای کاربری فعال نیست.

در تلاش دوباره برای API، از backoff استفاده کنید تا اختلال شبکه باعث موج درخواست نشود. خطای موقت مانند timeout با خطای دائمی مجوز یا داده نامعتبر فرق دارد. خطای موقت می‌تواند با تعداد تلاش محدود و فاصله افزایشی تکرار شود؛ پاسخ نامعتبر داده باید به تیم فنی گزارش شود و به تکرار بی‌پایان منجر نشود. زمان آخرین تلاش را ثبت کنید و پس از موفقیت، نشانگر همگام‌سازی را به‌روزرسانی کنید. برای اطلاعات وضعیت در مرورگر نیز حداقل‌گرایی را رعایت کنید و داده حساس Subscription را به‌عنوان کلید محلی دائمی ذخیره نکنید، مگر نیاز روشن و ارزیابی امنیتی وجود داشته باشد.

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

اشتراک نامعتبر را چگونه شناسایی کنیم؟

اشتراکی که زمانی معتبر بوده ممکن است دیگر قابل‌استفاده نباشد؛ برای مثال، کاربر سایت را از تنظیمات مرورگر پاک کرده، اشتراک را لغو کرده، مرورگر آن را تغییر داده یا سرویس Push endpoint را کنار گذاشته باشد. برنامه معمولاً نمی‌تواند فقط با بررسی یک فیلد در پایگاه داده، این موضوع را قطعی بداند. پاسخ سرویس Push در زمان ارسال یکی از مهم‌ترین سیگنال‌های عملیاتی است. کد پاسخ و بدنه خطا را با راهنمای کتابخانه و سرویس مربوط بررسی کنید و تنها بر پایه یک خطای شبکه عمومی اشتراک را حذف نکنید.

پاسخ‌های HTTP مانند 404 یا 410 در برخی سرویس‌های Push می‌توانند نشان دهند endpoint دیگر قابل‌استفاده نیست. تفسیر دقیق به سرویس و کتابخانه ارسال وابسته است؛ در بسیاری از پیاده‌سازی‌ها، این پاسخ‌ها دلیل مناسبی برای غیرفعال‌کردن اشتراک‌اند، اما بهتر است پیش از اجرای حذف گسترده، رفتار واقعی زیرساخت خود را اعتبارسنجی کنید. timeout، خطای DNS موقت، محدودیت نرخ یا خطای 5xx به‌تنهایی نشان نمی‌دهد اشتراک از بین رفته است. چنین خطاهایی باید در صف تلاش مجدد کنترل‌شده باقی بمانند.

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

پاک‌سازی دوره‌ای مفید است، اما معیار آن را هوشمندانه انتخاب کنید. اشتراکی که مدت‌ها پیام نگرفته لزوماً نامعتبر نیست؛ شاید کاربر پیام‌های کم‌تعداد را دریافت می‌کند یا برنامه مدتی فعالیت نداشته است. برعکس، اشتراکی که دیروز پیام گرفته هم می‌تواند امروز از کار بیفتد. قدم‌های مناسب عبارت‌اند از: پاک‌سازی رکوردهایی که سرویس Push صریحاً نامعتبر اعلام کرده، بررسی رکوردهای بدون رضایت قابل‌اثبات، حذف داده‌های منقضی طبق سیاست نگه‌داری و پایش نسبت خطاها به تفکیک مرورگر و نسخه سامانه.

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

لغو اشتراک و رعایت انتخاب کاربر

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

هنگام لغو، ابتدا انتخاب کاربر را در سرور ثبت کنید تا حتی اگر عملیات مرورگر به دلیل قطعی شبکه شکست خورد، سامانه ارسال دیگر پیام ناخواسته نفرستد. سپس تا حد امکان Subscription را از طریق unsubscribe لغو کنید و نتیجه را در سرور همگام سازید. ترتیب دقیق می‌تواند به محصول و دسترس‌پذیری شبکه وابسته باشد، اما اصل مهم این است که پس از درخواست کاربر، سرور سریعاً وضعیت ارسال را متوقف کند. لغو سمت مرورگر و حذف رکورد سرور را یک تراکنش واحد فرض نکنید؛ این دو سامانه مستقل‌اند و ممکن است یکی موفق و دیگری ناموفق شود.

اگر لغو مرورگر موفق شد ولی تماس با سرور شکست خورد، برنامه باید در فرصتی بعد تغییر را همگام کند. اگر سرور انتخاب کاربر را ثبت کرد ولی unsubscribe مرورگر شکست خورد، در رابط کاربری به‌جای ادعای خاموش‌شدن کامل، وضعیت را دقیق توضیح دهید و دوباره‌تلاش کنترل‌شده ارائه کنید. برای جلوگیری از فراموش‌شدن درخواست، می‌توان یک نشانگر محلی حداقلی نگه داشت؛ این نشانگر نباید جای وضعیت مرجع سرور را بگیرد و باید پس از همگام‌سازی پاک شود.

پاک‌کردن مجوز اعلان از تنظیمات مرورگر را خود سایت نمی‌تواند در همه مرورگرها کنترل کند. اگر مجوز به default یا denied تغییر کند، هنگام مراجعه بعدی وضعیت را بخوانید و Subscription موجود را بررسی کنید. در صورت نبود اشتراک، رکورد را طبق سیاست محصول غیرفعال کنید. مهم است این وضعیت را با کاربری که از داخل سایت فقط یک دسته پیام را خاموش کرده اشتباه نگیرید. مجوز مرورگر لایه دسترسی فنی است؛ ترجیحات محتوایی لایه‌ای جداست.

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

ارتباط اشتراک با حساب کاربری

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

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

در حساب‌هایی که چند کاربر مجاز دارند، دسترسی به مدیریت Subscription باید بر اساس اختیار همان حساب باشد. تغییر اشتراک یک کاربر نباید باعث حذف ناخواسته اشتراک همه اعضای سازمان شود. برای سامانه‌های چندنفره، نقش‌ها و مجوزها را در API بررسی کنید و هر تغییر را با actor و زمان ثبت کنید. برای رعایت حداقل‌گرایی، لازم نیست تمام اطلاعات هویتی را کنار endpoint ذخیره کنید؛ کلیدهای داخلی و ارجاع به مدل حساب می‌تواند کافی باشد.

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

امنیت و حریم خصوصی در ذخیره Subscription

Subscription را داده عملیاتی حساس در نظر بگیرید. افشای endpoint و کلیدهای همراه می‌تواند امکان سوءاستفاده یا ارسال پیام ناخواسته را افزایش دهد، حتی اگر این داده‌ها رمز عبور حساب نباشند. دسترسی پایگاه داده را به سرویس‌ها و کارکنانی محدود کنید که واقعاً به آن نیاز دارند؛ endpoint کامل را در داشبورد عمومی یا گزارش پشتیبانی نشان ندهید؛ و در لاگ، در صورت نیاز از شناسه داخلی یا نسخه ماسک‌شده استفاده کنید. دسترسی‌های مدیریتی باید ثبت و بازبینی شوند.

انتقال اطلاعات از مرورگر به سرور باید روی HTTPS باشد. کلید خصوصی VAPID هرگز نباید در کد فرانت‌اند قرار بگیرد؛ مرورگر فقط به کلید عمومی لازم برای ایجاد اشتراک نیاز دارد. کلید خصوصی و اعتبارهای ارسال را در مدیریت امن اسرار نگه دارید و برای محیط توسعه و تولید کلیدهای جدا استفاده کنید. اگر کلیدها چرخانده می‌شوند، برنامه تغییر را با اشتراک‌های موجود آزمایش کنید و مستندات کتابخانه و سرویس Push را دنبال کنید؛ تغییر کلید بدون برنامه ممکن است مسیر ارسال یا ساخت Subscription را مختل کند.

امنیت API ثبت اشتراک تنها به HTTPS محدود نیست. اعتبارسنجی نشست، مجوز اتصال به حساب، محدودسازی نرخ، بررسی منشأ درخواست در معماری مبتنی بر کوکی، محدودیت اندازه ورودی و مدیریت خطا هم ضروری‌اند. endpoint را ورودی قابل‌اعتماد فرض نکنید. در عملیات ارسال، کتابخانه معتبر Web Push را به‌کار ببرید و خودتان پروتکل رمزنگاری را بازنویسی نکنید. هیچ‌وقت داده‌ای را که از کلاینت دریافت کرده‌اید مستقیماً در HTML داشبورد قرار ندهید؛ آن را با قواعد مناسب خنثی‌سازی و نمایش دهید.

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

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

ملاحظات مرورگرها و وب‌اپ در iOS

رفتار Web Push بین مرورگرها و پلتفرم‌ها یکسان نیست؛ بنابراین پیاده‌سازی نباید فرض کند یک مسیر واحد در همه دستگاه‌ها وجود دارد. پشتیبانی Push API، شیوه نمایش درخواست مجوز، رفتار سرویس‌ورکر، وضعیت‌های اشتراک و ابزارهای توسعه می‌تواند متفاوت باشد. قابلیت اعلان وب در iOS و iPadOS از نسخه ۱۶٫۴ به بعد در شرایط مشخص پشتیبانی شده است و برای تجربه وب‌اپ نصب‌شده روی صفحه اصلی، مسیر کاربر اهمیت دارد. الزامات دقیق را با نسخه‌های فعلی سیستم‌عامل و مستندات رسمی مرورگر هدف آزمایش کنید.

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

از شناسایی مرورگر با رشته User-Agent به‌عنوان تنها معیار قابلیت استفاده خودداری کنید؛ این رشته ممکن است ناقص یا متغیر باشد. تشخیص قابلیت از APIهای موجود و رسیدگی به شکست واقعی مطمئن‌تر است. بااین‌حال، برای نمایش راهنمای ویژه پلتفرم می‌توانید از نشانه‌های کم‌خطر محیط استفاده کنید و آن‌ها را به‌عنوان تضمین قابلیت تلقی نکنید. تست را روی دستگاه واقعی، مرورگرهای اصلی و وضعیت‌های متفاوت مجوز انجام دهید؛ شبیه‌ساز به‌تنهایی برای بررسی نمایش اعلان و رفتار پس‌زمینه کافی نیست.

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

پایش، لاگ و شاخص‌های عملیاتی

سامانه مدیریت اشتراک بدون مشاهده‌پذیری، دیر یا زود به حدس‌زدن وابسته می‌شود. برای هر مرحله رخدادهای جدا تعریف کنید: نمایش پیشنهاد، شروع درخواست مجوز، نتیجه مجوز، ساخت Subscription، ارسال API، ثبت یا به‌روزرسانی در سرور، تلاش ارسال، پاسخ سرویس Push، حذف از چرخه و لغو از داخل سایت. رویدادها را با شناسه داخلی اشتراک یا شناسه رخداد پیوند دهید، نه با چاپ endpoint کامل. این ساختار امکان پیگیری یک مسیر را می‌دهد بدون آنکه داده حساس در داشبورد تحلیل پخش شود.

شاخص‌هایی مانند نسبت موفقیت ثبت به درخواست مجوز، سهم خطاهای ثبت API، تعداد اشتراک‌های تازه، درصد درخواست‌های ارسال با پاسخ دائمی نامعتبر، تعداد اشتراک‌های لغوشده و سن آخرین همگام‌سازی می‌توانند روند مشکل را نشان دهند. این شاخص‌ها باید تعریف روشن داشته باشند. برای نمونه، نرخ موفقیت ثبت را بر مبنای کاربرانی بسنجید که واقعاً اجازه داده‌اند، نه کل بازدیدکنندگان سایت؛ در غیر این صورت تغییر ترافیک یا نحوه نمایش دعوت به اشتراک، تفسیر عدد را به‌هم می‌زند.

داده را به تفکیک مرورگر، پلتفرم، نسخه کلاینت و نسخه API بررسی کنید؛ اما اندازه نمونه و حریم خصوصی را در نظر بگیرید. اگر خطا فقط پس از انتشار نسخه خاصی افزایش یافته، همبستگی زمانی می‌تواند سرنخ باشد، نه اثبات علت. رخدادهای سامانه را با انتشارها و تغییرهای کلیدهای VAPID مرتبط کنید. هشدارها را برای جهش غیرعادی در پاسخ‌های دائمی، خطای ثبت یا زمان انتظار صف تنظیم کنید. هشدار بیش‌ازحد زیاد باعث می‌شود تیم به آن بی‌توجه شود؛ آستانه را با خط مبنای واقعی تعیین کنید.

گزارش وضعیت باید واژگان دقیق داشته باشد: «درخواست به سرویس Push فرستاده شد»، «سرویس Push درخواست را پذیرفت»، «سرویس Push اشتراک را نامعتبر دانست» یا «کاربر روی اعلان کلیک کرد». هیچ‌یک را بدون شواهد با «اعلان قطعاً دیده شد» یکی نکنید. نمایش نهایی در اختیار مرورگر و سیستم‌عامل است و ممکن است تحت تأثیر حالت تمرکز، تنظیمات اعلان، اتصال، سیاست باتری یا رفتار خود کاربر باشد. تعریف دقیق شاخص‌ها مانع تصمیم‌های بازاریابی اشتباه می‌شود.

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

برنامه آزمون چرخه عمر اشتراک

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

سناریوی رد مجوز باید بدون خراب‌شدن عملکرد اصلی سایت تمام شود. بررسی کنید درخواست خودکار دوباره ظاهر نمی‌شود، وضعیت default با denied اشتباه نشده و راهنمای تنظیمات فقط در زمان مناسب نمایش داده می‌شود. سپس مجوز را از تنظیمات مرورگر تغییر دهید و ببینید مراجعه بعدی چگونه تغییر را تشخیص می‌دهد. به همین شکل، Subscription را از ابزارها یا تنظیمات قابل‌دسترس مرورگر لغو کنید و بررسی کنید سرور در ارسال‌های بعدی چه رفتاری دارد.

آزمون شکست شبکه مهم است. اتصال را هنگام ثبت API قطع کنید، پاسخ سرور را با تأخیر برگردانید، یک بار خطای 5xx بسازید و یک بار داده نامعتبر ارسال کنید. ببینید تلاش مجدد با backoff اجرا می‌شود، درخواست تکراری رکورد جدید نمی‌سازد و خطای موقت اشتراک را زودهنگام حذف نمی‌کند. در مرحله ارسال، پاسخ دائمی نامعتبر را از timeout و خطای موقت جدا کنید. این آزمون‌ها را در محیط آزمایشی انجام دهید و از ارسال اعلان ناخواسته به مشترکان واقعی بپرهیزید.

سناریوهای هویت و حریم خصوصی نیز باید در برنامه آزمون باشند: ورود کاربر پس از ثبت ناشناس، خروج از حساب، جابه‌جایی بین دو حساب در یک مرورگر، حذف حساب، استفاده از دستگاه مشترک و حذف داده‌های سایت. بررسی کنید یک حساب نمی‌تواند Subscription حساب دیگر را مدیریت کند و پس از خروج، پیام حساس با هویت قبلی باقی نماند. اگر محصول چند دسته اعلان دارد، لغو یک دسته نباید دسته‌های دیگر را بی‌دلیل خاموش کند.

در نهایت، ماتریس محیط بسازید: مرورگرهای دسکتاپ پرکاربرد، مرورگرهای Android، وب‌اپ‌های نصب‌شده در iOS و نسخه‌های پشتیبانی‌شده محصول. هر ترکیب لازم نیست تمام سناریوها را دستی و با همه نسخه‌ها اجرا کند؛ می‌توان آزمون خودکار قابلیت، آزمون دستی روی دستگاه واقعی و پایش پس از انتشار را ترکیب کرد. اما هر تغییر مهم در سرویس‌ورکر، تنظیمات VAPID، API ثبت یا مدل حساب باید مجموعه آزمون رگرسیون چرخه عمر را اجرا کند.

نقشه پیاده‌سازی مرحله‌ای

اگر اکنون اشتراک‌ها بدون مدل روشن ذخیره می‌شوند، بازنویسی کامل را با یک برنامه مرحله‌ای جایگزین کنید. ابتدا جریان فعلی را مستند کنید: محل ثبت مجوز، نسخه سرویس‌ورکر، ساختار پایگاه داده، API ثبت و نحوه مدیریت خطای ارسال. سپس اصطلاحات را یکسان کنید و وضعیت‌های مجوز، اشتراک مرورگر، ثبت سرور و رضایت محتوایی را از هم جدا سازید. این کار مشخص می‌کند مشکل فعلی دقیقاً در کدام مرحله است و جلوی اصلاح اشتباه را می‌گیرد.

  1. مرحله اول، تعریف قرارداد: ساختار ورودی و خروجی API، وضعیت‌های قابل‌قبول، سیاست تکرار، عملیات لغو و قواعد اتصال به حساب را بنویسید. شناسه‌های داخلی و کدهای خطا را مشخص کنید.
  2. مرحله دوم، اصلاح داده: فیلدهای لازم برای وضعیت فعال، زمان‌های ثبت و آخرین همگام‌سازی، دلیل غیرفعال‌شدن و شناسه پروژه را اضافه کنید. رکوردهای قدیمی را بدون حذف عجولانه ارزیابی و طبقه‌بندی کنید.
  3. مرحله سوم، بهبود کلاینت: بررسی قابلیت، ثبت سرویس‌ورکر، درخواست رضایت در زمان مناسب، خواندن Subscription موجود، همگام‌سازی و نمایش خطا را به مسیرهای جدا تقسیم کنید.
  4. مرحله چهارم، مقاوم‌سازی سرور: API را idempotent کنید، احراز هویت و مجوز را بررسی کنید، ورودی را محدود سازید و خطاهای دائمی ارسال را از خطاهای موقت جدا کنید.
  5. مرحله پنجم، ابزارپذیری: رخدادها و شاخص‌ها را اضافه کنید، داده حساس را از لاگ حذف کنید و برای تغییر غیرعادی نرخ خطا هشدار بسازید.
  6. مرحله ششم، انتشار کنترل‌شده: ابتدا روی گروه داخلی یا درصد محدودی از کاربران منتشر کنید، نتایج را بسنجید و در صورت مشکل امکان بازگشت به نسخه قبلی را نگه دارید.

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

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

خطاهای رایج و راه‌حل آن‌ها

  • یکی‌گرفتن مجوز و اشتراک: granted به‌تنهایی وجود Subscription را ثابت نمی‌کند. هر دو وضعیت را جدا بررسی و در گزارش جدا ثبت کنید.
  • ثبت دوباره در هر بار بازدید: ایجاد رکورد تازه به ازای هر درخواست، آمار و ارسال را خراب می‌کند. API را idempotent و کلیدهای یکتا را درست طراحی کنید.
  • حذف اشتراک با هر خطای ارسال: timeout یا خطای موقت به معنی endpoint مرده نیست. خطاهای دائمی و موقت را بر اساس پاسخ سرویس تفکیک کنید.
  • چاپ endpoint در لاگ: این کار داده عملیاتی حساس را در ابزارهای متعدد پخش می‌کند. شناسه داخلی یا مقدار ماسک‌شده ثبت کنید.
  • اجبار به مجوز: درخواست بدون زمینه و نمایش مداوم آن تجربه را آزاردهنده می‌کند. ارزش پیام و اختیار ردکردن را روشن سازید.
  • نادیده‌گرفتن لغو داخل سایت: تکیه صرف به تنظیمات مرورگر برای کاربر پیچیده است. مسیر واضح لغو و همگام‌سازی سرور فراهم کنید.
  • فرض مالکیت براساس دستگاه: دستگاه ممکن است مشترک باشد و حساب تغییر کند. اتصال Subscription به حساب را با رویداد ورود و خروج مدیریت کنید.
  • تکیه کامل به pushsubscriptionchange: پشتیبانی این رخداد در همه محیط‌ها تضمین‌شده نیست. بررسی کنترل‌شده و پاسخ ارسال را نیز در طراحی لحاظ کنید.
  • ادعای تحویل قطعی: پاسخ موفق سرویس Push، مشاهده اعلان را تضمین نمی‌کند. نام شاخص‌ها و پیام‌های گزارش را دقیق نگه دارید.
  • نگه‌داری بی‌پایان رکورد خاموش: داده قدیمی هم هزینه و ریسک دارد. سیاست حذف و مدت نگه‌داری را مستند کنید.

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

همچنین از به‌روزرسانی اشتراک بر اساس حدس درباره مرورگر پرهیز کنید. اگر endpoint تغییر کرد، اشتراک جدید را ثبت کنید؛ اما فقط به دلیل تغییر نسخه مرورگر، همه Subscriptionها را از نو نسازید. ایجاد بی‌مورد اشتراک تازه می‌تواند تعداد رکورد و احتمال خطای همگام‌سازی را بالا ببرد. رفتار واقعی API مرورگر و پاسخ سرویس را مبنا قرار دهید و تغییر را در داده‌های مشاهده‌پذیری دنبال کنید.

چک‌لیست نهایی مدیریت وب پوش نوتیفیکیشن

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

  • آیا کاربر پیش از نمایش پنجره مجوز می‌داند چه نوع پیامی دریافت خواهد کرد؟
  • آیا وضعیت default، granted و denied از وجود Subscription جدا نگه داشته می‌شود؟
  • آیا سرویس‌ورکر در scope درست ثبت می‌شود و خطای ثبت قابل‌تشخیص است؟
  • آیا اشتراک موجود پیش از ساخت اشتراک تازه بررسی می‌شود؟
  • آیا API ثبت در برابر تلاش دوباره و درخواست تکراری مقاوم است؟
  • آیا مالکیت اشتراک هنگام ورود، خروج و تغییر حساب طبق سیاست روشن تغییر می‌کند؟
  • آیا کاربر می‌تواند نوع اعلان یا کل اشتراک را از داخل سایت مدیریت کند؟
  • آیا پاسخ دائمی نامعتبر از خطای موقت شبکه جدا می‌شود؟
  • آیا endpoint و کلیدها در لاگ‌ها و داشبوردهای عمومی پنهان می‌مانند؟
  • آیا دوره نگه‌داری، حذف حساب و پاک‌سازی داده‌های پشتیبان تعریف شده است؟
  • آیا روی مرورگرها و دستگاه‌های هدف، لغو و تغییر مجوز آزمایش شده است؟
  • آیا گزارش‌ها بین پذیرش سرویس Push و مشاهده واقعی اعلان تفاوت می‌گذارند؟

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

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