# Design: fluxo de e-mails via Twilio SendGrid + OTP por SMS via Twilio (2026-07-23)

## Contexto e decisão

A AWS negou a liberação de produção do SES, então o cliente decidiu trocar o
provedor de e-mail para o Twilio. Decisão do dono nesta sessão: **preparar o
transporte de e-mail via Twilio SendGrid E migrar o OTP para SMS via Twilio**
(reduz a dependência de e-mail no fluxo crítico de onboarding/login).

Fatos provados empiricamente em 2026-07-23:

- Credencial live (`AC8b7c1211...`): válida, conta "Monetarie", active, tipo Full
  (HTTP 200 em `api.twilio.com`).
- Credencial test (`AC15ec8682...`): válida para a API core (mensagem com números
  mágicos aceita, `status=queued`); dá 403 em recursos fora do escopo de teste.
- **Essas credenciais NÃO enviam e-mail**: e-mail no Twilio é o produto Twilio
  SendGrid, com API key própria (`SG.xxx`). `api.sendgrid.com` rejeita o par
  SID/token com 401 (provado). Falta o cliente gerar a API key no console do
  Twilio SendGrid e autenticar o domínio `monetarie.com` (SPF/DKIM).
- Conta Twilio live tem: 1 número (+14143009694, SMS ok), 1 Messaging Service
  (default de Conversations), 1 Verify Service (não usados por este design).
- Task-defs vivas (HML e PRD core-api): `EMAIL_TRANSPORT=ses`, ZERO envs
  `TWILIO_*` — ou seja, o SMS de MFA por Twilio também está inerte hoje.

## Estado atual do código (mapeado nesta sessão)

- `Monetarie.MailerConfig.resolve/1` seleciona adapter Swoosh por env:
  `ses` / `smtp` / ausente→Logger; qualquer outro valor dá raise.
- Fluxos que ENVIAM de verdade (via `Monetarie.Mailer`): OTP de onboarding
  (`Onboarding.OtpEmail`, branded com logo CID) e notificações CCS/CADOC
  (`Ccs.Notifications`).
- `Auth.Notifier` (reset de senha, ativação de conta, código MFA por e-mail,
  alerta cert e-CNPJ) é STUB: transporte `:email_transport` nunca configurado
  (default `:logger`) e o ramo SMTP só loga e devolve `{:ok, :queued}`.
  **Esses e-mails nunca foram entregues.**
- SMS: `Auth.Notifier.Sms` → `Auth.TwilioClient` (Req, envs `TWILIO_*`,
  `SMS_TRANSPORT` default twilio em prod). Usado pelo MFA. O SMS de verificação
  de telefone do onboarding (`ContactVerification.deliver_code(:phone, ...)`)
  publica no NATS `monetarie.core.notification.sms` **sem nenhum consumidor**
  (nunca entregue).
- Defeito de marca: o SMS do MFA diz "Seu codigo de verificacao Owem"
  (`mfa.ex:152`).
- SPB `BacenGateway.Alerts.EmailDelivery` envia por gen_smtp direto
  (`SMTP_HOST` etc.) — vira consumidor natural do relay SMTP do SendGrid,
  só configuração, sem código.

## Mudanças de código (todas em core/backend, sem migration)

1. **`MailerConfig`: novo transporte `EMAIL_TRANSPORT=sendgrid`** →
   `[adapter: Swoosh.Adapters.Sendgrid, api_key: SENDGRID_API_KEY]`.
   Fail-closed: `sendgrid` sem `SENDGRID_API_KEY` dá raise no boot (mesmo
   contrato do smtp sem host). SES/SMTP/Logger preservados (rollback barato:
   voltar a env). `runtime.exs` passa a setar `Swoosh.ApiClient.Req` para SES
   **e** Sendgrid.
