3.7 KiB
3.7 KiB
F-152 — Tech Spec
Principios
- Best-effort: un email fallido o SMTP no configurado nunca debe fallar el registro ni el webhook de pagos. Se loguea y se continúa.
- Reusar infraestructura existente: SMTP desde
store_settings(smtp_host/port/secure/user/pass/from), mismo patrón queSettingsPasswordResetMailerysendOrderStatusEmail. - Boundaries: identity no importa orders/payments a nivel de dominio; el wiring
del order-confirmation email se hace en el route handler de payments (posee
deps.pool), reusandosendOrderStatusEmailexportado públicamente pororders/index.ts.
Cambios
1. Order confirmation on PaymentSucceeded (payments)
orders/index.ts: exportarsendOrderStatusEmail(yORDER_STATE_LABELS).payments/api/payments.routes.ts: en el handler de/payments/webhook, trasconst outcome = await service.handleWebhook(event), sievent.type === 'PaymentSucceeded' && event.orderId && outcome.kind === 'processed', fetch customer email (identity_users.emailviaorders_orders.user_id) ysendOrderStatusEmail(deps.pool, { to, orderId: event.orderId, state: 'PAID' })dentro de try/catch; log de advertencia si falla SMTP/no-config.
2. Welcome email on registration (identity)
identity/domain/ports.ts: nuevo puertoWelcomeMailerconsendWelcome(input: { email: string; name?: string }): Promise<void>(name es opcional:Userno almacena nombre en el dominio actual).identity/infrastructure/settings-welcome-mailer.ts:SettingsWelcomeMailer(pool)modelado enSettingsPasswordResetMailer— lee SMTP destore_settings, usanodemailer, y una función purabuildWelcomeEmail(verificable sin SMTP). El subject (¡Bienvenido a Mercado de Vida!) coincide con la plantillaaccount_createdde notificaciones. Lanza si SMTP no está configurado.identity/api/identity.routes.ts:IdentityRoutesDeps.welcomeMailer?: WelcomeMailer; en el handler dePOST /auth/register, trasregisterUser.executeexitoso, se despacha el welcome email fire-and-forget (void mailer.sendWelcome(...).catch( request.log.warn(...))). Best-effort: un fallo SMTP se loguea (warning) y se traga; el registro nunca se rompe por email.RegisterUserse mantiene sin depender de email (puro orquestación de dominio).identity/index.ts: re-exportaSettingsWelcomeMailer(ySettingsPasswordResetMailer) para quebuild-app.tslos importe desde el index en lugar de deep-importar infra (cumple R2 de boundaries).notifications/domain/notification.ts+notifications/api/notifications.routes.ts: añadiraccount_createdal unionEmailTemplate, a los mapas SUBJECTS/BODIES deLoggingEmailProvidery al enum del schema dePOST /notifications/dispatch.
SMTP / store_settings
Claves existentes: smtp_host, smtp_port, smtp_secure, smtp_user, smtp_pass, smtp_from.
El welcome mailer reusa exactamente estas claves.
Testing
settings-welcome-mailer.test.ts:buildWelcomeEmail(greeting, nombre, XSS),SettingsWelcomeMailer.sendWelcome(nodemailer mockeado: sendmail called once con recipient == email y subject == plantillaaccount_created), y lanza cuando SMTP no está configurado (SMTP is not configured).orders/tests/orders-index.test.ts: el barrel deorders/index.tsre-exportasendOrderStatusEmail,buildOrderStatusEmail,ORDER_STATE_LABELS.order-status-mailer.test.tsya existe cubriendobuildOrderStatusEmail(PAID pertenece aORDER_STATE_LABELS).tsc --noEmitlimpio;prettier --checkyeslintlimpios en los archivos tocados; suite completa de vitest verde (197 tests);lint:boundariessin nuevas violaciones.- verify.sh green.