# PROGRESS — Reference Parity Project > Read this file FIRST at the start of every session and after every `/compact`. > Rules live in `CLAUDE.md` (workspace root). Method lives in the `reference-parity-audit` skill. ## Current state | Field | Value | |---|---| | **Phase** | Security hotfix (out-of-band, authorised by D7/T1–T3) — **stage 1 ✅ done**, stage 2 next | | **Branch** | `parity/security-hotfix` | | **Status** | Stage 1 complete and tested live: 23/23 smoke assertions pass. Decisions D0–D12 + T1–T3 recorded. | | **Next step** | Stage 2 — customer JWT (`typ` claim, separate secret) + real OTP + migrate both apps' login; then remove `GET /customers` from the public surface | | **Blocked on** | nothing for stage 2. Still pending later: D0 migration + `percent` migration must be **shown and approved before running** | | **Last updated** | 2026-09-22 | ### Security hotfix — stage 1 result | Route | Was | Now | Rid | |---|---|---|---| | `GET accounting/customers/:id/balance` | public | admin | `wallet.list` | | `POST accounting/customers/:id/reconcile` | public **write** | admin | `wallet.charge` | | `POST accounting/repayments/gold` | public **write** | admin | `document.create` | | `POST accounting/repayments/rial` | public **write** | admin | `document.create` | | `POST accounting/entries/:id/confirm` | public **write** | admin | `document.list.confirm` | | `PATCH orders/:id/status` | public **write** | admin | `order.list.sts.submit` | | `GET customers` | 18 fields incl. national ID, debts, doc URLs | 4 fields | still public until stage 2 | Test: `apps/api/scripts/auth-smoke.sh` — **23 passed, 0 failed**. Typecheck: api ✅ · user-app ✅ · user-app-v2 ✅. ## ⚠️ Read `DECISIONS.md` before doing anything All user rulings live there (D0–D12). 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 `reference-parity-audit` skill (Step C rule C0, Step E rule E0). - **D0** — split `fullName` into `firstName`/`lastName` via an additive migration; **show the migration and get approval before running it**. - **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. ## Phase checklist - [x] P0.1 — All 3 reference folders readable (`henza_server`, `henza_admin`, `henza_pwa`) - [x] P0.2 — Branch `parity/phase-0` + `docs/parity/` created - [x] P0.3 — Inventory all 7 projects → `_inv-*.md` (8111 lines total) → consolidated in `00-INVENTORY.md` - [x] P0.4 — Mapping tables, missing list, extra list (`00-INVENTORY.md` §2–4) - [x] P0.5 — Draft `PROTECTED.md` - [x] **P0.6 — GATE passed** — `PROTECTED.md` confirmed, D0–D12 recorded - [x] P0.7 — Urgent traces delivered: `percent`, `@Public` list, login leak - [x] P0.8 — Skill updated with rules C0 (field-by-field) and E0 (round-trip test) - [ ] **P1.0 — user approves: 5 ledger routes, `percent` column, D0 migration** ← HERE - [ ] Phase 1 — Admin parity (branch `parity/phase-1-admin`, `01-ADMIN-MATRIX.md`) - [ ] **GATE:** "Admin parity is complete and tested. Shall we move on to the apps (user-app & user-app-v2)?" - [ ] Phase 2 — Apps parity (`02-APPS-MATRIX.md`, both user apps) - [ ] Phase 3 — Work through `ISSUES.md` (only when user asks) ## Answered — see `DECISIONS.md` for the full text | # | Ruling | |---|---| | D0 | Split `fullName` → `firstName`/`lastName`, additive migration, backfill, sync, report multi-token rows. Approval needed before running. | | D1 | Target's stricter auth stands. Build the "reference operation ↔ rid" matrix; explain 172 vs 174. | | D2 | Audit only what the reference has. Target-only features → ➕, untouched. | | D3 | Build the 5 missing screens in Phase 2, both apps, plus analytics, `isLoaded`/`sts_verify_step_two` guards, guest toast+home, and v2's cart ceiling. | | D4 | Don't port breakage; do match calculations/rounding/messages. Unit-test the price formula. | | D5 | Leave the stray folder; delete last, own commit. | | D6 | **OTP must verify** — parity gap, fix it (plus expiry + attempt limits, which exceed the reference). | | D7 | `@Public` ledger routes: list delivered, awaiting approval to protect. | | D8 | Login leak: **target**, full customer book incl. national IDs and debts. | | D9 | `percent`: trace delivered — **the target's implementation is wrong**. | | 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. | ## Open — awaiting user approval 1. **Protect the 5 `@Public` ledger-write routes** (`DECISIONS.md` group A). 2. **`percent` schema change** — add `makingChargeOffsetPercent` to `Customer`. 3. **D0 migration file** — must be shown and approved before it runs. ## Key context (survives context loss) - **Domain correction:** the reference is a **gold-jewellery B2B/B2C e-commerce** system, not a gold bank. No buy/sell order book, no spread, no deposit/withdraw, no P2P transfer, no KYC levels, no daily limits (only `gram_level`), no payment callback route, no cron, no websockets. See `00-INVENTORY.md` §0. - **The gold price formula** (Phase 1 row #1) — `henza_server/app/Models/ProductVariant.php:183-190`: `+extra%` → `+7%` margin → `+9%` VAT **on the non-metal portion only** → `×grams` → `floor(/1000)*1000`. Three superseded commented-out variants above it apply VAT to the whole price — do **not** port those. - **A large prior port already happened** — see `docs/ADMIN-PORT-PLAN.md` and `docs/CHANGELOG-PORT-HISTORY.md` (80 views, 25 Nest modules, 29 Prisma models, 154 admin routes, 144/144 rids). Prior port notes **no view was ever visually verified in a browser**. - **Stack changed across the port:** Laravel→NestJS/Prisma, Vue2/Vuesax→Vue3/antd. Port behaviour, not code style. - **Reference scale is inflated:** 541 admin `.vue` files but only ~69 reachable (rest are Vuexy template demos); 9 reference router files are dead (not imported); ~28 legacy Django-era DB tables have no migrations. - **v1 ⇄ v2 logic gaps** (5, all v2 behind v1) are parity work, not design: `ISSUES.md` MON-01, V2-01..05. ## Inventory files (Phase 0 working files) | File | Scope | Lines | |---|---|---| | `_inv-ref-server.md` | henza_server | 1313 | | `_inv-tgt-api.md` | apps/api | 1179 | | `_inv-ref-admin.md` | henza_admin | 1705 | | `_inv-tgt-admin.md` | apps/admin-panel | 1261 | | `_inv-ref-pwa.md` | henza_pwa | 1178 | | `_inv-tgt-userapp.md` | apps/user-app | 612 | | `_inv-tgt-userappv2.md` | apps/user-app-v2 | 700 | Consolidated into `00-INVENTORY.md`. Issues found: `ISSUES.md` (26 entries).