2. **`Auth.Notifier` entrega de verdade via `Monetarie.Mailer`**: reset de
   senha, ativação, código MFA por e-mail e alerta de cert e-CNPJ constroem
   `Swoosh.Email` (HTML branded com logo CID no padrão do OtpEmail + text) e
   entregam pelo Mailer. O switch `:email_transport` e o stub SMTP morrem.
   Em dev/test os adapters Local/Test do Swoosh cobrem o papel do `:logger`.
   Novo módulo `Monetarie.Emails.Branded` (layout compartilhado); o
   `OtpEmail` validado visualmente pelo dono em 22/07 NÃO é tocado.
3. **OTP de telefone do onboarding via Twilio**:
   `ContactVerification.deliver_code(:phone, ...)` passa a chamar
   `Auth.Notifier.Sms.send/2` (fail-soft, mesmo padrão do ramo e-mail);
   o publish NATS morto é removido.
4. **Normalização E.164 fail-safe no funil `Notifier.Sms`** (cobre MFA e
   onboarding): strip de máscara; começa com `+` mantém; 12-13 dígitos
   começando com 55 ganham `+`; 10-11 dígitos ganham `+55`; resto passa
   como veio.
5. **Marca do SMS de MFA**: "Owem" → "Monetarie".
6. `.env.example`: linha `EMAIL_TRANSPORT=logger` (inválida — daria raise em
   prod) corrigida para documentar os valores reais.

## Configuração/deploy (após OK do dono)

- Secrets Manager: `monetarie/homolog/twilio/auth_token` (credencial TEST),
  `monetarie/prod/twilio/auth_token` (LIVE); `monetarie/{env}/sendgrid/api_key`
  quando o cliente entregar a key.
- Task-def core-api HML: `TWILIO_ACCOUNT_SID=AC15ec8682...`,
  `TWILIO_FROM_NUMBER=+15005550006` (número mágico: test creds SÓ aceitam esse
  From — nada é entregue de verdade em HML, por design), `TWILIO_ENABLED=true`,
  secret `TWILIO_AUTH_TOKEN`.
- Task-def core-api PRD: `TWILIO_ACCOUNT_SID=AC8b7c1211...`,
  `TWILIO_FROM_NUMBER=+14143009694`, `TWILIO_ENABLED=true`, secret.
- `EMAIL_TRANSPORT` permanece `ses` até a API key SendGrid chegar; flip para
  `sendgrid` + secret `SENDGRID_API_KEY` nos 2 ambientes depois.
- SPB (quando a key chegar, só env): `SMTP_HOST=smtp.sendgrid.net`,
  `SMTP_PORT=587`, `SMTP_USERNAME=apikey`, `SMTP_PASSWORD=<SG key>`.

## Pendências com o cliente

1. Gerar API key do Twilio SendGrid (permissão Mail Send) — test e prod se
   tiverem subusers; sem ela NENHUM e-mail sai.
2. Autenticar o domínio `monetarie.com` no SendGrid (CNAMEs de DKIM/SPF no
   DNS) e verificar o remetente `noreply@monetarie.com`.
3. Deliverability de SMS para +55 a partir do número US +14143009694: funciona,
   mas para volume/entregabilidade o caminho recomendado é um Messaging Service
   com sender local BR (registro junto às operadoras). Validar com 1 SMS real
   no flip de PRD.

## Riscos e mitigação

- Twilio fora do ar / credencial errada: `Notifier.Sms`/`TwilioClient` já são
  fail-soft com log de erro; OTP de onboarding segue o padrão fail-soft do
  e-mail (código persiste, cliente pode reenviar).
- SendGrid key ausente com `EMAIL_TRANSPORT=sendgrid`: raise no boot
  (fail-closed, nunca degrada em silêncio) — flip só com a secret criada.
- Rollback: e-mail volta com `EMAIL_TRANSPORT=ses|smtp`; SMS desliga com
  `TWILIO_ENABLED=false` (volta ao comportamento atual).
