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
+46 -2
View File
@@ -10,7 +10,7 @@
| **Phase** | **Phase 1 — admin parity, matrix in progress** |
| **Branch** | `parity/phase-1-admin` (cut from `parity/security-hotfix`) |
| **Status** | Both stages done and verified live: **46/46** smoke assertions, **7/7** jest unit tests, typecheck + build clean on all three projects. |
| **Next step** | Owner is reviewing the matrix summary; §3 PRICE-01 is fix #1 once the order is confirmed |
| **Next step** | Phase 1 (a) Persons — report where the reference uses the 5 sales-expert fields for `type=1`, then implement per D16 |
| **Blocked on** | nothing |
| **Last updated** | 2026-09-22 |
@@ -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–D15). Highlights that change how work is done:
All user rulings live there (D0–D16). 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
@@ -105,6 +105,7 @@ All user rulings live there (D0–D15). Highlights that change how work is done:
| 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. |
| D14 | **`migrate dev` in development, `migrate deploy` in production and nowhere else.** Never `migrate reset`; never edit `_prisma_migrations`. On drift + a reset offer: **stop and report**. |
| D15 | **`_goldbank_migrations` is KEPT** — it is the tracking table of the app's own migration runner (`src/prisma/migrate.ts`), needed because the Docker image has no Prisma CLI. Declared `@@ignore`d; drift is zero. **Persian test input must come from a FILE, never a shell argument.** |
| D16 | **PRICE-01 STOPPED** — price display is retail-storefront (⏸️ D13); the B2B app works in making charge only. `variant-price.ts` + tests kept but unused. **Making charge stays in scope.** New work order: Persons → Products/variants/order-detail → the rest of the admin → gate → apps. **Per section: implement gaps, then field-by-field test, and show a gap summary BEFORE fixing.** |
## Open — awaiting user approval
@@ -215,3 +216,46 @@ The Windows shell replaces Persian characters with `?`. A test that passes its
data inline can "pass" while storing `????`. Write fixtures in the test file or
a UTF-8 JSON file and send bodies with `curl --data-binary @file`. Console
output of Persian is never evidence — compare values in Node.
## ⚠️ Phase 1 work order (D16 — supersedes the earlier ordering)
**(a) Persons (اشخاص)** ← current
1. The 5 missing sales-expert fields (`ncode`, `phone`, `city_id`, `gram_level`,
`reagent_id`): **report first** where the reference uses each for `type=1`,
then add accordingly (proposal: `SalesExpertProfile` related to `AdminUser`,
D10). Unused fields are listed for the owner, not added speculatively.
2. `singleCustomer` → diff-send (D11).
3. Field-by-field audit of every Persons form and grid (retail, wholesale,
sales expert) per D12, each with its round-trip test.
**(b) Products, categories, variants, admin order detail** — deep field-by-field.
The variant image picker is PROTECTED (§B) — additive only. Making charge on
every variant and order line must display and persist exactly as the reference.
**(c) The rest, in order:** financial documents → users & permissions → admin SMS
templates → promotions / notifications / cities / branches / workshops → reports.
**(d)** Full admin test pass → Phase 1 report → gate question → **STOP and wait**.
### Method per section (D16)
Implement the gaps first, then field-by-field test that same section. **Show the
owner a short gap summary BEFORE fixing each section.**
## ✅ SEC-02 — verified complete (re-tested 2026-09-22)
| Check | Result |
|---|---|
| `POST /orders` without a token | 401 (was `@Public`) |
| Body `customerId: "customer-2"` with a `customer-dev-test` token | order landed on **customer-dev-test**; spoof blocked and warn-logged |
| `GET /orders/:id` own order | 200 |
| `GET /orders/:id` another customer's order | **404**, not 403 — ids stay unenumerable |
| `GET /orders/:id` unknown id | 404, identical response |
| `GET /orders/admin/:id` with a customer token | 401 |
**9/9 passed** live, plus **32/32** in `auth-smoke.sh`. The server derives the
customer from the token only (`orders.controller.ts:26-29`,
`orders.service.ts` `createOrder(dto, customerId)`).
Client-supplied `wagePercent` / `discountPercent` / `flatRialCharge` remain —
that is **MON-08**, scheduled as Phase 2 item #1 per the owner's ruling.