53 KiB
پلن پورت اپ کاربر کلاسیک — henza_pwa → apps/user-app-classic
سند برنامهریزی. قبل از تأیید شما هیچ کدی نوشته نمیشود.
مرجع پینشده:
henza_pwaدر کامیتb171fff(2026-09-02، «fee in bonakdar removed»). هر ارجاعpath:lineدر این سند به همین نسخه است و نسبت بهhenza_pwa/نوشته شده. منبع اصلی شواهد:docs/parity/_inv-ref-pwa.md(سیاههی کامل مرجع) بهعلاوهی راستیآزمایی مستقیم روی کد. اگر مرجع عوض شد، این سند باید دوباره راستیآزمایی شود.
خواسته
- یک اپ کاربر سوم در مونوریپو، کنار
user-appوuser-app-v2. - طراحی آن = طراحی قبلی همین سیستم، یعنی
henza_pwa. - همهی صفحهها، کارکردها، عملیات، انیمیشنها و ناوبری دقیقاً مثل مرجع.
- با تکنولوژی جدید و کد بهتر.
- هیچ چیزی از بین نرود.
قرارداد «دقیقاً مثل مرجع»
| لایه | قاعده |
|---|---|
| آنچه کاربر میبیند و انجام میدهد | عیناً مرجع. چیدمان و ابعاد، رنگها، فونت، آیکونها، متنهای فارسی (بایتبهبایت — حتی فاصلهی دوتایی بعد از «لطفا» و غلط املایی «کارکتر»)، ارقام، ترتیب و برچسب تبها، پیامهای اعتبارسنجی، رنگ و مدت toast ها، پارامترهای انیمیشن، مسیرها و نام route ها، رفتار guard ها، محاسبهها و گرد کردنها. |
| زیر کاپوت | بازنویسیشده و بهتر. TypeScript با strict، Pinia، composable ها، یک لایهی HTTP تایپشده، تنظیمات از env، حذف کد مرده و تکراری، تست. |
| کوییرک بصری بیخطر | عیناً تکرار میشود — مثلاً notify ورود که حتی برای موفقیت قرمز است، یا تشدید سرگردان در «ّکاربر فعال شود؟». |
| استثنا | فقط خرابیهای کارکردی مرجع، طبق D4. هر کدام شماره دارد، در §تنش ۴ و §چیزی که پورت نمیشود فهرست شده، و هیچکدام بیصدا نیست. |
«هیچ چیزی از بین نرود» دو معنا دارد و هر دو تعهد این پلن است:
- هیچ صفحه، کارکرد، انیمیشن یا متنی از مرجع جا نمیماند — با سرشماری خودکار اثبات میشود (§معیار تمام شد).
- هیچ چیز موجود در مونوریپو آسیب نمیبیند —
user-app،user-app-v2وadmin-panelدست نمیخورند؛ تغییراتapps/apiفقط افزایشی است.
قواعد حاکم (ارثبرده از پروژه)
henza_pwa/،henza_server/وhenza_admin/فقط خواندنیاند. برای اجرای مرجع یک کپی بیرون از آنها ساخته میشود؛ حتیnode_modulesهم داخلشان نصب نمیشود.- D4 — رفتار تکرار میشود، خرابی نه. هر عدمتکرار عمدی در ماتریس: «عمداً تکرار نشد — ISSUE #n».
- D2 — چیزی که مرجع ندارد ساخته نمیشود. یعنی اپ کلاسیک صفحهی اعلانها، تنظیمات ظاهر و تب پنجم ناوبری را ندارد، چون مرجع ندارد.
- PROTECTED.md —
user-appوuser-app-v2دست نمیخورند. حتی بازساختاردهی (مثلاً بیرون کشیدن کد مشترک) تأیید جدا میخواهد. - D13 — سطوح فروشگاه تکفروشی (کیف پول، cashback، قیمت محصول طبق D16) دست نمیخورند.
- D12 — ماتریس فیلد به فیلد، و تست رفتوبرگشت برای هر موجودیتی که endpoint نوشتنی تازه میگیرد.
- D18 — تأیید دائمی برای شکافهای بیابهام؛ توقف فقط برای موارد فهرست D18.
- T1 / D21 — مشتری همیشه از توکن، هرگز از بدنه یا URL؛ ادعای
typ؛ تست توکن متقابل. - D25 — خواندن env فقط با
envOr/envOrNull. - D15 — تستهایی که ورودی فارسی دارند، ورودی را از فایل UTF-8 میخوانند.
⚠️
CLAUDE.mdدر این مخزن نیست. اسناد parity مدام به §2، §3، §4 و §6 آن ارجاع میدهند، ولی فایل در ریشهی workspace قبلی بوده. قواعدش از روی همین ارجاعها بازسازی شده: §2 منطق اپهای کاربر باید یکسان باشد و فقط طراحی فرق کند؛ §3 باگ مرجع تکرار و ثبت شود، مگر حفرهی امنیتی در جریان پول — آنجا توقف و سؤال؛ §4 PROTECTED فقط افزایشی؛ §6 هر حذف داده در CHANGELOG ثبت شود. پیشنهاد: نسخهی اصلی را به مخزن برگردانید تا متن اصلی جای این بازسازی را بگیرد.
دامنهی واقعی کار (اعداد راستیآزماییشده)
| سنجه | عدد | نحوهی راستیآزمایی |
|---|---|---|
| route | 22 (۲۱ واقعی + catch-all) | _inv-ref-pwa.md §3 |
فایل .vue غیر vendored |
77 فایل، 12,445 خط | find src -name '*.vue' بدون دو پوشهی DatePicker |
فایلهای views/ |
34 — سهتا مرده: login.vue (کل فایل کامنت)، user/src/components/report.vue (صفحهی دیباگ)، NotificationList.vue (سوار نشده) |
§6.1 |
| کامپوننت اپ | 40 | §9 |
| store | ۹ singleton دستساز + ۱ Pinia | §7 |
| endpoint یکتا | 44 در ۵۸ محل فراخوانی → ۳۹ ردیف کارکردی زنده بعد از کنار گذاشتن مردهها | §2.4 + §نقشهی endpoint در همین سند |
| پوشش API هدف از آن ۳۹ ردیف | ✅ 12 · 🟡 9 · ❌ 18 | §نقشهی endpoint |
@keyframes |
8 | grep |
محل <transition> |
۷ زنده + ۲ کامنتشده (از جمله انتقال بین صفحهها) | grep |
GSAP / useTransition |
۱ / ۱ — هر دو در ناوبری پایین | navigation.vue:83,110 |
| overlay | ۲۰ Drawer، ۳ Modal، ۲ van-action-sheet |
grep |
| asset | ۲۴ svg، ۹ png، ۱ jpg، ۱ ico، فونت Yekan Bakh FaNum (۸ وزن × ۳ فرمت)، icons.json |
find src/assets public |
| نقص شناختهشدهی مرجع | 20 | §13 |
«تکنولوژی جدید» — چه چیزی عوض میشود و چه چیزی نه
کتابخانههای UI روی نسخهی lockfile مرجع قفل میشوند
یافته: yarn.lock مرجع خودش Vue 3.5.40 را resolve کرده. پس «تکنولوژی جدید» در
کتابخانههای UI معنایی ندارد — و نباید داشته باشد، چون ظاهر پیکسلی دقیقاً به همین نسخهها
وابسته است. مثلاً ant-design-vue 4 استایل را به CSS-in-JS برده و ظاهر عوض میشود.
| بسته | نسخهی دقیق (بدون ^) |
|---|---|
ant-design-vue |
3.2.20 |
vant |
4.10.0 — v1/v2 روی 4.10.2 هستند؛ اپ کلاسیک نسخهی مرجع را میگیرد |
swiper |
7.4.1 |
gsap |
3.15.0 |
tailwindcss |
3.0.18 |
@vueuse/core |
9.13.0 |
moment-jalaali |
0.10.4 |
@lottiefiles/dotlottie-vue |
0.4.18 |
vue3-lazyload |
0.2.5-beta |
vue / vue-router |
3.5.x / 4.x — همان خانوادهی lockfile |
ارقام فارسی از فونت میآیند، نه از تبدیل. مرجع هیچ تبدیل رقمی ندارد (§8.1)؛ ارقام بهخاطر فونت FaNum فارسی دیده میشوند. اپ کلاسیک هم تبدیل رقم اضافه نمیکند.
آنچه واقعاً نو میشود
| مرجع | اپ کلاسیک | چرا |
|---|---|---|
| Vite 3 + plugin-vue 2، TS 4.4 بدون strict، vue-tsc 0.29 | Vite 5، TS 5 با strict، vue-tsc 2 — همان زنجیرهی v1/v2 |
ابزار نگهداریشده؛ خطا در زمان build |
| axios 0.25 با سه instance؛ interceptor خطا promise را برنمیگرداند؛ response interceptor ندارد | یک client تایپشده؛ توکن در هر درخواست؛ رفتار 401 مرجع (myStore.init()) بهصورت سراسری |
نقص #1 و #2 |
| ۹ singleton کلاسی دستساز | Pinia — با همان شکل state و همان getter های readonly | یکدستی با v1/v2 |
Mixin ها (getProducts، product، favorite، ...) |
composable های تایپشده با تست واحد | قابل تست |
| URL و کلید هاردکد در ۵ فایل | متغیرهای VITE_* |
پیکربندی محیطها |
| دو درخت vendored از DatePicker (fork از ant-design-vue) | generatePicker عمومی ant-design-vue 3 با config جلالی — به شرط اثبات ظاهر یکسان در Phase 0 |
حذف هزاران خط کد شخص ثالث |
| ۵ کتابخانهی تاریخ | moment-jalaali برای فرمتها (خروجی یکسان) + dayjs/jalaliday فقط برای picker |
کمتر، با تست خروجی |
۴ کامپوننت تقریباً یکسان ScrollFetch* |
یک کامپوننت با prop | تکرار |
addTransaction.vue و addFindoc.vue تکراری |
یک فرم، دو پوسته (صفحه و drawer) | تکرار |
| کد مرده (§چیزی که پورت نمیشود) | پورت نمیشود | — |
PWA در mode: "development" |
production | نقص #17 |
| بدون تست | تست واحد (adapter، formatter، validator، موتور تخفیف) + e2e و مقایسهی تصویری با Playwright | اثبات «دقیقاً» |
تنشهایی که قبل از شروع باید تصمیمشان را بدانید
تنش ۱ — ۱۸ endpoint مرجع در API هدف نیست
از ۳۹ ردیف زنده، ۱۸ تا در هدف معادل ندارند و ۹ تا ناقصاند (§نقشهی endpoint). بدون آنها «دقیقاً مثل مرجع» ممکن نیست. وضعیت امروز v1/v2 این را نشان میدهد:
- ثبتنام هیچ چیزی ذخیره نمیکند — کامنت خود
RegisterView.vue:17این را میگوید. - علاقهمندیها فقط محلیاند (
favoritesStore.ts:1-3). - ثبت سند، سفارش ساخت، مدیریت مشتری توسط کارشناس، ویرایش سفارش مشتری، آنالیتیکس و فاکتور اصلاً وجود ندارند.
ساختن اینها در apps/api افزایشی است (route و جدول/ستون جدید). ولی با CLAUDE.md §2
تعارض دارد: منطق اپهای کاربر باید یکسان باشد. به محض اینکه اپ کلاسیک ثبتنام و
علاقهمندی واقعی داشته باشد، v1 و v2 عقب میافتند.
پیشنهاد: بکاند یک بار، افزایشی و تستشده ساخته شود. وصل کردن v1/v2 به آن یک کار جدا و ثبتشده باشد — نه بخشی از این پروژه. تصمیم شما لازم است که §2 شامل اپ کلاسیک هم میشود یا نه.
تنش ۲ — «انتخاب مشتری»: کار کردن بهجای مشتری
در مرجع: کارشناس فروش (type 1) روی یک مشتری میزند → toggleActiveUser توکن خود آن
مشتری را بهعنوان activeChildToken ذخیره میکند، و این توکن روی همهی درخواستها
اولویت دارد (store/tokenManage.ts:8-10، store/myDataStore.ts:159-169). از آن لحظه کل اپ
بهجای مشتری کار میکند: میز کار موجودی مشتری را نشان میدهد، سفارش سبد روی حساب مشتری
با from_parent: true ثبت میشود تا پیامک به کارشناس برسد (views/cart.vue:162-164)،
و دکمه به «خروج از حساب مشتری» تبدیل میشود.
در هدف: D21 سازوکار را رد کرد — ساختن توکن مشتری برای کارشناس یک ابزار ربودن نشست
است. CustomerChoiceView در v1 با لمس کارت فقط یک drawer جزئیات باز میکند
(openDetail). پس خود این قابلیت امروز در هدف وجود ندارد.
پیشنهاد: همان قابلیت، با سازوکار امن:
- توکن خود کارشناس + هدر
X-Acting-As: <customerId>. - سرور در هر درخواست چک میکند
referredByAgentIdآن مشتری = همین کارشناس. - موضوع همهی route های مشتری = آن مشتری.
- سفارش با پرچم
from_parentثبت میشود. - هر تعویض در لاگ ثبت میشود.
- هیچ توکنی ساخته نمیشود و سمت کلاینت فقط شناسهی مشتری انتخابشده نگه داشته میشود.
تأیید شما لازم است، چون امنیت و جریان پول است (CLAUDE.md §3). این کار ریسک REL-03 را هم
بالاتر میبرد — §پیشنیازها.
تنش ۳ — نقش کارگاه (type 5) در اپ
در مرجع: سرپرست کارگاه یک ردیف مشتری با type 5 است. کاشی «سفارش ساخت» برایش مستقیم به
صفحهی وضعیت میرود و دکمههای «تایید سفارش» و «ارسال سفارش» را میبیند
(makeOrderStatus.vue:68-75).
در هدف دو نامزد هست:
AdminUserبا نقشWORKSHOP_SUPERVISOR—Workshop.supervisorIdبه اینجا اشاره میکند وPreOrder.workshopIdبهWorkshop.Customerباkind = WORKSHOP_SUPERVISOR— این مقدار درCustomerKindهست و برخلافSALES_AGENTمنسوخ اعلام نشده.
D21 فقط به SALES_EXPERT اجازهی ورود به اپها را داده.
پیشنهاد: AdminUser، چون مسیر دادهای تمیز همین است. الگوی D21 به WORKSHOP_SUPERVISOR
گسترش پیدا کند، با دامنهی محدود به PreOrder های کارگاه خودش. تصمیم شما لازم است،
از جمله اینکه مشتری با kind = WORKSHOP_SUPERVISOR در این صورت چه نقشی دارد.
تنش ۴ — خرابیهای مرجع که به منطق کسبوکار میخورند
D18 برای اینها توقف میخواهد (مورد ۴). شمارهها از _inv-ref-pwa.md §13 است.
| # | خرابی در مرجع | اثر برای کاربر | پیشنهاد من |
|---|---|---|---|
| 4 | دکمهی ثبت در صفحهی addTransaction بیرون از <Form> است و html-type="submit" ندارد (addTransaction.vue:84-97) |
ثبت سند از صفحه کار نمیکند؛ فقط از drawer | درست شود — یک فرم مشترک، هر دو پوسته کار کنند |
| 5 | کاشی «سفارش مشتریان» تابع را صدا نمیزند (Dashboard.vue:119) |
کارشناس از میز کار به آن صفحه نمیرسد | درست شود — D3 خود صفحه را خواسته |
| 6 | کادرهای تهحساب طلایی و ریالی اندیسها و formatter ها را جابهجا خواندهاند (Dashboard.vue:182-192) |
موجودی طلا و ریال در کادر اشتباه و با قالب اشتباه | هر کادر مقدار درست را با قالب متناسب با برچسبش نشان دهد |
| 8 | دکمهی بهروزرسانی قیمت، فهرستی را تازه میکند که نمایش داده نمیشود (store.ts:107 در برابر Dashboard.vue:632) |
بهروزرسانی بیاثر | قبلاً تصمیم گرفته شده (D4): فهرست دیدهشده تازه شود |
| 9 | «ارسال سفارش» همان {sts: 2} «تایید سفارش» را میفرستد (makeOrderStatus.vue:212,234) |
ارسال در سرور ثبت نمیشود | تایید → «تایید کارگاه»، ارسال → «ساخته شده آماده ارسال». مقدار دقیق PreOrderStatus را شما تعیین کنید |
| 12 | radio «حواله به» اندیس آرایه را میفرستد نه متن مقصد (addTransaction.vue:50). سرور مرجع کل بدنه را بیتغییر ذخیره میکرد (ApiMobileController::setFindoc) |
مقصد حواله بهصورت عدد ذخیره میشد | سرور اندیس را به متن مقصد نگاشت کند؛ UI بیتغییر |
| 14 | در editUser سه آپلودر مدرک شناسه را دور میریزند و دو تا یک fileList مشترک دارند (editUser.vue:65,69) |
آپلود «موفق» دیده میشود ولی چیزی ذخیره نمیشود | عیناً تکرار شود و ثبت شود — وصل کردنش دادهی احراز را از صفحهای عوض میکند که مرجع هرگز اجازه نداده بود |
| 15 | شرط infinite scroll گزارش tableData.value.count را میخواند که هرگز مقدار نمیگیرد (report/index.vue:234) |
فقط صفحهی اول گزارش دیده میشود | درست شود — endpoint های D24 صفحهبندی دارند |
| 19 | پسوند تومان روی فیلدی به نام rial_remain (filters/index.ts:13)؛ ستون هدف fiatDebtRial به ریال است |
اگر واحدها نخوانند، بدهی ده برابر کم یا زیاد خوانده میشود | اول در henza_server واحد واقعی rial_remain معلوم شود؛ بعد adapter همان عدد و برچسبی را نشان دهد که مرجع برای همان بدهی نشان میداد |
| — | singleProduct دکمهی back را میرباید: history.pushState + window.onpopstate = () => history.go(1)، سراسری و هرگز برداشته نمیشود (singleProduct.vue:376-379) |
بعد از دیدن اولین محصول، back مرورگر یا گوشی در کل اپ از کار میافتد | محدود به خود صفحهی محصول — نیت ظاهری کد همین است، نشتش به کل اپ خرابی است |
تنش ۵ — سرور هدف از مرجع سختگیرتر است
سرور مرجع تقریباً هر چیزی را قبول میکرد. سرور هدف بیشتر رد میکند: قاعدهی موجودی و
پیشسفارش (PROTECTED §C.1)، MON-05 وقتی اجرا شود، DTO های اعتبارسنجی، قیدهای یکتایی.
ولی UI مرجع در بیشتر خطاها هیچ چیزی نشان نمیدهد — فقط console.log(e)، مثلاً در
Register.vue:340-342، cart.vue:189-191 و ثبت سند. پس درخواستی که مرجع بیصدا قبول میکرد،
در اپ کلاسیک بیصدا شکست میخورد و کاربر گیج میشود.
| مورد | پیشنهاد من |
|---|---|
سقف موجودی: سبد مرجع سقف ندارد؛ قاعدهی موجودی هدف (capQty/maxQty در v1) وجود دارد |
سقف بیصدا در دکمهی + اعمال شود — بدون هیچ عنصر یا متن تازه |
| خطاهای بیصدا | هر جا مرجع بیصدا بوده بیصدا بماند، مگر جایی که سرور هدف ردی میکند که مرجع هرگز نداشت. آنجا نزدیکترین پیام موجود مرجع نشان داده شود (مثلاً «خطا در ثبت سفارش» از makeOrder.vue:229). هیچ متن تازهای ساخته نمیشود |
تصمیمهای کوچکتر
| # | سؤال | پیشنهاد من |
|---|---|---|
| Q1 | نام، مسیر و پورت اپ | apps/user-app-classic، پورت 5183 (USER_APP_CLASSIC_PORT)، سرویس docker با همین نام. «classic» و نه «v3»، چون v3 «جدیدترین» را القا میکند در حالی که این قدیمیترین طراحی است |
| Q2 | کد مشترک بین سه اپ | فعلاً داخل خود اپ در src/core/ (api، adapter، قواعد دامنه)، با مرز تمیز تا بعداً قابل استخراج باشد. پکیج مشترک یعنی بازساختاردهی v1/v2 → PROTECTED → تصمیم جدا |
| Q3 | فیلتر رنگ در جستوجو — هدف اصلاً دادهی رنگ ندارد (Product و ProductVariant فقط brand دارند) |
مدل افزایشی Color و ارتباطش با variant؛ ویرایشش در پنل ادمین کار جداگانه است. تا آن موقع فهرست خالی — همان چیزی که مرجع با دادهی خالی نشان میداد |
| Q4 | تابلوی قیمت میز کار: مرجع ۱۴ ردیف دارد (۸ طلا و سکه + ۶ ارز و انس، store.ts:118-119)؛ هدف فقط نرخ طلا به ازای عیار |
ردیفهایی که هدف دادهی واقعی برایشان دارد نمایش داده شوند؛ بقیه حذف (قاعدهی صداقت، مثل REP-01) تا منبع قیمت تأیید شود. منبع خارجی = تصمیم شما |
| Q5 | ترتیب دستههای خانه: آرایهی هاردکد [37, 45, 31, 32, 42, 26, 36, 35, 34] با شناسهی عددی legacy (home/index.vue:189-204)؛ شناسهی Category در هدف cuid است و نه legacyId دارد نه ستون ترتیب |
ستون افزایشی ترتیب روی Category و پر کردنش از نگاشت مهاجرت. پر کردن = تغییر دادهی موجود → D18 توقف #5 → تأیید لازم |
| Q6 | آنالیتیکس مهمان: مرجع برای مهمان هم لاگ میفرستد؛ CustomerActivityLog.customerId اجباری است و ستون پایان ندارد |
فقط کاربر واردشده لاگ شود؛ ستون افزایشی endedAt برای معادل log/update |
| Q7 | اعلانها، FCM و پرکردن خودکار OTP — هر سه در مرجع سوار نیستند یا غیرفعالاند | ساخته نمیشوند — دقیقاً مثل مرجع |
| Q8 | اجرای مرجع برای مقایسهی تصویری | کپی در .parity/ref-pwa/ (gitignored) و رهگیری شبکه با Playwright؛ خود مرجع دست نمیخورد |
| Q9 | وضعیت D19 (حالت تحویل) | این پلن فرض میکند D19 تمام شده و D18 برقرار است |
پیشنیازهای باز از کارهای قبلی
| مورد | چرا این اپ به آن نیاز دارد | Batch |
|---|---|---|
D9 قدم ۵ — جابهجایی filterPercentPay به اندازهی آفست مشتری |
اسلایدر اجرت در فیلتر جستوجو | B |
شکاف یکتایی شماره بین Customer و AdminUser — هر چهار بررسی تداخل فقط adminUser را چک میکنند؛ در ISSUES.md ثبت نشده |
ثبتنام و «افزودن کاربر» هر دو مشتری میسازند | A، F |
| MON-08 — سرور اجرت و تخفیف را خودش بسازد | ثبت سفارش از سبد | E |
MON-05 — اجرای canPlaceOrders و verificationStep |
مرجع فقط در کلاینت چک میکند (sts_verify_step_two === 2) |
E |
REL-03 — مقدار جدای JWT_CUSTOMER_SECRET |
کار بهجای مشتری (تنش ۲) ریسک آن را بیشتر میکند | قبل از F |
نقشهی endpoint ها — مرجع ↔ هدف
✅ موجود (فقط adapter شکل) · 🟡 ناقص · ❌ وجود ندارد
| # | مرجع | هدف امروز | وضعیت | Batch |
|---|---|---|---|---|
| 1 | POST /web/auth |
POST /customer/auth/request-otp |
✅ | A |
| 2 | POST /user-verfiy |
POST /customer/auth/verify-otp |
✅ — رد ورود برای sts_verify_step_one == 3 بررسی شود |
A |
| 3 | POST /major/register |
— | ❌ | A |
| 4 | POST /major/complete |
POST /customer/me/complete-profile |
✅ (D22) | A |
| 5 | POST file/create |
POST /customer/me/documents |
✅ با purpose |
A، D، G |
| 6 | POST /me-data |
GET /customer/me |
🟡 هیچکدام از filterBrand، filterColor، filterGram، filterPercentPay، favorits، to، reagent، grams_sell، mcode را ندارد |
Phase 2 |
| 7 | POST /front |
GET /catalog/products |
🟡 دستهها، more و ciny آماده نیستند |
B |
| 8 | POST /get-products (Query) |
GET /catalog/products |
🟡 فیلتر و صفحهبندی سمت سرور ندارد (STUB-03) | B |
| 9 | POST /get-products (products_id) |
GET /catalog/products |
🟡 | B، E |
| 10 | GET /ciny/{cat} |
داخل catalog (collections) |
🟡 | B |
| 11 | GET /product/{id} |
— فقط فهرست | 🟡 | B |
| 12 | GET /config |
GET /home/slider |
🟡 about ندارد |
B |
| 13 | GET /promotion |
— | ❌ | B |
| 14 | GET /ignore |
— | ❌ | B |
| 15 | GET /price |
GET /pricing/latest |
🟡 فقط طلا به ازای عیار (Q4) | C |
| 16 | GET /tahesab/me |
GET /customer/me/report/balances |
✅ (D24) | C |
| 17 | POST /add-to-fav |
— | ❌ (v1/v2 محلی) | D |
| 18 | POST /get-favorites |
— | ❌ | D |
| 19 | POST /get-orders |
GET /customer/me/orders |
✅ فیلتر sts در کلاینت |
D |
| 20 | POST /update-profile |
— | ❌ | D |
| 21 | POST /get-my-findoc |
GET /customer/me/ledger-entries |
🟡 شکل متفاوت | D |
| 22 | POST /set-findoc |
— | ❌ | D |
| 23 | GET /fin_tahesab/table |
GET /customer/me/report |
✅ (D24) | D |
| 24 | GET /fin_tahesab/my_detail/{offset} |
GET /customer/me/report/detail |
✅ | D |
| 25 | GET /fin_tahesab/detail/{code} |
GET /customer/me/report/:id |
✅ | D |
| 26 | report/order?order_id — فاکتور با window.open |
— | ❌ | D |
| 27 | report/doc?doc_id — فایل سند |
— | ❌ | D |
| 28 | POST /set-order |
POST /orders |
✅ (MON-08) | E |
| 29 | POST /my-child |
POST /expert/my-customers |
✅ | F |
| 30 | POST /customer/toggle-active |
— | ❌ | F |
| 31 | POST /customer/create |
— | ❌ | F |
| 32 | POST /customer/update |
— | ❌ | F |
| 33 | GET admin/major/list_type |
— | ❌ از CustomerKind ساخته میشود |
F |
| 34 | POST /order/child |
POST /expert/child-orders |
✅ | F |
| 35 | PUT /order/child/{id} |
— | ❌ | F |
| 36 | POST /create-custom-order |
— مدل PreOrder فقط در ادمین |
❌ | G |
| 37 | GET /get-custom-orders |
— | ❌ | G |
| 38 | POST /update-custom-order/{id} |
— | ❌ | G |
| 39 | POST /log/create/{key} + GET /log/update/{id} |
— | ❌ | G |
ساخته نمیشوند (در مرجع مردهاند): POST /hesab_detail/table (هرگز صدا زده نمیشود)،
تکرار GET /ignore در getCustomerListType، تکرار مردهی toggle-active در Dashboard،
POST /cities/list (داده گرفته میشود ولی UI آبشاری کامنت است و فیلد شهر متن آزاد است —
Register.vue:58-64)، و سه endpoint اعلان (کامپوننتشان سوار نیست).
مشخصات حس و حرکت — انیمیشنها و ناوبری
این بخش همان چیزی است که یک پورت سرسری از دست میدهد. هر ردیف در Phase 0 با ضبط frame اثبات میشود.
انیمیشنها
| # | انیمیشن | پارامتر دقیق | محرک | شاهد |
|---|---|---|---|---|
| 1 | فرورفتگی (notch) ناوبری پایین | gsap.to('.from-path', {duration: .3, attr: {d: draw()}}) |
تغییر تب | components/ui/navigation.vue:50-86 |
| 2 | جابهجایی آیکون فعال | useTransition با TransitionPresets.easeInOutCubic، 150ms |
تغییر تب | navigation.vue:110-117 |
| 3 | shutter هدر | @keyframes shutter در 1s با cubic-bezier(0.33, 1, 0.68, 1)؛ max-height از 0 تا 120px و opacity از 0 تا 1 |
هر تغییر route: afterEach پرچم را false و بعد از 100ms دوباره true میکند |
components/appHeader.vue:1-45، router/index.ts:273-286 |
| 4 | فاصلهی محتوا از هدر | margin-top = headerHeight وقتی transitionEnded |
همراه ۳ | components/content.vue:2 |
| 5 | انتقال بین صفحهها | ندارد. <transition> در App.vue:6,17 کامنت است. CSS slideDown (App.vue:151-166) و setPgaTransition زندهاند ولی به هیچ چیز وصل نیستند |
— | اضافه نمیشود |
| 6 | باز شدن بخش فیلتر | @keyframes drop با mode="out-in" appear |
باز و بسته کردن | components/dropDown.vue:11,40 |
| 7 | تعویض تصویر گالری | slideUp با mode="out-in" |
تغییر تصویر یا تنوع | views/singleProduct.vue:28، components/slider/slider.vue:22 |
| 8 | اسپینر | @keyframes rotate و rotateOpacity (سه حلقه) |
بارگذاری | components/spinner.vue:104,115 |
| 9 | ریل سفارش ساخت | @keyframes gradientMove و colorChange روی رابط مرحلهی جاری |
نمایش وضعیت | makeOrderStatus.vue:283,295 |
| 10 | دیالوگها و notify | قواعد animation: |
باز شدن | DialogVant.vue، DialogVantOneButton.vue، NotifyVant.vue |
| 11 | فهرست اسناد | TransitionGroup name="list" + کوییرک testBind (#13) |
بارگذاری فهرست | transactions.vue:17,177-205 |
| 12 | notify قدیمی | @keyframes notify-in |
— | customNotification.vue:47، Notification.vue:81 — اول بررسی شود سوار هستند یا نه |
| 13 | اسلایدر خانه | Swiper با loop و autoplay |
خودکار | slider/homeSlider.vue:7,10 |
| 14 | اسلایدر محصول | Swiper با ماژول Zoom، بدون loop |
لمس | slider/slider.vue:43-45 |
| 15 | overlay ها | انیمیشن خود کتابخانه برای ۲۰ Drawer، ۳ Modal و ۲ action-sheet | — | با قفل نسخهها تضمین میشود |
| 16 | دیالوگ نسخهی جدید | Lottie | تغییر version |
App.vue:22-38 |
زمانبندیها
| چه چیزی | مقدار | شاهد |
|---|---|---|
| دیالوگ تشویق به ورود در خانه | 5 ثانیه، در هر بازدید — گارد «فقط یک بار» کامنت شده | home/index.vue:210-216 |
| شمارش معکوس OTP | 120 ثانیه، با صفر پیشرو زیر 10 | Login.vue:122-131,187-189 |
| toast ها | 4000ms | Dashboard.vue:269-284 و بقیه |
| debounce جستوجو | 700ms | components/search/SearchInput.vue |
| بازگرداندن پرچم انتقال هدر | 100ms | router/index.ts:273-286 |
ناوبری
- ۲۲ route با همان path، name و meta، از جمله حروف و نامهای عجیب:
/ChildOrder،/customerChoice،/addTransaction،/makeOrder_status،/complete_profile،userPage::hasSubRoute. خانه/homeاست و/به آن redirect میشود. beforeEachهمان شش قدم_inv-ref-pwa.md§5.1، با تصمیمهای D3:- مهمان روی پنج route محافظتشده → toast «ابتدا وارد شوید» + خانه.
- کاربر واردشده روی
/loginیا/→ خانه. - تلهی cold-boot (
isLoaded) — D3 گفته تکرار شود. completeProfileبسته است وقتیsts_verify_step_two ∈ {1, 2}.
- route هایی که مرجع در guard ندارد (
addTransaction،makeOrderList،makeOrderStatus،addUser،editUser،ChildOrder،customerChoice، وreport/reportDetailکه خودشان redirect میکنند) در اپ کلاسیک هم در guard نیستند؛ سرور هدف بههرحال 401 میدهد. - ناوبری پایین: چهار تب به ترتیب index — کاربر (۱)، سبد (۲)، جستوجو (۳)، خانه (۴)؛ پیشفرض فعال ۴. فقط روی همین چهار route دیده میشود، و وقتی پنل فیلتر باز است پنهان میشود.
keep-alive+suspenseبا کلیدroute.name— هر صفحهی دیدهشده mount میماند (مثلاً نتایج جستوجو بعد از برگشت حفظ میشوند). این بخشی از حس ناوبری مرجع است و حفظ میشود.scrollBehavior: بازگرداندنsavedPosition، وگرنه بالای صفحه.- layout
FullPage(بدون ناوبری پایین) برای همان ۸ route مرجع؛ بقیهMaster. - ربودن دکمهی back در صفحهی محصول — تنش ۴.
ساختار فازها
Phase 0 — تصمیمها و زیرساخت اثبات (بدون کد اپ)
- پاسخ شما به تنشهای ۱ تا ۵ و Q1 تا Q9.
- اجرای مرجع: کپی
henza_pwa@b171fffدر.parity/ref-pwa/(gitignored)،yarn install --frozen-lockfile، اجرا روی پورت 3030. اگر toolchain قدیمی روی Node فعلی بالا نیاید → ریسک R1. - یک مجموعهداده با دو خروجی: JSON به شکل API مرجع (برای رهگیری درخواستهای
https://henzagold.com/oapi/**در Playwright) و seed دیتابیس برای API هدف. یک منبع، دو projection — تا هر دو اپ دقیقاً یک داده را نشان دهند. - پرسوناها: مهمان؛ مشتری تأییدنشده؛ مشتری تأییدشده (
sts_verify_step_two = 2)؛ بنکدار (type 4)؛ کارشناس فروش (type 1)، و کارشناس در حال کار بهجای مشتری؛ کارگاه (type 5). - مقایسهی تصویری: Playwright روی یک ماشین و یک مرورگر برای هر دو اپ؛ viewport های 390×844 و 768×1024 (کانتینر مرجع
max-w-screen-mdاست)؛ نواحی پویا مثل تاریخ و تایمر ماسک میشوند. آستانهی قبول همینجا توافق میشود. - بررسی انیمیشن: ضبط frame در زمانهای ثابت پس از محرک (مثلاً 0، 150، 300 و 1000ms) برای هر ردیف جدول انیمیشن.
- spike تقویم جلالی:
generatePickerعمومی + config جلالی کنار fork مرجع. اگر مقایسهی تصویری صفر نشد، fork بهصورت vendored نگه داشته میشود. - ساخت
docs/parity/03-PWA-CLASSIC-MATRIX.md— فیلد به فیلد طبق D12.
🛑 Gate — توقف و تأیید شما.
Phase 1 — پایهی apps/user-app-classic
- اسکلت Vite 5 + Vue 3.5 + TS strict + Pinia + vue-router، با نسخههای قفلشدهی بالا.
- asset ها بایتبهبایت با checksum: فونتها،
icons.jsonوIcon.vue، تصاویرassets/imgو empty، favicon، آیکونهای manifest، فایل Lottie،whatsapp.png. themeConfig/colors.json، متغیرهای less،tailwind.config.jsوpostcss-rtl— همان مقادیر.index.htmlهمان: عنوان «طلای هنزا»،theme-color#1C2D56، قفل zoom، دکمهی شناور واتساپ (شماره از env، با مقدار پیشفرض مرجع).bale.pngدرpublic/هست ولی درindex.htmlاستفاده نمیشود — بررسی میشود.- PWA:
injectManifest،sw.tsفقط precache، manifest همان، mode production. - زیرساخت: پورت 5183،
Dockerfileو nginx به الگوی v1، سرویس compose، اضافه شدن بهbuild:release، بهروزرسانیDELIVERY.md.
Phase 2 — لایهی core
- client HTTP: base از env، توکن در هر درخواست؛ 401 سراسری = همان کار
myStore.init()مرجع (پاک کردنappToken،appCartو کلید acting-as، رفتن به خانه). - adapter ها — قلب کار: DTO هدف → شکلهایی که view های مرجع انتظار دارند (
MyData،Product،Variant،cartItem، سفارش باstsعددی، ردیف سند، ردیف گزارش). view ها با همان نام فیلدهای مرجع bind میشوند. قاعدهی صداقت: چیزی که هدف نداردnullمیشود و ردیفش پنهان — هرگز مقدار ساختگی. - نگاشت enum ها:
CustomerKind→typeمرجع (۲، ۳، ۴، ۵؛ و ۱ برای کارشناس).OrderStatusهدف (۹ وضعیت) →stsمرجع (۸ تب).PreOrderStatus→ رشتههای فارسیsts_str_fa.LedgerSourceType→ نوع سند ۱ تا ۴ و ۹.
- بکاند پایه: معادل کامل
POST /me-data(ردیف ۶ نقشه) — همهی صفحهها به آن وابستهاند. - store های Pinia با همان state مرجع: base، me (از همین حالا با جای
_activeUserبرای تنش ۲)، cart (useStorage('appCart')با همان کلید و شکل)، nav، query، token، transition، windowData، report. - composable ها:
getProductsبا فرمول دقیق صفحهبندیfloor(count/limit) - 1؛ موتور تخفیف (۴ نوع، نوع ۳ خاموش، بیشترینdiscount_percent)؛getWage؛getHasDiscountWage؛ علاقهمندی خوشبینانه. - formatter ها با همان خروجی:
تومانبا فاصلهها، truncate (نه round) درuseTowDecimal، حذف علامت درuseFormat. validator ها با همان پیامها، ولی بدون پرچمg(نقص #18). - تست واحد برای همهی اینها، با نمونههای مرجع.
Phase 3 — پوسته، ناوبری، انیمیشن
App.vueباkeep-alive/suspense، دو layout، چک نسخه + دیالوگ Lottie، بهروزرسانی بیصدای service worker.- router با ۲۲ route و guard ها؛ hook آنالیتیکس (وصلش در Batch G).
- ناوبری پایین با GSAP،
appHeaderبا shutter،contentبا margin. - کامپوننتهای پایه:
DialogVant،DialogVantOneButton،NotifyVant،spinner،empty،WorkActionSheet،container،ScrollFetch،SearchInput،otpInput،SingleImageUploader،InputDatePicker. - هر ردیف جدول انیمیشن با harness فاز ۰ اثبات میشود.
Batch A — ورود، ثبتنام، تکمیل پروفایل · حجم بکاند: کم
- صفحهها:
LoginRegister/index.vue،Login.vue،Register.vue،completeProfile.vue،input/otpInput.vue،input/SingleOtpInput.vue. - بکاند:
- معادل
POST /major/register— مشتری تازه باverificationStep = UNVERIFIED، با بررسی یکتایی شماره در هر دو جدول. - رد ورود برای
sts_verify_step_one == 3با پیام «مجوز ورود ندارید» — نگاشتش به وضعیت هدف بررسی میشود. - تکمیل پروفایل و آپلود مدارک: موجود (D22).
- معادل
- کوییرکهایی که حفظ میشوند: OTP چهاررقمی (APP-01)؛ رنگ notify همیشه قرمز
#DC2626، حتی برای موفقیت؛ برچسب دکمه «دریافت رمز عبور» / «دریافت مجدد رمز عبور»؛ دیالوگ موفقیت ثبتنام که با کلیک بیرون بسته نمیشود؛ فیلد شهر متن آزاد؛ تلفن فروشگاه بدون الگو.
Batch B — کاتالوگ · حجم بکاند: زیاد
- صفحهها:
home/index.vue،search/searchPage.vue،search/collection/index.vueوCollectionCard.vue،newest.vue،singleProduct.vue(صفحه و حالت drawer)،components/product/*،components/search/*،components/slider/*،viewAll.vue. - بکاند:
- معادل
POST /front: دستهها باtotal،iconوimage؛ محصولات جدید؛more؛ciny. - معادل
POST /get-products: همهی کلیدهایQuery(colors،brands،limit_percent،limit_gram،has_discount،text،cats،ciny_id،page،limit) با پاسخ{rows, count, limit}، و حالتproducts_idبرای rehydrate سبد. سمت سرور، چون صفحهبندی مرجع سمت سرور است. - معادل
GET /product/{id}وGET /ciny/{cat}. - معادل
GET /config(about+main_slider). - معادل
GET /promotionوGET /ignoreبرای کاربر واردشده.
- معادل
- کوییرکها: ترتیب ۹ دسته (Q5)؛ دیالوگ ورود در هر بازدید بعد از ۵ ثانیه؛ ارتفاع اسلایدر
min(width, 768) / 2.2125؛ تنوع پیشفرض = کمترینpercentage_payبا fallback «بدون تنوع»؛ تخفیف نوع ۳ خاموش؛ «افزودن به سبد» فقط باsts_verify_step_two === 2؛ نمونهی تصادفی ۶ کالکشن؛ برچسب «N فیلتر» / «اعمال فیلتر»؛ بازه فقط وقتی «فعال» حساب میشود که هر دو سرش عوض شده باشد؛ بنکدار اسلایدر اجرت را نمیبیند. - وابسته به: D9 قدم ۵، Q3، Q5، تصمیم دکمهی back.
Batch C — میز کار (/user) · حجم بکاند: کم تا متوسط
- صفحهها:
views/user/index.vue،Dashboard.vue،about.vue. - بکاند: تابلوی قیمت (Q4)؛
grams_sellبرای کارشناس. - کوییرکها: «بدهکار گرمی» / «بستانکار گرمی» با قدر مطلق؛ «فروش گرمی» فقط برای کارشناس؛ کاشیها برای مهمان → دیالوگ ورود؛ دیالوگ «ّکاربر فعال شود؟» با همان تشدید سرگردان؛ دیالوگ خروج؛ متنهای toast قیمت؛ سرتیتر تاریخ و ساعت قیمت که همیشه خالی است (#7 — کوییرک بصری).
- تصمیمها: #5، #6، #8، #19؛ تنش ۲ برای دکمهی «انتخاب مشتری» / «خروج از حساب مشتری».
Batch D — سفارشها، علاقهمندیها، پروفایل، اسناد، گزارش · حجم بکاند: زیاد
- صفحهها:
Orders.vue،product/order.vue،product/orderItem.vue،favorits.vue،profile.vue،editUser.vue،transactions.vue،addTransaction.vue،addFindoc.vue،report/index.vue،report/detail.vue،Accounting.vue،AccountingDetail.vue. - بکاند:
- علاقهمندی: جدول افزایشی، toggle و list.
- ویرایش پروفایل: فقط فیلدهای فرم (whitelist). مرجع کل بدنه را روی ردیف مشتری مینوشت (
ApiMobileController::updateProfile— همان خانوادهی SEC-14). ستونهای افزایشیbirthDateوmarriageDate(PERS-03). - اسناد: فهرست به شکل مرجع از
LedgerEntry. ثبت سند بهصورت ورودی تأییدنشده، با نرمالسازی آبشدهvalue × ayar / 750(همانREPAYMENT_MELTED_GOLD). پیامک به مدیران از env، بهجای دو شمارهی هاردکد مرجع (الگوی SEC-15). مرجع اینجا هم کل بدنه را ذخیره میکرد. - فاکتور سفارش و فایل سند (معادل
report/orderوreport/doc). - گزارش: موجود (D24).
- کوییرکها: ۸ تب وضعیت با همان رنگها (۰ و ۲ بدون رنگ)؛ ریل چهارمرحلهای با
current = 1پیشفرض؛ جستوجوی دقیق شماره در کلاینت؛ مودال تمامصفحه؛ باز شدن فاکتور در پنجرهای به نام_bank؛ دو دکمهی شناور همپوشان در اسناد، با همان ترتیب لایهها؛ رنگ و آیکون ردیف برایtype == 9؛ چهار تب فرم سند و متن ثابت تب «پولی»؛ دکمهی «افزودن کاربر» که هنگام کار بهجای مشتری پنهان است (#11). - تصمیمها: #4، #12، #14، #15.
Batch E — سبد و ثبت سفارش · حجم بکاند: متوسط
- صفحهها:
cart.vue،product/cartItem.vue. - بکاند: MON-08؛ MON-05؛ پرچم
from_parent(تنش ۲). - کوییرکها: کلید
appCartو شکلش؛ حذف بیصدای ردیفهایی که محصولشان دیگر نیست؛ وقتی تعداد ۱ است، منفی به سطل زباله تبدیل میشود؛ drawer یادداشت 280px با textarea پنجخطی؛ جمع فقط وزن با.toFixed(2)؛ دیالوگ تأیید؛ صفحهی موفقیت با شمارهی سفارش؛ بنکدار اجرت را نمیبیند. - تصمیمها: تنش ۵.
Batch F — کارشناس فروش · حجم بکاند: زیاد
- صفحهها:
customerChoice.vue،addUser.vue،ChildOrders.vue، و بخشهای کارشناس در Dashboard و profile. - بکاند:
- کار بهجای مشتری (تنش ۲).
- ساخت، ویرایش و فعال/غیرفعال کردن مشتری توسط کارشناس، با دامنهی
referredByAgentIdو یکتایی شماره در هر دو جدول. - فهرست نوع مشتری (معادل
admin/major/list_type) ازCustomerKind. - ویرایش سفارش مشتری و ثبت نهایی (معادل
PUT /order/child/{id}).
- کوییرکها: پیشپر کردن از
sessionStorage.editCustomer؛ برگشت بهcustomerChoiceیاprofileبر اساسquery.from؛ ۲۲ منطقهی تهران؛ بنکدار →sts = -1؛ toast شمارهی تکراری با قرمز#b10f0f؛ جستوجوی نام در کلاینت؛ ویرایش وزن خام (بدون اجرت)؛ دو متن تأیید.
Batch G — سفارش ساخت + آنالیتیکس · حجم بکاند: متوسط
- صفحهها:
makeOrder.vue،makeOrderStatus.vue، کاشی سفارش ساخت در Dashboard،router/customAnalytics.ts. - بکاند:
- ثبت و فهرست سفارش ساخت مشتری روی مدل موجود
PreOrder(colorName،sizeSpec،minaColor،stoneColor،description، تصویر) + ستون افزایشی تعداد — فیلدsumمرجع درPreOrderنیست. - تأیید و ارسال توسط کارگاه (تنش ۳، #9).
- آنالیتیکس روی
CustomerActivityLog+ ستون افزایشیendedAt(Q6).
- ثبت و فهرست سفارش ساخت مشتری روی مدل موجود
- کوییرکها: نگاشت ۵ مرحله از رشتهی فارسی
sts_str_fa— سرور باید همان رشتهها را بدهد؛confirmedOrdersفقط در حافظه است و با reload از دست میرود؛ کاشی برای type 5 مستقیم و برای بقیه مودال دوگزینهای؛ اسپینری که بهخاطر سایهانداختن متغیرloadingهرگز دیده نمیشود.
Phase نهایی — ممیزی و تحویل
- همهی ردیفهای ماتریس: ✅، یا ➖ با شمارهی ISSUE، یا ⏸️.
- گزارش مقایسهی تصویری همهی صفحهها × پرسوناها × viewport ها.
- سرشماریها (§معیار تمام شد).
- typecheck، lint، build،
docker compose،build:release. - بهروزرسانی
DELIVERY.mdوPROGRESS.md.
روش کار هر Batch
- خواندن خطبهخط فایلهای مرجع آن batch — نه فقط inventory.
- ردیفهای ماتریس، فیلد به فیلد.
- شکافهای بکاند: endpoint افزایشی + تست (رفتوبرگشت، توکن متقابل، IDOR).
- پورت view ها: template و style تا جای ممکن عین مرجع؛ script بازنویسیشده.
- مقایسهی تصویری و انیمیشن در برابر مرجع.
- typecheck، lint، build.
- گزارش کوتاه: چه پورت شد، چه عمداً نشد (با شماره)، چه باگ تازهای در مرجع پیدا شد.
تحت D18 بین batch ها توقف نمیشود؛ فقط برای موارد توقف D18 و gate فاز ۰.
معیار «تمام شد» — اثبات خودکار اینکه چیزی از دست نرفت
| سرشماری | چطور | قبول |
|---|---|---|
| route | استخراج path، name و meta از هر دو router | ۲۲ از ۲۲، یکسان |
| رشتهها | استخراج هر literal فارسی از فایلهای زندهی مرجع (template و script) | همه در اپ کلاسیک موجود؛ هر غایب یا در §چیزی که پورت نمیشود هست یا خطاست |
| asset | checksum | همه یکسان |
| endpoint | هر ردیف نقشه | ✅ یا تصمیم ثبتشده |
| تصویر | مقایسهی هر صفحه × پرسونا × viewport | زیر آستانهی توافقشده در فاز ۰ |
| انیمیشن | frame های زمان ثابت | منطبق |
| ماتریس | — | بدون ردیف باز |
| کیفیت | typecheck strict، lint، build، compose | سبز |
چیزی که پورت نمیشود (و چرا)
هر مورد «کد مرده» قبل از کنار گذاشتن با جستوجوی importer تأیید میشود.
| مورد | چرا | شاهد |
|---|---|---|
src/views/login.vue |
کل فایل کامنت است | login.vue:1,201 |
user/src/components/report.vue |
صفحهی دیباگ، سوار نشده | _inv-ref-pwa.md §6.1 |
NotificationList.vue و سه endpoint اعلان |
در مرجع سوار نیست | home/index.vue:5 |
FCM (Mixins/fireBase.js) و firebase-messaging-sw.js |
در مرجع غیرفعال؛ کلید API هاردکد | App.vue:105 |
| پرکردن خودکار OTP (Web OTP API) | غیرفعال | App.vue:100 |
POST /cities/list |
UI آبشاری کامنت است | Register.vue:58-64 |
cax، noneAuthUrl، canNavigate، getHomeRouteForLoggedInUser، getCustomerListType، loadingStore، filters sample.js، Date.vue، UploadPic.vue، updateProfile بیمصرف در makeOrder.vue، logOut دوم در user/index.vue |
کد مرده | _inv-ref-pwa.md §2.2، §5.1، §8.6، §9 |
دو fetch تکراری در singleProduct |
یک fetch؛ نتیجهی دیدهشده یکسان | #20 |
wage_weight و weight ثابت در payload سفارش |
سرور نادیده میگیرد | DEAD-06 |
حلقهی setInterval(reload) |
یک reload | #10 |
کلید analytics به شکل undefined |
کلید از نام route | #16 |
| PWA در dev mode | production | #17 |
ریسکها
| # | ریسک | اثر | کاهش |
|---|---|---|---|
| R1 | مرجع روی Node فعلی بالا نیاید (Vite 3، plugin-vue 2، وابستگی webpack 5.0.0) |
بدون مقایسهی تصویری، «دقیقاً» فقط با خواندن کد ادعا میشود | Node قدیمیتر فقط در همان کپی؛ اگر نشد، اعلام صریح سطح اطمینان پایینتر |
| R2 | تفاوت داده بین دو API | adapter وسوسه میشود چیزی جعل کند | قاعدهی صداقت؛ تست adapter با fixture |
| R3 | تقویم جلالی | ظاهر متفاوت | spike فاز ۰؛ fallback به fork |
| R4 | حجم بکاند | بیشتر کار در apps/api است، نه در UI |
batch بندی بر اساس وابستگی |
| R5 | رندر فونت بین ماشینها | تفاوت کاذب در مقایسهی تصویری | هر دو اپ روی یک ماشین و یک مرورگر |
| R6 | keep-alive |
state کهنه بعد از برگشت — که رفتار مرجع است | حفظ، با تست سناریوی برگشت |
| R7 | v1/v2 عقب میافتند (CLAUDE.md §2) |
ناسازگاری منطقی بین اپها | تنش ۱ |
| R8 | شناسههای عددی دستهها | ترتیب اشتباه دستهها در خانه | Q5 |
وضعیت اجرا
هنوز شروع نشده. قدم بعدی: پاسخ شما به تنشهای ۱ تا ۵ و Q1 تا Q9؛ بعد Phase 0.