parity(api,apps): delivery-mode gaps — master OTP, non-blocking SMS, faToEn, v2 cart cap
D20: OTP_MASTER_CODE login bypass read only from the environment, disabled when unset, audited on every use, with a boot banner while armed. SMS no longer aborts the boot in production — it warns and declines silently, so no message can stop an operation. D19: port Utility::faTOen onto admin-entered mobiles (before the uniqueness lookup, which could previously be bypassed with Persian digits), and the create-only welcome SMS, byte-identical to the reference and fire-and-forget. user-app-v2 was missing the cart stock ceiling entirely: capQty/maxQty, the un-orderable guard and the qty clamp are ported, leaving v2's own design intact. The two cart stores are now byte-identical. isVariantOrderable and the orderable-first default selection ported too. jest 45/45; typecheck clean on api, admin-panel, user-app, user-app-v2. [ref: henza_server/app/Http/Controllers/Adm/AdminController.php:333,348,364,378-387] [ref: henza_server/app/Models/Utility.php:26] Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2194b3d4d9
commit
460cf276b6
@@ -68,30 +68,30 @@ export function smsConfigured(): boolean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from main.ts before the app listens. In production a missing key is
|
||||
* fatal: without it no customer can log in, and a silent no-op gives no clue
|
||||
* why. Outside production it is only a warning, so local development works
|
||||
* with no credentials at all.
|
||||
* Called from main.ts before the app listens. Reports the SMS configuration
|
||||
* and NEVER throws.
|
||||
*
|
||||
* D20 reversed the earlier rule (D14) that a missing credential should abort
|
||||
* the boot in production. The server now always starts: a missing or unknown
|
||||
* provider is a warning, `send()` declines silently and logs, and no message —
|
||||
* including the welcome SMS — can stop an operation. The trade-off is
|
||||
* deliberate and accepted: with SMS unconfigured, customers cannot receive a
|
||||
* login code, which is why `OTP_MASTER_CODE` exists for the delivery.
|
||||
*/
|
||||
export function assertSmsConfigured(logger: Logger = new Logger('SmsConfig')): void {
|
||||
const c = smsConfig();
|
||||
|
||||
if (c.provider === 'none') {
|
||||
const message = 'SMS_PROVIDER=none — no SMS will be sent.';
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
throw new Error(
|
||||
`${message} Refusing to start in production: customers could not log in. ` +
|
||||
'Set SMS_PROVIDER=trez and the SMS_TREZ_* variables.',
|
||||
);
|
||||
}
|
||||
logger.warn(message);
|
||||
logger.warn('SMS_PROVIDER=none — no SMS will be sent.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (c.provider !== 'trez') {
|
||||
throw new Error(
|
||||
`Unknown SMS_PROVIDER "${c.provider}". Supported values: "trez", "none".`,
|
||||
logger.warn(
|
||||
`Unknown SMS_PROVIDER "${c.provider}" (supported: "trez", "none"). ` +
|
||||
'No SMS will be sent.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const missing = (
|
||||
@@ -106,14 +106,10 @@ export function assertSmsConfigured(logger: Logger = new Logger('SmsConfig')): v
|
||||
|
||||
if (missing.length === 0) return;
|
||||
|
||||
const message = `SMS provider "trez" is selected but these are not set: ${missing.join(', ')}.`;
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
throw new Error(
|
||||
`${message} Refusing to start in production: no customer could receive a login code. ` +
|
||||
'Set them, or set SMS_PROVIDER=none to acknowledge that SMS is disabled.',
|
||||
);
|
||||
}
|
||||
logger.warn(`${message} Running in development mode — messages are logged, not sent.`);
|
||||
logger.warn(
|
||||
`SMS provider "trez" is selected but these are not set: ${missing.join(', ')}. ` +
|
||||
'Messages are logged, not sent. Customers cannot receive a login code.',
|
||||
);
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
|
||||
Reference in New Issue
Block a user