Applies the two approved additive migrations and fixes every consumer.
D0 — Customer.firstName / lastName
The reference has had two columns since 2020
(2020_10_01_120430_customers_table.php:18-19); the port collapsed them, so
the edit form showed the whole name in the "first name" box and saved an
empty last name. Adds both columns, backfills first-token/rest, and keeps
fullName in sync with a customer_sync_full_name trigger. Nothing dropped.
The trigger is SQL, so Prisma cannot see it: writing the parts rebuilds
fullName, writing fullName re-derives the parts, and writing both in one
statement lets THE PARTS WIN. Documented in the migration header, the
Customer model doc comment and DECISIONS.md §D14, because a write can now
store something other than what was passed.
D9 — Customer.makingChargeOffsetPercent
Legacy customers.percent, the per-customer making-charge offset that the
app adds to the variant's making charge (henza_pwa
Mixins/product/index.ts:69-75). toRow() was returning the referring
AGENT's commission rate instead (CUST-02). DB default 0 reproduces
today's behaviour exactly, so no existing customer's price moves; the
reference's application-layer default of 3 for NEW customers
(AdminController.php:338) lives in the create form, and the field is
required on create with the reference's own message (:354).
update() and updateCredit() both accepted percent and silently discarded
it; both now persist it. Sort/filter aliases fname/lname pointed at
fullName and now point at the real columns.
SMS — Trez provider (Sms.php:57-82)
New global SmsModule/SmsService: form-urlencoded POST, 20s timeout, body
trimmed, every message persisted. send() never throws, matching the
reference, which discarded Sms::Send's result so a gateway outage never
aborted the order or approval that triggered it. The OTP text is
byte-identical, including the Android SMS Retriever markers. Credentials
come from env only; production refuses to boot without them rather than
silently locking every customer out. .env.example carries names, no values.
Admin panel: the split(' ') fallback is removed from singleCustomer.vue,
and bulkCustomer.vue defaults percent to 3, requires it, coerces the
Decimal on load so diff-send works, and only re-sends `name` when a name
part changed. ReagentCustomer.vue is untouched — its «درصد کمیسیون» is
AdminUser.wagePercent, a different field.
Tests: 32 jest (incl. 14 new SMS config/template), 9 trigger assertions,
53 auth smoke, and the full D12 round-trip on the customer entity —
«محمد علی» + «احمدی» survives create, edit, a byte-identical no-op save,
and single-field edits. Typecheck clean on api and admin-panel.
Note: migrate dev is interactive-only and could not run here, so the
migrations were applied with migrate deploy after a read-only drift check.
The only drift is the pre-existing _goldbank_migrations table, which
Prisma would DROP; it was NOT dropped (DEAD-07).
[ref: henza_server/app/Models/Sms.php, app/Http/Controllers/Adm/AdminController.php]
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
39 lines
1.8 KiB
Bash
39 lines
1.8 KiB
Bash
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/gold_bank?schema=public"
|
|
|
|
# Must match API_PORT in the repo-root .env (source of truth for all dev
|
|
# ports). NestJS/Prisma only load .env from this app's own directory, so this
|
|
# value is kept in sync manually rather than read from the root file.
|
|
PORT=3000
|
|
|
|
# Customer app sessions (security hotfix stage 2).
|
|
# Separate from JWT_SECRET so an admin token can never validate as a customer
|
|
# token. Falls back to JWT_SECRET, then to a dev-only string, when unset.
|
|
JWT_CUSTOMER_SECRET=
|
|
# Customer token lifetime. The reference issued a token that never expired.
|
|
JWT_CUSTOMER_EXPIRES_IN=30d
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# SMS gateway — Trez panel (port of henza_server/app/Models/Sms.php:57-82)
|
|
# ---------------------------------------------------------------------------
|
|
# NEVER commit real values. The reference hardcoded its live production
|
|
# credentials in the source (SEC-12); those are treated as compromised and are
|
|
# not reused. Set the real values in .env, which is gitignored.
|
|
#
|
|
# In production the server REFUSES TO START when the three required variables
|
|
# below are unset, because without them no customer can receive a login code.
|
|
# Outside production it only warns, and OTP codes are logged locally instead.
|
|
|
|
# "trez" (default) or "none" to disable sending entirely.
|
|
SMS_PROVIDER=trez
|
|
# Defaults to the reference endpoint when unset; override for staging.
|
|
SMS_TREZ_URL=
|
|
# Required in production:
|
|
SMS_TREZ_USERNAME=
|
|
SMS_TREZ_PASSWORD=
|
|
# The panel's sender line — the `PhoneNumber` form field.
|
|
SMS_TREZ_SENDER_LINE=
|
|
# Comma-separated admin numbers for order/document notifications. The reference
|
|
# hardcoded six mobile numbers across its controllers (STUB-05); empty means
|
|
# no admin notifications are sent.
|
|
SMS_ADMIN_RECIPIENTS=
|