Files
tehran_taj/docs/parity/PROTECTED.md
T
s.esmaeiliandClaude Opus 5 71192ba2ba parity(docs): Phase 0 inventory, mapping and draft PROTECTED list
Read-only inventory of all 7 projects (3 reference + 4 target) produced by
parallel subagents, every claim cited path:line. No source code changed.

- 00-INVENTORY.md  consolidated mapping: stack, backend, admin, user apps
- PROTECTED.md     draft protected list (awaiting user confirmation)
- ISSUES.md        26 logged issues (security, money/stock, validation, dead code)
- CHANGELOG.md     change log scaffold
- PROGRESS.md      resumable state + Q1-Q5 blocking Phase 1
- _inv-*.md        7 raw per-project inventories (8111 lines)

Key finding: the reference is a gold-jewellery B2B/B2C e-commerce system, not a
gold bank. Buy/sell, deposit/withdraw, transfer, KYC levels, payment callbacks,
cron and websockets do not exist in it, so they cannot be parity gaps.

[ref: henza_server, henza_admin, henza_pwa]

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 18:09:46 +03:30

9.9 KiB
Raw Blame History

PROTECTED — intentional monorepo additions (additive-only)

DRAFT — awaiting user confirmation (Phase 0 gate).

Items here are intentional changes in gold-banking-monorepo. Per CLAUDE.md §4 they must not be removed, restyled, restructured, or have their behaviour changed. You may only ADD what the reference has and they lack, in a way that doesn't break them. Any fix that touches a protected item needs explicit approval with a diff plan first.

Legend: [brief] = named as protected in the kickoff brief · [found] = discovered in Phase 0, proposed for protection · [?] = needs your ruling.


A. Admin panel — Dashboard · [brief]

Location: apps/admin-panel/src/views/Dashboard.vue (327 lines) — one file serving both /dashboard/ecommerce and /dashboard/analytics. Gate: rid dashboard.view; lacking it redirects to my-data (not a 403 page). Data: a single GET admin/dashboard/overview on mount, then client-side sorts (reagent desc by grams_sell; lastOrder desc by w).

Contents, in render order:

  1. 4 KPI tiles — مشتریان جدید (نفر) · طلای فروش‌رفته (گرم) · تعداد سفارشات · نرخ هر گرم طلای ۱۸ عیار
  2. 2 KPI tiles — سفارشات تحویل‌شده · مجموع بدهی طلای مشتریان (گرم)
  3. Area chart «روند سفارش‌ها» — 2 series (تک / عمده); x-labels rotated -45° with rotateAlways + hideOverlappingLabels (a deliberate overlap fix — do not "tidy" it)
  4. 2 donuts — وضعیت سفارشات (8-entry colour array) · تفکیک عمده/تک
  5. Horizontal bar + an always-rendered agent table (کارشناس فروش / میزان فروش گرم / تعداد سفارش)
  6. Vertical bar «محصولات پرفروش» with an a-empty fallback
  7. a-descriptions «میزان فروش» — 3 columns incl. a computed average
  8. Table «سفارشات هفته جاری» — pageSize 10, sts_str as a coloured a-tag, caj via jdate

Fixed palette #1c2d56 / #28c76f / #ff9f43 / #ea5455. No filters, no date range, no export, no refresh — that is the intended design, not a gap.

Why this matters for parity: the reference's two dashboards (DashboardECommerce.vue, DashboardAnalytics.vue) were found in the earlier port to be mostly commented-out Vuexy demo markup, with ApexCharts imported but never used in live markup (docs/CHANGELOG-PORT-HISTORY.md). So there is essentially nothing to port into this dashboard. Phase 1 will confirm and record that, and will not touch this file.


B. Admin panel — the extra option in product Variants · [brief]

Location: apps/admin-panel/src/views/apps/product/AddProduct.vue:151-270, 315-361, 519-568 (Create/Edit Product). Gate: the card is gated product.list.variants; add/edit/remove on .add / .edit / .remove.

Variant table columns: تصویر | عنوان | وزن | اجرت درصدی | تعداد | فعال (tag) | « پیش سفارش» (tag) | عملیات.

The protected extra field is تصویر تنوع (variant image). It is a picker, not an uploader: a 64×64 flex grid over the product's already-saved gallery (data.gallery, each {id, url, role, sortOrder}), whose first tile is a بدون تصویر option and whose selected tile gets a blue .is-on border. pickVariantImage() sets image_id (posted) plus image_url (thumbnail only, stripped before POST).

It is populated only in edit mode — on create the gallery is empty and an a-alert shows a context-dependent message (ابتدا محصول را ذخیره کنید… vs برای این محصول تصویری ثبت نشده است.).

Variants are edited purely in memory (row key __key = v-<ts>-<rand>) and saved with the product via PUT product/update/{id} / POST product/create under a variants[] array — there is no per-variant endpoint. Only validation is عنوان تنوع الزامی است; delete has no confirm dialog.

Related, and NOT protected by itself: the same imageId/image contract on the user-app side. user-app consumes it; user-app-v2 does not (gap V2-03). Closing that gap in v2 is additive and does not touch this admin code.


C. User apps — new designs and new features · [brief]

