- Ajout du champ 'periode' dans la table presences - Modification des procédures backend pour gérer les deux périodes - Mise à jour de l'interface EmargementScan avec choix de période - Mise à jour de l'interface FormateurEmargement avec validation séparée matin/après-midi - La feuille de présence PDF était déjà configurée avec deux colonnes
571 lines
24 KiB
TypeScript
571 lines
24 KiB
TypeScript
import { boolean, int, mysqlEnum, mysqlTable, text, timestamp, varchar, datetime, decimal } from "drizzle-orm/mysql-core";
|
|
|
|
/**
|
|
* Core user table backing auth flow.
|
|
* Extend this file with additional tables as your product grows.
|
|
* Columns use camelCase to match both database fields and generated types.
|
|
*/
|
|
export const users = mysqlTable("users", {
|
|
/**
|
|
* Surrogate primary key. Auto-incremented numeric value managed by the database.
|
|
* Use this for relations between tables.
|
|
*/
|
|
id: int("id").autoincrement().primaryKey(),
|
|
/** Manus OAuth identifier (openId) returned from the OAuth callback. Unique per user. */
|
|
openId: varchar("openId", { length: 64 }).notNull().unique(),
|
|
name: text("name"),
|
|
email: varchar("email", { length: 320 }),
|
|
/** Identifiant de connexion unique pour l'utilisateur */
|
|
username: varchar("username", { length: 100 }).unique(),
|
|
/** Mot de passe hashé (bcrypt) */
|
|
password: varchar("password", { length: 255 }),
|
|
loginMethod: varchar("loginMethod", { length: 64 }),
|
|
role: mysqlEnum("role", ["user", "admin", "formateur"]).default("user").notNull(),
|
|
/** Statut du compte (actif/inactif) */
|
|
isActive: boolean("isActive").default(true).notNull(),
|
|
/** ID du formateur associé (si role = formateur) */
|
|
formateurId: int("formateurId"),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
lastSignedIn: timestamp("lastSignedIn").defaultNow().notNull(),
|
|
});
|
|
|
|
export type User = typeof users.$inferSelect;
|
|
export type InsertUser = typeof users.$inferInsert;
|
|
|
|
/**
|
|
* Table des tokens de réinitialisation de mot de passe
|
|
*/
|
|
export const passwordResetTokens = mysqlTable("passwordResetTokens", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
/** Email de l'utilisateur qui demande la réinitialisation */
|
|
email: varchar("email", { length: 320 }).notNull(),
|
|
/** Token unique généré pour la réinitialisation */
|
|
token: varchar("token", { length: 255 }).notNull().unique(),
|
|
/** Date d'expiration du token (24h après création) */
|
|
expiresAt: timestamp("expiresAt").notNull(),
|
|
/** Indique si le token a déjà été utilisé */
|
|
used: boolean("used").default(false).notNull(),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
});
|
|
|
|
export type PasswordResetToken = typeof passwordResetTokens.$inferSelect;
|
|
export type InsertPasswordResetToken = typeof passwordResetTokens.$inferInsert;
|
|
|
|
/**
|
|
* Table des formations (ex: Manager Itinova)
|
|
*/
|
|
export const formations = mysqlTable("formations", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
nom: varchar("nom", { length: 255 }).notNull(),
|
|
description: text("description"),
|
|
/** Lien unique pour l'inscription à cette formation */
|
|
lienUnique: varchar("lienUnique", { length: 100 }).notNull().unique(),
|
|
actif: boolean("actif").default(true).notNull(),
|
|
/** Mode de génération des attestations (auto = génération automatique, manuel = import de documents) */
|
|
modeAttestation: mysqlEnum("modeAttestation", ["auto", "manuel"]).default("auto").notNull(),
|
|
/** Mode d'envoi des attestations (auto = envoi automatique, manuel = envoi manuel) */
|
|
modeEnvoi: mysqlEnum("modeEnvoi", ["auto", "manuel"]).default("manuel").notNull(),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type Formation = typeof formations.$inferSelect;
|
|
export type InsertFormation = typeof formations.$inferInsert;
|
|
|
|
/**
|
|
* Table des séquences de formation (ex: Groupe A, Groupe B)
|
|
* Chaque séquence peut avoir jusqu'à 4 dates de formation
|
|
*/
|
|
export const sequences = mysqlTable("sequences", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
formationId: int("formationId").notNull(),
|
|
nom: varchar("nom", { length: 255 }).notNull(),
|
|
lieu: varchar("lieu", { length: 255 }).notNull(),
|
|
capaciteMax: int("capaciteMax").notNull(),
|
|
statut: mysqlEnum("statut", ["ouverte", "bloquee", "terminee", "fermee", "annulee"]).default("ouverte").notNull(),
|
|
/** Public cible de la séquence (Directeur, Chef de service, Autre, Tous) */
|
|
publicCible: mysqlEnum("publicCible", ["directeur", "chef_service", "autre", "tous"]).default("tous").notNull(),
|
|
/** ID du formateur assigné à cette séquence */
|
|
formateurId: int("formateurId"),
|
|
/** Date limite d'inscription (blocage) */
|
|
dateBlocage: datetime("dateBlocage"),
|
|
/** Token unique pour le QR code d'émargement */
|
|
qrCodeToken: varchar("qrCodeToken", { length: 100 }).unique(),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type Sequence = typeof sequences.$inferSelect;
|
|
export type InsertSequence = typeof sequences.$inferInsert;
|
|
|
|
/**
|
|
* Table des dates de formation pour chaque séquence
|
|
* Une séquence peut avoir jusqu'à 4 dates
|
|
*/
|
|
export const datesFormation = mysqlTable("datesFormation", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
sequenceId: int("sequenceId").notNull(),
|
|
/** Ordre de la date (1, 2, 3 ou 4) */
|
|
ordre: int("ordre").notNull(),
|
|
dateDebut: datetime("dateDebut").notNull(),
|
|
dateFin: datetime("dateFin").notNull(),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
});
|
|
|
|
export type DateFormation = typeof datesFormation.$inferSelect;
|
|
export type InsertDateFormation = typeof datesFormation.$inferInsert;
|
|
|
|
/**
|
|
* Table des apprenants
|
|
*/
|
|
export const apprenants = mysqlTable("apprenants", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
nom: varchar("nom", { length: 255 }).notNull(),
|
|
prenom: varchar("prenom", { length: 255 }).notNull(),
|
|
email: varchar("email", { length: 320 }).notNull().unique(),
|
|
codeEtablissement: varchar("codeEtablissement", { length: 50 }),
|
|
/** Fonction de l'apprenant (Directeur, Chef de service, Autre) */
|
|
fonction: varchar("fonction", { length: 100 }),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type Apprenant = typeof apprenants.$inferSelect;
|
|
export type InsertApprenant = typeof apprenants.$inferInsert;
|
|
|
|
/**
|
|
* Table des inscriptions
|
|
*/
|
|
export const inscriptions = mysqlTable("inscriptions", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
sequenceId: int("sequenceId").notNull(),
|
|
apprenantId: int("apprenantId").notNull(),
|
|
statut: mysqlEnum("statut", ["confirmee", "en_attente", "annulee"]).default("confirmee").notNull(),
|
|
dateInscription: timestamp("dateInscription").defaultNow().notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type Inscription = typeof inscriptions.$inferSelect;
|
|
export type InsertInscription = typeof inscriptions.$inferInsert;
|
|
|
|
/**
|
|
* Table de configuration des emails
|
|
*/
|
|
export const emailConfig = mysqlTable("emailConfig", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
/** Provider d'envoi d'emails (resend, smtp, simulation) */
|
|
provider: mysqlEnum("provider", ["resend", "smtp", "simulation"]).default("simulation").notNull(),
|
|
/** Clé API (pour Resend ou autres) */
|
|
apiKey: text("apiKey"),
|
|
/** Hôte SMTP */
|
|
smtpHost: varchar("smtpHost", { length: 255 }),
|
|
/** Port SMTP */
|
|
smtpPort: int("smtpPort"),
|
|
/** Sécurité SMTP (TLS, SSL, None) */
|
|
smtpSecure: mysqlEnum("smtpSecure", ["none", "tls", "ssl"]),
|
|
/** Utilisateur SMTP */
|
|
smtpUser: varchar("smtpUser", { length: 320 }),
|
|
/** Mot de passe SMTP */
|
|
smtpPassword: text("smtpPassword"),
|
|
/** Email expéditeur */
|
|
fromEmail: varchar("fromEmail", { length: 320 }).notNull(),
|
|
/** Nom de l'expéditeur */
|
|
fromName: varchar("fromName", { length: 255 }).default("Formation Manager Itinova").notNull(),
|
|
/** Mode de fonctionnement (simulation ou production) */
|
|
mode: mysqlEnum("mode", ["simulation", "production"]).default("simulation").notNull(),
|
|
/** Domaine vérifié */
|
|
domainVerified: boolean("domainVerified").default(false).notNull(),
|
|
/** Configuration active */
|
|
active: boolean("active").default(true).notNull(),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type EmailConfig = typeof emailConfig.$inferSelect;
|
|
export type InsertEmailConfig = typeof emailConfig.$inferInsert;
|
|
|
|
/**
|
|
* Table des templates d'emails
|
|
*/
|
|
export const emailTemplates = mysqlTable("emailTemplates", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
/** Type de template (inscription, teaser, rappel1, rappel2, rappel3, rappel4, rappel5, rappel6, reset_password) */
|
|
type: mysqlEnum("type", ["inscription", "teaser", "rappel1", "rappel2", "rappel3", "rappel4", "rappel5", "rappel6", "reset_password"]).notNull().unique(),
|
|
titre: varchar("titre", { length: 255 }).notNull(),
|
|
/** Corps du message avec variables dynamiques */
|
|
bodyContent: text("bodyContent").notNull(),
|
|
couleurPrincipale: varchar("couleurPrincipale", { length: 7 }).default("#283581").notNull(),
|
|
couleurSecondaire: varchar("couleurSecondaire", { length: 7 }).default("#0578BE").notNull(),
|
|
piedDePage: text("piedDePage"),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type EmailTemplate = typeof emailTemplates.$inferSelect;
|
|
export type InsertEmailTemplate = typeof emailTemplates.$inferInsert;
|
|
|
|
/**
|
|
* Table des formateurs
|
|
*/
|
|
export const formateurs = mysqlTable("formateurs", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
nom: varchar("nom", { length: 255 }).notNull(),
|
|
email: varchar("email", { length: 320 }),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type Formateur = typeof formateurs.$inferSelect;
|
|
export type InsertFormateur = typeof formateurs.$inferInsert;
|
|
|
|
/**
|
|
* Table des rappels automatiques
|
|
*/
|
|
export const rappels = mysqlTable("rappels", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
nom: varchar("nom", { length: 255 }).notNull(),
|
|
/** Type de template d'email à utiliser (rappel1, rappel2, rappel3, rappel4, rappel5, rappel6) */
|
|
templateType: mysqlEnum("templateType", ["rappel1", "rappel2", "rappel3", "rappel4", "rappel5", "rappel6"]).notNull(),
|
|
/** Nombre de jours avant la séquence */
|
|
joursAvant: int("joursAvant").notNull(),
|
|
/** Heure d'envoi (format HH:mm) */
|
|
heureEnvoi: varchar("heureEnvoi", { length: 5 }).default("09:00").notNull(),
|
|
/** Timing du rappel (pre_formation ou post_formation) */
|
|
timing: mysqlEnum("timing", ["pre_formation", "post_formation"]).default("pre_formation").notNull(),
|
|
/** Nom du fichier joint (optionnel) */
|
|
nomFichier: varchar("nomFichier", { length: 255 }),
|
|
/** URL du fichier sur S3 (optionnel) */
|
|
urlFichier: varchar("urlFichier", { length: 500 }),
|
|
/** Clé S3 du fichier (optionnel) */
|
|
s3Key: varchar("s3Key", { length: 500 }),
|
|
/** Type MIME du fichier (optionnel) */
|
|
typeFichier: varchar("typeFichier", { length: 100 }),
|
|
/** Taille du fichier en octets (optionnel) */
|
|
tailleFichier: int("tailleFichier"),
|
|
actif: boolean("actif").default(true).notNull(),
|
|
derniereExecution: datetime("derniereExecution"),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type Rappel = typeof rappels.$inferSelect;
|
|
export type InsertRappel = typeof rappels.$inferInsert;
|
|
|
|
/**
|
|
* Table de liaison entre rappels et dates de formation
|
|
* Si aucune date n'est associée, le rappel s'applique à toutes les dates
|
|
*/
|
|
export const rappelDates = mysqlTable("rappelDates", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
rappelId: int("rappelId").notNull(),
|
|
dateFormationId: int("dateFormationId").notNull(),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
});
|
|
|
|
export type RappelDate = typeof rappelDates.$inferSelect;
|
|
export type InsertRappelDate = typeof rappelDates.$inferInsert;
|
|
|
|
/**
|
|
* Table des logs de rappels envoyés
|
|
*/
|
|
export const logsRappels = mysqlTable("logsrappels", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
rappelId: int("rappelId").notNull(),
|
|
sequenceId: int("sequenceId").notNull(),
|
|
apprenantId: int("apprenantId").notNull(),
|
|
email: varchar("email", { length: 320 }).notNull(),
|
|
/** Type de rappel (rappel1, rappel2, rappel3, rappel4, rappel5, rappel6) */
|
|
type: mysqlEnum("type", ["rappel1", "rappel2", "rappel3", "rappel4", "rappel5", "rappel6"]).notNull(),
|
|
/** Type d'envoi (automatique, test) - les tests ne bloquent pas les envois automatiques */
|
|
typeEnvoi: mysqlEnum("typeEnvoi", ["automatique", "test"]).default("automatique").notNull(),
|
|
statut: mysqlEnum("statut", ["succes", "echec"]).notNull(),
|
|
messageErreur: text("messageErreur"),
|
|
/** Nombre de tentatives d'envoi */
|
|
nbTentatives: int("nbTentatives").default(1).notNull(),
|
|
/** Date du prochain essai en cas d'échec */
|
|
prochainEssai: datetime("prochainEssai"),
|
|
dateEnvoi: timestamp("dateEnvoi").defaultNow().notNull(),
|
|
});
|
|
|
|
export type LogRappel = typeof logsRappels.$inferSelect;
|
|
export type InsertLogRappel = typeof logsRappels.$inferInsert;
|
|
|
|
/**
|
|
* Table des questionnaires de satisfaction et d'évaluation
|
|
*/
|
|
export const questionnaires = mysqlTable("questionnaires", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
titre: varchar("titre", { length: 255 }).notNull(),
|
|
description: text("description"),
|
|
/** Type de questionnaire (satisfaction, evaluation_pre, evaluation_post) */
|
|
type: mysqlEnum("type", ["satisfaction", "evaluation_pre", "evaluation_post"]).notNull(),
|
|
actif: boolean("actif").default(true).notNull(),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type Questionnaire = typeof questionnaires.$inferSelect;
|
|
export type InsertQuestionnaire = typeof questionnaires.$inferInsert;
|
|
|
|
/**
|
|
* Table des questions d'un questionnaire
|
|
*/
|
|
export const questions = mysqlTable("questions", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
questionnaireId: int("questionnaireId").notNull(),
|
|
texte: text("texte").notNull(),
|
|
/** Type de question (choix_multiple, echelle, texte_libre, oui_non) */
|
|
typeQuestion: mysqlEnum("typeQuestion", ["choix_multiple", "echelle", "texte_libre", "oui_non"]).notNull(),
|
|
/** Options pour les questions à choix multiples (JSON) */
|
|
options: text("options"),
|
|
/** Valeur minimale pour les échelles */
|
|
valeurMin: int("valeurMin"),
|
|
/** Valeur maximale pour les échelles */
|
|
valeurMax: int("valeurMax"),
|
|
obligatoire: boolean("obligatoire").default(false).notNull(),
|
|
ordre: int("ordre").notNull(),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
});
|
|
|
|
export type Question = typeof questions.$inferSelect;
|
|
export type InsertQuestion = typeof questions.$inferInsert;
|
|
|
|
/**
|
|
* Table des réponses aux questionnaires
|
|
*/
|
|
export const reponsesQuestionnaires = mysqlTable("reponsesQuestionnaires", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
questionnaireId: int("questionnaireId").notNull(),
|
|
sequenceId: int("sequenceId").notNull(),
|
|
apprenantId: int("apprenantId").notNull(),
|
|
dateReponse: timestamp("dateReponse").defaultNow().notNull(),
|
|
});
|
|
|
|
export type ReponseQuestionnaire = typeof reponsesQuestionnaires.$inferSelect;
|
|
export type InsertReponseQuestionnaire = typeof reponsesQuestionnaires.$inferInsert;
|
|
|
|
/**
|
|
* Table des réponses individuelles aux questions
|
|
*/
|
|
export const reponsesQuestions = mysqlTable("reponsesQuestions", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
reponseQuestionnaireId: int("reponseQuestionnaireId").notNull(),
|
|
questionId: int("questionId").notNull(),
|
|
/** Réponse textuelle */
|
|
reponseTexte: text("reponseTexte"),
|
|
/** Réponse numérique (pour échelles et oui/non) */
|
|
reponseNumerique: int("reponseNumerique"),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
});
|
|
|
|
export type ReponseQuestion = typeof reponsesQuestions.$inferSelect;
|
|
export type InsertReponseQuestion = typeof reponsesQuestions.$inferInsert;
|
|
|
|
/**
|
|
* Table des envois de questionnaires
|
|
*/
|
|
export const envoisQuestionnaires = mysqlTable("envoisQuestionnaires", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
questionnaireId: int("questionnaireId").notNull(),
|
|
sequenceId: int("sequenceId").notNull(),
|
|
apprenantId: int("apprenantId").notNull(),
|
|
/** Token unique pour accéder au questionnaire */
|
|
token: varchar("token", { length: 100 }).notNull().unique(),
|
|
dateEnvoi: timestamp("dateEnvoi").defaultNow().notNull(),
|
|
dateReponse: timestamp("dateReponse"),
|
|
statut: mysqlEnum("statut", ["envoye", "repondu"]).default("envoye").notNull(),
|
|
});
|
|
|
|
export type EnvoiQuestionnaire = typeof envoisQuestionnaires.$inferSelect;
|
|
export type InsertEnvoiQuestionnaire = typeof envoisQuestionnaires.$inferInsert;
|
|
|
|
/**
|
|
* Table des supports de formation uploadés par les formateurs
|
|
*/
|
|
export const supportsFormation = mysqlTable("supportsFormation", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
sequenceId: int("sequenceId").notNull(),
|
|
formateurId: int("formateurId").notNull(),
|
|
nomFichier: varchar("nomFichier", { length: 255 }).notNull(),
|
|
typeFichier: varchar("typeFichier", { length: 100 }).notNull(),
|
|
tailleFichier: int("tailleFichier").notNull(),
|
|
urlFichier: varchar("urlFichier", { length: 500 }).notNull(),
|
|
s3Key: varchar("s3Key", { length: 500 }).notNull(),
|
|
description: text("description"),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
});
|
|
|
|
export type SupportFormation = typeof supportsFormation.$inferSelect;
|
|
export type InsertSupportFormation = typeof supportsFormation.$inferInsert;
|
|
|
|
/**
|
|
* Table des présences (émargement)
|
|
*/
|
|
export const presences = mysqlTable("presences", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
inscriptionId: int("inscriptionId").notNull(),
|
|
dateFormationId: int("dateFormationId").notNull(),
|
|
/** Période de la journée (matin ou après-midi) */
|
|
periode: mysqlEnum("periode", ["matin", "apres_midi"]).notNull().default("matin"),
|
|
heurePresence: timestamp("heurePresence").defaultNow().notNull(),
|
|
/** Mode de validation (qrcode, manuel) */
|
|
modeValidation: mysqlEnum("modeValidation", ["qrcode", "manuel"]).notNull(),
|
|
/** ID de l'utilisateur qui a validé (formateur ou admin) */
|
|
validateurId: int("validateurId"),
|
|
commentaire: text("commentaire"),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
});
|
|
|
|
export type Presence = typeof presences.$inferSelect;
|
|
export type InsertPresence = typeof presences.$inferInsert;
|
|
|
|
/**
|
|
* Table des attestations de formation
|
|
*/
|
|
export const attestations = mysqlTable("attestations", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
apprenantId: int("apprenantId").notNull(),
|
|
sequenceId: int("sequenceId").notNull(),
|
|
inscriptionId: int("inscriptionId").notNull(),
|
|
urlPdf: varchar("urlPdf", { length: 500 }),
|
|
s3Key: varchar("s3Key", { length: 500 }),
|
|
/** URL du document uploadé manuellement */
|
|
documentUrl: varchar("documentUrl", { length: 500 }),
|
|
/** Clé S3 du document uploadé manuellement */
|
|
documentS3Key: varchar("documentS3Key", { length: 500 }),
|
|
/** ID de l'utilisateur qui a uploadé le document */
|
|
uploadedBy: int("uploadedBy"),
|
|
/** Date d'upload du document */
|
|
uploadedAt: timestamp("uploadedAt"),
|
|
/** Email envoyé ou non */
|
|
emailEnvoye: boolean("emailEnvoye").default(false).notNull(),
|
|
/** Date d'envoi de l'email */
|
|
dateEnvoiEmail: timestamp("dateEnvoiEmail"),
|
|
dateGeneration: timestamp("dateGeneration").defaultNow().notNull(),
|
|
});
|
|
|
|
export type Attestation = typeof attestations.$inferSelect;
|
|
export type InsertAttestation = typeof attestations.$inferInsert;
|
|
|
|
/**
|
|
* Table de configuration des attestations
|
|
*/
|
|
export const configAttestation = mysqlTable("configAttestation", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
/** Texte personnalisable de l'attestation avec variables dynamiques */
|
|
texteAttestation: text("texteAttestation").notNull(),
|
|
/** Nom du signataire */
|
|
nomSignataire: varchar("nomSignataire", { length: 255 }).notNull(),
|
|
/** Fonction du signataire */
|
|
fonctionSignataire: varchar("fonctionSignataire", { length: 255 }).notNull(),
|
|
/** URL du logo sur S3 */
|
|
logoUrl: varchar("logoUrl", { length: 500 }),
|
|
/** Clé S3 du logo */
|
|
logoS3Key: varchar("logoS3Key", { length: 500 }),
|
|
/** URL de la signature sur S3 */
|
|
signatureUrl: varchar("signatureUrl", { length: 500 }),
|
|
/** Clé S3 de la signature */
|
|
signatureS3Key: varchar("signatureS3Key", { length: 500 }),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type ConfigAttestation = typeof configAttestation.$inferSelect;
|
|
export type InsertConfigAttestation = typeof configAttestation.$inferInsert;
|
|
|
|
/**
|
|
* Table des notifications envoyées
|
|
*/
|
|
export const logsNotifications = mysqlTable("logsNotifications", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
/** Type de notification */
|
|
type: mysqlEnum("type", [
|
|
"remerciement",
|
|
"notification_formateur_inscription",
|
|
"notification_formateur_annulation",
|
|
"alerte_capacite",
|
|
"notification_liste_attente"
|
|
]).notNull(),
|
|
/** Email du destinataire */
|
|
emailDestinataire: varchar("emailDestinataire", { length: 320 }).notNull(),
|
|
/** Sujet de l'email */
|
|
sujet: varchar("sujet", { length: 500 }).notNull(),
|
|
/** ID de la séquence concernée */
|
|
sequenceId: int("sequenceId"),
|
|
/** ID de l'apprenant concerné */
|
|
apprenantId: int("apprenantId"),
|
|
/** ID du formateur concerné */
|
|
formateurId: int("formateurId"),
|
|
/** Statut de l'envoi */
|
|
statut: mysqlEnum("statut", ["success", "failed"]).notNull(),
|
|
/** Message d'erreur en cas d'échec */
|
|
messageErreur: text("messageErreur"),
|
|
/** Métadonnées supplémentaires (JSON) */
|
|
metadata: text("metadata"),
|
|
dateEnvoi: timestamp("dateEnvoi").defaultNow().notNull(),
|
|
});
|
|
|
|
export type LogNotification = typeof logsNotifications.$inferSelect;
|
|
export type InsertLogNotification = typeof logsNotifications.$inferInsert;
|
|
|
|
/**
|
|
* Table des paramètres de l'application
|
|
* Stocke les paramètres globaux de configuration
|
|
*/
|
|
export const parametres = mysqlTable("parametres", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
/** URL publique de l'application pour les QR codes d'émargement */
|
|
urlPublique: varchar("urlPublique", { length: 500 }).notNull().default("https://formations.itinova.org"),
|
|
/** Délai d'expiration des QR codes en minutes (par défaut 30 minutes) */
|
|
delaiExpirationQR: int("delaiExpirationQR").default(30).notNull(),
|
|
/** Durée de validité des tokens d'émargement en heures (par défaut 24 heures) */
|
|
dureeValiditeToken: int("dureeValiditeToken").default(24).notNull(),
|
|
/** Activer ou désactiver les notifications automatiques */
|
|
notificationsActives: boolean("notificationsActives").default(true).notNull(),
|
|
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
|
});
|
|
|
|
export type Parametre = typeof parametres.$inferSelect;
|
|
export type InsertParametre = typeof parametres.$inferInsert;
|
|
|
|
/**
|
|
* Table de l'historique des modifications des paramètres
|
|
* Permet de tracer qui a modifié quoi et quand
|
|
*/
|
|
export const historiqueParametres = mysqlTable("historiqueParametres", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
/** ID de l'utilisateur qui a effectué la modification */
|
|
userId: int("userId").notNull(),
|
|
/** Nom de l'utilisateur (pour historique même si user supprimé) */
|
|
userName: varchar("userName", { length: 255 }).notNull(),
|
|
/** Champ modifié */
|
|
champModifie: varchar("champModifie", { length: 100 }).notNull(),
|
|
/** Ancienne valeur (JSON) */
|
|
ancienneValeur: text("ancienneValeur"),
|
|
/** Nouvelle valeur (JSON) */
|
|
nouvelleValeur: text("nouvelleValeur"),
|
|
dateModification: timestamp("dateModification").defaultNow().notNull(),
|
|
});
|
|
|
|
export type HistoriqueParametre = typeof historiqueParametres.$inferSelect;
|
|
export type InsertHistoriqueParametre = typeof historiqueParametres.$inferInsert;
|
|
|
|
/**
|
|
* Table de l'historique des envois d'attestations de formation
|
|
* Permet de tracer tous les envois d'attestations
|
|
*/
|
|
export const historiqueAttestations = mysqlTable("historiqueAttestations", {
|
|
id: int("id").autoincrement().primaryKey(),
|
|
sequenceId: int("sequenceId").notNull(),
|
|
apprenantId: int("apprenantId").notNull(),
|
|
dateEnvoi: timestamp("dateEnvoi").defaultNow().notNull(),
|
|
statut: mysqlEnum("statut", ["envoye", "erreur"]).notNull(),
|
|
messageErreur: text("messageErreur"),
|
|
urlAttestation: varchar("urlAttestation", { length: 500 }),
|
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
});
|
|
|
|
export type HistoriqueAttestation = typeof historiqueAttestations.$inferSelect;
|
|
export type InsertHistoriqueAttestation = typeof historiqueAttestations.$inferInsert;
|
|
|