- Ajout d'un badge de compteur indiquant le nombre de rappels actifs (ex: "1")
- Désactivation visuelle du bouton pour les séquences sans rappels actifs (icône grisée)
- Tooltip informatif adapté selon le contexte (nombre de rappels ou message d'erreur)
- Amélioration de l'expérience utilisateur avec feedback visuel clair
- Modification du backend pour envoyer un email par inscrit confirmé (tous à l'adresse de test)
- Ajout d'un indicateur de progression moderne avec animation (spinner + effet ping)
- Message de succès affichant le nombre d'emails envoyés
- Validation avec séquence "test 3" : 3 emails envoyés correctement (4ème inscrit sans email ignoré)
- Synchronisation complète de la structure de la table logsrappels avec le VPS
- Ajout d'un champ de saisie pour l'email du destinataire
- Modification du texte : "Tous les rappels configurés pour cette séquence seront envoyés à l'adresse email que vous indiquez ci-dessous"
- Validation de l'email avant envoi
- Backend modifié pour envoyer à l'email saisi au lieu de tous les inscrits
- Les logs enregistrent correctement l'email de test utilisé
**Corrections d'erreurs :**
1. **Erreurs SQL DATE_FORMAT corrigées** (analyticsDb.ts) :
- Remplacement des sous-requêtes corrélées par des JOIN dans getTauxRemplissageByMonth()
- Utilisation de COUNT(CASE WHEN...) au lieu de SUM(SELECT COUNT(*))
- Ajout de leftJoin pour éviter les erreurs de sous-requêtes
2. **Erreur React "Cannot read properties of null" corrigée** (AdminRapportPublicCible.tsx) :
- Ajout de l'opérateur null-safe `?.` pour accéder à `insc.apprenant?.fonction`
- Vérification explicite si la fonction est null/undefined
- Gestion du cas "public cible = tous" qui correspond toujours
3. **Tests réussis** :
- Page rapport-public-cible : affiche correctement les statistiques et recommandations
- Tableau de bord analytique : graphiques et statistiques fonctionnels
- Page suivi questionnaires : affiche correctement les données
**Harmonisation charte graphique :**
- Application du style bleu clair (#6B9FE8) avec ombre portée à tous les titres des 32 pages
- Création de la classe CSS `.page-title` réutilisable dans index.css
- Cohérence visuelle sur toute l'application
**Résultat :**
✅ Toutes les erreurs SQL et React sont corrigées
✅ Les pages fonctionnent correctement sans erreur
✅ Charte graphique harmonisée sur toutes les pages
**Fonctionnalité ajoutée :**
- Bouton "Ajouter un inscrit" avec icône UserPlus dans le header de la liste des inscrits
- Dialogue de sélection avec liste déroulante des apprenants disponibles (filtrés pour exclure ceux déjà inscrits)
- Sélection du statut (Confirmé / Liste d'attente)
- Mutation backend `inscriptions.create` pour l'ajout manuel par l'admin (sans vérifications de blocage/capacité)
**Fichiers modifiés :**
- client/src/pages/AdminSequenceInscrits.tsx : Ajout du bouton et du dialogue
- client/src/components/AddInscritForm.tsx : Nouveau composant de formulaire
- server/routers.ts : Ajout de la mutation inscriptions.create
**Résultat :**
Les administrateurs peuvent maintenant ajouter manuellement des apprenants à une séquence depuis l'interface des inscrits.
**Problème résolu :**
Erreur "Invalid option: expected one of 'rappel1', 'rappel2', 'rappel3', 'rappel4', 'rappel5', 'rappel6'" lors de la création d'un rappel.
**Modifications apportées :**
- Correction des enums dans `sendGroupEmail` et `emailPreview` (lignes 926 et 986)
- Remplacement de ['teaser', 'rappel', 'rappel_j1'] par ['teaser', 'rappel1', 'rappel2', 'rappel3', 'rappel4', 'rappel5', 'rappel6']
- Harmonisation complète avec le renommage précédent des types de rappels
**Résultat :**
La création de rappels fonctionne maintenant correctement sans erreur de validation.
**Modifications du schéma Drizzle :**
- logsrappels.type : enum('rappel1','rappel2','rappel3','rappel4','rappel5','rappel6')
- emailTemplates.type : enum('inscription','teaser','rappel1','rappel2','rappel3','rappel4','rappel5','rappel6','reset_password')
- rappels.templateType : enum('rappel1','rappel2','rappel3','rappel4','rappel5','rappel6')
**Modifications du code :**
- server/routers.ts : mise à jour des enums Zod
- server/db.ts : renommage des templates par défaut (rappel → rappel1, rappelJ1 → rappel2)
- server/rappelRetry.ts : correction de la condition rappelJ1 → rappel2
- drizzle/schema.ts : mise à jour de tous les enums
**Migration de la base de données MySQL :**
- Script SQL créé et exécuté avec succès sur le VPS
- Migration en 3 étapes : élargir enum → mettre à jour données → restreindre enum
- Toutes les données existantes migrées correctement
**Résultat :**
- ✅ Plus d'erreur "Unknown column 'type'" dans les logs
- ✅ Cohérence parfaite entre l'interface (Rappel 1, Rappel 2) et le backend (rappel1, rappel2)
- ✅ Système de rappels fonctionnel
- ✅ Déployé et testé sur le VPS de production (https://formations.itinova.org)
1. Ajout de l'enregistrement dans l'historique lors de l'envoi d'attestations (backend + frontend)
2. Correction du bouton Renvoyer inactif (selectedSequenceId -> apprenant.sequence.id)
3. Gestion des erreurs avec enregistrement dans l'historique en cas d'échec
4. Support des chemins locaux et URLs pour les fichiers PDF
- Correction du nom de table dans la procédure viderHistoriqueRappels (logsRappels → logsrappels)
- Le bouton de vidage fonctionne maintenant correctement sur le VPS de production
**Fonctionnalités ajoutées :**
1. **Procédure tRPC `viderHistoriqueRappels`** (server/routers.ts) :
- Mutation admin protégée pour supprimer tous les logs de la table logsRappels
- Retourne le nombre de logs supprimés
- Utilise une requête SQL directe pour optimiser les performances
2. **Bouton de vidage dans l'interface** (client/src/pages/admin/AdminRappelsHistorique.tsx) :
- Bouton rouge "Vider l'historique" avec icône de corbeille
- Dialogue de confirmation AlertDialog avec message d'avertissement
- Invalidation automatique de la requête historique après suppression
- Toast de succès avec le nombre de logs supprimés
3. **Correction d'une erreur TypeScript** :
- Ajout d'une parenthèse fermante manquante dans le router gestionAttestations
- Correction de l'erreur TS1135: Argument expression expected
**Fichiers modifiés :**
- server/routers.ts : Ajout de la procédure viderHistoriqueRappels
- client/src/pages/admin/AdminRappelsHistorique.tsx : Ajout du bouton avec dialogue
Déployé sur le VPS de production (https://formations.itinova.org)
**Améliorations apportées :**
1. **Colonne "Type d'envoi" avec badge coloré** :
- Ajout d'une nouvelle colonne dans l'interface d'historique des rappels
- Badge bleu pour les tests ("Test")
- Badge vert pour les envois automatiques ("Automatique")
- Permet de distinguer visuellement les envois de test des envois réels
2. **Correction des filtres** :
- Correction de l'enum du statut : "succes"/"echec" au lieu de "success"/"failed"
- Correction des noms de colonnes : "email" au lieu de "emailDestinataire", "type" au lieu de "typeRappel"
3. **Nettoyage des anciens logs** :
- Ajout d'une procédure tRPC `nettoyerLogsErrones` pour supprimer les logs sans email
- Exécution de la requête SQL sur le VPS pour nettoyer les données erronées
- Tous les logs créés avant la correction du schéma ont été supprimés
**Fichiers modifiés :**
- client/src/pages/admin/AdminRappelsHistorique.tsx : Ajout de la colonne Type d'envoi avec badges colorés
- server/routers.ts : Ajout de la procédure nettoyerLogsErrones + correction des enums
**Résultat :**
- L'historique des rappels affiche maintenant clairement si un envoi est un test ou automatique
- Les anciens logs erronés ont été supprimés de la base de données
- Les statistiques sont maintenant plus fiables et précises
Déployé sur le VPS de production (https://formations.itinova.org)
**Problèmes corrigés :**
1. Type de rappel erroné : utilisait typeRappel au lieu de type, affichait le mauvais template (J-1 au lieu de J+2)
2. Statut erroné : utilisait "success"/"failed" (anglais) au lieu de "succes"/"echec" (français)
3. Email erroné : utilisait emailDestinataire au lieu de email
4. Champs obsolètes : supprimé dateSequence qui n'existe plus dans le schéma
**Fichiers modifiés :**
- server/rappelDb.ts : Réécriture complète avec les bons noms de colonnes (email, type, statut, typeEnvoi)
- server/rappelScheduler.ts : Correction des appels à logRappelEnvoye avec les bons paramètres
- server/routers.ts : Correction de l'enum du statut dans la procédure historique (succes/echec)
**Résultat :**
- Les logs de rappels enregistrent maintenant correctement le type de rappel (J+2, J-7, etc.)
- Le statut est correctement enregistré en français (succes/echec)
- L'email du destinataire est correctement enregistré
- Les tests de rappel sont distingués des envois automatiques via typeEnvoi
Déployé sur le VPS de production (https://formations.itinova.org)
- Ajout du champ typeEnvoi (enum 'automatique', 'test') dans le schéma Drizzle de la table logsRappels
- Ajout de la fonction createLogRappel dans server/db.ts pour enregistrer les logs
- Modification de la procédure testerRappel pour enregistrer chaque envoi de test avec typeEnvoi='test'
- Enregistrement des succès et des échecs dans l'historique
- Les tests n'interfèrent pas avec les rappels automatiques (typeEnvoi='automatique')
- Migration SQL appliquée sur le VPS : ALTER TABLE logsRappels ADD COLUMN typeEnvoi
- Déployé sur le VPS de production (https://formations.itinova.org)
- Mise à jour du fichier todo.md
Les envois de test apparaissent maintenant dans l'historique des rappels et sont distingués des envois automatiques programmés.
- Page AdminSequences : ouvre en vue réduite par défaut
- DashboardLayout : seule la section "Gestion" est ouverte par défaut à la connexion
- Déployé sur le VPS de production
- Remplacement de l'envoi au premier inscrit uniquement par un envoi à tous les inscrits confirmés
- Ajout d'un compteur de succès et d'échecs
- Gestion des erreurs individuelles pour chaque envoi
- Message de retour détaillé avec le nombre d'envois réussis et échoués
- Déploiement sur le VPS de production
- Mise à jour du fichier todo.md
- Modification de la procédure testerRappel pour détecter automatiquement le premier rappel actif configuré pour la séquence
- Suppression du paramètre typeRappel (n'est plus nécessaire)
- Création de la fonction sendRappelEmail générique qui utilise le templateType du rappel configuré
- Le bouton frontend envoie maintenant le bon template (rappel 1, 3, 4, 5, 6, etc.) selon la configuration de la séquence
- Gestion des pièces jointes configurées dans le rappel
- Mise à jour du fichier todo.md pour marquer la tâche comme terminée
- Ajout de la mutation testerRappelMutation connectée à la procédure tRPC rappels.testerRappel
- Ajout de l'icône Send dans les imports
- Ajout du bouton dans la colonne Actions du tableau des séquences (entre Edit et Delete)
- Le bouton envoie un email de test à l'administrateur avec les données de la séquence sélectionnée
- Validation : le bouton est désactivé si la séquence n'a pas de dates configurées
- Feedback utilisateur : toast de succès ou d'erreur après l'envoi
- Mise à jour du fichier todo.md pour marquer la tâche comme terminée
**Ajouts :**
- Template "Réinitialisation de mot de passe" (reset_password) ajouté à l'enum et au système
**Corrections de bugs :**
- Bug de mise à jour du type de template (ajout de key={selectedType} pour forcer remontage)
- Erreur SQL configuration SMTP (correction schéma emailConfig avec champs active, domainVerified, apiKey)
- Erreur de type formateurId (conversion string → number dans AdminSequences.tsx)
- Date de blocage non sauvegardée (ajout champ dateBlocage au schéma sequences)
- Table logsRappels incohérente (suppression colonnes obsolètes, correction enum statut)
**Schémas Drizzle mis à jour :**
- emailTemplates : ajout reset_password à l'enum type
- emailConfig : ajout active, domainVerified, correction apiKey
- sequences : ajout dateBlocage (datetime)
- logsRappels : structure nettoyée et conforme
**Déploiement VPS :**
- Toutes les migrations SQL exécutées avec succès
- Application redémarrée et fonctionnelle
- Historique des rappels prêt à fonctionner (table logsRappels corrigée)
- Ajout de "reset_password" à l'enum du schéma Drizzle (table emailTemplates)
- Migration SQL pour modifier l'enum dans la base de données
- Création du template dans la base de données avec un contenu par défaut approprié
- Mise à jour de la procédure tRPC emailTemplates.upsert pour utiliser les noms de colonnes français (titre, couleurPrincipale, couleurSecondaire, piedDePage)
- Mise à jour de la fonction upsertEmailTemplate dans server/db.ts pour utiliser les noms de colonnes français
- Réécriture complète de AdminEmailTemplates.tsx pour utiliser les noms de colonnes français
- Test complet de l'interface : le template s'affiche correctement, peut être modifié et prévisualisé
- Le template contient les variables {{prenom}}, {{nom}}, {{lienReinitialisation}} pour la réinitialisation de mot de passe
- Total de 9 templates d'emails maintenant disponibles (inscription, teaser, rappel, rappelJ1, rappel3-6, reset_password)
- Correction des 170 erreurs TypeScript liées aux types templateType dans les procédures rappels.create et rappels.update (passage de z.string() à z.enum() avec les valeurs correctes)
- Nettoyage complet des fichiers de migration Drizzle (suppression des 32 anciens fichiers et génération d'une nouvelle migration propre 0000_clean_justice.sql)
- Création du guide utilisateur GUIDE_CONFIGURATION_ATTESTATIONS.md expliquant en détail le nouveau workflow de configuration des attestations (modes de génération et d'envoi, workflows recommandés, bonnes pratiques, dépannage)
- Vérification que tous les paramètres liés aux attestations sont bien accessibles dans la page de gestion des attestations (mode de génération et mode d'envoi)
- Retrait du champ envoiAutomatiqueAttestations du schéma Drizzle
- Suppression de la colonne envoiAutomatiqueAttestations de la table parametres dans la base de données
- Mise à jour de la procédure tRPC parametres.update pour retirer ce champ
- Test complet du workflow : le serveur fonctionne correctement et le tableau de bord s'affiche sans erreur
- Changement du champ 'nom' en 'titre' pour les questionnaires (backend et frontend)
- Suppression de la propriété 'complete' inexistante dans reponsesQuestionnaires
- Correction du type 'provider' dans la configuration email
- Gestion des valeurs null pour le champ 'fonction' des apprenants
- Résolution de l'erreur logsRappels.email après redémarrage du serveur
Fonctionnalités :
- Configuration par formation (génération auto/manuel, envoi auto/manuel)
- Affichage de la liste des apprenants inscrits
- Upload de documents PDF par apprenant (mode manuel)
- Boutons de prévisualisation et d'envoi manuel
- Gestion complète des attestations
Corrections :
- Ajout des colonnes modeAttestation et modeEnvoi dans la table formations
- Ajout des colonnes documentUrl, documentS3Key, uploadedBy, uploadedAt, emailEnvoye, dateEnvoiEmail dans la table attestations
- Correction de l'erreur SQL en retirant la colonne urlPdf inexistante de la requête
Nouvelle fonctionnalité complète pour gérer les attestations :
- Schéma de base de données : colonnes modeAttestation et modeEnvoi dans formations, colonnes documentUrl, documentS3Key, uploadedBy, uploadedAt dans attestations
- Backend : fichier gestionAttestationsDb.ts, procédures tRPC, fonction sendAttestationEmail
- Interface : page AdminGestionAttestations avec sélection de formation, configuration des modes, tableau des apprenants, boutons upload/prévisualisation/envoi/suppression
- Navigation : lien dans menu Gestion, route /admin/gestion-attestations
- Ajout du paramètre d'envoi automatique des attestations dans la page Paramètres
- Ajout de la prévisualisation du modèle d'attestation avec génération PDF
- Création de la page Historique des attestations dans la section Traçabilité
- Création de la table historiqueAttestations pour tracer les envois
- Ajout des procédures tRPC pour l'historique et la prévisualisation
- Ajout de 3 nouveaux paramètres globaux : délai d'expiration QR codes (minutes), durée de validité tokens (heures), notifications actives (boolean)
- Création de la table historiqueParametres pour tracer toutes les modifications avec userId, userName, champModifié, ancienneValeur, nouvelleValeur et dateModification
- Ajout d'un bouton "Tester l'URL" avec indicateur visuel de statut (vert si accessible, rouge si erreur)
- Affichage de l'historique des modifications dans un tableau avec toutes les informations de traçabilité
- Mise à jour automatique de l'historique lors de chaque modification de paramètre
Modifications apportées :
- Création de la table parametres dans la base de données
- Création du fichier server/parametresDb.ts avec les fonctions getParametres et updateUrlPublique
- Ajout du router parametres dans server/routers.ts avec les procédures get et updateUrlPublique
- Création de la page client/src/pages/AdminParametres.tsx avec formulaire de modification
- Ajout de la route /admin/parametres dans App.tsx
- Ajout du lien "Paramètres" dans le menu après "Configuration SMTP" dans DashboardLayout
- Modification de server/qrCodeGenerator.ts pour utiliser l'URL de la BDD au lieu de getAppBaseUrl
- URL par défaut définie : https://formations.itinova.org
Fonctionnalités :
- Interface graphique pour modifier l'URL publique de l'application
- Les QR codes d'émargement utilisent maintenant l'URL configurée dans la base de données
- Validation de l'URL avant enregistrement
- Message d'information sur l'impact des modifications
Corrections apportées :
- Correction des références à heureDebut/heureFin dans AdminRappels.tsx (utilisation de dateDebut/dateFin)
- Correction de l'accès à la propriété dates dans EmargementScan.tsx (cast de type)
- Ajout de l'import manquant de QrCode dans DashboardLayout.tsx
- Correction des erreurs TypeScript dans DashboardLayout.tsx (gestion de subItems)
- Ajout de downlevelIteration dans tsconfig.json
- Correction de l'utilisation de Set dans DateFormationMultiSelect.tsx (Array.from)
- Correction de l'appel à createAttestation (utilisation de enregistrerAttestation)
L'application fonctionne maintenant correctement sans erreurs TypeScript.
## Base de données
- ✅ Table `presences` créée (inscriptionId, dateFormationId, heurePresence, modeValidation, validateurId)
- ✅ Colonne `qrCodeToken` ajoutée à la table `sequences`
## Backend
- ✅ Génération de QR code unique par séquence (qrCodeGenerator.ts)
- ✅ Procédures tRPC pour l'émargement (presences.generateQRCode, presences.valider, presences.listBySequence)
- ✅ Fonctions de base de données (presenceDb.ts) pour gérer les présences
- ✅ Génération automatique d'attestation après validation de toutes les présences
- ✅ Intégration avec le service d'attestations existant
## Interface formateur (/formateur/emargement)
- ✅ Sélection de la séquence
- ✅ Génération et affichage du QR code en modal
- ✅ Liste des inscrits avec statut de présence par date
- ✅ Validation manuelle de présence possible
- ✅ Actualisation en temps réel des présences
- ✅ Entrée de menu "Émargement" dans DashboardLayout
## Interface publique (/emargement/:token)
- ✅ Page de scan QR code accessible sans authentification
- ✅ Recherche de l'apprenant par email
- ✅ Sélection de la formation et de la date
- ✅ Validation automatique de la présence via QR code
- ✅ Écrans de confirmation (succès/erreur)
- ✅ Gestion des erreurs (QR invalide, déjà émargé, etc.)
## Génération automatique d'attestations
- ✅ Vérification automatique après chaque validation de présence
- ✅ Génération du PDF d'attestation si toutes les présences sont validées
- ✅ Enregistrement en base de données
- ✅ Upload automatique sur S3
## Dépendances installées
- qrcode (génération de QR codes)
- @types/qrcode (types TypeScript)
Le système est entièrement fonctionnel et prêt à être utilisé par les formateurs et apprenants.
Fonctionnalités ajoutées :
- Table de liaison rappelSequences pour associer rappels et séquences
- Composant SequenceMultiSelect avec recherche et multi-sélection
- Gestion des associations dans les procédures create/update
- Modification du scheduler pour filtrer les séquences selon les associations
- Si aucune séquence n'est sélectionnée, le rappel s'applique à toutes les séquences (comportement par défaut)
Le système permet maintenant de configurer des rappels spécifiques pour certaines dates/séquences particulières, offrant une flexibilité complète dans la gestion des rappels automatiques.
Modifications apportées :
- Ajout des colonnes nomFichier, urlFichier, s3Key, typeFichier, tailleFichier dans la table rappels
- Création du composant FileUpload pour l'upload de fichiers vers S3 (max 10 Mo)
- Création de l'endpoint API /api/upload-file pour gérer l'upload
- Intégration du composant FileUpload dans les formulaires de création et modification de rappels
- Mise à jour des procédures tRPC create et update pour gérer les informations de fichier
- Modification des fonctions sendRappelJ7Email et sendRappelJ1Email pour inclure les pièces jointes
- Mise à jour du scheduler de rappels pour passer les informations de fichier lors de l'envoi
- Les fichiers sont téléchargés depuis S3 et convertis en base64 pour être attachés aux emails
## Modifications effectuées :
### Base de données (drizzle/schema.ts)
Ajout d'un champ `timing` dans la table `rappels` :
- Type : ENUM('pre_formation', 'post_formation')
- Valeur par défaut : 'pre_formation'
- Permet de distinguer les rappels avant et après formation
### Interface utilisateur (client/src/pages/AdminRappels.tsx)
**Formulaire de création et d'édition :**
- Ajout de radio buttons pour choisir "Pré-formation" ou "Post-formation"
- Le label du champ "Nombre de jours" change dynamiquement selon le choix :
* "Nombre de jours avant la séquence" (pré-formation)
* "Nombre de jours après la séquence" (post-formation)
- Le texte d'aide s'adapte également au timing choisi
**États et formulaires :**
- Ajout du champ `timing` dans `formData`
- Mise à jour de `resetForm()` et `handleEdit()` pour gérer le nouveau champ
### Backend (server/routers.ts)
Mise à jour des procédures tRPC :
- `rappels.create` : ajout du champ `timing` avec validation Zod
- `rappels.update` : ajout du champ `timing` optionnel
## Fonctionnement
L'utilisateur peut maintenant créer des rappels qui seront envoyés soit avant (pré-formation) soit après (post-formation) une séquence, avec un nombre de jours personnalisable pour chaque cas.
## Modifications effectuées :
### Backend (server/routers.ts)
- Ajout de la procédure `users.listWithFormateurs` qui retourne :
* Tous les utilisateurs
* Tous les formateurs avec leur statut de compte (hasAccount, user)
- Cette procédure combine les données des tables `users` et `formateurs`
### Frontend (client/src/pages/AdminUsers.tsx)
- Remplacement de `users.list` par `users.listWithFormateurs`
- Ajout d'une section dédiée "Formateurs sans compte utilisateur" affichée en haut de la page
- Cette section liste tous les formateurs qui n'ont pas encore de compte utilisateur
- Bouton "Créer un compte" pour chaque formateur qui :
* Pré-remplit le formulaire avec les données du formateur (nom, email)
* Lie automatiquement le `formateurId`
* Définit le rôle sur "formateur"
## Résultat
Les formateurs existants dans la table `formateurs` sont maintenant visibles dans la page Utilisateurs. L'administrateur peut facilement créer un compte pour chaque formateur en un clic, ce qui lie automatiquement le compte au formateur existant.
## Authentification formateur
- Ajout du rôle "formateur" dans l'enum de la table users
- Ajout du champ formateurId pour lier un compte à un formateur
- Mise à jour de l'interface AdminUsers avec sélection du formateur
- Redirection automatique selon le rôle (admin → /admin, formateur → /formateur)
- Badges et filtres mis à jour pour inclure le rôle formateur
## Upload logo et signature
- Création du composant ImageUpload.tsx avec prévisualisation
- Création de l'endpoint /api/upload-image avec multer pour l'upload vers S3
- Intégration dans AdminAttestations.tsx
- Modification du service PDF pour inclure le logo (en haut à droite) et la signature (en bas)
- Mise à jour des procédures tRPC pour accepter logoUrl, logoS3Key, signatureUrl, signatureS3Key
✅ Infrastructure backend :
- Tables attestations et configAttestation en base de données
- Service de génération PDF avec PDFKit (attestationService.ts)
- Génération automatique de PDF avec template personnalisable
- Upload automatique vers S3 avec URLs publiques
- Procédures tRPC pour générer, récupérer et configurer
✅ Interface utilisateur :
- Page de configuration des attestations (/admin/attestations)
- Personnalisation du texte avec variables dynamiques (nomComplet, nomFormation, dateDebut, dateFin)
- Configuration du signataire (nom et fonction)
- Bouton "Générer" dans la page de validation des présences formateur
- Génération automatique avec ouverture du PDF dans un nouvel onglet
✅ Fonctionnalités :
- Vérification des doublons (une seule attestation par apprenant/séquence)
- Génération uniquement pour les apprenants marqués comme présents
- PDF professionnel avec détails de la formation et dates
- Stockage permanent sur S3
📋 Améliorations futures possibles :
- Upload de logo et signature personnalisés
- Envoi automatique par email aux apprenants
- Espace apprenant pour télécharger les attestations
✅ Infrastructure backend complète :
- Tables attestations et configAttestation en base de données
- Service de génération PDF (attestationService.ts) avec PDFKit
- Procédures tRPC pour générer, récupérer et configurer les attestations
- Stockage S3 des PDF générés
✅ Interface d'administration :
- Page de configuration des attestations (/admin/attestations)
- Personnalisation du texte avec variables dynamiques
- Champs pour signataire (nom et fonction)
- Placeholders pour logo et signature (à implémenter en phase 2)
📋 À faire en Phase 2 :
- Upload des images (logo/signature) vers S3
- Génération automatique après validation de présence
- Envoi automatique par email aux apprenants
- Espace apprenant pour télécharger les attestations
1. Interface de gestion des emails formateurs (Configuration > Formateurs) - permet de gérer les adresses email des formateurs pour activer/désactiver les notifications
2. Tableau de bord des notifications (Configuration > Notifications) - historique complet des emails envoyés avec filtres et statistiques
3. Lien vers questionnaire de satisfaction automatiquement inclus dans l'email de remerciement post-formation