Files
hedena_gold/docs/PHASE2-D3-PLAN.md
T
s.esmaeili ea86636027 Initial commit: Hedena Gold monorepo.
First commit of the Hedena Gold product (separate from gold-bank): branding, package names, and deploy defaults aligned to the new brand; legacy Henza trees stay local-only via .gitignore.
2026-10-15 17:19:10 +03:30

9.8 KiB
Raw Blame History

طرح فاز ۲ — قلم ۲ (D3): سه رفتار جامانده در اپ‌ها

تاریخ: ۱۴۰۵/۰۷/۲۰ (2026-10-12)

وضعیت — تصمیم مالک گرفته شد (۲۰۲۶/۱۰/۱۲)

«الف و ب مهم پس به ترتیب برو جلو — ج اصلا اولیوت نداره جزو اخرین چیز هایی هست که شاید درستش کنیم»

قلم تصمیم وضعیت
الف — پیام مهمان انجام شود ✅ انجام شد — گزینه ب (پیام + حفظ بازگشت به مقصد) در هر دو اپ
ب — گارد isLoaded انجام شود، طبق پیشنهاد پورت نشود ✅ ثبت شد به‌عنوان «عمداً تکرار نشد — D3/ب» در configStore.ts هر دو اپ
ج — آمار بازدید آخرین اولویت، شاید هرگز ⏸️ معوق — بخش «شکاف ۳» پایین به‌عنوان طرحِ آماده نگه داشته شد


چه چیزی قبلاً انجام شده (بررسی شد، ادعا نیست)

D3 ده کار بود. هفت‌تایش انجام شده است:

کار وضعیت مدرک
۵ صفحه /report، /report/detail، /ChildOrder، /customerChoice، /complete_profile ✅ در هر دو اپ apps/user-app/src/router/index.ts و همان فایل در user-app-v2 — هر پنج مسیر ثبت شده با meta.layout='FullPage'
گارد sts_verify_step_two روی تکمیل پروفایل ✅ router/index.ts گارد requiresIncompleteProfile؛ از سرور می‌پرسد نه از حافظه، پس پروفایلی که روی دستگاه دیگر کامل شده هم محترم است
سقف موجودی سبد v2 (capQty/maxQty) ✅ یکسان در هر دو اپ stores/cartStore.ts:80,88 در هر دو

سه کار باقی است و هر سه را بررسی و در مرجع تأیید کردم.


شکاف ۱ — رفتار مهمان: الان به صفحه ورود پرتاب می‌شود

مرجع (henza_pwa/src/router/index.ts:253-261): کاربر وارد‌نشده که یکی از پنج صفحه شخصی را باز کند، یک پیام «ابتدا وارد شوید» می‌بیند و به خانه می‌رود.

if (to.name === 'ordersList' || ... || to.name === 'completeProfile') {
    showNotify('ابتدا وارد شوید');
    return next({name: 'home'})
} else return next()

تارگت (apps/user-app/src/router/index.ts:139-141): به /login می‌رود با query.redirect، و هیچ پیامی نشان نمی‌دهد.

if (to.meta.requiresAuth && !session.isLoggedIn) {
  return { name: 'login', query: { redirect: to.fullPath } };
}

چرا مهم است: کاربر مهمان که روی «سفارش‌های من» می‌زند، بی‌هیچ توضیحی در صفحه ورود می‌افتد و نمی‌داند چه شد. رفتار مرجع صریح‌تر است و D3 هم همان را خواسته.

⚠️ یک تضاد که باید خودت تصمیم بگیری

رفتار فعلی تارگت از یک جهت بهتر است: query.redirect دارد، یعنی بعد از ورود، کاربر به همان صفحه‌ای که می‌خواست برمی‌گردد. رفتار مرجع این را ندارد — کاربر به خانه می‌رود و باید دوباره دستی به آن صفحه برود.

سه گزینه:

گزینه نتیجه
الف) عیناً مرجع toast + خانه. query.redirect از بین می‌رود. تطبیق کامل با D3.
ب) بهترین هر دو (پیشنهاد من) toast «ابتدا وارد شوید» نشان داده شود، ولی مقصد همان صفحه ورود با redirect بماند. کاربر هم می‌فهمد چه شد، هم بعد از ورود سرِ جایش برمی‌گردد. در ماتریس به‌عنوان «عمداً تکرار نشد» ثبت می‌شود.
ج) دست نزن شکاف باز می‌ماند و در ماتریس ثبت می‌شود.

هزینه هر سه یکی است (چند خط). تفاوت فقط در تجربه کاربر است.


شکاف ۲ — گارد isLoaded

مرجع (router/index.ts:263-266): کاربر وارد‌شده‌ای که داده‌های اولیه‌اش (memory.state.isLoaded) هنوز نیامده، به هر صفحه‌ای جز home برود به خانه برگردانده می‌شود — مگر آن مسیر meta.skipLoadedCheck داشته باشد.

