feat(plataforma): tema de e-mail Athletic Map

This commit is contained in:
deploy
2026-09-25 00:32:56 +00:00
parent 62aa13bbb1
commit f26f4a4559
+291
View File
@@ -0,0 +1,291 @@
# GERADO por scripts/tema_email_athleticmap.py — nao edite na mao.
# Fonte: keycloak-theme/escolinha/email/
#
# O `items` do volume (ver 20-keycloak.yaml) desfaz o achatamento das
# chaves: `template.ftl` vira `html/template.ftl` na montagem.
apiVersion: v1
kind: ConfigMap
metadata:
name: kc-email-athleticmapv2
namespace: plataforma-prod
annotations:
# Mesmo motivo do tema de login: sem isto o ArgoCD guarda o
# manifesto inteiro numa anotacao limitada a 256 KiB.
argocd.argoproj.io/sync-options: ServerSideApply=true
data:
theme.properties: |-
# O tema de E-MAIL do Athletic Map.
#
# `parent=base` e nao `keycloak`: o tema `keycloak` de e-mail nao acrescenta
# nada ao `base` alem de recursos que nao usamos, e herdar dele traria um
# template.ftl que este aqui substitui inteiro.
#
# Ao sobrescrever `template.ftl`, TODO e-mail do realm ganha a moldura da marca
# — inclusive os que este tema nao reescreve (redefinicao de senha, verificacao
# de e-mail). O corpo deles continua vindo do `base`, dentro da moldura nova.
parent=base
# pt-BR primeiro: o cliente e brasileiro. O `en` fica porque o Keycloak cai
# nele quando o navegador de quem recebe pede outra coisa, e um e-mail em
# ingles e melhor do que um e-mail com as chaves cruas.
locales=pt-BR,en
template.ftl: |-
<#--
A moldura de TODO e-mail do realm.
── POR QUE TABELA, E NAO DIV ────────────────────────────────────────────────
Outlook no Windows renderiza com o motor do Word, que ignora `flex`, `grid` e
boa parte de `margin`. Tabela aninhada com largura fixa e o unico layout que
chega igual no Gmail, no Outlook e no app do celular. Nao e gosto antigo: e o
que o cliente que acabou de pagar vai abrir.
── POR QUE ESTILO EM LINHA ──────────────────────────────────────────────────
Gmail REMOVE a tag <style> do <head>. Tudo que precisa valer vai em `style=`
no proprio elemento.
── POR QUE A MARCA NAO E IMAGEM ─────────────────────────────────────────────
A tela de login embute o logo em data URI, e ali funciona. Em e-mail nao: o
Gmail nao carrega `src="data:..."`, e o Outlook bloqueia imagem externa ate
o leitor clicar em "exibir". As tres barras sao celulas com `bgcolor`, que
todo cliente pinta, e o nome e texto — a marca chega inteira mesmo com as
imagens desligadas.
Cores: as mesmas variaveis do login.ftl.
laranja #F58220 · navy #0B2C3D · papel #F6F5F3 · linha #E7E5E1 · fraco #6B6B6B
-->
<#macro emailLayout>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${msg("emailTituloDaJanela")}</title>
</head>
<body style="margin:0; padding:0; background:#F6F5F3;">
<!-- A primeira linha do preview, no lugar de um trecho do HTML. -->
<div style="display:none; max-height:0; overflow:hidden; opacity:0;">
${msg("emailPreCabecalho")}
</div>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"
style="background:#F6F5F3; padding:32px 16px;">
<tr>
<td align="center">
<table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0"
style="width:600px; max-width:100%; background:#FFFFFF;
border:1px solid #E7E5E1; border-radius:14px; overflow:hidden;
font-family:'Inter','Segoe UI',system-ui,-apple-system,Roboto,Helvetica,Arial,sans-serif;">
<!-- ── cabecalho ─────────────────────────────────────────────── -->
<tr>
<td style="background:#0B2C3D; padding:26px 32px;">
<table role="presentation" cellpadding="0" cellspacing="0" border="0">
<tr>
<!-- as tres barras -->
<td style="padding-right:4px;">
<table role="presentation" cellpadding="0" cellspacing="0" border="0">
<tr>
<td width="5" height="14" bgcolor="#F58220"
style="font-size:0; line-height:0;">&nbsp;</td>
<td width="4">&nbsp;</td>
<td width="5" height="20" bgcolor="#F58220"
style="font-size:0; line-height:0;">&nbsp;</td>
<td width="4">&nbsp;</td>
<td width="5" height="26" bgcolor="#F58220"
style="font-size:0; line-height:0;">&nbsp;</td>
</tr>
</table>
</td>
<td style="padding-left:10px; color:#FFFFFF; font-size:19px;
font-weight:700; letter-spacing:-0.2px;">
Athletic&nbsp;Map
</td>
</tr>
</table>
</td>
</tr>
<!-- a fatia laranja, o mesmo corte diagonal da tela de login -->
<tr>
<td height="4" bgcolor="#F58220" style="font-size:0; line-height:0;">&nbsp;</td>
</tr>
<!-- ── corpo ─────────────────────────────────────────────────── -->
<tr>
<td style="padding:36px 32px 8px 32px; color:#0B2C3D; font-size:16px; line-height:1.6;">
<#nested>
</td>
</tr>
<!-- ── rodape ────────────────────────────────────────────────── -->
<tr>
<td style="padding:24px 32px 30px 32px;">
<div style="border-top:1px solid #E7E5E1; padding-top:18px;
color:#6B6B6B; font-size:12px; line-height:1.6;">
${msg("emailRodapeAviso")}<br>
<span style="color:#9C9A95;">${msg("emailRodapeAssinatura")}</span>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
</#macro>
executeActions.ftl: |-
<#--
O e-mail que o cliente que ACABOU DE PAGAR recebe.
E o primeiro contato dele com o produto depois do cartao passar, e ate
2026-09-24 ele chegava com o texto de fabrica do Keycloak: "Your administrator
has just requested that you update your account". Nao ha administrador nenhum,
ninguem pediu nada, e o cliente nao fala ingles.
── AS VARIAVEIS QUE O KEYCLOAK ENTREGA ──────────────────────────────────────
link o endereco de uso unico
linkExpiration o prazo, em minutos
linkExpirationFormatter formata o prazo por extenso ("12 horas")
realmName o displayName do realm
requiredActions a lista de acoes (UPDATE_PASSWORD, VERIFY_EMAIL...)
user quem recebe
── POR QUE O BOTAO E UMA TABELA ─────────────────────────────────────────────
`<a>` com padding nao vira area clicavel no Outlook: ele so pinta o texto. A
tabela com `bgcolor` e o <a> ocupando a celula inteira e o unico jeito de o
botao ser um botao nos tres clientes.
── E POR QUE O LINK APARECE EM TEXTO TAMBEM ─────────────────────────────────
Cliente corporativo reescreve href para passar por filtro, e as vezes quebra.
Com o endereco visivel, quem recebe consegue copiar e colar. Custa tres linhas
e salva o cliente de ligar para o suporte no primeiro dia.
-->
<#assign acoes><#if requiredActions??><#list requiredActions><#items as a>${msg("requiredAction.${a}")}<#sep>, </#sep></#items></#list></#if></#assign>
<#import "template.ftl" as layout>
<@layout.emailLayout>
<h1 style="margin:0 0 6px 0; font-size:26px; line-height:1.25; font-weight:700; color:#0B2C3D;">
${msg("boasVindasTitulo")} <span style="color:#F58220;">${msg("boasVindasTituloDestaque")}</span>
</h1>
<p style="margin:0 0 22px 0; color:#6B6B6B; font-size:15px;">
${msg("boasVindasSubtitulo", realmName)}
</p>
<p style="margin:0 0 26px 0;">
${msg("boasVindasCorpo", acoes)}
</p>
<!-- o botao -->
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:0 0 22px 0;">
<tr>
<td bgcolor="#F58220" style="border-radius:10px;">
<a href="${link}"
style="display:inline-block; padding:15px 30px; color:#FFFFFF;
font-size:16px; font-weight:700; text-decoration:none;
font-family:'Inter','Segoe UI',system-ui,Helvetica,Arial,sans-serif;">
${msg("boasVindasBotao")} &nbsp;&rarr;
</a>
</td>
</tr>
</table>
<p style="margin:0 0 24px 0; padding:14px 16px; background:#FFF5E8;
border-left:3px solid #F58220; border-radius:0 8px 8px 0;
color:#0B2C3D; font-size:14px; line-height:1.55;">
${msg("boasVindasPrazo", linkExpirationFormatter(linkExpiration))}
</p>
<p style="margin:0 0 6px 0; color:#6B6B6B; font-size:13px;">
${msg("boasVindasLinkManual")}
</p>
<p style="margin:0 0 10px 0; font-size:13px; line-height:1.5; word-break:break-all;">
<a href="${link}" style="color:#2563EB; text-decoration:underline;">${link}</a>
</p>
</@layout.emailLayout>
messages_pt_BR.properties: |-
# Textos do e-mail do Athletic Map.
#
# ISO-8859-1 e o encoding que o Keycloak le aqui - em .properties, tudo fora do
# Latin-1 precisa de \uXXXX. Acento comum (a, e, i, o, u com til/agudo/circunflexo)
# passa direto; travessao, aspas curvas e emoji NAO passam, e viram simbolo torto
# na caixa de quem recebe.
#
# Chave `{0}`, `{1}`... sao os argumentos na ordem em que o .ftl passa.
# -- o assunto ---------------------------------------------------------------
# Sem "Update Your Account". O cliente acabou de pagar; o assunto diz o que ele
# precisa fazer, e a marca aparece para ele reconhecer na lista.
executeActionsSubject=Sua conta Athletic Map esta pronta
# -- a moldura ---------------------------------------------------------------
emailTituloDaJanela=Athletic Map
# O trecho que Gmail e Outlook mostram ao lado do assunto, antes de abrir.
emailPreCabecalho=Falta um passo para voce entrar: defina sua senha de acesso.
emailRodapeAviso=Se voce nao reconhece este pedido, pode ignorar esta mensagem \u2014 nada muda na sua conta.
emailRodapeAssinatura=Athletic Map \u2014 gestao para escolinhas esportivas
# -- o corpo das boas-vindas -------------------------------------------------
boasVindasTitulo=Sua conta esta
boasVindasTituloDestaque=pronta!
# {0} = nome do realm (displayName)
boasVindasSubtitulo=Acesso a {0}
# {0} = as acoes pedidas, ja traduzidas ("Atualizar senha")
boasVindasCorpo=Falta um passo para voce comecar: {0}. Clique no botao abaixo e leve menos de um minuto.
boasVindasBotao=Definir minha senha
# {0} = o prazo por extenso
boasVindasPrazo=Este link vale por {0} e pode ser usado uma vez so. Depois disso, peca outro na tela de acesso, em "Esqueceu sua senha?".
boasVindasLinkManual=Se o botao nao funcionar, copie e cole este endereco no navegador:
# -- as acoes, em portugues --------------------------------------------------
# O Keycloak traduz estas chaves para montar a lista do corpo. Sem elas, o
# cliente brasileiro le "Update Password" no meio de uma frase em portugues.
requiredAction.UPDATE_PASSWORD=definir sua senha
requiredAction.VERIFY_EMAIL=confirmar seu e-mail
requiredAction.UPDATE_PROFILE=completar seu cadastro
requiredAction.CONFIGURE_TOTP=configurar a verificacao em duas etapas
requiredAction.TERMS_AND_CONDITIONS=aceitar os termos de uso
requiredAction.CONFIGURE_RECOVERY_AUTHN_CODES=gerar seus codigos de recuperacao
messages_en.properties: |-
# O MESMO conjunto de chaves, em ingles.
#
# Nao e capricho: o Keycloak escolhe o locale pelo idioma de quem recebe, e se
# ele cair no `en` sem estas chaves o e-mail sai com o NOME DELAS no lugar do
# texto - "boasVindasTitulo" literal no corpo. Um arquivo faltando aqui nao
# quebra nada em teste e estraga o primeiro e-mail de um cliente estrangeiro.
executeActionsSubject=Your Athletic Map account is ready
emailTituloDaJanela=Athletic Map
emailPreCabecalho=One step left: set your password.
emailRodapeAviso=If you did not expect this, you can ignore this message \u2014 nothing changes in your account.
emailRodapeAssinatura=Athletic Map \u2014 management for sports schools
boasVindasTitulo=Your account is
boasVindasTituloDestaque=ready!
boasVindasSubtitulo=Access to {0}
boasVindasCorpo=One step left before you start: {0}. Click the button below \u2014 it takes less than a minute.
boasVindasBotao=Set my password
boasVindasPrazo=This link is valid for {0} and can be used once. After that, request a new one on the sign-in screen, under "Forgot your password?".
boasVindasLinkManual=If the button does not work, copy and paste this address into your browser:
requiredAction.UPDATE_PASSWORD=set your password
requiredAction.VERIFY_EMAIL=confirm your e-mail
requiredAction.UPDATE_PROFILE=complete your profile
requiredAction.CONFIGURE_TOTP=set up two-step verification
requiredAction.TERMS_AND_CONDITIONS=accept the terms of use
requiredAction.CONFIGURE_RECOVERY_AUTHN_CODES=generate your recovery codes