diff --git a/docs/parity/00-INVENTORY.md b/docs/parity/00-INVENTORY.md index 03ac753..4745ff3 100644 --- a/docs/parity/00-INVENTORY.md +++ b/docs/parity/00-INVENTORY.md @@ -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` | | 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` diff --git a/docs/parity/DECISIONS.md b/docs/parity/DECISIONS.md index 05712f0..17ee743 100644 --- a/docs/parity/DECISIONS.md +++ b/docs/parity/DECISIONS.md @@ -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**. diff --git a/docs/parity/ISSUES.md b/docs/parity/ISSUES.md index dd1166e..f2358be 100644 --- a/docs/parity/ISSUES.md +++ b/docs/parity/ISSUES.md @@ -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). | diff --git a/docs/parity/PROGRESS.md b/docs/parity/PROGRESS.md index 6868695..417fe2f 100644 --- a/docs/parity/PROGRESS.md +++ b/docs/parity/PROGRESS.md @@ -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 diff --git a/docs/parity/PROTECTED.md b/docs/parity/PROTECTED.md index f2632c1..5776d7b 100644 --- a/docs/parity/PROTECTED.md +++ b/docs/parity/PROTECTED.md @@ -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.