Commit Graph

294 Commits

Author SHA1 Message Date
Serreau Jovann
5d47db73d4 fix: corriger les checks Mailcow DNS et ignorer DKIM Mailcow
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>
2026-04-02 21:47:38 +02:00
Serreau Jovann
3313d28ef3 fix: corriger le parsing de l'API Mailcow pour getDomain et getDomainStatus
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>
2026-04-02 21:45:07 +02:00
Serreau Jovann
b9261f2946 feat: afficher les vraies valeurs AWS SES attendues dans le rapport DNS
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>
2026-04-02 21:41:46 +02:00
Serreau Jovann
d1fdb5ab52 fix: corriger la verification de disponibilite Cloudflare
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>
2026-04-02 21:38:23 +02:00
Serreau Jovann
cdf09cab01 feat: ajout notification Discord en prod + mail priority HIGH pour le rapport DNS
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>
2026-04-02 21:37:10 +02:00
Serreau Jovann
c666e0db65 feat: enrichir le rapport DNS avec colonnes attendu/dig/cloudflare + envoi a monitor@siteconseil.fr
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>
2026-04-02 21:35:46 +02:00
Serreau Jovann
484c48e331 feat: ajout service Mailcow et integration dans la verification DNS
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>
2026-04-02 21:31:54 +02:00
Serreau Jovann
fea7dbfb61 feat: refactoring complet de la verification DNS avec services separes
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>
2026-04-02 21:28:24 +02:00
Serreau Jovann
b6696df087 feat: ajout commande app:dns:check pour verifier la configuration DNS
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>
2026-04-02 21:22:45 +02:00
Serreau Jovann
2119d4be88 fix: dupliquer les styles du body sur la table wrapper dans le base email
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>
2026-04-02 21:13:57 +02:00
Serreau Jovann
9ac03358f6 fix: remplacer les div spacers par des table spacers dans les emails
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 + &nbsp; pour forcer la hauteur sur tous les clients

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 21:10:34 +02:00
Serreau Jovann
a3077ee5db feat: ajout commande app:mail:test + correction compatibilite text-decoration
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>
2026-04-02 20:45:37 +02:00
Serreau Jovann
3dc94d67a6 feat: ajout des liens applications SITECONSEIL dans le webhook Discord
.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>
2026-04-02 20:39:45 +02:00
Serreau Jovann
27cd61193b fix: corriger line-height et supprimer box-shadow dans les templates email
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>
2026-04-02 20:37:37 +02:00
Serreau Jovann
1299d846f2 fix: remplacer padding shorthand par longhand dans tous les templates email
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>
2026-04-02 20:36:05 +02:00
Serreau Jovann
361bb01463 fix: remplacer background shorthand, rgba() et border-radius dans les emails
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>
2026-04-02 20:34:54 +02:00
Serreau Jovann
551fdfe7cf fix: rendre les templates email compatibles avec tous les clients mail
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 &bull; remplacee par &#8226; 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>
2026-04-02 19:40:13 +02:00
Serreau Jovann
e97116fc9d feat: complete glassmorphism redesign across all templates + Keycloak groups auto-provisioning
Templates updated to glassmorphism (40+ files):
- templates/admin/clients/ (create, index): glass cards, input-glass inputs,
  btn-gold buttons, glass table headers, semi-transparent badges
- templates/admin/dashboard.html.twig: glass KPI cards
- templates/admin/profil/index.html.twig: glass form panels
- templates/admin/revendeurs/ (create, edit, index): glass cards and tables
- templates/admin/services/index.html.twig: glass service cards
- templates/admin/status/ (index, manage): glass panels
- templates/admin/sync/index.html.twig: glass panels
- templates/admin/facturation/index.html.twig: glass tables
- templates/admin/membres.html.twig: glass form, checkboxes with esy-* group
  values (esy-web, esy-mail, esy-mailer, esy-analytics, esy-monitor,
  esy-defender, esy-translate, esy-signature, esy-creator, esy-aide,
  esy-meet, esy-tchat, esy-ndd), Keycloak groups column in table,
  available groups section
- templates/admin/stats/index.html.twig: glass KPI cards, glass-gold CA TTC,
  factures emises/payees/impayees cards, services renamed to Esy-*,
  rounded progress bars, bg-gray-200 track backgrounds
- templates/security/ (2fa_email, 2fa_google, forgot_password, set_password,
  set_password_expired): glass headers, glass-heavy cards, input-glass
- templates/legal/ (cgu, cgv, cookie, conformite, hebergement,
  mention_legal, rgpd, tarif): removed thick borders, font-black to
  font-bold, text-3xl to text-2xl headings
- templates/attestation/ (verify, not_found): glass panels
- templates/espace_client/index.html.twig: glass panels
- templates/espace_prestataire/index.html.twig: glass panels
- templates/external_redirect.html.twig: glass card
- templates/status/index.html.twig: glass panels
- templates/email/base.html.twig: gradient gold header, rounded-16px
  container, semi-transparent bg, soft shadow, footer address
