src/Controller/DnsReportController.php:
- Remplacement de \$this->container->get('doctrine')->getManager()
par injection de EmailTrackingRepository dans les parametres de __invoke()
- Le service locator du controller ne contient pas 'doctrine',
l'injection de dependance est la bonne pratique Symfony
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
src/Controller/DnsReportController.php (nouveau):
- Route /email/configuration/{token} accessible via le lien dans le mail
- Utilise le messageId de l'EmailTracking comme token d'acces
(seuls les destinataires du mail ont le lien)
- Execute tous les checks en temps reel: DnsCheckService (SPF, DMARC, MX,
Bounce via dig @1.1.1.1), AwsSesService (domaine, 3 DKIM CNAME,
MAIL FROM MX/TXT, bounce notif), CloudflareService (zone, records),
MailcowService (domaine, DKIM, MX, autodiscover, autoconfig, SRV, MTA-STS)
- Enrichit chaque check avec la colonne Cloudflare
- Passe les resultats au template Twig pour affichage complet
templates/dns_report/index.html.twig (nouveau):
- Page glassmorphism avec header glass
- Resume en haut: 3 cards (verifications OK, erreurs, avertissements)
avec bordures laterales colorees vert/rouge/jaune
- Tableau par domaine avec 6 colonnes: Source (badge colore par type:
orange AWS, violet Mailcow, bleu Cloudflare, gris DNS), Verification,
Attendu, Dig (actuel), Cloudflare, Statut (rond colore)
- Section erreurs detaillees avec liste
- Section avertissements avec liste
- Footer "Esy-Infra - Service de monitoring d'infra"
templates/emails/dns_report.html.twig (simplifie):
- Mail ne contient plus les details: seulement un tableau avec
chaque domaine et son statut (OK vert / WARN jaune / KO rouge)
- Bouton "Voir le rapport complet" avec lien vers la page web
(VML fallback pour Outlook)
- Le lien utilise le placeholder __DNS_REPORT_URL__ remplace par
le MailerService avec le messageId du mail
src/Service/MailerService.php:
- Ajout du remplacement de __DNS_REPORT_URL__ par l'URL absolue
/email/configuration/{messageId} dans sendEmail(), au meme
endroit que __VIEW_URL__
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
src/Service/DnsCheckService.php:
- Constante RESOLVER = '1.1.1.1' (Cloudflare DNS)
- Methode dig() utilise la commande dig @1.1.1.1 pour toutes les
requetes DNS afin d'avoir des resultats coherents quel que soit
le resolver local du serveur
- isDigAvailable(): detecte si dig est installe (cache static)
- fallbackDnsGetRecord(): quand dig n'est pas installe, utilise
dns_get_record() PHP natif et formate la sortie au format dig
+noall +answer pour que le parsing reste identique
- getTxtRecords(), getCnameRecord(), getMxRecords(), getSrvRecords()
utilisent tous dig() en interne
- getCnameRecord() et getSrvRecords() rendues publiques pour utilisation
par la commande
src/Command/CheckDnsCommand.php:
- Suppression du check DKIM generique (DKIM verifie uniquement via
AWS SES avec les 3 CNAME individuels par domaine)
- checkDnsRecordExists(), checkMxExists(), checkTxtContains() utilisent
maintenant $this->dnsCheck au lieu de dns_get_record() direct
- getCnameRecord() supprimee de la commande (delegue au service)
- getMxValues() et getTxtSpfValue() utilisent le service
docker/php/dev/Dockerfile:
- Ajout du paquet dnsutils (fournit la commande dig)
docker/php/prod/Dockerfile:
- Ajout du paquet dnsutils (fournit la commande dig)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
src/Service/MailcowService.php - getExpectedDnsRecords() reecrit:
- Suppression des checks SPF et DMARC (deja verifies par DnsCheckService)
- Suppression du check DKIM TXT (le DKIM est gere par AWS SES, pas Mailcow)
- Ajout du champ 'optional' (bool) dans chaque enregistrement attendu
au lieu de deviner l'optionnalite par le nom
- Enregistrements verifies:
- MX {domain} → mail.esy-web.dev (obligatoire)
- CNAME autodiscover.{domain} → mail.esy-web.dev (obligatoire)
- CNAME autoconfig.{domain} → mail.esy-web.dev (obligatoire)
- SRV _autodiscover._tcp.{domain} (optionnel)
- TXT _mta-sts.{domain} v=STSv1 (optionnel)
- CNAME mta-sts.{domain} → mail.esy-web.dev (optionnel)
src/Command/CheckDnsCommand.php - checkMailcow():
- DKIM Mailcow marque comme OK avec detail "Ignore (DKIM via AWS SES)"
car l'envoi des mails utilise le DKIM d'AWS SES, pas celui de Mailcow
- Suppression de la methode getDkimFromDns() devenue inutile
- Utilisation du champ 'optional' de getExpectedDnsRecords() au lieu
de deviner par le nom de l'enregistrement
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
src/Service/MailcowService.php:
- getDomain(): l'API Mailcow retourne un objet JSON {} pour un seul
domaine (pas un tableau [{...}]). Ajout de la detection: si $data[0]
existe c'est un tableau, sinon c'est directement l'objet domaine
- getDomainStatus(): la cle du nombre de boites mail est
'mboxes_in_domain' (pas 'mbox_count' qui n'existe pas dans la reponse)
Resultat: Mailcow affiche maintenant correctement:
- siteconseil.fr: actif, 28 boites mail
- esy-web.dev: actif, 20 boites mail
- Autodiscover, autoconfig, SRV, MTA-STS: tous OK pour les 2 domaines
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
src/Service/AwsSesService.php:
- Ajout methode getMailFromStatus() qui recupere via l'API SES:
- mail_from_domain: le sous-domaine MAIL FROM (ex: bounce.siteconseil.fr)
- mail_from_status: statut de verification (Success/Pending/Failed)
- mx_expected: le MX attendu (feedback-smtp.{region}.amazonses.com)
- txt_expected: le SPF attendu (v=spf1 include:amazonses.com ~all)
Les valeurs sont specifiques a chaque domaine et region AWS
src/Command/CheckDnsCommand.php - methode checkAwsSes() reecrite:
- Verification domaine: attendu="Success", dig=statut reel
- DKIM statut global: attendu="Enabled=oui, Verified=oui", dig=statut reel
- 3 DKIM CNAME individuels: pour chaque token retourne par SES,
verifie que {token}._domainkey.{domain} CNAME {token}.dkim.amazonses.com
existe dans le DNS. Attendu=CNAME cible, Dig=valeur trouvee ou "Non trouve"
- MAIL FROM: attendu=sous-domaine configure dans SES, dig=statut
- MAIL FROM MX: attendu="{bounce.domain} MX feedback-smtp.{region}.amazonses.com",
dig=MX reel trouve
- MAIL FROM TXT: attendu="{bounce.domain} TXT v=spf1 include:amazonses.com ~all",
dig=enregistrement SPF reel trouve
- Bounce notifications: attendu="Forwarding ou SNS topic", dig=config reelle
- Ajout methodes getMxValues() et getTxtSpfValue() pour recuperer les
valeurs reelles du DNS a afficher dans la colonne Dig
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
src/Service/CloudflareService.php:
- isAvailable(): remplace l'appel /user/tokens/verify par /zones?per_page=1
car certains tokens API Cloudflare n'ont pas le scope User:Read
necessaire pour /user/tokens/verify mais ont bien le scope Zone:DNS:Read
- Verifie maintenant que le champ 'success' est true dans la reponse
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
src/Command/CheckDnsCommand.php:
- Injection de HttpClientInterface et kernel.environment dans le constructeur
- Constante DISCORD_WEBHOOK avec l'URL du webhook Discord
- sendReport(): appel sendEmail avec priority=1 (HIGH) pour que le mail
soit marque comme urgent dans tous les clients mail
- sendDiscordNotification(): envoie un embed Discord avec:
- Titre "Esy-Infra : ALERTE DNS" (rouge), "DNS avertissements" (jaune)
ou "DNS Configuration OK" (vert)
- Description avec le nombre de succes/erreurs/warnings
- Les 5 premieres erreurs en citation markdown
- Footer "Esy-Infra - Monitoring DNS" avec timestamp
- La notification Discord est envoyee UNIQUEMENT en environnement prod
(condition sur kernel.environment == 'prod')
src/Service/MailerService.php:
- Ajout du parametre $priority (int, defaut 3 = normal) a sendEmail()
- Appel de ->priority($priority) sur l'objet Email Symfony
- Priority 1 = highest, 2 = high, 3 = normal, 4 = low, 5 = lowest
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
src/Service/DnsCheckService.php:
- Methode check() enrichie avec 4 nouveaux champs: expected (valeur attendue),
dig (valeur actuelle trouvee par dig), cloudflare (valeur dans la zone CF),
cf_status (statut de la colonne CF: ok/error/vide)
- checkSpf(): expected = "include:X dans le SPF", dig = contenu SPF complet
- checkDmarc(): expected = "p=reject ou p=quarantine", dig = contenu DMARC
- checkDkim(): expected = "FQDN CNAME/TXT", dig = cible CNAME ou debut TXT
- checkMx(): expected = MX attendu, dig = liste des MX trouves avec priorite
- checkBounce(): expected = "feedback-smtp.*.amazonses.com", dig = valeur trouvee
src/Command/CheckDnsCommand.php:
- Nouveau champ MONITOR_EMAIL = 'monitor@siteconseil.fr' pour l'envoi du rapport
- loadCloudflareRecords(): charge les records CF une seule fois par domaine
au debut de l'execution, retourne un array indexe par domaine
- enrichWithCloudflare(): apres chaque check DNS, parcourt les records CF
pour trouver l'enregistrement correspondant et remplir les colonnes
cloudflare et cf_status dans chaque check
- checkAwsSes(): utilise DnsCheckService::check() avec expected/dig
(ex: expected="Success", dig="Absent" pour la verification domaine)
- checkMailcow(): utilise DnsCheckService::check() avec expected/dig
(ex: expected="Cle Mailcow: abc...", dig="Cle DNS: xyz..." pour DKIM)
- sendReport(): envoie a MONITOR_EMAIL au lieu de l'admin email
templates/emails/dns_report.html.twig:
- Tableau par domaine avec 6 colonnes: Type, Check, Attendu, Dig (actuel),
Cloudflare, Statut (OK/erreur/warning)
- Colonne Dig coloree en vert/rouge/jaune selon le statut du check
- Colonne Cloudflare coloree selon cf_status
- Colonnes avec word-break: break-all pour les longues valeurs DNS
- Bandeau resume en haut avec compteurs succes/erreurs/warnings
avec bordures laterales colorees
- Pied de mail: "Rapport par Esy-Infra - Service de monitoring d'infra"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
src/Service/MailcowService.php (nouveau):
- Connexion a l'API Mailcow via X-API-Key header
- getDomains(): liste tous les domaines configures
- getDomain(): informations d'un domaine specifique
- getDomainStatus(): statut actif, nombre de boites, quota, quota utilise
- getDkimKey(): recupere la cle DKIM TXT configuree dans Mailcow
- getExpectedDnsRecords(): retourne la liste des enregistrements DNS
attendus par Mailcow pour un domaine (MX, SPF, DMARC, DKIM,
autodiscover CNAME, autoconfig CNAME, SRV _autodiscover, _mta-sts TXT)
- getMailboxes(): liste les boites mail d'un domaine
- isAvailable(): test de connectivite API via /api/v1/get/status/containers
src/Command/CheckDnsCommand.php:
- Ajout de MailcowService dans le constructeur
- Nouvelle methode checkMailcow() qui:
- Verifie si le domaine existe et est actif dans Mailcow
- Recupere la cle DKIM Mailcow et la compare avec celle du DNS
(comparaison partielle des 40 premiers caracteres)
- Verifie chaque enregistrement DNS attendu par Mailcow:
- MX, SPF, DMARC, DKIM : marques comme erreur si absents
- autodiscover, autoconfig, SRV, _mta-sts : marques comme
warning (optionnels)
- Methodes utilitaires: getDkimFromDns(), checkDnsRecordExists(),
checkMxExists(), checkTxtContains(), getCnameRecord()
Variables d'environnement:
- .env: MAILCOW_URL=https://mail.esy-web.dev, MAILCOW_API_KEY (vide)
- .env.local: MAILCOW_API_KEY=DF0E7E-0FD059-16226F-8ECFF1-E558B3
- ansible/vault.yml: mailcow_api_key ajoutee
- ansible/env.local.j2: MAILCOW_URL et MAILCOW_API_KEY ajoutees
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Architecture:
- Les domaines (siteconseil.fr, esy-web.dev) sont definis en constante
dans la commande uniquement, pas dans les services
- 3 services independants reutilisables:
src/Service/DnsCheckService.php (nouveau):
- Methodes publiques checkSpf(), checkDmarc(), checkDkim(), checkMx(),
checkBounce() qui prennent le domaine en parametre
- Verification SPF: presence des includes amazonses.com et mail.esy-web.dev
- Verification DMARC: politique, presence de rua
- Verification DKIM: test de 10 selecteurs en CNAME et TXT
- Verification MX: le MX attendu est passe en parametre par la commande
- Verification Bounce: MX/CNAME/TXT sur bounce.*
src/Service/AwsSesService.php (nouveau):
- Authentification AWS Signature V4 via HTTP direct (pas de SDK)
- isDomainVerified(): verification du statut du domaine dans SES
- getDkimStatus(): statut DKIM (enabled, verified, tokens)
- getNotificationStatus(): bounce_topic, complaint_topic, forwarding
- listVerifiedIdentities(): liste des domaines verifies
- isAvailable(): test de connectivite API
src/Service/CloudflareService.php (nouveau):
- Authentification Bearer token via HTTP direct (pas de SDK)
- getZoneId(): recupere le zone ID dynamiquement par nom de domaine
(plus besoin de CLOUDFLARE_ZONE_ID en dur)
- getDnsRecords(): tous les enregistrements d'une zone
- getDnsRecordsByType(): filtrage par type (TXT, MX, CNAME...)
- getZone(): informations d'une zone
- isAvailable(): verification du token API
src/Command/CheckDnsCommand.php (reecrit):
- Utilise les 3 services pour orchestrer les verifications
- Affichage console colore avec icones OK/ERREUR/ATTENTION
- Envoie un rapport email via le template Twig dns_report.html.twig
templates/emails/dns_report.html.twig (nouveau):
- Template email compatible tous clients (table-based, CSS inline,
margin/padding longhand, mso-line-height-rule, pas de rgba/border-radius)
- Bandeau colore vert/jaune/rouge selon le statut global
- Section succes avec checkmarks verts dans un tableau alterne
- Section erreurs en rouge avec croix dans un tableau fond #fef2f2
- Section avertissements en jaune avec triangles fond #fffbeb
- Detail par domaine avec tableau type/verification/statut
- Utilise le template email/base.html.twig (header gold, footer dark)
Variables d'environnement ajoutees:
- .env: AWS_PK, AWS_SECRET, AWS_REGION (eu-west-3), CLOUDFLARE_KEY (vides)
- .env.local: valeurs reelles des cles AWS et Cloudflare
- ansible/vault.yml: aws_pk, aws_secret, cloudflare_key
- ansible/env.local.j2: AWS_PK, AWS_SECRET, AWS_REGION, CLOUDFLARE_KEY
avec references au vault
- CLOUDFLARE_ZONE_ID supprime (recupere dynamiquement via l'API)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
src/Command/CheckDnsCommand.php (nouveau fichier):
- Commande Symfony app:dns:check qui verifie les DNS de siteconseil.fr
et esy-web.dev
- Verification SPF: presence des includes amazonses.com et mail.esy-web.dev,
terminaison -all ou ~all
- Verification DMARC: presence sur _dmarc.*, politique p=reject/quarantine/none,
presence de rua (adresse de rapport)
- Verification DKIM: test de 10 selecteurs (ses1/ses2/ses3, default, mail, k1,
google, selector1/selector2, dkim) en CNAME et TXT
- Verification MX: presence de mail.esy-web.dev comme serveur de reception
- Verification Bounce: enregistrements MX/CNAME/TXT sur bounce.*,
verification du SPF bounce avec include:amazonses.com
- Envoi d'un email de rapport complet a l'admin avec:
- Bandeau colore vert (OK) / jaune (warnings) / rouge (erreurs)
- Tableau des verifications reussies avec checkmarks verts
- Tableau des erreurs en rouge avec croix
- Tableau des avertissements en jaune avec triangles
- Date du rapport et liste des domaines verifies
- Le rapport est envoye dans tous les cas (succes ou echec)
- Retourne FAILURE si au moins une erreur est detectee
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Gmail, ProtonMail, SFR, Yahoo, Outlook.com, Orange et d'autres clients
email suppriment ou remplacent la balise <body> par un <div>, ce qui
fait perdre tous les styles inline definis sur le body.
templates/email/base.html.twig:
- Table wrapper principale: ajout de margin-top/right/bottom/left: 0,
padding-top/right/bottom/left: 0, font-family: Arial, color: #111827,
-webkit-text-size-adjust: 100%, -ms-text-size-adjust: 100%
en plus du background-color: #eeeef3 deja present
- Les styles restent aussi sur le body pour les clients qui le supportent
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Outlook Windows (2007-2019) ne supporte pas la propriete height sur
les elements div, span et p. AOL et Yahoo remplacent height par
min-height ce qui casse le rendu.
templates/emails/revendeur_created.html.twig:
- 2 div spacers <div style="height: 8px;"> remplaces par des table
spacers avec td font-size: 1px et mso-line-height-rule: exactly
line-height: 8px + pour forcer la hauteur sur tous les clients
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
src/Command/TestMailCommand.php (nouveau fichier):
- Commande Symfony app:mail:test <email> --mode=dev|prod
- Envoie un email de test complet pour verifier le rendu sur tous les clients
- Option --mode pour afficher un bandeau DEV (jaune) ou PROD (rouge)
templates/emails/test_mail.html.twig (nouveau fichier):
- Bandeau environnement colore (dev: #f59e0b jaune, prod: #dc2626 rouge)
- Bloc info sombre avec destinataire, environnement et date/heure
- Tableau de donnees avec 3 services (Esy-Web, Esy-Mail, Esy-Defender Pro),
tarifs, statuts (ACTIF vert, IMPAYE rouge) et ligne TOTAL
- Liste de verification des styles: gras, italique, souligne, lien, couleurs
- Bloc alerte avec bordure laterale gold et fond gris
- 2 boutons centres (Gold #fabf04 et Dark #111827) avec fallback VML
pour Outlook via v:roundrect
- Tableau des 5 applications SITECONSEIL avec liens et descriptions
- Simulation de fichier joint avec icone trombone
- Pied de mail avec mention de la commande utilisee
- Tout en CSS inline compatible: padding longhand, margin longhand,
mso-line-height-rule:exactly, line-height en px, background-color,
pas de rgba/border-radius/box-shadow
templates/emails/test_mail.html.twig:
- Balise <u> remplacee par span avec text-decoration: underline en inline
(la balise <u> n'est pas supportee par ProtonMail, Orange iOS, SFR iOS)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
.gitea/workflows/discord-notify.yml:
- Ajout du champ "Applications SITECONSEIL" dans l'embed Discord
avec 5 liens cliquables et leur description:
- crm.siteconseil.fr: plateforme de gestion clients et revendeurs
- sign.siteconseil.fr: signature electronique des documents (DocuSeal)
- payment.siteconseil.fr: portail de paiement securise (Stripe)
- status.siteconseil.fr: page de status et disponibilite des services
- stripe.siteconseil.fr: reception des webhooks Stripe et redirection
vers le dashboard Stripe Connect des revendeurs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Outlook Windows (2007-2019) a un bug avec line-height en em et sans unite:
le rendu est imprevisible. La solution est d'utiliser des valeurs en px
avec mso-line-height-rule:exactly.
templates/email/base.html.twig:
- cellule contenu: line-height: 1.6 remplace par line-height: 22px
avec ajout de mso-line-height-rule: exactly
templates/emails/2fa_code.html.twig:
- 3 paragraphes: line-height: 1.6 remplace par 22px + mso-line-height-rule
templates/emails/forgot_password_code.html.twig:
- 3 paragraphes: line-height: 1.6 remplace par 22px + mso-line-height-rule
templates/emails/membre_created.html.twig:
- 4 paragraphes: line-height: 1.6 remplace par 22px + mso-line-height-rule
- 2 listes ul: line-height: 1.8 remplace par 25px (font 14px)
et 23px (font 13px) + mso-line-height-rule
templates/emails/password_changed.html.twig:
- 4 paragraphes: line-height: 1.6 remplace par 22px + mso-line-height-rule
templates/emails/revendeur_created.html.twig:
- 5 paragraphes: line-height: 1.6 remplace par 22px + mso-line-height-rule
templates/emails/rgpd_access.html.twig:
- 4 paragraphes: line-height: 1.6 remplace par 22px + mso-line-height-rule
templates/emails/rgpd_attestation_signed.html.twig:
- 4 paragraphes: line-height: 1.6 remplace par 22px + mso-line-height-rule
templates/emails/rgpd_deletion.html.twig:
- 4 paragraphes: line-height: 1.6 remplace par 22px + mso-line-height-rule
templates/emails/rgpd_no_data.html.twig:
- 5 paragraphes: line-height: 1.6 remplace par 22px + mso-line-height-rule
Suppression de box-shadow dans tous les templates email (non supporte
par Outlook Windows, Orange, GMX, WEB.DE, Samsung Email).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Outlook Windows (2007-2019) a un bug ou le padding vertical d'une cellule
est applique a toutes les cellules de la meme ligne avec la plus grande
valeur. SFR, Samsung Email, GMX, WEB.DE, HEY ne supportent que
partiellement le shorthand.
templates/emails/2fa_code.html.twig:
- span code: padding: 16px 32px remplace par padding-top/right/bottom/left
templates/emails/forgot_password_code.html.twig:
- span code: padding: 16px 32px remplace par padding-top/right/bottom/left
templates/emails/membre_created.html.twig:
- bloc identifiants: padding: 20px remplace par les 4 proprietes longhand
- 2 divs internes: padding: 4px 0 remplace par longhand
- bouton connexion: padding: 12px 24px remplace par longhand
templates/emails/revendeur_created.html.twig:
- bloc identifiants: padding: 20px remplace par longhand
- 3 blocs etapes: padding: 12px 16px remplace par longhand
- bouton mot de passe: padding: 14px 24px remplace par longhand
- bouton connexion: padding: 12px 24px remplace par longhand
- bloc info: padding: 16px remplace par longhand
- 3 divs internes: padding: 2px 0 remplace par longhand
templates/emails/rgpd_attestation_signed.html.twig:
- 3 blocs info: padding: 8px 12px remplace par longhand
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Outlook Windows (2007-2019) ne supporte que background-color, pas
le shorthand background. rgba() et border-radius ne sont pas non plus
supportes par Outlook Windows Mail, GMX, Samsung Email, Orange.
templates/emails/2fa_code.html.twig:
- code de verification: background: #111827 remplace par background-color: #111827
templates/emails/forgot_password_code.html.twig:
- code de verification: background: #111827 remplace par background-color: #111827
templates/emails/membre_created.html.twig:
- bloc identifiants: background: #111827 remplace par background-color: #111827
- bouton connexion: background: #fabf04 remplace par background-color: #fabf04,
border rgba(0,0,0,0.1) remplace par #e5e5e5, border-radius: 8px supprime
templates/emails/revendeur_created.html.twig:
- bloc identifiants: background: #111827 remplace par background-color: #111827
- 3 blocs etapes: background: #f9fafb remplace par background-color: #f9fafb
- bouton mot de passe: background: #fabf04 remplace par background-color: #fabf04,
border rgba supprime, border-radius supprime
- bouton connexion: background: #fff remplace par background-color: #ffffff,
border rgba supprime, border-radius supprime
- bloc info: background: #f9fafb remplace par background-color: #f9fafb
templates/emails/rgpd_attestation_signed.html.twig:
- 2 blocs info: background: #f9fafb remplace par background-color: #f9fafb
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
templates/email/base.html.twig:
- Remplacement de la structure div par une structure table-based (role=presentation)
pour compatibilite Outlook/Orange/SFR/Yahoo
- Suppression de rgba(), linear-gradient(), border-radius, box-shadow
(non supportes par Outlook Windows 2007-2019)
- Ajout du doctype XHTML 1.0 Transitional pour Outlook
- Ajout du bloc conditionnel <!--[if mso]> pour forcer Arial sur Outlook
- Remplacement de margin: 0 par margin-top/right/bottom/left: 0
(margin shorthand non supporte par Orange, SFR, certains Outlook)
- Remplacement de padding shorthand par padding-top/right/bottom/left
dans le body et les cellules principales
- Ajout de -webkit-text-size-adjust et -ms-text-size-adjust sur body
- Logo: ajout de width et height auto explicites + border: 0
- Fond semi-transparent rgba(255,255,255,0.92) remplace par #ffffff opaque
- Gradient gold remplace par background-color: #fabf04 fixe
- Couleur footer rgba(255,255,255,0.7) remplacee par #b0b0b0 fixe
- Entite • remplacee par • pour compatibilite XHTML
templates/emails/*.html.twig (9 fichiers):
- Remplacement de toutes les proprietes margin shorthand par les
proprietes longhand margin-top/margin-right/margin-bottom/margin-left
dans 2fa_code, forgot_password_code, membre_created, password_changed,
revendeur_created, rgpd_access, rgpd_attestation_signed, rgpd_deletion,
rgpd_no_data
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Problem: OAuth login failed because the authenticator was checking for
old Keycloak group names (super_admin_asso, gp_member) that no longer
exist in the master realm.
Changes:
- src/Security/KeycloakAuthenticator.php:106: resolveRoles() now checks
for 'siteconseil_admin' instead of 'super_admin_asso' to grant ROLE_ROOT
- src/Controller/Admin/MembresController.php:140: member creation role
resolution updated from 'super_admin_asso' to 'siteconseil_admin'
- templates/admin/membres.html.twig: checkbox values updated from
'gp_member' to 'siteconseil_member' and 'super_admin_asso' to
'siteconseil_admin' in the member management form
- assets/app.js:5-6: JS mutual exclusion logic updated to use new
group values 'siteconseil_member' and 'siteconseil_admin'
- tests/Security/KeycloakAuthenticatorTest.php:79: test data updated
from 'super_admin_asso' to 'siteconseil_admin'
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove jq dependency
- Use file-based payload with cat > /tmp/discord.json instead of inline HEREDOC
- Fix HEREDOC indentation issue
- Escape JSON properly with sed
- Use curl -d @file for reliable payload delivery
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Email templates: replace table/tr/td with div-based CSS layout
- PDF templates: replace table with display:table/table-row/table-cell CSS (Dompdf compatible)
- Only table.data (RGPD access session data) remains as actual HTML table
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add thead/th to commissions table in tarif.html.twig
- Add th headers to contrat_revendeur parties table
- Add role=presentation to PDF layout tables (info-grid, verify-box, signatures)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace email layout tables with CSS divs in base.html.twig
- Replace deprecated width/align attributes with CSS styles in PDF templates
- Add role="presentation" to email layout tables
- Convert td to th[scope=row] in profil and attestation verify tables
- Reduce function nesting in app.js by extracting renderHit/performSearch
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add for/id attributes to all form labels for accessibility compliance
- Add <title> tags to PDF templates (rgpd_access, rgpd_no_data, rgpd_deletion, contrat_revendeur)
- Add role="presentation" to email layout tables
- Remove deprecated cellpadding/cellspacing attributes from all templates
- Fix PHPUnit notices by replacing createMock with createStub where no expectations are set
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ForgotPasswordController::validateResetInput: reduce from 4 to 3 returns using match expression
- DocuSealService::downloadSignedDocuments: reduce from 4 to 3 returns by extracting fetchAndStoreDocuments
- User: add @SuppressWarnings for getEmailAuthRecipient/getGoogleAuthenticatorUsername (required by 2FA interfaces)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reduce cognitive complexity and fix code smells across multiple files:
- Extract helper methods in DocuSealService, ForgotPasswordController, WebhookDocuSealController
- Reduce MembresController.persistLocalUser from 8 to 3 parameters using typed array
- Replace chained if/returns with ROLE_ROUTES map in LoginSuccessHandler
- Add 100% test coverage for AnalyticsCryptoService (15 tests)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- src/Controller/Admin/MembresController.php: reduce return statements in 'create' and add error logging
- src/Controller/Admin/ProfilController.php: reduce return statements in 'password' and 'update', and fill empty catch blocks with logging
- src/Controller/Admin/ClientsController.php: reduce cognitive complexity by extracting private methods and adding error logging
- src/Service/MeilisearchService.php: fill empty catch blocks with error logging for better traceability
- src/Service/UserManagementService.php: use dedicated UserAlreadyExistsException instead of generic Exception
- src/Service/KeycloakAdminService.php: define and use PATH_USERS and AUTH_BEARER constants to reduce duplication
- src/Service/DocuSealService.php: reduce method return points to comply with project standards
- src/Command/CheckServicesCommand.php: reduce return statements count to comply with static analysis rules
- src/Command/CleanAttestationsCommand.php: replace native unlink/file_exists with Symfony Filesystem for better security
- src/Command/StripeSyncCommand.php: replace TODOs with ID logging for better observability during sync
- Created UserManagementService to centralize common user creation logic.
- Refactored ClientsController and RevendeursController to use UserManagementService.
- Reduced code duplication in StatsController and RgpdService.
- Fixed type mismatch in StatusController for ServiceMessage author.
- Improved data consistency in MailerService and EmailTrackingController for attachments.
- Added missing MessengerLogRepository.
- Fixed getFlashBag() call in KeycloakAuthenticator using FlashBagAwareSessionInterface.
- Added missing PHPDoc type specifications in WebhookDocuSealController and RgpdService.
- Removed unused MailerService injection in RgpdService.