s.esmaeiliandClaude Opus 5 69f4ba2b29 feat(api): sales-expert login to the customer apps (D21)
A sales expert can now sign into the apps with their AdminUser account, without
reversing D17 — the expert remains an AdminUser and is never turned back into a
Customer.

The app token carries a `typ` of 'customer' or 'sales-expert'; the strategy
resolves both to one principal whose `id` is always a Customer id, so every
route already written for a customer works unchanged for an expert. That is what
the reference gave them, where an agent was a customer with extra screens.

Each expert gets ONE linked trading Customer row (additive migration, dry-run
clean and rolled back before applying) created at first sign-in, seeded from the
two numbers the reference read off the agent's own row: SalesExpertProfile
.gramLevel -> goldCreditLimitGrams and AdminUser.wagePercent ->
makingChargeOffsetPercent. Orders the expert places land there, exactly as the
reference's single row did.

New expert-only routes scope on the AdminUser id from the token:
POST expert/child-orders (legacy /order/child, ApiMobileController:759, keeping
its sts=5 filter as DELIVERED_TO_AGENT), POST expert/my-customers (legacy
/my-child, :184) and GET expert/whoami so the apps can hide the entries.

Security: jwt.strategy now rejects any token carrying an app `typ`. An expert's
app token holds their AdminUser id in `sub`, and JWT_CUSTOMER_SECRET falls back
to JWT_SECRET when unset — in that configuration the token would otherwise have
validated as an admin with full panel permissions.

NOT ported: myChild minted an api_token per listed customer (:197-201), letting
an agent act AS that customer. Recorded in D21 rather than silently dropped.

Tests: new test-sales-expert-app-login.cjs 36/36 — expert sign-in, trading
account seeding, own-customers-only (with both negatives), child orders, the
expert ordering for themselves, an ordinary customer refused both screens with
their own app unaffected, and all four token boundaries including immediate
lockout on deactivation. jest 45/45, admin smoke 43/43, apps smoke 43/43,
B2B scan 34/34, B2B writes 25/25, auth-smoke 32/32.

[ref: henza_server/app/Http/Controllers/Api/ApiMobileController.php:184-195,534-535,759-781]

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 01:05:36 +03:30
2026-09-18 17:16:36 +03:30
2026-09-16 11:59:35 +03:30
2026-09-10 12:17:47 +03:30
2026-09-18 17:16:36 +03:30
2026-09-09 23:31:31 +03:30
2026-09-09 06:46:27 +03:30
2026-09-09 06:46:27 +03:30
2026-09-09 06:46:27 +03:30
S
Description
No description provided
113 MiB
Languages
JavaScript 69.8%
TypeScript 15.2%
Vue 13.9%
Less 0.6%
PLpgSQL 0.3%
Other 0.1%