Both apps/user-app and apps/user-app-v2 keep their own visual design. The following were identified in Phase 0 as design/feature additions with no henza_pwa equivalent.

C.1 Shared by both apps

Item Location
/notifications route + screen (self-documented "no legacy equivalent") views/user/NotificationsView.vue
ui/PageBar.vue replacing the legacy AppHeader components/ui/
Redesigned CSS bottom nav (5 tabs; legacy was a 4-tab GSAP notch) layout/
GallerySlider.vue rewrite + teleported full-screen image preview components/product/
Variant chips with per-variant images, stock badges, «نمایش همه» components/product/SingleProduct.vue
The whole stock / pre-order rule (qty, isPreOrder, capQty, maxQty) stores/cartStore.ts, composables/useProduct.ts — v1 only; porting to v2 is gap MON-01
vant pull-to-refresh on 5 screens various views
IntersectionObserver incremental rendering (20-item window) list views
Ledger-based «اسناد» screen views/user/TransactionsView.vue
Order-detail drawer + 4-step tracker + useOrderItemProduct join views/user/OrdersView.vue
9-chip OrderStatus enum types/
Dotlottie update dialog app shell
New API contracts: GET /home/slider, GoldPriceQuote, productCode, collections[], gold-bank:* session keys api/client.ts

C.2 user-app (design v1) only

Home family: components/home/RateStrip.vue, ShowcaseSlider.vue, ShowcaseCard.vue, CategoryRail.vue, SectionHead.vue, AccountStrip.vue; admin banner via GET /home/slider + AdminSlide; the «برگزیده منتزر» and «تازه‌ها» home sections; trust-badge rows.

C.3 user-app-v2 (design v2) only

components/home/HeroCarousel.vue, ProductCarousel.vue, CategoryGrid.vue, ProductPanel.vue; the IRANSans FaNum font family (12 files, src/assets/styles/fonts/iransans/); redesigned HomeView structure; redesigned DashboardView (hero card + 4 settings rows, replacing card + tile grid); the staggered first-paint reveal system (module-scope hasRevealed) in HomeView/CartView/DashboardView; the compact RateStrip pill variant; SingleProduct's scroll-driven solid header + category deep-link pill; the pill-shaped SearchInput.

Important boundary. C.2 and C.3 are design differences and stay separate. The five items in ISSUES.md §V2-01..05 are logic differences and are not protected — CLAUDE.md §2 requires logic to be identical across both apps.


D. Backend — stricter auth than the reference · [?] needs your ruling

Not yet protected — Q1 in the gate.

The reference leaves every admin route unauthenticated (henza_server/routes/admin.php:12 and :272 — the auth:api group wrapper is commented out at both ends, verified). apps/api instead applies a global JwtAuthGuard + PermissionsGuard with 144 server-enforced rids, and only 15 routes opt out via @Public().

Strict parity would mean removing authentication from ~215 admin endpoints. CLAUDE.md §3 already carves out exactly this case ("if matching the reference would cause … a clear security hole in money flows → STOP and ask").

Proposed: protect the target's stricter auth as an accepted deviation; log the reference behaviour as SEC-01 and the residual @Public() routes as SEC-02.


E. Backend — Decimal money discipline · [found] proposed

The reference uses PHP floats throughout. apps/api has zero Float columns in prisma/schema.prisma; ledger and order math run on Prisma.Decimal.

Reverting to floats for "parity" would introduce rounding error into money and gram values. Proposed: protect the Decimal discipline. The one leak (GRAMS_PER_MESGHAL as a JS float, ledger.service.ts:189) is logged as MON-03, to be fixed in Phase 3 — not now.

Note this does not exempt the target from matching the reference's arithmetic, including the floor(price/1000)*1000 rounding in ProductVariant.php:183-190. Same result, better representation.


F. Prior deliberate non-ports · [?] needs your ruling (Q4)

Recorded in docs/CHANGELOG-PORT-HISTORY.md as intentionally not ported:

  1. Unauthenticated file upload (file/create had no middleware in the reference)
  2. SMS sent inside toggleActive
  3. Six destructive data behaviours — deleting a confirmed document, editing a confirmed amount, deleting a category that has dependents, creating a category cycle, orphaning the audit trail — each replaced with a Persian 400 message
  4. The reference's avatar-load crash (ReagentCustomer.vue:280 dereferenced data.image.id unguarded)
  5. The branch-mode horizontal layout (HorizontalNavMenu, 4 files never ported; mainLayoutType narrowed to 'vertical')

Items 1–4 are security/data-loss carve-outs consistent with CLAUDE.md §3 and are proposed for protection. Item 5 is different — it is a missing feature, not a safety carve-out, and Phase 1 should treat it as a real gap unless you say otherwise.


Summary — what needs your decision

Section Item Proposed
A Admin Dashboard protect (per brief)
B Product Variants image picker protect (per brief)
C User-app designs + new features protect (per brief), excluding the 5 v1↔v2 logic gaps
D Stricter admin auth in apps/api protect — confirm (Q1)
E Decimal money types protect — confirm
F.1–4 Prior security / data-loss non-ports protect — confirm (Q4)
F.5 Branch horizontal layout treat as a real gap — confirm