| `JWT_CUSTOMER_SECRET` | Signs **customer and sales-expert app** tokens. Must be its own value — see the warning at the top of this file. Unset, it falls back to `JWT_SECRET` and the two token realms merge. |
| `PROFILE_ADMIN_MOBILES` | *(blank)* | Comma-separated admin mobiles told when a customer completes their profile. The reference hardcoded four numbers; blank means nobody is notified and the upload still succeeds. |
Flows walked end to end: admin login, customer creation, sales-expert
create/edit, product and variant create/edit, order list/detail/status change,
wholesale order placement from the admin panel, cash document creation +
confirm + un-confirm; and in **both** customer apps: OTP login with the master
code, product browsing, cart, order placement, order history.
Money paths were checked against the reference's own formulas, not just for a
200: making charge `rash × (1 + (wage − discount)/100)` reproduced exactly, and
the cash-document conversion `price / (price_per_gram / 4.331802)` moved the
customer's gold debt by the expected amount and restored it exactly on
un-confirm.
Every test script deletes only the rows it created; the write test also asserts
the customer's balances end exactly as they started.
---
## 5. Known issues — not done tonight
Nothing here blocks the delivery. Full detail in `docs/parity/ISSUES.md`.
### Missing app pages (not started)
Present in the reference PWA, absent in both apps. Listed in the owner's own
priority order:
| Page | Reference | Notes |
|---|---|---|
| `report` + `report/detail` | `henza_pwa/src/views/report/` | The accounting statement — a store plus two components (`Accounting.vue`, `AccountingDetail.vue`). The largest of the four. |
| **Sales-expert app login (D21)** | ✅ Done. An expert signs into both apps with their AdminUser account and the ordinary OTP flow; the master code works for them too. They get the whole app — browsing, cart, ordering, order history — plus their own two screens. |
| **«سفارش مشتریان» (ChildOrder)** | ✅ Done in both apps. Their referred customers' orders at «تحویل مسئول فروش», searchable, infinite-scrolled. |
| **«مشتریان من» (customerChoice)** | ✅ Done in both apps. Their referred customers, searchable, with a read-only detail sheet. |
| **APP-02 — admin home slider in v2** | ✅ Fixed. v2 now prefers admin-configured slides and keeps its category-derived hero as the fallback. |
| **«تکمیل پروفایل» (complete_profile)** | ✅ Done in both apps. Three document uploads (جواز کسب، سردر مغازه، کارت ملی), then the profile is marked verified. Reached from the profile screen, and only while the documents are missing — exactly the reference's condition. |
| **APP-02** | `user-app-v2` has no `getHomeSlider`, so slides configured in the admin panel appear in **user-app only**; v2 always derives its hero from categories. Not fixed because v2's home is its own design and rewiring it during a delivery risks the page being demonstrated. |
| **PERS-02** | The reference's cities are a province → city **tree** (provinces not selectable); the target flattened this to a `province` string and a flat select on all three Persons forms. The city itself is still captured correctly. |
| **PERS-03** | The reference collects a Jalali **birth date** on the customer forms; the target has no column for it. |
| **PERS-01** | The reference makes a customer's **mobile immutable on edit**; the target allows editing it. Owner ruled this NOT ported — the target keeps its current behaviour. |
| **PERF-01** | `listReagents()` runs one aggregate per row (N+1) for the per-agent sales total. Harmless at the current agent count. |
### Parity work not reached
Phase 1 was not completed: the field-by-field audit stopped after the Persons
section, and products/categories/variants, financial documents, users and
permissions, SMS templates, promotions, cities, branches, workshops and reports
have had only the breakage scan above, not a full parity audit. The
**Phase 1 gate was lifted for tonight only** (D19) and still stands as the next
milestone.
`PERM-01` (the database holds 178 distinct permission ids against the UI's 174)
is still awaiting a decision, because resolving it means deleting rows.
---
## 6. Decisions that shaped this build
Recorded in `docs/parity/DECISIONS.md`:
- **D13** — the retail storefront (`single*`, wallet, comments, `customer.php`,
`site.php`) is **preserved but out of scope**. Nothing there was changed.
- **D19** — delivery mode: implement the main gaps, do not stop to ask, choose
the lowest-risk option, change nothing protected.
- **D20** — SMS can never block a boot or an operation; `OTP_MASTER_CODE` for