parity(docs): D16 — stop PRICE-01 as storefront, reorder Phase 1, verify SEC-02

Owner ruling: computing and displaying price / price_with_discount is retail
storefront work, so it falls under D13 and is marked out of scope. The B2B
app works in making charge only.

variant-price.ts and its 11 hand-checked tests are kept and still run, just
unused. Nothing needed reverting: computeVariantPrice was never called from
outside its own file and spec, verified by grep over apps/api/src and
apps/admin-panel/src, so no price had been wired into any screen. PRICE-01
is re-marked in ISSUES.md rather than deleted so the evidence survives if
the storefront is ever taken up.

Making-charge work stays fully in scope: percentage_pay,
makingChargeOffsetPercent, and wage display on variants and order lines.

New Phase 1 order: Persons -> products/categories/variants/order detail ->
financial documents -> users and permissions -> admin SMS -> promotions,
notifications, cities, branches, workshops -> reports -> gate. Per section:
implement the gaps, then field-by-field test that section, and show a gap
summary before fixing.

SEC-02 re-verified live rather than quoted: 9/9 assertions, plus 32/32 in
auth-smoke.sh. POST /orders is 401 without a token; a body customerId of
"customer-2" sent with a customer-dev-test token still lands the order on
customer-dev-test and is warn-logged; a foreign order id returns 404 rather
than 403 so ids stay unenumerable; the admin read rejects a customer token.
Client-supplied wagePercent/discountPercent/flatRialCharge remain as MON-08,
already scheduled as Phase 2 item #1.

Also records why the dev OTP log briefly looked broken: a stale API process
still held port 3077, so the new instance died with EADDRINUSE and the
tailed log belonged to the old process. Not a regression.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
s.esmaeili
2026-09-22 16:43:11 +03:30
co-authored by Claude Opus 5
parent 64e76a8616
commit e3af31948e
5 changed files with 193 additions and 9 deletions
+80
View File
@@ -878,3 +878,83 @@ three rows from both attempts were deleted and logged.
- Console output of Persian is not evidence: the Windows console renders it as
`?` even when the data is correct. Verify by comparing values or codepoints in
Node, as `scripts/test-name-trigger.cjs` does.
---
# D16 — Price display is storefront; new work order (2026-09-22)
## 1. PRICE-01 is stopped — price belongs to the retail storefront
**Owner's ruling.** Computing and displaying `price` / `price_with_discount` is a
**retail storefront (تک‌فروشی)** concern. The B2B app works in **making charge
(اجرت)** only. So PRICE-01 falls under D13 and is marked **⏸️ preserved — out of
current scope**.
| Item | Ruling |
|---|---|
| `apps/api/src/modules/pricing/variant-price.ts` | **Kept, not deleted.** Simply not used. |
| `variant-price.spec.ts` (11 hand-checked tests) | **Kept** and still runs in CI. |
| Any code wiring price into the admin panel | **Revert.** — *None existed: `computeVariantPrice` was never called from anywhere outside its own file and spec, so there was nothing to revert. Verified by grep over `apps/api/src` and `apps/admin-panel/src`.* |
| Making-charge fields — `percentage_pay`, `makingChargeOffsetPercent`, wage display | **Still fully in scope.** |
PRICE-01 in `ISSUES.md` is re-marked ⏸️ rather than deleted, so the analysis and
its evidence stay available if the storefront is ever taken up.
**Why this matters beyond one row:** the reference's `ProductVariant::$appends`
carries `price`, `color_str` and `price_with_discount` together
(`ProductVariant.php:115-119`). Only the price pair is storefront; anything else
appended there is still judged on its own merits.
## 2. The gate stands: admin first, then the apps
### Phase 1 — admin, in this order
**(a) Persons (اشخاص)**
1. The **5 missing sales-expert fields** (`ncode`, `phone`, `city_id`,
`gram_level`, `reagent_id`): **report first** — where the reference uses each
one for `type=1` — then add according to what that shows. Standing proposal:
a `SalesExpertProfile` related to `AdminUser` (D10). Fields with no use are
**listed for the owner to decide**, not added speculatively.
2. `singleCustomer` migrates to **diff-send** (D11).
3. Field-by-field audit of every form and grid in Persons — retail customer,
wholesale customer, sales expert — per D12, each with its round-trip test.
**(b) Products, categories, variants, and order detail in the admin** — deep
field-by-field: every form field, column, filter and button (D12).
- The **variant image picker stays untouched** (PROTECTED, `PROTECTED.md` §B);
only genuine omissions are added.
- The **making charge of every variant and every order line must display and
persist exactly as the reference does.**
**(c) The rest of the admin, in order:** financial documents → users and
permissions → admin SMS templates → promotions / notifications / cities /
branches / workshops → reports.
**(d)** Full admin test pass, the Phase 1 report, then the gate question
**«ادمین کامل و تست شد. بریم سراغ اپ‌ها؟»** — and **stop and wait**.
### Phase 2 — apps (only after the owner approves)
**(a)** The 5 v2-behind-v1 logic gaps, most important the **cart stock ceiling
(`capQty`/`maxQty`)**, matching v1 and the reference exactly — v2's design fully
preserved, with a test proving v1 and v2 behave identically.
**(b)** The missing screens (`report`, `report/detail`, `ChildOrder`,
`customerChoice`, `complete_profile`) in **both** apps, each in its own design,
plus whatever backend they need.
**(c)** Field-by-field audit of products, categories, variants, cart and order in
the apps.
**(d)** The remaining Phase 2 items: MON-08, removing `customerId` from the order
DTO, route analytics, the `isLoaded` / `sts_verify_step_two` guards, guest
behaviour, app SMS templates, and the remaining screens.
## 3. Working method per section
**Implement the gaps first, then field-by-field test that same section.** Before
fixing any section, **show the owner a short summary of the gaps found** and wait.
This supersedes the "audit everything, then fix everything" reading of D12: the
field-by-field requirement is unchanged, but it is applied **per section**, with
a checkpoint before each one.