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>
9.9 KiB
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:
- 4 KPI tiles — مشتریان جدید (نفر) · طلای فروشرفته (گرم) · تعداد سفارشات · نرخ هر گرم طلای ۱۸ عیار
- 2 KPI tiles — سفارشات تحویلشده · مجموع بدهی طلای مشتریان (گرم)
- Area chart «روند سفارشها» — 2 series (تک / عمده); x-labels rotated -45° with
rotateAlways+hideOverlappingLabels(a deliberate overlap fix — do not "tidy" it) - 2 donuts — وضعیت سفارشات (8-entry colour array) · تفکیک عمده/تک
- Horizontal bar + an always-rendered agent table (کارشناس فروش / میزان فروش گرم / تعداد سفارش)
- Vertical bar «محصولات پرفروش» with an
a-emptyfallback a-descriptions«میزان فروش» — 3 columns incl. a computed average- Table «سفارشات هفته جاری» —
pageSize10,sts_stras a coloureda-tag,cajviajdate
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/imagecontract on the user-app side.user-appconsumes it;user-app-v2does 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:
- Unauthenticated file upload (
file/createhad no middleware in the reference) - SMS sent inside
toggleActive - 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
- The reference's avatar-load crash (
ReagentCustomer.vue:280dereferenceddata.image.idunguarded) - The branch-mode horizontal layout (
HorizontalNavMenu, 4 files never ported;mainLayoutTypenarrowed 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 |