- templates/emails/*.html.twig (9 files): removed 4px borders,
  font-weight 900 to 700
- templates/pdf/*.html.twig (4 files): rounded borders, gradient header,
  lighter borders

Keycloak auto-provisioning:
- src/Service/KeycloakAdminService.php: added REQUIRED_GROUPS constant
  (15 groups: siteconseil_admin, siteconseil_member, esy-web, esy-mail,
  esy-mailer, esy-analytics, esy-monitor, esy-defender, esy-translate,
  esy-signature, esy-creator, esy-aide, esy-meet, esy-tchat, esy-ndd),
  ensureRequiredGroups() method that checks existing groups and creates
  missing ones, createGroup() method, getRequiredGroups() static accessor
- src/Controller/Admin/MembresController.php: calls ensureRequiredGroups()
  on page load, shows flash for each auto-created group, fetches user
  groups per member, passes availableGroups to template

Stats controller updated:
- src/Controller/Admin/StatsController.php: services renamed to Esy-*
  (13 services), added factures_emises/payees/impayees KPI data

OAuth fix:
- src/Security/KeycloakAuthenticator.php: removed dd() debug calls,
  restored flash message on auth failure with error detail

Config:
- .env: KEYCLOAK_ADMIN_CLIENT_ID=crm_siteconseil_admin, secret updated
- .env.local: same updates
- ansible/env.local.j2: KEYCLOAK_ADMIN_CLIENT_ID=crm_siteconseil_admin

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 19:34:35 +02:00
Serreau Jovann
f8155c9454 fix: update Keycloak group names for SITECONSEIL OAuth authentication
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>
2026-04-02 19:01:21 +02:00
Serreau Jovann
397867d882 feat: redesign entire CRM theme from brutalist to glassmorphism
Templates modified:
- templates/base.html.twig: header frosted glass (glass-heavy, backdrop-blur-24px),
  footer dark glass (glass-dark-heavy), cookie banner floating glass panel with
  rounded corners, all buttons converted to btn-glass/btn-gold/btn-dark classes,
  body background with radial gradient mesh (gold + indigo orbs), removed all
  border-4/border-8 thick borders, added rounded-lg corners on nav items
- templates/admin/_layout.html.twig: sidebar dark glass (glass-dark-heavy),
  nav items with sidebar-nav-item class (rounded-lg, hover glow), active items
  with gold glow shadow, avatar rounded-lg, dropdown borders changed to
  border-white/10, mobile overlay with backdrop-blur-4px
- templates/home/index.html.twig: login card with glass-heavy + glass-gold header,
  inputs with input-glass class (frosted blur, gold focus ring), buttons btn-gold
  with hover lift effect
- templates/security/login.html.twig: same glass treatment as home
- templates/security/2fa_*.html.twig: glass cards and inputs
- templates/security/forgot_password.html.twig: glass treatment
- templates/security/set_password*.html.twig: glass treatment
- templates/legal/_layout.html.twig: glass header
- templates/legal/tarif.html.twig: tabs converted to glass/glass-dark,
  all pricing cards glass/glass-gold, tables glass with rounded overflow
- templates/external_redirect.html.twig: glass card

SCSS (assets/app.scss):
- Added CSS custom properties: --glass-bg, --glass-border, --glass-blur,
  --gold, --gold-glow, --radius, --shadow-glass, etc.
- Added glass classes: .glass, .glass-heavy, .glass-dark, .glass-dark-heavy,
  .glass-gold (each with backdrop-filter, semi-transparent bg, subtle borders)
- Added button classes: .btn-glass, .btn-gold, .btn-dark (with hover lift,
  glow shadows, smooth cubic-bezier transitions)
- Added .input-glass (frosted input with gold focus ring)
- Added .sidebar-nav-item with .active/.active-danger states
- Added .glass-bg body class with radial gradient background
- Added custom scrollbar for sidebar
- Moved admin layout styles from inline <style> to SCSS

JavaScript (assets/app.js):
- Updated tarif tab classes from brutalist to glass

Config:
- .env.local: OAUTH_KEYCLOAK_REALM changed from siteconseil to master

Design direction: frosted glass panels over gradient mesh background,
semi-transparent surfaces, subtle 1px borders with white/20 opacity,
soft box-shadows, rounded-16px corners, smooth hover transitions with
translateY(-1px) lift effect, gold (#fabf04) accent glow shadows

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 18:59:41 +02:00
Serreau Jovann
56ec1841d7 fix: rewrite Discord webhook workflow for Gitea compatibility
- 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>
2026-04-02 18:51:33 +02:00
Serreau Jovann
6fa970e60d refactor: rebrand project to CRM SITECONSEIL (SARL SITECONSEIL)
- Rename all references from E-Cosplay/Ecosplay to SITECONSEIL
- Update entity from Association to SARL SITECONSEIL (Siret: 418664058)
- Update address to 27 rue Le Serurier, 02100 Saint-Quentin
- Update emails: contact@siteconseil.fr, rgpd@siteconseil.fr
- Update hosting from GCP to OVHcloud (Roubaix, Gravelines, Strasbourg, Paris)
- Update legal pages: mentions legales, CGV, RGPD, conformite, hebergement, cookies, CGU
- Add tarifs page with tabs: Site Internet, E-Commerce, Nom de domaine, Esy-Mail, Esy-Mailer, Esy-Tchat, Esy-Meet, Esy-Defender
- Add Discord webhook notification workflow
- Disable deploy and sonarqube workflows
- Update OAuth Keycloak realm to master
- Update logo references to logo_facture.png
- Remove forced image sizing in Liip Imagine filters
- Update SonarQube project key and badge token
- Update tribunal competent to Saint-Quentin
- Move tarif tabs JS to app.js (CSP compliance)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 18:48:25 +02:00
Serreau Jovann
363cea260b fix: replace all layout tables with CSS in email and PDF templates
- 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>
2026-04-01 19:57:26 +02:00
Serreau Jovann
a76e96fb21 fix: add th headers and role=presentation to PDF and legal tables
- 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>
2026-04-01 19:50:56 +02:00
Serreau Jovann
242f8337e1 fix: replace deprecated HTML attributes and reduce JS nesting
- 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>
2026-04-01 19:36:42 +02:00
Serreau Jovann
5f144ba4d2 fix: resolve SonarQube accessibility and test issues across templates
- 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>
2026-04-01 19:30:53 +02:00
Serreau Jovann
b0060bd831 test: achieve 100% coverage for CheckServicesCommand and update SonarQube config
- Add 26 tests covering all service check types (HTTP, DocuSeal, Vault, Minio, Stripe)
- Include assets/ and templates/ in SonarQube sources
- Ignore php:S4144 globally (interface-imposed duplicate methods)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:24:15 +02:00
Serreau Jovann
409691fbad fix: reduce return count and suppress interface-imposed duplicate warnings
- 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>
2026-04-01 19:18:23 +02:00
Serreau Jovann
b0731a430c refactor: fix SonarQube code smells and add AnalyticsCryptoService tests
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>
2026-04-01 19:14:51 +02:00
Serreau Jovann
36271b1fe1 refactor: fix SonarQube code smells and reduce cognitive complexity
- ForgotPasswordController: extract handleSendCode/handleReset methods to reduce complexity from 17 to ~10
- HomeController: replace multiple if/return with const map + foreach (4 returns → 2)
- LegalController: extract '#exercer-droits' into RGPD_ANCHOR constant
- WebhookDocuSealController: extract verifySecret/syncSubmitterIdFromMetadata, add ATTESTATION_NOT_FOUND constant, remove unused params ($em, $reason)
- MembresController/RevendeursController: minor linter fixes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 18:57:59 +02:00
Serreau Jovann
bc4289a7c5 chore: remove Semgrep from quality analysis pipeline 2026-04-01 18:44:16 +02:00
Serreau Jovann
798e1480d7 fix: add mandatory 'type' field to semgrep report rules for SonarQube 2026-04-01 18:20:47 +02:00
Serreau Jovann
466b05bfe2 refactor: improve MembresController and ProfilController quality
- 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
2026-04-01 18:10:35 +02:00
Serreau Jovann
fd822b5b7f test: achieve 100% coverage for Exception and Twig namespaces 2026-04-01 18:10:10 +02:00
Serreau Jovann
dbaf23e13a test: achieve 100% coverage for KeycloakAuthenticator and LoginSuccessHandler 2026-04-01 17:57:10 +02:00
Serreau Jovann
3044a7a4b8 test: achieve 100% coverage for LegalController 2026-04-01 17:53:32 +02:00
Serreau Jovann
75bd0a795c refactor: update semgrep report format for SonarQube compatibility 2026-04-01 17:52:41 +02:00
Serreau Jovann
197916c4e0 test: add HomeControllerTest to generate PHPUnit report 2026-04-01 17:47:12 +02:00
Serreau Jovann
2a70b63549 refactor: improve code quality, security and maintainability
- 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
2026-04-01 17:44:57 +02:00
Serreau Jovann
227da01926 refactor: improve commands security, quality and observability
- 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
2026-04-01 17:32:54 +02:00
Serreau Jovann
25c593874c refactor: address static analysis warnings and reduce code duplication
- 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.
2026-04-01 17:18:51 +02:00
Serreau Jovann
686de99909 init 2026-04-01 15:42:52 +02:00
Serreau Jovann
beb12d2b75 Add webapp packages 2026-03-30 18:52:03 +02:00
Serreau Jovann
c1485046af Add initial set of files 2026-03-30 18:51:57 +02:00