Checkpoint: Système de questionnaires de satisfaction et d'évaluation - Phase 1 & 2 complétées
✅ Schéma de base de données créé : - Table questionnaires (satisfaction, evaluation_pre, evaluation_post) - Table questions (choix_multiple, echelle, texte_libre, oui_non) - Table reponsesQuestionnaires - Table reponsesQuestions - Table envoisQuestionnaires ✅ Backend complet implémenté : - Fichier questionnaireDb.ts avec toutes les fonctions CRUD - Procédures tRPC pour questionnaires (list, getById, create, update, delete, getStats, getReponsesDetaillees) - Procédures tRPC pour questions (list, create, update, delete) - Procédures tRPC publiques pour réponses (getByToken, submit) - Fonctions de statistiques (taux de réponse, réponses détaillées) ✅ Corrections : - Erreurs TypeScript dans exportService.ts corrigées 🚧 À faire dans la prochaine session : - Interfaces d'administration (AdminQuestionnaires, AdminQuestionnaireEdit) - Page publique de réponse aux questionnaires - Système d'envoi automatique post-formation - Tableaux de bord d'analyse avec graphiques - Exports Excel/PDF des feedbacks
This commit is contained in:
1530
drizzle/meta/0018_snapshot.json
Normal file
1530
drizzle/meta/0018_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -127,6 +127,13 @@
|
||||
"when": 1764540514199,
|
||||
"tag": "0017_unique_skrulls",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 18,
|
||||
"version": "5",
|
||||
"when": 1764934995109,
|
||||
"tag": "0018_smooth_purifiers",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -288,3 +288,132 @@ export const rappels = mysqlTable("rappels", {
|
||||
|
||||
export type Rappel = typeof rappels.$inferSelect;
|
||||
export type InsertRappel = typeof rappels.$inferInsert;
|
||||
|
||||
/**
|
||||
* Table des questionnaires
|
||||
* Stocke les questionnaires de satisfaction et d'évaluation des acquis
|
||||
*/
|
||||
export const questionnaires = mysqlTable("questionnaires", {
|
||||
id: int("id").autoincrement().primaryKey(),
|
||||
/** Nom du questionnaire */
|
||||
nom: varchar("nom", { length: 255 }).notNull(),
|
||||
/** Type de questionnaire (satisfaction, evaluation_pre, evaluation_post) */
|
||||
type: mysqlEnum("type", ["satisfaction", "evaluation_pre", "evaluation_post"]).notNull(),
|
||||
/** Description du questionnaire */
|
||||
description: text("description"),
|
||||
/** ID de la formation liée (null = tous les formations) */
|
||||
formationId: int("formationId"),
|
||||
/** Actif ou non */
|
||||
actif: boolean("actif").default(true).notNull(),
|
||||
/** Envoi automatique après la formation */
|
||||
envoiAutomatique: boolean("envoiAutomatique").default(false).notNull(),
|
||||
/** Délai en jours après la dernière date de la séquence (pour envoi automatique) */
|
||||
delaiEnvoiJours: int("delaiEnvoiJours").default(1).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
|
||||
* Stocke les questions associées à chaque questionnaire
|
||||
*/
|
||||
export const questions = mysqlTable("questions", {
|
||||
id: int("id").autoincrement().primaryKey(),
|
||||
/** ID du questionnaire */
|
||||
questionnaireId: int("questionnaireId").notNull(),
|
||||
/** Ordre d'affichage */
|
||||
ordre: int("ordre").notNull(),
|
||||
/** Texte de la question */
|
||||
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 choix multiple (JSON array) */
|
||||
options: text("options"),
|
||||
/** Valeur minimale pour échelle */
|
||||
echelleMin: int("echelleMin"),
|
||||
/** Valeur maximale pour échelle */
|
||||
echelleMax: int("echelleMax"),
|
||||
/** Label pour valeur minimale (ex: "Pas du tout satisfait") */
|
||||
echelleLabelMin: varchar("echelleLabelMin", { length: 100 }),
|
||||
/** Label pour valeur maximale (ex: "Très satisfait") */
|
||||
echelleLabelMax: varchar("echelleLabelMax", { length: 100 }),
|
||||
/** Question obligatoire */
|
||||
obligatoire: boolean("obligatoire").default(false).notNull(),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
||||
});
|
||||
|
||||
export type Question = typeof questions.$inferSelect;
|
||||
export type InsertQuestion = typeof questions.$inferInsert;
|
||||
|
||||
/**
|
||||
* Table des réponses aux questionnaires
|
||||
* Stocke les réponses complètes d'un apprenant à un questionnaire
|
||||
*/
|
||||
export const reponsesQuestionnaires = mysqlTable("reponsesQuestionnaires", {
|
||||
id: int("id").autoincrement().primaryKey(),
|
||||
/** ID du questionnaire */
|
||||
questionnaireId: int("questionnaireId").notNull(),
|
||||
/** ID de l'apprenant */
|
||||
apprenantId: int("apprenantId").notNull(),
|
||||
/** ID de la séquence */
|
||||
sequenceId: int("sequenceId").notNull(),
|
||||
/** Date de réponse */
|
||||
dateReponse: timestamp("dateReponse").defaultNow().notNull(),
|
||||
/** Questionnaire complété */
|
||||
complete: boolean("complete").default(false).notNull(),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
||||
});
|
||||
|
||||
export type ReponseQuestionnaire = typeof reponsesQuestionnaires.$inferSelect;
|
||||
export type InsertReponseQuestionnaire = typeof reponsesQuestionnaires.$inferInsert;
|
||||
|
||||
/**
|
||||
* Table des réponses aux questions
|
||||
* Stocke les réponses individuelles à chaque question
|
||||
*/
|
||||
export const reponsesQuestions = mysqlTable("reponsesQuestions", {
|
||||
id: int("id").autoincrement().primaryKey(),
|
||||
/** ID de la réponse au questionnaire */
|
||||
reponseQuestionnaireId: int("reponseQuestionnaireId").notNull(),
|
||||
/** ID de la question */
|
||||
questionId: int("questionId").notNull(),
|
||||
/** Réponse numérique (pour échelle, oui_non) */
|
||||
reponseNumerique: int("reponseNumerique"),
|
||||
/** Réponse texte (pour texte_libre, choix_multiple) */
|
||||
reponseTexte: text("reponseTexte"),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
||||
});
|
||||
|
||||
export type ReponseQuestion = typeof reponsesQuestions.$inferSelect;
|
||||
export type InsertReponseQuestion = typeof reponsesQuestions.$inferInsert;
|
||||
|
||||
/**
|
||||
* Table des envois de questionnaires
|
||||
* Stocke l'historique des envois de questionnaires aux apprenants
|
||||
*/
|
||||
export const envoisQuestionnaires = mysqlTable("envoisQuestionnaires", {
|
||||
id: int("id").autoincrement().primaryKey(),
|
||||
/** ID du questionnaire */
|
||||
questionnaireId: int("questionnaireId").notNull(),
|
||||
/** ID de l'apprenant */
|
||||
apprenantId: int("apprenantId").notNull(),
|
||||
/** ID de la séquence */
|
||||
sequenceId: int("sequenceId").notNull(),
|
||||
/** Date d'envoi */
|
||||
dateEnvoi: timestamp("dateEnvoi").defaultNow().notNull(),
|
||||
/** Token unique pour accéder au questionnaire */
|
||||
token: varchar("token", { length: 100 }).notNull().unique(),
|
||||
/** Date de réponse (null si pas encore répondu) */
|
||||
dateReponse: timestamp("dateReponse"),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
||||
});
|
||||
|
||||
export type EnvoiQuestionnaire = typeof envoisQuestionnaires.$inferSelect;
|
||||
export type InsertEnvoiQuestionnaire = typeof envoisQuestionnaires.$inferInsert;
|
||||
|
||||
Reference in New Issue
Block a user