Checkpoint: Phase 1 : Système d'attestations de formation automatiques

 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
This commit is contained in:
Manus
2026-01-07 06:35:12 -05:00
parent 29b35fceaa
commit 2eb352206f
14 changed files with 3098 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -169,6 +169,13 @@
"when": 1765830109012,
"tag": "0023_jittery_gorgon",
"breakpoints": true
},
{
"idx": 24,
"version": "5",
"when": 1767770858914,
"tag": "0024_panoramic_goliath",
"breakpoints": true
}
]
}

View File

@@ -520,3 +520,58 @@ export const logsNotifications = mysqlTable("logsNotifications", {
export type LogNotification = typeof logsNotifications.$inferSelect;
export type InsertLogNotification = typeof logsNotifications.$inferInsert;
/**
* Table des attestations de formation
* Stocke les attestations générées pour chaque apprenant ayant terminé une formation
*/
export const attestations = mysqlTable("attestations", {
id: int("id").autoincrement().primaryKey(),
/** ID de l'inscription concernée */
inscriptionId: int("inscriptionId").notNull(),
/** ID de l'apprenant */
apprenantId: int("apprenantId").notNull(),
/** ID de la séquence */
sequenceId: int("sequenceId").notNull(),
/** Clé S3 du PDF généré */
s3Key: varchar("s3Key", { length: 500 }).notNull(),
/** URL publique du PDF */
pdfUrl: varchar("pdfUrl", { length: 1000 }).notNull(),
/** Date de génération de l'attestation */
dateGeneration: timestamp("dateGeneration").defaultNow().notNull(),
/** Statut de l'envoi par email */
emailEnvoye: boolean("emailEnvoye").default(false).notNull(),
/** Date d'envoi de l'email */
dateEnvoiEmail: timestamp("dateEnvoiEmail"),
createdAt: timestamp("createdAt").defaultNow().notNull(),
});
export type Attestation = typeof attestations.$inferSelect;
export type InsertAttestation = typeof attestations.$inferInsert;
/**
* Table de configuration des attestations
* Stocke le logo, la signature et le template personnalisable
*/
export const configAttestation = mysqlTable("configAttestation", {
id: int("id").autoincrement().primaryKey(),
/** Clé S3 du logo */
logoS3Key: varchar("logoS3Key", { length: 500 }),
/** URL du logo */
logoUrl: varchar("logoUrl", { length: 1000 }),
/** Clé S3 de la signature */
signatureS3Key: varchar("signatureS3Key", { length: 500 }),
/** URL de la signature */
signatureUrl: varchar("signatureUrl", { length: 1000 }),
/** Nom du signataire */
nomSignataire: varchar("nomSignataire", { length: 255 }),
/** Fonction du signataire */
fonctionSignataire: varchar("fonctionSignataire", { length: 255 }),
/** Texte personnalisable de l'attestation */
texteAttestation: text("texteAttestation"),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
export type ConfigAttestation = typeof configAttestation.$inferSelect;
export type InsertConfigAttestation = typeof configAttestation.$inferInsert;