parity(docs): record D13 — retail storefront preserved but out of scope
The owner ruled that the reference also ran a retail storefront (B2C
single-customer shop) and that the wallet, cashback and
ConfigStatic['percent'] belong to it. These are preserved exactly as they
are: nothing deleted or disabled on either side, no parity work, listed in
the matrices with status "preserved — out of current scope" and no gap or
work row. Shared surfaces (product, variant, price, order, customer) need
the owner's approval before a change that could reach the storefront.
Classifying the endpoints for that split surfaced a counting error in the
Phase 0 inventory: routes/admin.php has 151 live explicit routes, not the
117 recorded, so the reference total is 412 and not 369 (logged DOC-01).
get-analytics-tak reads SingleCustomerOrders, so it is a storefront route
despite its neutral name (logged DOC-02).
Of the 412 reference endpoints, 109 are retail storefront, 15 are web.php
dev/ops closures, and 288 remain in scope (218 admin + 70 B2B app).
[ref: henza_server/routes/{admin,api,customer,site,web}.php]
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
024e3dd045
commit
c71574b1d2
@@ -73,17 +73,50 @@ the *target* has something bank-like, it is an intentional addition, not a gap.
|
||||
|
||||
| Metric | `henza_server` | `apps/api` |
|
||||
|---|---|---|
|
||||
| Routes / endpoints | **369** (admin 215, api 70, customer 44, site 30, web 10) | **179** |
|
||||
| Routes / endpoints | **412** (admin 249, api 70, customer 48, site 30, web 15) — corrected, see below | **179** |
|
||||
| Controllers | 46 | 25 |
|
||||
| Models | 57 files (34 migrated tables + ~28 legacy Django-era tables) | 29 Prisma models |
|
||||
| Enums | PHP static arrays | 14 Prisma enums |
|
||||
| DTO / validation | **zero FormRequests**, all inline, several endpoints unvalidated | 8 DTO classes; most admin bodies untyped `Record<string, unknown>` |
|
||||
| Seeders | 1, **empty** | `prisma/seed.ts` — user types, 144 rids, admins |
|
||||
|
||||
The 369 → 179 drop is expected, not automatically a gap: the reference counts
|
||||
The 412 → 179 drop is expected, not automatically a gap: the reference counts
|
||||
`Route::resource` expansions, ~28 dead legacy tables, a `site.php` storefront and
|
||||
a `web.php` that the monorepo replaces with its own apps. **Which of the 369 are
|
||||
genuinely unmapped is Phase 1 / Phase 2 matrix work**, per route group.
|
||||
a `web.php` that the monorepo replaces with its own apps. **Which of the in-scope
|
||||
routes are genuinely unmapped is Phase 1 / Phase 2 matrix work**, per route group.
|
||||
|
||||
**⚠️ Count correction (2026-09-22).** The **369** reported throughout Phase 0 is
|
||||
**wrong**; the real total is **412**. Recounting the
|
||||
live routes (excluding the 6 commented-out ones, expanding `Route::resource` ×7
|
||||
and `Route::match(['get','post'])` ×2) gives **412**. The error was in
|
||||
`admin.php`: §3.6 of `_inv-ref-server.md` recorded 117 explicit routes where the
|
||||
file actually has **151**, so admin is **249**, not 215. Verified with
|
||||
`grep -E "^\s*Route::(get|post|…)" | grep -v "^\s*//"` per file.
|
||||
|
||||
| File | Explicit | `match` ×2 | `resource` ×7 | Total |
|
||||
|---|---|---|---|---|
|
||||
| `admin.php` | 151 | 0 | 14 → 98 | **249** |
|
||||
| `api.php` | 61 | 1 → 2 | 1 → 7 | **70** |
|
||||
| `customer.php` | 18 | 1 → 2 | 4 → 28 | **48** |
|
||||
| `site.php` | 30 | 0 | 0 | **30** |
|
||||
| `web.php` | 13 | 1 → 2 | 0 | **15** |
|
||||
| **Total** | | | | **412** |
|
||||
|
||||
**Scope split (D13, 2026-09-22).** The retail storefront is preserved but out of
|
||||
scope, so the 412 divide as follows:
|
||||
|
||||
| Group | Endpoints | Scope |
|
||||
|---|---|---|
|
||||
| Admin panel — B2B | 218 | ✅ Phase 1 |
|
||||
| B2B mobile app (`api.php`) | 70 | ✅ Phase 2 |
|
||||
| Retail storefront — customer API (`customer.php`) | 48 | ⏸️ preserved, out of scope |
|
||||
| Retail storefront — public site API (`site.php`) | 30 | ⏸️ preserved, out of scope |
|
||||
| Retail storefront — admin management (wallet 6, `single` 15, `comment` 9, `get-analytics-tak` 1) | 31 | ⏸️ preserved, out of scope |
|
||||
| `web.php` dev/ops closures, price cron, redirects | 15 | ⏸️ out of scope (dead/dev) |
|
||||
| **Total** | **412** | **288 in scope · 124 out** |
|
||||
|
||||
**109 of the 412 are retail storefront**; 15 more are `web.php` dev/ops. Full
|
||||
classification with evidence: `DECISIONS.md` § D13.
|
||||
|
||||
### 2.2 Core business logic — where each rule lives
|
||||
|
||||
@@ -238,7 +271,7 @@ in `HomeView` and `DashboardView` only.
|
||||
|
||||
## 5. What Phase 0 did NOT determine (goes to Phase 1 / Phase 2)
|
||||
|
||||
- Route-by-route mapping of the reference's 369 backend routes onto the target's 179.
|
||||
- Route-by-route mapping of the reference's 412 backend routes (288 in scope after D13) onto the target's 179.
|
||||
- Field-by-field comparison of request/response shapes per endpoint.
|
||||
- Per-view form/validation/table comparison for the ~69 live admin views.
|
||||
- Whether the target's gold-price implementation matches `ProductVariant.php:183-190`
|
||||
|
||||
@@ -459,3 +459,73 @@ now exists, so they can be closed, but `CreateOrderDto` carries `customerId` in
|
||||
the body and changing that is an API-contract change touching both apps' cart
|
||||
flow. Left for the Phase 2 apps work rather than widened into this hotfix.
|
||||
Tracked as SEC-02 (B1/B2) in `ISSUES.md`.
|
||||
|
||||
---
|
||||
|
||||
# D13 — Retail storefront: preserved, but out of scope (2026-09-22)
|
||||
|
||||
**Owner's ruling.** The reference also contained a **retail storefront**
|
||||
(single-customer / B2C shop). The **wallet**, **cashback** and
|
||||
`ConfigStatic['percent']` belong to that storefront, not to the B2B gold
|
||||
business this project is porting.
|
||||
|
||||
## The rule
|
||||
|
||||
1. **Nothing is deleted or disabled.** No code, table, column, endpoint, setting
|
||||
or data belonging to the storefront may be removed or switched off — neither
|
||||
in the target nor in the reference. Whatever exists in the target today stays
|
||||
exactly as it is.
|
||||
2. **No work is done on it.** No parity, no fixes, no refactoring.
|
||||
3. **In the matrices** these items are listed with status
|
||||
**⏸️ حفظشده — خارج از کار فعلی** (preserved — out of current scope) so they
|
||||
remain visible, but **no gap row and no work row is created for them**.
|
||||
4. **Shared surfaces need a heads-up.** If fixing something shared — product,
|
||||
variant, price, order, customer — would affect the storefront, **ask the
|
||||
owner before changing it**, so nothing in the storefront breaks.
|
||||
5. **No guessing.** If it is unclear whether something is storefront-only or
|
||||
shared, **list it and ask**.
|
||||
|
||||
## Status legend addition
|
||||
|
||||
| Symbol | Meaning |
|
||||
|---|---|
|
||||
| ⏸️ | Preserved — out of current scope (D13). Listed for visibility only; no gap row, no work row. |
|
||||
|
||||
## Endpoint classification — where the reference endpoints go
|
||||
|
||||
**The previously reported total of 369 was wrong; the real figure is 412.**
|
||||
Recounting the live routes per file (excluding the 6 commented-out ones,
|
||||
expanding `Route::resource` ×7 and `Route::match(['get','post'])` ×2) shows
|
||||
`admin.php` has **151** explicit routes, not the 117 recorded in
|
||||
`_inv-ref-server.md` §3.6 — so admin is **249**, not 215. Corrected in
|
||||
`00-INVENTORY.md` §2.1.
|
||||
|
||||
| Surface | Route file(s) | Endpoints | In scope? |
|
||||
|---|---|---|---|
|
||||
| Admin panel — B2B | `admin.php` minus the storefront block below | **218** | ✅ in scope (Phase 1) |
|
||||
| Admin panel — storefront management | `admin.php`: wallet 6, `single*` 8, comment 2, `get-analytics-tak` 1 explicit + `single` resource 7 + `comment` resource 7 | **31** | ⏸️ preserved, out of scope |
|
||||
| B2B mobile app | `api.php` | **70** | ✅ in scope (Phase 2) |
|
||||
| Retail storefront — customer API | `customer.php` | **48** | ⏸️ preserved, out of scope |
|
||||
| Retail storefront — public site API | `site.php` | **30** | ⏸️ preserved, out of scope |
|
||||
| Dev/ops closures, price cron, redirects | `web.php` | **15** | ⏸️ out of scope (dead/dev — see DEAD-\* in `ISSUES.md`) |
|
||||
| **Total** | | **412** | |
|
||||
|
||||
**Result: 109 of the 412 endpoints belong to the retail storefront**
|
||||
(48 `customer.php` + 30 `site.php` + 30 storefront management inside
|
||||
`admin.php`), **15 more are dev/ops closures in `web.php`**, and
|
||||
**288 remain in scope** (218 admin + 70 B2B app).
|
||||
|
||||
Evidence for the storefront classification:
|
||||
|
||||
| Block | Where | Why it is storefront |
|
||||
|---|---|---|
|
||||
| `routes/customer.php` (prefix `cu`) | whole file | guarded by `auth:api-singleCustomer`; cart, fav, address, comment, payment gateway, `customer/wallet` |
|
||||
| `routes/site.php` (prefix `site`) | whole file | public shop front: `Site\SiteController`, `Site\CollectionController`, `Api\SiteController` |
|
||||
| `admin/wallet/*` | `admin.php:186-191` | `Adm\WalletController` — cashback percent, charge, config |
|
||||
| `admin/single*` | `admin.php:35,59,60,194-199` | `Adm\SingleCustomerController` — the retail customer's orders, transactions, wallet, report |
|
||||
| `admin/comment*` | `admin.php:150-152` | `Adm\CommentController` — product reviews, a storefront feature |
|
||||
|
||||
The three unrelated `percent` meanings were already separated in
|
||||
`MIGRATION-STATE.md`. D13 confirms that **`ConfigStatic['percent']` (wallet
|
||||
cashback) is storefront and out of scope**, while **`customers.percent`
|
||||
(→ `makingChargeOffsetPercent`) is B2B and stays in scope**.
|
||||
|
||||
@@ -97,3 +97,10 @@ Severity: `Critical` (money loss / security / data loss) · `High` · `Medium`
|
||||
|---|---|---|---|---|---|
|
||||
| SEC-11 | High | TGT `apps/api/src/modules/customer-auth/customer-auth.service.ts` (deliver) | The OTP message text, **code included**, was persisted to `SmsMessage.body`, which the admin SMS grid lists and full-text searches (`admin-misc.service.ts:135-136`). Any operator holding the `sms` rid could read live codes — defeating the bcrypt hashing of `codeHash`. | Read both files; grid `allowed` includes `body`. | ✅ Fixed in stage 3: the persisted row is a redacted audit line. |
|
||||
| MON-08 | Medium | TGT `apps/api/src/modules/orders/orders.service.ts:40-52` | `wagePercent`, `discountPercent` and `flatRialCharge` are taken from the **client** on order creation, so a caller can set their own making charge. `rashWeightGrams` is correctly read from the variant. **The reference is worse** — `ApiMobileController.php:538-539,619` takes `rash_weight` from the client too — so this is a partial improvement already. Reported per the user's instruction to flag client-supplied pricing. | REF `:536-545,615-632` vs TGT `:40-52` | Log only (D4). Fix in Phase 2 alongside the price-formula work. |
|
||||
|
||||
## Found while classifying scope for D13
|
||||
|
||||
| ID | Severity | Where | Description | Evidence | Status |
|
||||
|---|---|---|---|---|---|
|
||||
| DOC-01 | Medium | DOC `docs/parity/_inv-ref-server.md:588` (§3.6) | The Phase 0 inventory undercounted `routes/admin.php`: it recorded **117** explicit routes where the file has **151** live ones (6 more are commented out). Every downstream total inherited the error, so the reference endpoint count was reported as **369** when it is **412** (admin 249, not 215). No code is affected — only the planning figures. | `grep -E "^\s*Route::(get\|post\|put\|patch\|delete\|any)" routes/admin.php \| grep -v "^\s*//" \| wc -l` → 151; resources 14×7=98; 151+98=249 | ✅ Corrected in `00-INVENTORY.md` §2.1 and `DECISIONS.md` §D13. `_inv-ref-server.md` left as the raw subagent record. |
|
||||
| DOC-02 | Low | REF `routes/admin.php:38` | `GET admin/get-analytics-tak` reads `SingleCustomerOrders` (`Adm/AdminController.php:557-579`), so it is a **retail-storefront** endpoint despite its neutral name. A keyword scan for `wallet\|single\|comment` misses it. Noted so the D13 scope split stays correct — anything else named neutrally but querying `SingleCustomerOrders`, `Fav`, `Address`, `Comment` or `Transaction` is storefront too. | `AdminController.php:563` — `SingleCustomerOrders::select(...)` | ✅ Classified as ⏸️ storefront in D13 (the 31st admin storefront route). |
|
||||
|
||||
@@ -51,7 +51,7 @@ while the id and the id-addressed routes remain.**
|
||||
|
||||
## ⚠️ Read `DECISIONS.md` before doing anything
|
||||
|
||||
All user rulings live there (D0–D12). Highlights that change how work is done:
|
||||
All user rulings live there (D0–D13). Highlights that change how work is done:
|
||||
|
||||
- **D12 — the matrix is FIELD-BY-FIELD, not page-by-page**, and a 4-step
|
||||
round-trip test per entity is mandatory. Both rules were added to the
|
||||
@@ -61,6 +61,13 @@ All user rulings live there (D0–D12). Highlights that change how work is done:
|
||||
- **D4** — never port broken behaviour, but match calculations/rounding/messages
|
||||
exactly; annotate each non-replication «عمداً تکرار نشد — ISSUE #n».
|
||||
- **D2** — target-only features get status ➕ and are left alone.
|
||||
- **D13** — the **retail storefront** (48 `customer.php` + 30 `site.php` + 31
|
||||
storefront-management admin routes = **109 of the reference's 412 endpoints**)
|
||||
is **preserved but out of scope**: status ⏸️, no gap row, no work row, nothing
|
||||
deleted or disabled. **288 endpoints stay in scope** (218 admin + 70 B2B app).
|
||||
Note: the reference total is **412, not 369** — `admin.php` was undercounted
|
||||
in Phase 0; corrected in `00-INVENTORY.md` §2.1.
|
||||
Ask before changing shared surfaces (product, variant, price, order, customer).
|
||||
|
||||
## Phase checklist
|
||||
|
||||
@@ -95,6 +102,7 @@ All user rulings live there (D0–D12). Highlights that change how work is done:
|
||||
| D10 | Sales expert: keep `AdminUser`; investigate the 5 missing fields; propose `SalesExpertProfile`. |
|
||||
| D11 | `singleCustomer.vue` → diff-send. |
|
||||
| D12 | **Field-by-field matrix + mandatory round-trip test.** Added to the skill. |
|
||||
| D13 | **Retail storefront (wallet, cashback, `ConfigStatic['percent']`) preserved but OUT OF SCOPE.** Nothing deleted or disabled; no parity work; matrices list it ⏸️ with no gap/work row; ask before touching shared surfaces. |
|
||||
|
||||
## Open — awaiting user approval
|
||||
|
||||
|
||||
@@ -235,3 +235,37 @@ it is a keep-out list.
|
||||
- Unverified OTP — D6
|
||||
- The public customer list — D8
|
||||
- `singleCustomer.vue`'s full-form send — D11
|
||||
|
||||
---
|
||||
|
||||
## H — Retail storefront (D13) — preserved, out of current scope
|
||||
|
||||
Owner's ruling of 2026-09-22. The reference also ran a **retail storefront**
|
||||
(B2C single-customer shop). The **wallet**, **cashback** and
|
||||
`ConfigStatic['percent']` belong to it.
|
||||
|
||||
**Keep-out rule — stronger than "protected":** these are neither fixed nor
|
||||
touched. Nothing is deleted or disabled on either side; no parity work is done
|
||||
on them; they appear in the matrices only with status **⏸️ حفظشده — خارج از
|
||||
کار فعلی**, with no gap row and no work row.
|
||||
|
||||
| Surface | Reference | Endpoints |
|
||||
|---|---|---|
|
||||
| Customer API (prefix `cu`) | `routes/customer.php` | 48 |
|
||||
| Public site API (prefix `site`) | `routes/site.php` | 30 |
|
||||
| Wallet / cashback admin | `admin.php:186-191`, `Adm\WalletController` | 6 |
|
||||
| Retail-customer admin | `admin.php:35,59,60,194-199` + `single` resource | 15 |
|
||||
| Retail analytics | `admin.php:38` `get-analytics-tak` → `SingleCustomerOrders` | 1 |
|
||||
| Product comments admin | `admin.php:150-152` + `comment` resource | 9 |
|
||||
| **Total** | | **109** |
|
||||
|
||||
Whatever of this already exists in `gold-banking-monorepo` stays exactly as it
|
||||
is — it is not restyled, not refactored, not removed.
|
||||
|
||||
**Shared-surface warning.** Product, variant, price, order and customer are
|
||||
shared between the B2B business and the storefront. Before changing any of
|
||||
them, check whether the change reaches the storefront and **ask the owner
|
||||
first** (D13 rule 4). When in doubt whether something is storefront-only or
|
||||
shared, **list it and ask — never guess** (D13 rule 5).
|
||||
|
||||
Full reasoning and the endpoint classification: `DECISIONS.md` § D13.
|
||||
|
||||
Reference in New Issue
Block a user