تارگت: پورت نشده، و در کد صریحاً نوشته شده چرا:

// apps/user-app/src/stores/configStore.ts:19
// Not ported (no backend): promotionList, ignoreList, priceList, isLoaded.

نظر من: این یکی را نباید پورت کنیم، و پیشنهادم «نه» است.

دلیل: isLoaded در مرجع پرچمِ «یک درخواست بزرگ اولیه نشست» بود که تارگت ندارد — تارگت هر صفحه داده‌ی خودش را می‌گیرد. اگر این گارد را اضافه کنیم، چیزی به کاربر اضافه نمی‌شود و فقط یک پرش ناخواسته به خانه ساخته می‌شود: مثلاً کاربری که لینک محصول را از تلگرام باز می‌کند، به‌جای محصول در خانه می‌افتد. این دقیقاً مصداق «باگ مرجع را پورت نکن» (D4) است.

اگر موافقی، به‌عنوان «عمداً تکرار نشد — D4» ثبت می‌شود و D3 بسته می‌شود. اگر مخالفی، پورت می‌کنم.


شکاف ۳ — آمار بازدید صفحه‌ها (log/create و log/update)

مرجع دو مسیر دارد و زمان ماندن کاربر در هر صفحه را اندازه می‌گیرد:

مرجع
ورود به صفحه POST /log/create/{title} → یک ردیف با start_at، ip، title، customer_id (اگر وارد شده باشد) می‌سازد و id را برمی‌گرداند
خروج از صفحه GET /log/update/{id} → end_at و time_present را پر می‌کند
صفحه محصول data: {product_id} هم می‌فرستد تا بازدید هر محصول جدا شمرده شود
مستثنا login و userPage::hasSubRoute

مرجع: henza_server/app/Http/Controllers/Api/LogController.php، henza_pwa/src/router/customAnalytics.ts.

تارگت: نه مسیر، نه جدول، نه فراخوانی. کامل غایب.

این بزرگ‌ترین قلم از سه‌تاست — جدول، مدل Prisma، مهاجرت، دو مسیر API، یک composable در هر اپ، و صفحه‌های گزارش ادمین (queryTitle، queryAllCustomer، queryCustomer، ago) که آمار را نشان می‌دهند.

⚠️ دو ایراد مرجع که عیناً پورت نمی‌کنم

۱. مسیر بی‌محافظ است. در مرجع log/create احراز هویت ندارد و هر عنوانی را می‌پذیرد، پس هر کسی از بیرون می‌تواند جدول را با ردیف‌های جعلی پر کند و آمار را بی‌معنا یا دیسک را پر کند. پیشنهاد: عنوان فقط از یک فهرست بسته (نام مسیرهای واقعی) پذیرفته شود و نرخ درخواست محدود شود. ۲. GET که داده را عوض می‌کند. log/update یک GET است که ردیف را می‌نویسد. پیشنهاد: POST باشد. (اپ‌های تارگت تازه نوشته می‌شوند، پس سازگاری عقب‌رو لازم نیست.)

⚠️ و یک پرسش که فقط تو می‌توانی جواب بدهی

این قابلیت رفتار هر مشتری را با IP ثبت می‌کند — کدام صفحه‌ها را دید و چند ثانیه ماند. فنی‌اش ساده است، ولی این داده‌ی شخصی است و مرجع هیچ‌وقت آن را پاک نمی‌کرد (جدول بی‌نهایت رشد می‌کند).

سه پرسش:

پرسش پیشنهاد من
این آمار را واقعاً لازم داری، یا در سیستم قدیم هم عملاً نگاهش نمی‌کردی؟ اگر نگاهش نمی‌کردی، نسازیم. ساده‌ترین قابلیت، قابلیتی است که وجود ندارد.
اگر لازم است، چند وقت نگه داشته شود؟ ۹۰ روز، و قدیمی‌ترها خودکار پاک شوند.
IP هم ذخیره شود؟ نه. برای «کدام صفحه چقدر دیده شد» لازم نیست و حساس‌ترین بخش داده است.

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

# قلم پیشنهاد من هزینه
۱ toast مهمان گزینه ب — هم پیام، هم بازگشت به صفحه مقصد کم (نیم ساعت، هر دو اپ)
۲ گارد isLoaded پورت نشود — «عمداً تکرار نشد — D4» صفر
۳ آمار بازدید اول جواب بده لازمش داری یا نه. اگر بله: با عنوان بسته، POST، بدون IP، نگه‌داری ۹۰ روزه متوسط تا زیاد (جدول + مهاجرت + ۲ مسیر + ۲ اپ + صفحه گزارش ادمین)

اگر بگویی «قلم ۱ و ۲ را انجام بده، ۳ را فعلاً نه»، D3 با یک ردیف «عمداً تکرار نشد» برای آمار بسته می‌شود و می‌رویم سراغ قلم بعدی فاز ۲.