Add paged orders API and infinite scroll, short order numbers, and align the guest invite card with the logged-in hero shell. Co-authored-by: Cursor <cursoragent@cursor.com>
21 KiB
چکلیست تکرار ایرادها (کاری — قدمبهقدم)
منبع جزئیات: parity/CHANGELOG.md، parity/ISSUES.md، parity/DECISIONS.md.
این سند برای همین ریپو (gold-bank / تهران تاج) است تا ایرادها را verify کنیم یا باقیماندهها را ببندیم — و در عین حال قالب تکرار برای پروژهٔ مشابه.
قبل از هر تغییر UI سمت اپ: از مالک (Honar) بپرس. منطق/رفتار بدون سوال؛ ظاهر نه. اپ مبنا برای منطق: هر دو
apps/user-appوapps/user-app-v2(مگر خلافش گفته شود).
دامنهٔ تکرار (قوانین سخت)
| موضوع | تکرار؟ | قانون |
|---|---|---|
| ایرادهای امنیتی / پولی / دامنه / UX کارکردی | بله | منطق یکسان |
| فونت IRANSans (اپ + ادمین) | بله | همان فونت و wiring |
| لوگو / فاویکون / آیکن برند / wordmark | خیر | برند تهران تاج دستنخورده — BRANDING.md |
| کاروسل / hero / ShowcaseSlider | خیر | اصلاً دست نزن (حتی در verify) |
| فیچر اپ مثل PWA install، pull-refresh، incomplete-profile banner | بله | فقط منطق/رفتار؛ UI با زبان طراحی خودِ اپ |
| دیزاین / layout ادمین | بله | ادمین قابلرفرنس از همین ریپو (بدون تعویض لوگو) |
نحوهٔ کار
| نماد وضعیت | معنا |
|---|---|
انجامشده — verify |
در parity بهعنوان FIXED ثبت شده؛ فقط smoke/خواندن کد، بازپیادهسازی نکن |
باقیمانده |
هنوز باید پیاده یا اصلاح شود |
منتظر تصمیم |
منتظر ruling مالک |
عمداً خارج |
یخزده یا deferred — دست نزن |
چکباکسها:
[x]= بسته / verify پاس شده در همین دور کار[ ]= هنوز باز یا verify نشده
ترتیب پیشنهادی: ۱ امنیت → ۲ پول/سفارش → ۳ مشتری → ۴ UX اپ (منطق) → ۵ کاتالوگ/SMS → ۶ فیچر اپ → ۷ ادمین → ۸ حسابداری.
یخزده (عمداً خارج — دست نزن)
| موضوع | قانون |
|---|---|
| کاروسل / hero اسپرینگ / ShowcaseSlider | هیچ پورت دیزاین Hedena؛ هیچ بازنویسی layout |
| لوگو / فاویکون / brand-* / wordmark | فقط طبق BRANDING.md؛ از Hedena کپی نکن |
- تأیید کلامی: کاروسل و برند در این دور کار دست نخوردهاند
۱) امنیت و احراز هویت (اولویت بحرانی)
| ID | ایراد | مسیر تقریبی | فیکس | وضعیت | انجام |
|---|---|---|---|---|---|
| SEC-09 | روتهای ledger با @Public() قابل نوشتن |
API accounting.controller.ts |
حذف @Public سطح کلاس؛ rid روی هر روت: wallet.list, wallet.charge, document.create, document.list.confirm |
انجامشده — verify | [ ] |
| SEC-10 | PATCH orders/:id/status عمومی + actorAdminUserId جعلی |
API orders.controller.ts |
فقط ادمین؛ rid order.list.sts.submit |
انجامشده — verify | [ ] |
| SEC-08 | GET /customers کل دفتر مشتری را لو میداد |
API customers (حذف)؛ اپ Login / api/client |
حذف روتهای با customerId؛ /customer/me* از JWT |
انجامشده — verify | [ ] |
| SEC-03 / D6 | OTP تأیید نمیشد | API customer-auth/ + CustomerOtp؛ اپ Login |
bcrypt، انقضا ۲ دقیقه، ۵ تلاش، یکبارمصرف، throttle | انجامشده — verify | [ ] |
| T1 | سشن مشتری جدا نبود | customer-auth/، JWT_CUSTOMER_SECRET، typ: 'customer' |
JWT جدا از ادمین؛ خواندن مجدد DB در هر درخواست | انجامشده — verify | [ ] |
| SEC-02 | POST /orders عمومی با customerId از body |
orders.controller/service، DTO، Cart |
@CustomerAuth()؛ customerId فقط از توکن |
انجامشده — verify | [ ] |
| SEC-02b | GET /orders/:id IDOR |
همان ماژول | getOwnedById → 404 نه 403؛ ادمین مسیر جدا |
انجامشده — verify | [ ] |
| SEC-11 | OTP در SmsMessage.body plaintext |
customer-auth.service deliver() |
فقط خط audit سانسورشده | انجامشده — verify | [ ] |
| SEC-04 | JWT ضعیف پیشفرض + CORS باز | boot API / CORS | production بدون JWT_SECRET بالا نیاید؛ CORS_ORIGINS |
انجامشده — verify | [ ] |
| SEC-05 | seed دمو (پسورد = موبایل) در production | prisma/seed.ts، bootstrap.ts |
دمو فقط با SEED_DEMO_DATA=true |
انجامشده — verify | [ ] |
| SEC-07 | setRoles رشتهٔ دلخواه |
admin-users / roles | فقط ALL_RIDS (+ والدین درخت) |
انجامشده — verify | [ ] |
| DEPLOY-02 | env خالی "" در Docker JWT را میشکست |
common/env.ts (envOr) |
blank = unset | انجامشده — verify | [ ] |
| DEPLOY-01 | compose بدون JWT/SMS/OTP | docker-compose.yml |
forward همهٔ envهای auth/SMS | انجامشده — verify | [ ] |
| REL-01 | master OTP در production | customer-auth، boot checks |
OTP_MASTER_CODE؛ در prod ممنوع مگر فلگ تست |
انجامشده — verify | [ ] |
| REL-03 | JWT_CUSTOMER_SECRET fallback به secret ادمین |
customer JWT helper | secret جدا؛ enforce در production | انجامشده — verify | [ ] |
Smoke پیشنهادی: apps/api/scripts/auth-smoke.sh (در صورت در دسترس بودن سرور محلی).
۲) پول، قیمت، سفارش
| ID | ایراد | مسیر تقریبی | فیکس | وضعیت | انجام |
|---|---|---|---|---|---|
| MON-08 | کلاینت میتوانست wage/discount/rial بگذارد | orders.service، pricing/wage-formula، wage-quote |
قیمت فقط سرور؛ نادیده کلاینت؛ لاگ mismatch | انجامشده — verify | [ ] |
| ACC-03 / MON-04 | بدهی دوبار با ورود مجدد به DELIVERED_TO_AGENT |
LedgerService.syncOrderDebt |
sync به هدف؛ فقط delta؛ rollback/cancel درست | انجامشده — verify | [ ] |
| MON-05 | canPlaceOrders اعمال نمیشد |
مسیر create سفارش | اپ → 403؛ ادمین میتواند برای مشتری ثبت کند | انجامشده — verify | [ ] |
| MON-01 | سقف موجودی در سبد نبود (v2) | cartStore، CartItem/SingleProduct |
capQty/maxQty + disable + toast |
انجامشده — verify | [ ] |
| ORD-01 | ویرایش وضعیت سفارش retail خراب | admin order/List.vue |
body از tempRow.id مثل Omde/Tamin |
انجامشده — verify | [ ] |
| کانال سفارش اپ | سفارش اپ بهاشتباه RETAIL | orders.service، DTO، migration، admin-orders |
پیشفرض/ذخیره WHOLESALE برای مسیر اپ + migrate ردیفهای قبلی | انجام شد 2026-10-17 — placedBy=customer ⇒ WHOLESALE؛ migration 20261017120000_app_orders_wholesale_channel |
[x] |
۳) مشتری / اشخاص / نام / درصد
| ID | ایراد | مسیر تقریبی | فیکس | وضعیت | انجام |
|---|---|---|---|---|---|
| CUST-01 | fname: fullName, lname: '' نامها را یکی میکرد |
migration firstName/lastName؛ فرمها |
ستونهای واقعی؛ حذف split(' ') |
انجامشده — verify (schema دارد) | [ ] |
| CUST-02 | percent از کمیسیون نماینده |
makingChargeOffsetPercent؛ CRUD مشتری |
ستون خود مشتری؛ پیشفرض ۳؛ required در create | انجامشده — verify | [ ] |
| D17 / CUST-03 | فرم کارشناس فروش ناقص | SalesExpertProfile؛ ReagentCustomer.vue |
پروفایل جدا؛ autofill شهر→کمیسیون | انجامشده — verify (فرم ncode/city/gram دارد) | [ ] |
| PERS-02 | شهر flat بهجای درخت استان | City.parentId، CityTreeSelect |
درخت استان؛ ارثبری درصد از ancestor | انجامشده — verify | [ ] |
| PERS-03 | تاریخ تولد نبود | Customer.birthDate، DateInput |
فیلد جلالی create/update | انجامشده — verify | [ ] |
| D19 | موبایل نرمال نمیشد / SMS خوشآمد | admin-customers / admin-users | faToEn قبل uniqueness؛ welcome SMS fire-and-forget |
انجامشده — verify | [ ] |
۴) لاگین اپ / act-as / ناوبری / تازگی داده
فقط رفتار را port/verify کن؛ ظاهر Login/Dialog/Nav را از زبان طراحی خودِ اپ بگیر — کپی پیکسلی Hedena نکن. قبل از تغییر UI از Honar بپرس.
| ID | ایراد | مسیر تقریبی | فیکس | وضعیت | انجام |
|---|---|---|---|---|---|
| AUTH-01 | شماره ثبتنشده → موفقیت جعلی → OTP | requestOtp، Login |
404 + پیام فارسی | انجامشده — verify | [ ] |
| AUTH-02 | شکست SMS → موفقیت جعلی | deliver |
503 + «SMS در دسترس نیست» | انجامشده — verify | [ ] |
| AUTH-03 | مشکل حساب کارشناس مثل «ثبتنشده» | resolveExpertTradingAccount |
پیامهای 403 جدا | انجامشده — verify | [ ] |
| APP-03 | صفحات شخصی مهمان silent redirect | router/index.ts |
toast «ابتدا وارد شوید» + نگه داشتن ?redirect= |
انجامشده — verify | [ ] |
| EXP-01…03 | «ورود به حساب مشتری» برای کارشناس نبود | JWT strategy، X-Act-As-Customer، session، ActingAsBar |
act-as با هدر (نه توکن minted)؛ پاک کردن cache/cart؛ نوار دائمی | انجامشده — verify | [ ] |
| NAV-01…04 | back همیشه route ثابت؛ login/401 تاریخچه مرده | PageBar، navStore، Login، main.ts |
back تاریخچهدار؛ replace بعد login/401 |
انجامشده — verify | [ ] |
| READ-01…03 | keep-alive صفحه را دوباره fetch نمیکرد | Orders/Transactions/Home/Dashboard، queryCache |
refresh روی onMounted+onActivated |
انجامشده — verify | [ ] |
۵) کاتالوگ / علاقهمندی / SMS / آپلود
| ID | ایراد | مسیر تقریبی | فیکس | وضعیت | انجام |
|---|---|---|---|---|---|
| STUB-03 | کل کاتالوگ یکجا؛ pagination فقط کلاینت | catalog API + اپها | page/filter/sort سرور؛ ?ids=، /:id، /facets |
مرحله ۴ انجام شد 2026-10-17 — Search/Newest/Home/Collection روی هر دو اپ؛ UI همان زبان طراحی | [x] |
| FAV-01 | علاقهمندی فقط memory | API customer/me/favorites*، favoritesStore |
load/toggle سمت سرور | انجامشده — verify | [ ] |
| SMS-03 | بدون SMS ثبت سفارش | orders.service notify + ORDER_ADMIN_MOBILES |
SMS بعد commit به ادمین/مشتری/کارشناس | انجامشده — verify | [ ] |
| STUB-05 | موبایل ادمین hardcode | env | PROFILE_ADMIN_MOBILES، ORDER_ADMIN_MOBILES |
انجامشده — verify | [ ] |
| UPL-01 | اپ نمیتوانست مدرک آپلود کند | POST customer/me/documents |
آپلود برای complete-profile | انجامشده — verify | [ ] |
| D22–D24 | complete-profile / گزارش بدون IDOR | customer modules | whitelist write؛ گزارش scoped | انجامشده — verify | [ ] |
۶) فیچرهای اپ (منطق بله — دیزاین خیر)
| تم | چه چیزی port شود | چه چیزی port نشود | وضعیت | انجام |
|---|---|---|---|---|
| فونت IRANSans | فایلهای فونت + fonts.less / wiring در اپ و ادمین |
— | ادمین wired (farsi.less)؛ اپها را verify کن |
[ ] |
| PWA install prompt | beforeinstallprompt، prompt قابل dismiss، logic |
ظاهر مودال Hedena | باقیمانده — usePwaInstall / InstallPromptModal در ریپو نیست؛ UI بعد از تأیید Honar |
[ ] |
| Pull-to-refresh / incomplete-profile / gate login | رفتار و شرطها | layout/illustration/رنگ Hedena | pull-refresh و complete-profile موجود — verify رفتار | [ ] |
| کاروسل / ShowcaseSlider / hero | — | اصلاً تکرار نکن | عمداً خارج | — |
| لوگو / فاویکون / brand assets | — | اصلاً تکرار نکن | عمداً خارج | — |
رفرنس منطق PWA (اگر از پروژهٔ مرجع بیاید — فقط رفتار، نه UI): composable usePwaInstall + مودال dismiss/defer؛ markup را با کامپوننتهای خود اپ بازنویسی کن.
۷) ادمین / پرمیشن / UX (دیزاین قابلرفرنس)
| ID / تم | ایراد | مسیر تقریبی | فیکس | وضعیت | انجام |
|---|---|---|---|---|---|
| PERM-01 | ridهای یتیم dashboard | migration merge → dashboard.view |
merge/حذف ridهای قدیمی | انجامشده — verify | [ ] |
| PERM-02 | ridهای enforced ولی غایب از درخت | permissionConst.ts |
افزودن newsletters، persons.list.sellers.view |
منتظر تصمیم | [ ] |
| D30 | ویژگیهای retail/بانک/شعبه فقط super-admin | super-admin.ts، منو/گارد |
gate با موبایل ثابت؛ hide + 403 | انجامشده — verify (در صورت پیاده) | [ ] |
| super-admin rids | سوپرادمین همه rid نداشت | super-admin.ts، permissionConst |
ALL_RIDS؛ اسلایدر زیر ثابتها |
انجامشده — verify | [ ] |
| Order UX | وضعیت سفارش UX ضعیف | Listها / مودال وضعیت | drawer راست + confirm خروج — دیزاین از ادمین همین ریپو | باقیمانده / verify — فایلهای OrderStatusModal.vue / OrderViewModal.vue در این ریپو پیدا نشد؛ List.vue فعلی را بسنج |
[ ] |
| Icon migration | وابستگی @ant-design/icons-vue |
Icon محلی + icons.json |
آیکون محلی | باقیمانده — ادمین هنوز از @ant-design/icons-vue زیاد استفاده میکند |
[ ] |
| Dashboard unify / فرم محصول و مشتری | chrome ناهماهنگ | Dashboard.vue، AddProduct، AddCustomer |
unify بصری (بدون تعویض لوگو) | بخشی انجامشده — PROTECTED dashboard chrome؛ verify | [ ] |
| فونت ادمین | خوانایی | farsi.less / IRANSans |
همان فونت؛ لوگو را عوض نکن | انجامشده — verify | [ ] |
| PROMO-TAK-01 | type_customer / ridهای .tak |
promotions | ثبت و/یا gate API | باقیمانده (logged) | [ ] |
| CINY-01 | ciny_ids در update نادیده |
admin-products | update هم trays را ذخیره کند | باقیمانده (logged) | [ ] |
| ANLY-01 | analytics dwell-time | — | — | عمداً خارج — deferred، اولویت پایین | — |
۸) حسابداری یکپارچه
| ID | ایراد | فیکس | وضعیت | انجام |
|---|---|---|---|---|
| ACC-06 | TLS خودامضا / hostname fail | cert pin؛ هرگز verify را خاموش نکن | انجامشده — verify | [ ] |
| ACC-07 | «متصل است ولی sync نمیشود» | رد provider ناقص؛ inactiveReason؛ گروههای انتخابشده الزامی |
انجامشده — verify | [ ] |
| ACC-08/09 | sync کند / بدون on-demand | poll سریع + دکمه sync + وضعیت زنده | انجامشده — verify | [ ] |
جزئیات: ACCOUNTING-INTEGRATION-PLAN.md.
صف باقیماندهٔ واقعی (اولویت اجرا بعد از verify امنیت)
کانال WHOLESALE✅STUB-03 مرحله ۴✅ (منتظر چک UI تو)- PWA install — فقط منطق؛ UI بعد از سؤال از Honar
- PERM-02 — بعد از ruling
- Icon محلی ادمین / Order drawer UX — در صورت نیاز
- PROMO-TAK-01، CINY-01
پرامپت آماده برای Cursor پروژهٔ دوم
کپی کن و در چت پروژهٔ مشابه بگذار:
این پروژه شبیه hedena_gold / gold-banking-monorepo است و همان ایرادها را دارد.
همان فیکسها را با منطق یکسان پیاده کن. اولویت با امنیت و پول است.
قوانین دامنه (سخت):
- فونت IRANSans را برای اپ و ادمین بیاور (فایل + wiring).
- لوگو / فاویکون / آیکن برند / wordmark را عوض نکن و از Hedena کپی نکن.
- کاروسل / hero اسپرینگ / showcase دیزاینشدهٔ Hedena را اصلاً تکرار نکن.
- فیچرهای اپ مثل PWA install، pull-refresh، incomplete-profile banner: فقط منطق/رفتار را port کن؛ UI را با زبان طراحی و کامپوننتهای خودِ این اپ بساز — از مودال/رنگ/illustration هدنا کپی نکن.
- پنل ادمین یکی است: برای دیزاین drawer سفارش، Icon محلی، dashboard unify، فرمها میتوانی مستقیم از ادمین مرجع رفرنس بگیری (باز هم بدون تعویض لوگو).
- قبل از هر تغییر UI سمت اپ از مالک بپرس.
A) امنیت
- روتهای ledger و تغییر وضعیت سفارش را از Public دربیاور؛ فقط ادمین با rid مناسب
- GET لیست مشتری برای login را حذف کن؛ سشن مشتری با JWT جدا (JWT_CUSTOMER_SECRET، typ=customer)
- OTP واقعی: bcrypt، انقضا ۲ دقیقه، ۵ تلاش، یکبارمصرف، throttle؛ OTP را در SMS audit plaintext ذخیره نکن
- POST /orders پشت CustomerAuth؛ customerId فقط از توکن؛ GET order با مالکیت → 404 نه 403
- production بدون JWT_SECRET بالا نیاید؛ CORS از CORS_ORIGINS؛ seed دمو فقط با SEED_DEMO_DATA
- env خالی "" را unset بگیر (envOr)؛ JWT مشتری fallback به secret ادمین نداشته باشد
- OTP_MASTER_CODE در production ممنوع مگر فلگ تست
B) پول/سفارش
- wage/discount/rial را از کلاینت نپذیر؛ فرمول سرور + لاگ mismatch
- sync بدهی سفارش idempotent با delta (نه پست دوباره)
- canPlaceOrders در اپ 403 کند؛ ادمین بتواند برای مشتری ثبت کند
- سقف موجودی در سبد (capQty/maxQty)
- سفارشهای اپ را WHOLESALE ذخیره کن نه RETAIL (اگر دامنه B2B است)
C) مشتری
- firstName/lastName جدا؛ percent خود مشتری (makingChargeOffsetPercent) نه کمیسیون نماینده
- پروفایل کارشناس فروش کامل؛ درخت شهر استان؛ تاریخ تولد؛ faToEn روی موبایل
D) اپ (منطق بله — دیزاین از خودِ این پروژه)
- requestOtp: 404 ثبتنشده، 503 SMS fail، 403 پیام جدا برای کارشناس
- toast ورود برای صفحات شخصی + redirect=
- act-as کارشناس با هدر X-Act-As-Customer (نه mint توکن)
- back تاریخچهدار؛ بعد login/401 از replace استفاده کن
- صفحات keep-alive را روی activate دوباره fetch کن
- PWA install: beforeinstallprompt + dismiss/defer؛ UI با کامپوننتهای خود اپ
- IRANSans را وصل کن؛ لوگو و کاروسل را دست نزن
E) کاتالوگ/SMS
- pagination/فیلتر سرور برای محصولات؛ favorites سمت سرور
- SMS ثبت سفارش بعد commit؛ شمارهها از env نه hardcode
- آپلود مدرک مشتری برای complete-profile
F) ادمین (دیزاین قابلرفرنس)
- ridهای یتیم dashboard را merge کن
- ویژگیهای خطرناک فقط super-admin؛ سوپرادمین ALL_RIDS
- Order status UX به صورت drawer راست + confirm logout — layout از ادمین مرجع
- Icon محلی بهجای @ant-design/icons-vue اگر همان وابستگی را دارید
- IRANSans در ادمین؛ لوگو را عوض نکن
برای هر آیتم: اول محل معادل در این ریپو را پیدا کن، بعد فیکس را با تست/smoke کوتاه اعمال کن.
جزئیات کامل: در ریپوی مرجع فایل docs/REPLICATION-CHECKLIST.md
منبع برای جزئیات بیشتر
- لاگ کامل What/Why/Target:
parity/CHANGELOG.md - وضعیت FIXED/باز:
parity/ISSUES.md - تصمیمهای محصول:
parity/DECISIONS.md - برند / لوگو:
BRANDING.md - کاتالوگ:
CATALOG-PAGINATION-PLAN.md - حسابداری:
ACCOUNTING-INTEGRATION-PLAN.md - دیزاین ادمین قابلرفرنس:
apps/admin-panel/src/views/order/،apps/admin-panel/src/assets/styles/farsi.less