Files
formation-manager-itinova/drizzle/schema.ts
Manus Sandbox 703d0e4961 Checkpoint: Ajout du champ "Formateur" dans les séquences de formation :
 Base de données : colonne "formateur" ajoutée à la table sequences (VARCHAR 255, nullable)

 Backend : procédures tRPC mises à jour
- sequences.create : champ formateur ajouté (optionnel)
- sequences.update : champ formateur ajouté (optionnel)

 Frontend : formulaires mis à jour
- Formulaire de création : champ "Formateur" ajouté avec placeholder
- Formulaire de modification : champ "Formateur" ajouté avec placeholder
- Le champ est non obligatoire comme demandé

Le champ formateur permet maintenant de spécifier le nom du formateur pour chaque séquence de formation lors de la création ou de la modification.
2025-11-19 09:30:51 -05:00

203 lines
8.6 KiB
TypeScript

import { boolean, datetime, int, mysqlEnum, mysqlTable, text, timestamp, varchar } 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 }),
name: text("name"),
email: varchar("email", { length: 320 }),
loginMethod: varchar("loginMethod", { length: 64 }),
role: mysqlEnum("role", ["user", "admin"]).default("user").notNull(),
/** Statut du compte (actif/inactif) */
isActive: boolean("isActive").default(true).notNull(),
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 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(),
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 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 }).notNull(),
fonction: mysqlEnum("fonction", ["directeur", "chef_service", "autre"]).notNull(),
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 séquences de formation
* Une séquence peut contenir 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 de la formation */
lieu: varchar("lieu", { length: 500 }).notNull(),
/** Public cible de la séquence (Directeur, Chef de service, Tous, Autre) */
publicCible: mysqlEnum("publicCible", ["directeur", "chef_service", "tous", "autre"]).notNull(),
/** Nom du formateur (optionnel) */
formateur: varchar("formateur", { length: 255 }),
/** Capacité maximale (12 par défaut) */
capaciteMax: int("capaciteMax").default(12).notNull(),
/** Date de blocage des inscriptions (J-15 avant la première date) */
dateBlocage: datetime("dateBlocage").notNull(),
/** Statut de la séquence */
statut: mysqlEnum("statut", ["ouverte", "bloquee", "terminee"]).default("ouverte").notNull(),
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(),
/** Date de début de cette journée de formation */
dateDebut: datetime("dateDebut").notNull(),
/** Date de fin de cette journée de formation */
dateFin: datetime("dateFin").notNull(),
/** Ordre de la date dans la séquence (1 à 4) */
ordre: int("ordre").notNull(),
createdAt: timestamp("createdAt").defaultNow().notNull(),
});
export type DateFormation = typeof datesFormation.$inferSelect;
export type InsertDateFormation = typeof datesFormation.$inferInsert;
/**
* Table des inscriptions
* L'inscription à une séquence inscrit automatiquement à toutes ses dates
*/
export const inscriptions = mysqlTable("inscriptions", {
id: int("id").autoincrement().primaryKey(),
apprenantId: int("apprenantId").notNull(),
sequenceId: int("sequenceId").notNull(),
/** Statut de l'inscription */
statut: mysqlEnum("statut", ["confirmee", "liste_attente", "annulee"]).notNull(),
dateInscription: timestamp("dateInscription").defaultNow().notNull(),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
export type Inscription = typeof inscriptions.$inferSelect;
export type InsertInscription = typeof inscriptions.$inferInsert;
/**
* Table des tokens de réinitialisation de mot de passe
* Stocke les tokens temporaires générés pour la réinitialisation
*/
export const passwordResetTokens = mysqlTable("passwordResetTokens", {
id: int("id").autoincrement().primaryKey(),
userId: int("userId").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 génération) */
expiresAt: timestamp("expiresAt").notNull(),
/** Indique si le token a é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 templates d'emails personnalisables
*/
export const emailTemplates = mysqlTable("emailTemplates", {
id: int("id").autoincrement().primaryKey(),
/** Type de template (inscription, teaser, rappel, reset_password) */
type: varchar("type", { length: 50 }).notNull().unique(),
/** Nom affiché du template */
name: varchar("name", { length: 255 }).notNull(),
/** URL du logo (peut être vide pour utiliser le logo par défaut) */
logoUrl: text("logoUrl"),
/** Couleur principale (hex) */
primaryColor: varchar("primaryColor", { length: 7 }).default("#2563eb").notNull(),
/** Couleur de fond de l'en-tête (hex) */
headerBgColor: varchar("headerBgColor", { length: 7 }).default("#2563eb").notNull(),
/** Couleur du texte de l'en-tête (hex) */
headerTextColor: varchar("headerTextColor", { length: 7 }).default("#ffffff").notNull(),
/** Titre de l'en-tête */
headerTitle: varchar("headerTitle", { length: 255 }).default("Formation Manager Itinova").notNull(),
/** Texte du pied de page */
footerText: text("footerText"),
/** Actif ou non */
active: boolean("active").default(true).notNull(),
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
export type EmailTemplate = typeof emailTemplates.$inferSelect;
export type InsertEmailTemplate = typeof emailTemplates.$inferInsert;
/**
* Table de configuration SMTP/Email
* Stocke la configuration pour l'envoi d'emails (Resend, etc.)
*/
export const emailConfig = mysqlTable("emailConfig", {
id: int("id").autoincrement().primaryKey(),
/** Service d'envoi (resend, smtp) */
provider: varchar("provider", { length: 50 }).default("resend").notNull(),
/** Clé API Resend (chiffrée) */
apiKey: text("apiKey"),
/** 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: simulation ou production */
mode: mysqlEnum("mode", ["simulation", "production"]).default("simulation").notNull(),
/** Domaine vérifié (pour Resend) */
domainVerified: boolean("domainVerified").default(false).notNull(),
/** Actif ou non */
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;