parity(docs): record user decisions D0-D12 and urgent investigation results

Phase 0 gate passed. All rulings recorded in docs/parity/DECISIONS.md and
applied to PROTECTED.md, PROGRESS.md and ISSUES.md. No source code changed.

Urgent investigations requested by the user, all evidence-cited:

- percent trace: the target's implementation is WRONG. `percent` is the
  customer's OWN column in the reference (customer_add.php:32), a per-customer
  making-charge offset used to shift catalogue filter bounds
  (ApiMobileController.php:391-396,76-77). The target reads the referring
  agent's wagePercent instead (admin-customers.service.ts:245) and never
  writes the field at all. It is NOT part of the price formula -- that extra
  percent comes from a global ConfigStatic row (ProductVariant.php:50,183).
  Two unrelated `percent` keys exist and must not be confused with it.

- @Public audit: 15 routes across 7 controllers, grouped by risk. Group A is
  5 ledger routes (4 writes) that contradict decision D1; group B is 3 order
  routes incl. a public status change accepting a client-supplied
  actorAdminUserId; group C is 8 reads, of which only the catalogue, pricing,
  slider and uploads are legitimately public.

- Login leak: it is in the TARGET. GET /customers is public and returns every
  active customer with national ID numbers, debts and ID-document URLs.
  passwordHash is correctly excluded. Not possible in the reference.

Also logged 5 customer-module defects found in the deep check the user asked
for (CUST-01..05), including the fullName collapse the user reported.

Skill updated per D12: Step C gains rule C0 (field-by-field matrix, never
page-by-page) and Step E gains rule E0 (mandatory 4-step round-trip test).

[ref: henza_server, henza_admin]

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
s.esmaeili
2026-09-21 23:26:35 +03:30
co-authored by Claude Opus 5
parent 71192ba2ba
commit 004a3945c2
4 changed files with 481 additions and 29 deletions
+58 -14
View File
@@ -1,6 +1,7 @@
# PROTECTED — intentional monorepo additions (additive-only)
**DRAFT — awaiting user confirmation (Phase 0 gate).**
**CONFIRMED by the user at the Phase 0 gate (2026-09-21).**
Rulings are recorded in `DECISIONS.md` (D0–D12).
Items here are intentional changes in `gold-banking-monorepo`. Per `CLAUDE.md` §4
they must **not** be removed, restyled, restructured, or have their behaviour
@@ -125,9 +126,16 @@ pill-shaped SearchInput.
---
## D. Backend — stricter auth than the reference · **[?] needs your ruling**
## D. Backend — stricter auth than the reference · **CONFIRMED (D1)**
**Not yet protected — Q1 in the gate.**
**Protected.** The user ruled the target's stricter auth stands as an accepted
deviation. Additional obligation from D1: build a full
"reference admin operation ↔ target rid" matrix so no operation lacks a
permission, and explain the 172-vs-174 key difference.
⚠️ **Not yet satisfied:** 5 ledger-write routes are still `@Public()`
(`DECISIONS.md` §"@Public audit" group A). They contradict D1 and are awaiting
the user's go-ahead to be protected.
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).
@@ -143,7 +151,7 @@ reference behaviour as `SEC-01` and the residual `@Public()` routes as `SEC-02`.
---
## E. Backend — Decimal money discipline · **[found] proposed**
## E. Backend — Decimal money discipline · **CONFIRMED**
The reference uses PHP floats throughout. `apps/api` has **zero `Float` columns**
in `prisma/schema.prisma`; ledger and order math run on `Prisma.Decimal`.
@@ -159,7 +167,12 @@ Same result, better representation.
---
## F. Prior deliberate non-ports · **[?] needs your ruling (Q4)**
## F. Prior deliberate non-ports · **CONFIRMED (D4)**
Per D4: broken/destructive reference behaviour is not replicated, only logged —
but **business behaviour, calculations, rounding and messages must match the
reference exactly**, and every deliberate non-replication carries a matrix note
«عمداً تکرار نشد — ISSUE #n».
Recorded in `docs/CHANGELOG-PORT-HISTORY.md` as intentionally **not** ported:
@@ -180,14 +193,45 @@ otherwise.
---
## Summary — what needs your decision
---
| Section | Item | Proposed |
## G. Target-only capabilities · **CONFIRMED (D2) — status ➕, do not touch**
Per D2, features that exist only in the target are listed with status **➕** and
left alone. Ask before touching any of them.
| Capability | Where | Note |
|---|---|---|
| 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 |
| Dual-currency ledger (`LedgerEntry`, gold grams + rial) | `apps/api/src/modules/accounting/` | replaces the reference's single mixed-unit `balance` column |
| Gram / rial debt split (`goldDebtGrams`, `fiatDebtRial`) | `prisma/schema.prisma` | reference mixed both in one field |
| `Prisma.Decimal` money types throughout | schema + services | see §E |
| Server-enforced rid permissions | `auth/acl.constants.ts` | see §D |
| `UploadedFile` model + authenticated upload | `admin-uploads/` | reference upload was anonymous |
| Status-label / transition helpers | `admin-orders.service.ts` | reference had two divergent enums |
This list grows as Phase 1 and Phase 2 identify more. It is **not** a to-do list —
it is a keep-out list.
---
## Summary — confirmed status
| Section | Item | Status |
|---|---|---|
| A | Admin Dashboard | ✅ protected (brief) |
| B | Product Variants image picker | ✅ protected (brief) |
| C | User-app designs + new features | ✅ protected (brief), **excluding** the 5 v1↔v2 logic gaps (D3) |
| D | Stricter admin auth in `apps/api` | ✅ protected (D1) — 5 ledger routes still open, pending approval |
| E | Decimal money types | ✅ protected |
| F.1–4 | Prior security / data-loss non-ports | ✅ protected (D4) |
| F.5 | Branch horizontal layout | ❌ **a real gap**, not protected |
| G | Target-only capabilities | ✅ ➕ leave untouched (D2) |
### Explicitly NOT protected (parity work, per `DECISIONS.md`)
- The `fullName` collapse — **being reversed** under D0
- `percent` read from the referring agent — **wrong**, being corrected under D9
- The 5 v1↔v2 logic gaps — D3
- Unverified OTP — D6
- The public customer list — D8
- `singleCustomer.vue`'s full-form send — D11