Le crème vivait sur `<body>`, que Gmail supprime en réécrivant le message : la carte blanche se retrouvait collée au fond du client, blanc sur blanc chez les uns, bloc éblouissant sur fond noir chez les autres. Elle n'a plus de fond du tout — autour d'elle passe celui du lecteur, et c'est la bordure qui délimite, ce qui reste juste sur n'importe quel fond, y compris ceux qu'on ne connaît pas. Le mode sombre est déclaré (`color-scheme`) plutôt que subi : sans cette déclaration, Gmail et Apple inversent au jugé et le vert de marque en ressort délavé. Un piège qui ne se voyait qu'à l'écran : la marge intérieure était posée sur les `<table>`. En modèle de bordures fusionnées — celui de tout mail, et celui qu'Outlook applique de toute façon — la spécification CSS ignore la marge d'un élément `table`. Tout le message se collait aux bords. Elle est passée sur les `<td>`. Un châssis unique remplace les trois mises en page séparées. Le logo entre dans les mails, en image et non en texte, sur un bandeau qui reste sombre dans les deux modes : il n'a ainsi qu'une seule version à exister, juste partout. `public/` n'existait pas, et `output: "standalone"` ne le trace pas — sans la ligne ajoutée au Dockerfile le logo aurait répondu 404 chez tous les destinataires, panne invisible en développement. Les fiches promettaient 24 fois un geste qui n'existe pas — « si c'est déjà fait, dis-le-moi et je me tais », « dis-moi sa date d'expiration et je gère le tempo ». Le pied de page avait déjà été purgé de la même promesse ; le corps la répétait. Retirées sans remplacement : elles reviendront le jour où l'état utilisateur s'écrira. Le bloc d'accompagnement du rappel groupé disparaît aussi — « pour que tu n'aies pas à y penser toi-même » se démentait dans le seul message qui demande justement d'y penser. Et chaque échéance dont la fiche a une page publique porte désormais un lien vers elle : la bicéphalie ne servait que le SEO, alors que c'est au destinataire d'un rappel que l'explication entière manque le plus. Enfin, le lien d'activation. Il n'était pas un raccourci : sa vérification était la seule chose au monde capable de créer le compte de l'acheteur, better-auth ne le créant qu'à ce moment, `resolveMembership` n'inscrivant le premier membre que s'il y a une session, et `destinatairesFoyer` ne connaissant que les appartenances. Un mail lu le soir, un lien ouvert deux fois, un antispam qui le déclenche à vide, et un foyer payé 19,99 € restait sans compte, sans appartenance, donc sans destinataire de rappel, définitivement. Ce n'est pas un cas de bord : ce message n'est envoyé que quand personne n'était connecté avant de payer, donc l'unique mail d'activation qui existe était précisément celui dont l'expiration était fatale. Le webhook crée le compte et l'appartenance lui-même, depuis l'adresse que Stripe vient de collecter. Contrepartie assumée : Stripe ne prouve pas la possession de la boîte, et qui paierait pour l'adresse d'un tiers lui rattacherait un foyer — un ajout indésirable, jamais une prise de contrôle, et facturé à celui qui le tente. `npm run mails:echantillon` rend un exemplaire de chaque message depuis les vraies fiches, et, si une adresse est donnée, le rappel réel de ses foyers. D-048, D-049. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
7 lines
382 B
JSON
7 lines
382 B
JSON
{
|
|
"//": "Les scripts hors Next.js s'exécutent par tsx, qui compile lui-même le JSX. Le tsconfig du projet dit `preserve` — c'est Next.js qui transforme, et tsx ne le peut pas. Cette variante n'existe que pour les scripts qui rendent des gabarits React Email (scripts/mails-echantillon.ts).",
|
|
"extends": "./tsconfig.json",
|
|
"compilerOptions": {
|
|
"jsx": "react-jsx"
|
|
}
|
|
}
|