diff --git a/.manus/db/db-query-1767798017521.json b/.manus/db/db-query-1767798017521.json new file mode 100644 index 0000000..1624295 --- /dev/null +++ b/.manus/db/db-query-1767798017521.json @@ -0,0 +1,13 @@ +{ + "query": "SHOW TABLES LIKE 'attestations';", + "command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute SHOW TABLES LIKE 'attestations';", + "rows": [ + { + "Tables_in_7PAT67UmWoxv8vwp8Bbcv6 (attestations)": "attestations" + } + ], + "messages": [], + "stdout": "Tables_in_7PAT67UmWoxv8vwp8Bbcv6 (attestations)\nattestations\n", + "stderr": "", + "execution_time_ms": 53 +} \ No newline at end of file diff --git a/client/src/App.tsx b/client/src/App.tsx index 561de3f..944af09 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -29,6 +29,7 @@ import AdminRappelsHistorique from "./pages/admin/AdminRappelsHistorique"; import AdminRappelsStats from "./pages/admin/AdminRappelsStats"; import AdminFormateurs from "./pages/admin/AdminFormateurs"; import AdminNotifications from "./pages/admin/AdminNotifications"; +import AdminAttestations from "./pages/admin/AdminAttestations"; import QuestionnaireReponse from "./pages/QuestionnaireReponse"; import Inscription from "./pages/Inscription"; import Login from "./pages/Login"; @@ -53,6 +54,7 @@ function Router() { + diff --git a/client/src/components/DashboardLayout.tsx b/client/src/components/DashboardLayout.tsx index b9026e7..bbbb23a 100644 --- a/client/src/components/DashboardLayout.tsx +++ b/client/src/components/DashboardLayout.tsx @@ -21,7 +21,7 @@ import { } from "@/components/ui/sidebar"; import { APP_LOGO, APP_TITLE, getLoginUrl } from "@/const"; import { useIsMobile } from "@/hooks/useMobile"; -import { LayoutDashboard, LogOut, PanelLeft, Users, GraduationCap, Calendar, CalendarDays, Bell, BarChart3, UserCog, Mail, Settings, TrendingUp, Building2, FileSpreadsheet, ClipboardList, ChevronDown, User } from "lucide-react"; +import { LayoutDashboard, LogOut, PanelLeft, Users, GraduationCap, Calendar, CalendarDays, Bell, BarChart3, UserCog, Mail, Settings, TrendingUp, Building2, FileSpreadsheet, ClipboardList, ChevronDown, User, FileText } from "lucide-react"; import { CSSProperties, useEffect, useRef, useState } from "react"; import { useLocation } from "wouter"; import { DashboardLayoutSkeleton } from './DashboardLayoutSkeleton'; @@ -57,6 +57,7 @@ const menuSections = [ { icon: Mail, label: "Templates d'emails", path: "/admin/email-templates" }, { icon: Settings, label: "Configuration SMTP", path: "/admin/email-config" }, { icon: Mail, label: "Notifications", path: "/admin/notifications" }, + { icon: FileText, label: "Attestations", path: "/admin/attestations" }, ] }, { diff --git a/client/src/pages/admin/AdminAttestations.tsx b/client/src/pages/admin/AdminAttestations.tsx new file mode 100644 index 0000000..33bbfa6 --- /dev/null +++ b/client/src/pages/admin/AdminAttestations.tsx @@ -0,0 +1,155 @@ +import { useState, useEffect } from "react"; +import { trpc } from "@/lib/trpc"; +import DashboardLayout from "@/components/DashboardLayout"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; +import { Label } from "@/components/ui/label"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { toast } from "sonner"; +import { FileText, Save } from "lucide-react"; + +export default function AdminAttestations() { + const { data: config, isLoading, refetch } = trpc.attestations.getConfig.useQuery(); + const updateConfig = trpc.attestations.updateConfig.useMutation(); + + const [formData, setFormData] = useState({ + nomSignataire: "", + fonctionSignataire: "", + texteAttestation: "", + }); + + // Mettre à jour le formulaire quand les données sont chargées + useEffect(() => { + if (config) { + setFormData({ + nomSignataire: config.nomSignataire || "", + fonctionSignataire: config.fonctionSignataire || "", + texteAttestation: config.texteAttestation || "", + }); + } + }, [config]); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + try { + await updateConfig.mutateAsync(formData); + toast.success("Configuration enregistrée avec succès"); + refetch(); + } catch (error) { + toast.error("Erreur lors de l'enregistrement"); + console.error(error); + } + }; + + if (isLoading) { + return ( + + + Chargement... + + + ); + } + + return ( + + + + + + Configuration des attestations + + Personnalisez le contenu et la signature des attestations de formation + + + + + + + + Informations du signataire + + Ces informations apparaîtront en bas de l'attestation + + + + + Nom du signataire + + setFormData({ ...formData, nomSignataire: e.target.value }) + } + placeholder="Ex: Jean Dupont" + /> + + + + Fonction du signataire + + setFormData({ ...formData, fonctionSignataire: e.target.value }) + } + placeholder="Ex: Directeur de la formation" + /> + + + + + + + Texte de l'attestation + + Personnalisez le texte principal de l'attestation. Utilisez les variables suivantes : + + {'{{nomComplet}}'} - Nom complet de l'apprenant + {'{{nomFormation}}'} - Nom de la formation + {'{{dateDebut}}'} - Date de début de la formation + {'{{dateFin}}'} - Date de fin de la formation + + + + + + setFormData({ ...formData, texteAttestation: e.target.value }) + } + placeholder="Nous attestons que {{nomComplet}} a suivi avec assiduité la formation "{{nomFormation}}" organisée du {{dateDebut}} au {{dateFin}}." + rows={6} + className="font-serif" + /> + + + + + { + if (config) { + setFormData({ + nomSignataire: config.nomSignataire || "", + fonctionSignataire: config.fonctionSignataire || "", + texteAttestation: config.texteAttestation || "", + }); + } + }} + > + Annuler + + + + {updateConfig.isPending ? "Enregistrement..." : "Enregistrer"} + + + + + + ); +} diff --git a/client/src/pages/formateur/FormateurSequence.tsx b/client/src/pages/formateur/FormateurSequence.tsx index 8796a87..159efa1 100644 --- a/client/src/pages/formateur/FormateurSequence.tsx +++ b/client/src/pages/formateur/FormateurSequence.tsx @@ -13,9 +13,48 @@ import { } from "@/components/ui/table"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { trpc } from "@/lib/trpc"; -import { Calendar, FileText, MapPin, Upload, Users } from "lucide-react"; +import { Calendar, FileText, MapPin, Upload, Users, Award } from "lucide-react"; import { useParams } from "wouter"; import { toast } from "sonner"; +import { useState } from "react"; + +function AttestationButton({ inscriptionId, present }: { inscriptionId: number; present: boolean }) { + const [isGenerating, setIsGenerating] = useState(false); + const genererAttestation = trpc.attestations.generer.useMutation(); + + const handleGenerer = async () => { + if (!present) { + toast.error("L'apprenant doit être marqué comme présent pour générer une attestation"); + return; + } + + setIsGenerating(true); + try { + const result = await genererAttestation.mutateAsync({ inscriptionId }); + if (result.success && result.attestation) { + toast.success(result.message || "Attestation générée avec succès"); + // Ouvrir le PDF dans un nouvel onglet + window.open(result.attestation.pdfUrl, "_blank"); + } + } catch (error: any) { + toast.error(error.message || "Erreur lors de la génération de l'attestation"); + } finally { + setIsGenerating(false); + } + }; + + return ( + + + {isGenerating ? "Génération..." : "Générer"} + + ); +} export default function FormateurSequence() { const { id } = useParams(); @@ -189,6 +228,7 @@ export default function FormateurSequence() { Établissement Statut Présent + Attestation @@ -224,6 +264,9 @@ export default function FormateurSequence() { } /> + + + ))} diff --git a/drizzle/meta/0024_snapshot.json b/drizzle/meta/0024_snapshot.json new file mode 100644 index 0000000..f936ae8 --- /dev/null +++ b/drizzle/meta/0024_snapshot.json @@ -0,0 +1,2028 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "ba0ad665-1f5c-44ab-ab8c-b98211f33717", + "prevId": "e0c120cb-533e-435d-a5d7-a6a6c58698cb", + "tables": { + "alertes": { + "name": "alertes", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "enum('taux_remplissage','seuil_inscriptions')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "condition": { + "name": "condition", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "valeurSeuil": { + "name": "valeurSeuil", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "codeEtablissement": { + "name": "codeEtablissement", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "emailsDestinataires": { + "name": "emailsDestinataires", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actif": { + "name": "actif", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "derniereVerification": { + "name": "derniereVerification", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dernierEnvoi": { + "name": "dernierEnvoi", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "alertes_id": { + "name": "alertes_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "apprenants": { + "name": "apprenants", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "prenom": { + "name": "prenom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "codeEtablissement": { + "name": "codeEtablissement", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fonction": { + "name": "fonction", + "type": "enum('directeur','chef_service','autre')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "apprenants_id": { + "name": "apprenants_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "apprenants_email_unique": { + "name": "apprenants_email_unique", + "columns": [ + "email" + ] + } + }, + "checkConstraint": {} + }, + "attestations": { + "name": "attestations", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "inscriptionId": { + "name": "inscriptionId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "s3Key": { + "name": "s3Key", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pdfUrl": { + "name": "pdfUrl", + "type": "varchar(1000)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateGeneration": { + "name": "dateGeneration", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "emailEnvoye": { + "name": "emailEnvoye", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "dateEnvoiEmail": { + "name": "dateEnvoiEmail", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "attestations_id": { + "name": "attestations_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "configAttestation": { + "name": "configAttestation", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "logoS3Key": { + "name": "logoS3Key", + "type": "varchar(500)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logoUrl": { + "name": "logoUrl", + "type": "varchar(1000)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "signatureS3Key": { + "name": "signatureS3Key", + "type": "varchar(500)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "signatureUrl": { + "name": "signatureUrl", + "type": "varchar(1000)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "nomSignataire": { + "name": "nomSignataire", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fonctionSignataire": { + "name": "fonctionSignataire", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "texteAttestation": { + "name": "texteAttestation", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "configAttestation_id": { + "name": "configAttestation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "datesFormation": { + "name": "datesFormation", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateDebut": { + "name": "dateDebut", + "type": "datetime", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateFin": { + "name": "dateFin", + "type": "datetime", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ordre": { + "name": "ordre", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "datesFormation_id": { + "name": "datesFormation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "emailConfig": { + "name": "emailConfig", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "provider": { + "name": "provider", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'resend'" + }, + "apiKey": { + "name": "apiKey", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fromEmail": { + "name": "fromEmail", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fromName": { + "name": "fromName", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Formation Manager Itinova'" + }, + "mode": { + "name": "mode", + "type": "enum('simulation','production')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'simulation'" + }, + "domainVerified": { + "name": "domainVerified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "smtpHost": { + "name": "smtpHost", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "smtpPort": { + "name": "smtpPort", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "smtpSecure": { + "name": "smtpSecure", + "type": "enum('none','tls','ssl')", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'tls'" + }, + "smtpUser": { + "name": "smtpUser", + "type": "varchar(320)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "smtpPassword": { + "name": "smtpPassword", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "emailConfig_id": { + "name": "emailConfig_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "emailTemplates": { + "name": "emailTemplates", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "logoUrl": { + "name": "logoUrl", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "primaryColor": { + "name": "primaryColor", + "type": "varchar(7)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#2563eb'" + }, + "headerBgColor": { + "name": "headerBgColor", + "type": "varchar(7)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#2563eb'" + }, + "headerTextColor": { + "name": "headerTextColor", + "type": "varchar(7)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#ffffff'" + }, + "headerTitle": { + "name": "headerTitle", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Formation Manager Itinova'" + }, + "footerText": { + "name": "footerText", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bodyContent": { + "name": "bodyContent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "emailTemplates_id": { + "name": "emailTemplates_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "emailTemplates_type_unique": { + "name": "emailTemplates_type_unique", + "columns": [ + "type" + ] + } + }, + "checkConstraint": {} + }, + "envoisQuestionnaires": { + "name": "envoisQuestionnaires", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "questionnaireId": { + "name": "questionnaireId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateEnvoi": { + "name": "dateEnvoi", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "token": { + "name": "token", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateReponse": { + "name": "dateReponse", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "envoisQuestionnaires_id": { + "name": "envoisQuestionnaires_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "envoisQuestionnaires_token_unique": { + "name": "envoisQuestionnaires_token_unique", + "columns": [ + "token" + ] + } + }, + "checkConstraint": {} + }, + "formateurs": { + "name": "formateurs", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(320)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "formateurs_id": { + "name": "formateurs_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "formations": { + "name": "formations", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "lienUnique": { + "name": "lienUnique", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actif": { + "name": "actif", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "formations_id": { + "name": "formations_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "formations_lienUnique_unique": { + "name": "formations_lienUnique_unique", + "columns": [ + "lienUnique" + ] + } + }, + "checkConstraint": {} + }, + "inscriptions": { + "name": "inscriptions", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "statut": { + "name": "statut", + "type": "enum('confirmee','liste_attente','annulee')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateInscription": { + "name": "dateInscription", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "inscriptions_id": { + "name": "inscriptions_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "logsNotifications": { + "name": "logsNotifications", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "type": { + "name": "type", + "type": "enum('remerciement','notification_formateur_inscription','notification_formateur_annulation','alerte_capacite','notification_liste_attente')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "formateurId": { + "name": "formateurId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "emailDestinataire": { + "name": "emailDestinataire", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sujet": { + "name": "sujet", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateEnvoi": { + "name": "dateEnvoi", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "statut": { + "name": "statut", + "type": "enum('success','failed')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "messageErreur": { + "name": "messageErreur", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "logsNotifications_id": { + "name": "logsNotifications_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "logsRappels": { + "name": "logsRappels", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "rappelId": { + "name": "rappelId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "emailDestinataire": { + "name": "emailDestinataire", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "typeRappel": { + "name": "typeRappel", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateEnvoi": { + "name": "dateEnvoi", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "statut": { + "name": "statut", + "type": "enum('success','failed')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "messageErreur": { + "name": "messageErreur", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dateSequence": { + "name": "dateSequence", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nbTentatives": { + "name": "nbTentatives", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "prochainEssai": { + "name": "prochainEssai", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "logsRappels_id": { + "name": "logsRappels_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "passwordResetTokens": { + "name": "passwordResetTokens", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "userId": { + "name": "userId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "used": { + "name": "used", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "passwordResetTokens_id": { + "name": "passwordResetTokens_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "passwordResetTokens_token_unique": { + "name": "passwordResetTokens_token_unique", + "columns": [ + "token" + ] + } + }, + "checkConstraint": {} + }, + "questionnaires": { + "name": "questionnaires", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "enum('satisfaction','evaluation_pre','evaluation_post')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "formationId": { + "name": "formationId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actif": { + "name": "actif", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "envoiAutomatique": { + "name": "envoiAutomatique", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "delaiEnvoiJours": { + "name": "delaiEnvoiJours", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "questionnaires_id": { + "name": "questionnaires_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "questions": { + "name": "questions", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "questionnaireId": { + "name": "questionnaireId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ordre": { + "name": "ordre", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "texte": { + "name": "texte", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "typeQuestion": { + "name": "typeQuestion", + "type": "enum('choix_multiple','echelle','texte_libre','oui_non')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "echelleMin": { + "name": "echelleMin", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "echelleMax": { + "name": "echelleMax", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "echelleLabelMin": { + "name": "echelleLabelMin", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "echelleLabelMax": { + "name": "echelleLabelMax", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "obligatoire": { + "name": "obligatoire", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "questions_id": { + "name": "questions_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "rappels": { + "name": "rappels", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "templateType": { + "name": "templateType", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "joursAvant": { + "name": "joursAvant", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "heureEnvoi": { + "name": "heureEnvoi", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'09:00'" + }, + "actif": { + "name": "actif", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "derniereExecution": { + "name": "derniereExecution", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "rappels_id": { + "name": "rappels_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "reponsesQuestionnaires": { + "name": "reponsesQuestionnaires", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "questionnaireId": { + "name": "questionnaireId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateReponse": { + "name": "dateReponse", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "complete": { + "name": "complete", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "reponsesQuestionnaires_id": { + "name": "reponsesQuestionnaires_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "reponsesQuestions": { + "name": "reponsesQuestions", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "reponseQuestionnaireId": { + "name": "reponseQuestionnaireId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "questionId": { + "name": "questionId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reponseNumerique": { + "name": "reponseNumerique", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reponseTexte": { + "name": "reponseTexte", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "reponsesQuestions_id": { + "name": "reponsesQuestions_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "sequences": { + "name": "sequences", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "formationId": { + "name": "formationId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "lieu": { + "name": "lieu", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "publicCible": { + "name": "publicCible", + "type": "enum('directeur','chef_service','tous','autre')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "formateurId": { + "name": "formateurId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "capaciteMax": { + "name": "capaciteMax", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 12 + }, + "dateBlocage": { + "name": "dateBlocage", + "type": "datetime", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "statut": { + "name": "statut", + "type": "enum('ouverte','bloquee','terminee')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'ouverte'" + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "sequences_id": { + "name": "sequences_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "supportsFormation": { + "name": "supportsFormation", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "formateurId": { + "name": "formateurId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nomFichier": { + "name": "nomFichier", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "typeFichier": { + "name": "typeFichier", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tailleFichier": { + "name": "tailleFichier", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "urlFichier": { + "name": "urlFichier", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "s3Key": { + "name": "s3Key", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "supportsFormation_id": { + "name": "supportsFormation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "openId": { + "name": "openId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(320)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "loginMethod": { + "name": "loginMethod", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "enum('user','admin')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'user'" + }, + "isActive": { + "name": "isActive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + }, + "lastSignedIn": { + "name": "lastSignedIn", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "users_openId_unique": { + "name": "users_openId_unique", + "columns": [ + "openId" + ] + }, + "users_username_unique": { + "name": "users_username_unique", + "columns": [ + "username" + ] + } + }, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/0025_snapshot.json b/drizzle/meta/0025_snapshot.json new file mode 100644 index 0000000..6466c05 --- /dev/null +++ b/drizzle/meta/0025_snapshot.json @@ -0,0 +1,1848 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "7fe81e74-8e26-4a83-9438-f7b48e0f9373", + "prevId": "ba0ad665-1f5c-44ab-ab8c-b98211f33717", + "tables": { + "alertes": { + "name": "alertes", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "enum('taux_remplissage','seuil_inscriptions')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "condition": { + "name": "condition", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "valeurSeuil": { + "name": "valeurSeuil", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "codeEtablissement": { + "name": "codeEtablissement", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "emailsDestinataires": { + "name": "emailsDestinataires", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actif": { + "name": "actif", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "derniereVerification": { + "name": "derniereVerification", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dernierEnvoi": { + "name": "dernierEnvoi", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "alertes_id": { + "name": "alertes_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "apprenants": { + "name": "apprenants", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "prenom": { + "name": "prenom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "codeEtablissement": { + "name": "codeEtablissement", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fonction": { + "name": "fonction", + "type": "enum('directeur','chef_service','autre')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "apprenants_id": { + "name": "apprenants_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "apprenants_email_unique": { + "name": "apprenants_email_unique", + "columns": [ + "email" + ] + } + }, + "checkConstraint": {} + }, + "datesFormation": { + "name": "datesFormation", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateDebut": { + "name": "dateDebut", + "type": "datetime", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateFin": { + "name": "dateFin", + "type": "datetime", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ordre": { + "name": "ordre", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "datesFormation_id": { + "name": "datesFormation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "emailConfig": { + "name": "emailConfig", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "provider": { + "name": "provider", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'resend'" + }, + "apiKey": { + "name": "apiKey", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fromEmail": { + "name": "fromEmail", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fromName": { + "name": "fromName", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Formation Manager Itinova'" + }, + "mode": { + "name": "mode", + "type": "enum('simulation','production')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'simulation'" + }, + "domainVerified": { + "name": "domainVerified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "smtpHost": { + "name": "smtpHost", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "smtpPort": { + "name": "smtpPort", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "smtpSecure": { + "name": "smtpSecure", + "type": "enum('none','tls','ssl')", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'tls'" + }, + "smtpUser": { + "name": "smtpUser", + "type": "varchar(320)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "smtpPassword": { + "name": "smtpPassword", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "emailConfig_id": { + "name": "emailConfig_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "emailTemplates": { + "name": "emailTemplates", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "logoUrl": { + "name": "logoUrl", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "primaryColor": { + "name": "primaryColor", + "type": "varchar(7)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#2563eb'" + }, + "headerBgColor": { + "name": "headerBgColor", + "type": "varchar(7)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#2563eb'" + }, + "headerTextColor": { + "name": "headerTextColor", + "type": "varchar(7)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#ffffff'" + }, + "headerTitle": { + "name": "headerTitle", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Formation Manager Itinova'" + }, + "footerText": { + "name": "footerText", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bodyContent": { + "name": "bodyContent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "emailTemplates_id": { + "name": "emailTemplates_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "emailTemplates_type_unique": { + "name": "emailTemplates_type_unique", + "columns": [ + "type" + ] + } + }, + "checkConstraint": {} + }, + "envoisQuestionnaires": { + "name": "envoisQuestionnaires", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "questionnaireId": { + "name": "questionnaireId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateEnvoi": { + "name": "dateEnvoi", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "token": { + "name": "token", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateReponse": { + "name": "dateReponse", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "envoisQuestionnaires_id": { + "name": "envoisQuestionnaires_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "envoisQuestionnaires_token_unique": { + "name": "envoisQuestionnaires_token_unique", + "columns": [ + "token" + ] + } + }, + "checkConstraint": {} + }, + "formateurs": { + "name": "formateurs", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(320)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "formateurs_id": { + "name": "formateurs_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "formations": { + "name": "formations", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "lienUnique": { + "name": "lienUnique", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actif": { + "name": "actif", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "formations_id": { + "name": "formations_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "formations_lienUnique_unique": { + "name": "formations_lienUnique_unique", + "columns": [ + "lienUnique" + ] + } + }, + "checkConstraint": {} + }, + "inscriptions": { + "name": "inscriptions", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "statut": { + "name": "statut", + "type": "enum('confirmee','liste_attente','annulee')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateInscription": { + "name": "dateInscription", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "inscriptions_id": { + "name": "inscriptions_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "logsNotifications": { + "name": "logsNotifications", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "type": { + "name": "type", + "type": "enum('remerciement','notification_formateur_inscription','notification_formateur_annulation','alerte_capacite','notification_liste_attente')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "formateurId": { + "name": "formateurId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "emailDestinataire": { + "name": "emailDestinataire", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sujet": { + "name": "sujet", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateEnvoi": { + "name": "dateEnvoi", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "statut": { + "name": "statut", + "type": "enum('success','failed')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "messageErreur": { + "name": "messageErreur", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "logsNotifications_id": { + "name": "logsNotifications_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "logsRappels": { + "name": "logsRappels", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "rappelId": { + "name": "rappelId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "emailDestinataire": { + "name": "emailDestinataire", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "typeRappel": { + "name": "typeRappel", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateEnvoi": { + "name": "dateEnvoi", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "statut": { + "name": "statut", + "type": "enum('success','failed')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "messageErreur": { + "name": "messageErreur", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dateSequence": { + "name": "dateSequence", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nbTentatives": { + "name": "nbTentatives", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "prochainEssai": { + "name": "prochainEssai", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "logsRappels_id": { + "name": "logsRappels_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "passwordResetTokens": { + "name": "passwordResetTokens", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "userId": { + "name": "userId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "used": { + "name": "used", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "passwordResetTokens_id": { + "name": "passwordResetTokens_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "passwordResetTokens_token_unique": { + "name": "passwordResetTokens_token_unique", + "columns": [ + "token" + ] + } + }, + "checkConstraint": {} + }, + "questionnaires": { + "name": "questionnaires", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "enum('satisfaction','evaluation_pre','evaluation_post')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "formationId": { + "name": "formationId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actif": { + "name": "actif", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "envoiAutomatique": { + "name": "envoiAutomatique", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "delaiEnvoiJours": { + "name": "delaiEnvoiJours", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "questionnaires_id": { + "name": "questionnaires_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "questions": { + "name": "questions", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "questionnaireId": { + "name": "questionnaireId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ordre": { + "name": "ordre", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "texte": { + "name": "texte", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "typeQuestion": { + "name": "typeQuestion", + "type": "enum('choix_multiple','echelle','texte_libre','oui_non')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "echelleMin": { + "name": "echelleMin", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "echelleMax": { + "name": "echelleMax", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "echelleLabelMin": { + "name": "echelleLabelMin", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "echelleLabelMax": { + "name": "echelleLabelMax", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "obligatoire": { + "name": "obligatoire", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "questions_id": { + "name": "questions_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "rappels": { + "name": "rappels", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "templateType": { + "name": "templateType", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "joursAvant": { + "name": "joursAvant", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "heureEnvoi": { + "name": "heureEnvoi", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'09:00'" + }, + "actif": { + "name": "actif", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "derniereExecution": { + "name": "derniereExecution", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "rappels_id": { + "name": "rappels_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "reponsesQuestionnaires": { + "name": "reponsesQuestionnaires", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "questionnaireId": { + "name": "questionnaireId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateReponse": { + "name": "dateReponse", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "complete": { + "name": "complete", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "reponsesQuestionnaires_id": { + "name": "reponsesQuestionnaires_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "reponsesQuestions": { + "name": "reponsesQuestions", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "reponseQuestionnaireId": { + "name": "reponseQuestionnaireId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "questionId": { + "name": "questionId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reponseNumerique": { + "name": "reponseNumerique", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reponseTexte": { + "name": "reponseTexte", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "reponsesQuestions_id": { + "name": "reponsesQuestions_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "sequences": { + "name": "sequences", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "formationId": { + "name": "formationId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "lieu": { + "name": "lieu", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "publicCible": { + "name": "publicCible", + "type": "enum('directeur','chef_service','tous','autre')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "formateurId": { + "name": "formateurId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "capaciteMax": { + "name": "capaciteMax", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 12 + }, + "dateBlocage": { + "name": "dateBlocage", + "type": "datetime", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "statut": { + "name": "statut", + "type": "enum('ouverte','bloquee','terminee')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'ouverte'" + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "sequences_id": { + "name": "sequences_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "supportsFormation": { + "name": "supportsFormation", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "formateurId": { + "name": "formateurId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nomFichier": { + "name": "nomFichier", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "typeFichier": { + "name": "typeFichier", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tailleFichier": { + "name": "tailleFichier", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "urlFichier": { + "name": "urlFichier", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "s3Key": { + "name": "s3Key", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "supportsFormation_id": { + "name": "supportsFormation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "openId": { + "name": "openId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(320)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "loginMethod": { + "name": "loginMethod", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "enum('user','admin')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'user'" + }, + "isActive": { + "name": "isActive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + }, + "lastSignedIn": { + "name": "lastSignedIn", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "users_openId_unique": { + "name": "users_openId_unique", + "columns": [ + "openId" + ] + }, + "users_username_unique": { + "name": "users_username_unique", + "columns": [ + "username" + ] + } + }, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/0026_snapshot.json b/drizzle/meta/0026_snapshot.json new file mode 100644 index 0000000..f94bb4b --- /dev/null +++ b/drizzle/meta/0026_snapshot.json @@ -0,0 +1,2028 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "f0782a6b-0d76-4702-9f2d-ea3f55d57977", + "prevId": "7fe81e74-8e26-4a83-9438-f7b48e0f9373", + "tables": { + "alertes": { + "name": "alertes", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "enum('taux_remplissage','seuil_inscriptions')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "condition": { + "name": "condition", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "valeurSeuil": { + "name": "valeurSeuil", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "codeEtablissement": { + "name": "codeEtablissement", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "emailsDestinataires": { + "name": "emailsDestinataires", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actif": { + "name": "actif", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "derniereVerification": { + "name": "derniereVerification", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dernierEnvoi": { + "name": "dernierEnvoi", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "alertes_id": { + "name": "alertes_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "apprenants": { + "name": "apprenants", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "prenom": { + "name": "prenom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "codeEtablissement": { + "name": "codeEtablissement", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fonction": { + "name": "fonction", + "type": "enum('directeur','chef_service','autre')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "apprenants_id": { + "name": "apprenants_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "apprenants_email_unique": { + "name": "apprenants_email_unique", + "columns": [ + "email" + ] + } + }, + "checkConstraint": {} + }, + "attestations": { + "name": "attestations", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "inscriptionId": { + "name": "inscriptionId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "s3Key": { + "name": "s3Key", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pdfUrl": { + "name": "pdfUrl", + "type": "varchar(1000)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateGeneration": { + "name": "dateGeneration", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "emailEnvoye": { + "name": "emailEnvoye", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "dateEnvoiEmail": { + "name": "dateEnvoiEmail", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "attestations_id": { + "name": "attestations_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "configAttestation": { + "name": "configAttestation", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "logoS3Key": { + "name": "logoS3Key", + "type": "varchar(500)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logoUrl": { + "name": "logoUrl", + "type": "varchar(1000)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "signatureS3Key": { + "name": "signatureS3Key", + "type": "varchar(500)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "signatureUrl": { + "name": "signatureUrl", + "type": "varchar(1000)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "nomSignataire": { + "name": "nomSignataire", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fonctionSignataire": { + "name": "fonctionSignataire", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "texteAttestation": { + "name": "texteAttestation", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "configAttestation_id": { + "name": "configAttestation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "datesFormation": { + "name": "datesFormation", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateDebut": { + "name": "dateDebut", + "type": "datetime", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateFin": { + "name": "dateFin", + "type": "datetime", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ordre": { + "name": "ordre", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "datesFormation_id": { + "name": "datesFormation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "emailConfig": { + "name": "emailConfig", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "provider": { + "name": "provider", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'resend'" + }, + "apiKey": { + "name": "apiKey", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fromEmail": { + "name": "fromEmail", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fromName": { + "name": "fromName", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Formation Manager Itinova'" + }, + "mode": { + "name": "mode", + "type": "enum('simulation','production')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'simulation'" + }, + "domainVerified": { + "name": "domainVerified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "smtpHost": { + "name": "smtpHost", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "smtpPort": { + "name": "smtpPort", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "smtpSecure": { + "name": "smtpSecure", + "type": "enum('none','tls','ssl')", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'tls'" + }, + "smtpUser": { + "name": "smtpUser", + "type": "varchar(320)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "smtpPassword": { + "name": "smtpPassword", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "emailConfig_id": { + "name": "emailConfig_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "emailTemplates": { + "name": "emailTemplates", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "logoUrl": { + "name": "logoUrl", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "primaryColor": { + "name": "primaryColor", + "type": "varchar(7)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#2563eb'" + }, + "headerBgColor": { + "name": "headerBgColor", + "type": "varchar(7)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#2563eb'" + }, + "headerTextColor": { + "name": "headerTextColor", + "type": "varchar(7)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#ffffff'" + }, + "headerTitle": { + "name": "headerTitle", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Formation Manager Itinova'" + }, + "footerText": { + "name": "footerText", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bodyContent": { + "name": "bodyContent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "emailTemplates_id": { + "name": "emailTemplates_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "emailTemplates_type_unique": { + "name": "emailTemplates_type_unique", + "columns": [ + "type" + ] + } + }, + "checkConstraint": {} + }, + "envoisQuestionnaires": { + "name": "envoisQuestionnaires", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "questionnaireId": { + "name": "questionnaireId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateEnvoi": { + "name": "dateEnvoi", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "token": { + "name": "token", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateReponse": { + "name": "dateReponse", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "envoisQuestionnaires_id": { + "name": "envoisQuestionnaires_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "envoisQuestionnaires_token_unique": { + "name": "envoisQuestionnaires_token_unique", + "columns": [ + "token" + ] + } + }, + "checkConstraint": {} + }, + "formateurs": { + "name": "formateurs", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(320)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "formateurs_id": { + "name": "formateurs_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "formations": { + "name": "formations", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "lienUnique": { + "name": "lienUnique", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actif": { + "name": "actif", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "formations_id": { + "name": "formations_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "formations_lienUnique_unique": { + "name": "formations_lienUnique_unique", + "columns": [ + "lienUnique" + ] + } + }, + "checkConstraint": {} + }, + "inscriptions": { + "name": "inscriptions", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "statut": { + "name": "statut", + "type": "enum('confirmee','liste_attente','annulee')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateInscription": { + "name": "dateInscription", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "inscriptions_id": { + "name": "inscriptions_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "logsNotifications": { + "name": "logsNotifications", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "type": { + "name": "type", + "type": "enum('remerciement','notification_formateur_inscription','notification_formateur_annulation','alerte_capacite','notification_liste_attente')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "formateurId": { + "name": "formateurId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "emailDestinataire": { + "name": "emailDestinataire", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sujet": { + "name": "sujet", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateEnvoi": { + "name": "dateEnvoi", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "statut": { + "name": "statut", + "type": "enum('success','failed')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "messageErreur": { + "name": "messageErreur", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "logsNotifications_id": { + "name": "logsNotifications_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "logsRappels": { + "name": "logsRappels", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "rappelId": { + "name": "rappelId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "emailDestinataire": { + "name": "emailDestinataire", + "type": "varchar(320)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "typeRappel": { + "name": "typeRappel", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateEnvoi": { + "name": "dateEnvoi", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "statut": { + "name": "statut", + "type": "enum('success','failed')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "messageErreur": { + "name": "messageErreur", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dateSequence": { + "name": "dateSequence", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nbTentatives": { + "name": "nbTentatives", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "prochainEssai": { + "name": "prochainEssai", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "logsRappels_id": { + "name": "logsRappels_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "passwordResetTokens": { + "name": "passwordResetTokens", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "userId": { + "name": "userId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiresAt": { + "name": "expiresAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "used": { + "name": "used", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "passwordResetTokens_id": { + "name": "passwordResetTokens_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "passwordResetTokens_token_unique": { + "name": "passwordResetTokens_token_unique", + "columns": [ + "token" + ] + } + }, + "checkConstraint": {} + }, + "questionnaires": { + "name": "questionnaires", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "enum('satisfaction','evaluation_pre','evaluation_post')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "formationId": { + "name": "formationId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actif": { + "name": "actif", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "envoiAutomatique": { + "name": "envoiAutomatique", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "delaiEnvoiJours": { + "name": "delaiEnvoiJours", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "questionnaires_id": { + "name": "questionnaires_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "questions": { + "name": "questions", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "questionnaireId": { + "name": "questionnaireId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ordre": { + "name": "ordre", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "texte": { + "name": "texte", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "typeQuestion": { + "name": "typeQuestion", + "type": "enum('choix_multiple','echelle','texte_libre','oui_non')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "echelleMin": { + "name": "echelleMin", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "echelleMax": { + "name": "echelleMax", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "echelleLabelMin": { + "name": "echelleLabelMin", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "echelleLabelMax": { + "name": "echelleLabelMax", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "obligatoire": { + "name": "obligatoire", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "questions_id": { + "name": "questions_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "rappels": { + "name": "rappels", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "templateType": { + "name": "templateType", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "joursAvant": { + "name": "joursAvant", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "heureEnvoi": { + "name": "heureEnvoi", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'09:00'" + }, + "actif": { + "name": "actif", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "derniereExecution": { + "name": "derniereExecution", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "rappels_id": { + "name": "rappels_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "reponsesQuestionnaires": { + "name": "reponsesQuestionnaires", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "questionnaireId": { + "name": "questionnaireId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apprenantId": { + "name": "apprenantId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dateReponse": { + "name": "dateReponse", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "complete": { + "name": "complete", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "reponsesQuestionnaires_id": { + "name": "reponsesQuestionnaires_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "reponsesQuestions": { + "name": "reponsesQuestions", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "reponseQuestionnaireId": { + "name": "reponseQuestionnaireId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "questionId": { + "name": "questionId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reponseNumerique": { + "name": "reponseNumerique", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reponseTexte": { + "name": "reponseTexte", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "reponsesQuestions_id": { + "name": "reponsesQuestions_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "sequences": { + "name": "sequences", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "formationId": { + "name": "formationId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nom": { + "name": "nom", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "lieu": { + "name": "lieu", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "publicCible": { + "name": "publicCible", + "type": "enum('directeur','chef_service','tous','autre')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "formateurId": { + "name": "formateurId", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "capaciteMax": { + "name": "capaciteMax", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 12 + }, + "dateBlocage": { + "name": "dateBlocage", + "type": "datetime", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "statut": { + "name": "statut", + "type": "enum('ouverte','bloquee','terminee')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'ouverte'" + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "sequences_id": { + "name": "sequences_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "supportsFormation": { + "name": "supportsFormation", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "sequenceId": { + "name": "sequenceId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "formateurId": { + "name": "formateurId", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nomFichier": { + "name": "nomFichier", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "typeFichier": { + "name": "typeFichier", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tailleFichier": { + "name": "tailleFichier", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "urlFichier": { + "name": "urlFichier", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "s3Key": { + "name": "s3Key", + "type": "varchar(500)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "supportsFormation_id": { + "name": "supportsFormation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "openId": { + "name": "openId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(320)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "loginMethod": { + "name": "loginMethod", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "enum('user','admin')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'user'" + }, + "isActive": { + "name": "isActive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "onUpdate": true, + "default": "(now())" + }, + "lastSignedIn": { + "name": "lastSignedIn", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "users_openId_unique": { + "name": "users_openId_unique", + "columns": [ + "openId" + ] + }, + "users_username_unique": { + "name": "users_username_unique", + "columns": [ + "username" + ] + } + }, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 15855a7..8c4ca6c 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -169,6 +169,27 @@ "when": 1765830109012, "tag": "0023_jittery_gorgon", "breakpoints": true + }, + { + "idx": 24, + "version": "5", + "when": 1767770858914, + "tag": "0024_panoramic_goliath", + "breakpoints": true + }, + { + "idx": 25, + "version": "5", + "when": 1767795835957, + "tag": "0025_curious_wrecker", + "breakpoints": true + }, + { + "idx": 26, + "version": "5", + "when": 1767798385842, + "tag": "0026_panoramic_king_bedlam", + "breakpoints": true } ] } \ No newline at end of file diff --git a/drizzle/schema.ts b/drizzle/schema.ts index 844c290..b8f3083 100644 --- a/drizzle/schema.ts +++ b/drizzle/schema.ts @@ -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; diff --git a/package.json b/package.json index f29cb81..f053d3a 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "@trpc/client": "^11.6.0", "@trpc/react-query": "^11.6.0", "@trpc/server": "^11.6.0", + "@types/pdfkit": "^0.17.4", "axios": "^1.12.0", "bcryptjs": "^3.0.3", "class-variance-authority": "^0.7.1", @@ -74,6 +75,7 @@ "next-themes": "^0.4.6", "nodemailer": "^7.0.11", "openai": "^4.67.0", + "pdfkit": "^0.17.2", "react": "^19.1.1", "react-day-picker": "^9.11.1", "react-dom": "^19.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 138e36a..0018611 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -127,6 +127,9 @@ importers: '@trpc/server': specifier: ^11.6.0 version: 11.6.0(typescript@5.9.3) + '@types/pdfkit': + specifier: ^0.17.4 + version: 0.17.4 axios: specifier: ^1.12.0 version: 1.12.2 @@ -199,6 +202,9 @@ importers: openai: specifier: ^4.67.0 version: 4.104.0(zod@4.1.12) + pdfkit: + specifier: ^0.17.2 + version: 0.17.2 react: specifier: ^19.1.1 version: 19.2.0 @@ -2294,6 +2300,9 @@ packages: resolution: {integrity: sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==} engines: {node: '>=18.0.0'} + '@swc/helpers@0.5.18': + resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} + '@tailwindcss/node@4.1.14': resolution: {integrity: sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==} @@ -2761,6 +2770,9 @@ packages: '@types/pako@2.0.4': resolution: {integrity: sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==} + '@types/pdfkit@0.17.4': + resolution: {integrity: sha512-odAmVuuguRxKh1X4pbMrJMp8ecwNqHRw6lweupvzK+wuyNmi6wzlUlGVZ9EqMvp3Bs2+L9Ty0sRlrvKL+gsQZg==} + '@types/qs@6.14.0': resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} @@ -2917,6 +2929,10 @@ packages: resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==} engines: {node: '>= 0.6.0'} + base64-js@0.0.8: + resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==} + engines: {node: '>= 0.4'} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -2954,6 +2970,9 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brotli@1.3.3: + resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==} + browserslist@4.26.3: resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -3047,6 +3066,10 @@ packages: class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -3139,6 +3162,9 @@ packages: crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + css-line-break@2.1.0: resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==} @@ -3375,6 +3401,9 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dfa@1.2.0: + resolution: {integrity: sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==} + dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} @@ -3668,6 +3697,9 @@ packages: debug: optional: true + fontkit@2.0.4: + resolution: {integrity: sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==} + form-data-encoder@1.7.2: resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} @@ -3916,6 +3948,9 @@ packages: jose@6.1.0: resolution: {integrity: sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==} + jpeg-exif@1.1.4: + resolution: {integrity: sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -4041,6 +4076,9 @@ packages: resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} engines: {node: '>= 12.0.0'} + linebreak@1.1.0: + resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==} + linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} @@ -4472,6 +4510,9 @@ packages: package-manager-detector@1.5.0: resolution: {integrity: sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw==} + pako@0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} @@ -4508,6 +4549,9 @@ packages: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} + pdfkit@0.17.2: + resolution: {integrity: sha512-UnwF5fXy08f0dnp4jchFYAROKMNTaPqb/xgR8GtCzIcqoTnbOqtp3bwKvO4688oHI6vzEEs8Q6vqqEnC5IUELw==} + performance-now@2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} @@ -4524,6 +4568,9 @@ packages: pkg-types@2.3.0: resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + png-js@1.0.0: + resolution: {integrity: sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==} + pnpm@10.18.0: resolution: {integrity: sha512-6AT4ifHOzEDVctsITuw+SIFzn43sacD/ENLRvv+aTjCTg7ontbdQBZ1/TBSVNbbNDSyx7Trrc5I5pChKaPQM+g==} engines: {node: '>=18.12'} @@ -4798,6 +4845,9 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + restructure@3.0.2: + resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==} + rgbcolor@1.0.1: resolution: {integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==} engines: {node: '>= 0.8.15'} @@ -4990,6 +5040,9 @@ packages: text-segmentation@1.0.3: resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==} + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -5074,6 +5127,12 @@ packages: undici-types@7.14.0: resolution: {integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==} + unicode-properties@1.4.1: + resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} + + unicode-trie@2.0.0: + resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} + unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -7981,6 +8040,10 @@ snapshots: dependencies: tslib: 2.8.1 + '@swc/helpers@0.5.18': + dependencies: + tslib: 2.8.1 + '@tailwindcss/node@4.1.14': dependencies: '@jridgewell/remapping': 2.3.5 @@ -8500,6 +8563,10 @@ snapshots: '@types/pako@2.0.4': {} + '@types/pdfkit@0.17.4': + dependencies: + '@types/node': 24.7.0 + '@types/qs@6.14.0': {} '@types/raf@3.4.3': @@ -8689,6 +8756,8 @@ snapshots: base64-arraybuffer@1.0.2: optional: true + base64-js@0.0.8: {} + base64-js@1.5.1: {} baseline-browser-mapping@2.8.12: {} @@ -8738,6 +8807,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brotli@1.3.3: + dependencies: + base64-js: 1.5.1 + browserslist@4.26.3: dependencies: baseline-browser-mapping: 2.8.12 @@ -8838,6 +8911,8 @@ snapshots: dependencies: clsx: 2.1.1 + clone@2.1.2: {} + clsx@2.1.1: {} cmdk@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): @@ -8917,6 +8992,8 @@ snapshots: crelt@1.0.6: {} + crypto-js@4.2.0: {} + css-line-break@2.1.0: dependencies: utrie: 1.0.2 @@ -9154,6 +9231,8 @@ snapshots: dependencies: dequal: 2.0.3 + dfa@1.2.0: {} + dom-helpers@5.2.1: dependencies: '@babel/runtime': 7.28.4 @@ -9444,6 +9523,18 @@ snapshots: follow-redirects@1.15.11: {} + fontkit@2.0.4: + dependencies: + '@swc/helpers': 0.5.18 + brotli: 1.3.3 + clone: 2.1.2 + dfa: 1.2.0 + fast-deep-equal: 3.1.3 + restructure: 3.0.2 + tiny-inflate: 1.0.3 + unicode-properties: 1.4.1 + unicode-trie: 2.0.0 + form-data-encoder@1.7.2: {} form-data@4.0.4: @@ -9752,6 +9843,8 @@ snapshots: jose@6.1.0: {} + jpeg-exif@1.1.4: {} + js-tokens@4.0.0: {} jsesc@3.1.0: {} @@ -9877,6 +9970,11 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.1 lightningcss-win32-x64-msvc: 1.30.1 + linebreak@1.1.0: + dependencies: + base64-js: 0.0.8 + unicode-trie: 2.0.0 + linkify-it@5.0.0: dependencies: uc.micro: 2.1.0 @@ -10503,6 +10601,8 @@ snapshots: package-manager-detector@1.5.0: {} + pako@0.2.9: {} + pako@1.0.11: {} pako@2.1.0: {} @@ -10535,6 +10635,14 @@ snapshots: pathval@2.0.1: {} + pdfkit@0.17.2: + dependencies: + crypto-js: 4.2.0 + fontkit: 2.0.4 + jpeg-exif: 1.1.4 + linebreak: 1.1.0 + png-js: 1.0.0 + performance-now@2.1.0: optional: true @@ -10554,6 +10662,8 @@ snapshots: exsolve: 1.0.7 pathe: 2.0.3 + png-js@1.0.0: {} + pnpm@10.18.0: {} points-on-curve@0.2.0: {} @@ -10928,6 +11038,8 @@ snapshots: resolve-pkg-maps@1.0.0: {} + restructure@3.0.2: {} + rgbcolor@1.0.1: optional: true @@ -11180,6 +11292,8 @@ snapshots: utrie: 1.0.2 optional: true + tiny-inflate@1.0.3: {} + tiny-invariant@1.3.3: {} tinybench@2.9.0: {} @@ -11239,6 +11353,16 @@ snapshots: undici-types@7.14.0: {} + unicode-properties@1.4.1: + dependencies: + base64-js: 1.5.1 + unicode-trie: 2.0.0 + + unicode-trie@2.0.0: + dependencies: + pako: 0.2.9 + tiny-inflate: 1.0.3 + unified@11.0.5: dependencies: '@types/unist': 3.0.3 diff --git a/server/attestationService.ts b/server/attestationService.ts new file mode 100644 index 0000000..94da1c3 --- /dev/null +++ b/server/attestationService.ts @@ -0,0 +1,269 @@ +import { getDb } from "./db"; +import { attestations, configAttestation, inscriptions, apprenants, sequences, formations, datesFormation } from "../drizzle/schema"; +import { eq, and } from "drizzle-orm"; +import { storagePut } from "./storage"; +import PDFDocument from "pdfkit"; +import { format } from "date-fns"; +import { fr } from "date-fns/locale"; +import crypto from "crypto"; + +/** + * Génère une attestation de formation en PDF + */ +export async function genererAttestationPDF(inscriptionId: number): Promise<{ s3Key: string; pdfUrl: string }> { + const db = await getDb(); + if (!db) { + throw new Error("Base de données non disponible"); + } + + // Récupérer les données de l'inscription + const [inscriptionData] = await db + .select({ + inscription: inscriptions, + apprenant: apprenants, + sequence: sequences, + formation: formations, + }) + .from(inscriptions) + .innerJoin(apprenants, eq(inscriptions.apprenantId, apprenants.id)) + .innerJoin(sequences, eq(inscriptions.sequenceId, sequences.id)) + .innerJoin(formations, eq(sequences.formationId, formations.id)) + .where(eq(inscriptions.id, inscriptionId)) + .limit(1); + + if (!inscriptionData) { + throw new Error("Inscription introuvable"); + } + + const { inscription, apprenant, sequence, formation } = inscriptionData; + + // Récupérer les dates de la séquence + const dates = await db + .select() + .from(datesFormation) + .where(eq(datesFormation.sequenceId, sequence.id)); + + // Récupérer la configuration de l'attestation + const [config] = await db + .select() + .from(configAttestation) + .limit(1); + + // Créer le PDF + const doc = new PDFDocument({ + size: "A4", + margins: { top: 50, bottom: 50, left: 50, right: 50 }, + }); + + const chunks: Buffer[] = []; + doc.on("data", (chunk: Buffer) => chunks.push(chunk)); + + return new Promise((resolve, reject) => { + doc.on("end", async () => { + try { + const pdfBuffer = Buffer.concat(chunks); + + // Générer une clé S3 unique + const randomSuffix = crypto.randomBytes(8).toString("hex"); + const s3Key = `attestations/${apprenant.id}-${sequence.id}-${randomSuffix}.pdf`; + + // Upload vers S3 + const { url } = await storagePut(s3Key, pdfBuffer, "application/pdf"); + + resolve({ s3Key, pdfUrl: url }); + } catch (error) { + reject(error); + } + }); + + doc.on("error", reject); + + // Construction du PDF + try { + // Titre + doc.fontSize(24).font("Helvetica-Bold").text("ATTESTATION DE FORMATION", { align: "center" }); + doc.moveDown(2); + + // Texte personnalisable ou texte par défaut + const texteAttestation = config?.texteAttestation || + "Nous attestons que {{nomComplet}} a suivi avec assiduité la formation \"{{nomFormation}}\" organisée du {{dateDebut}} au {{dateFin}}."; + + // Remplacer les variables + const nomComplet = `${apprenant.prenom} ${apprenant.nom}`; + const dateDebut = dates.length > 0 ? format(new Date(dates[0].dateDebut), "dd MMMM yyyy", { locale: fr }) : ""; + const dateFin = dates.length > 0 ? format(new Date(dates[dates.length - 1].dateFin), "dd MMMM yyyy", { locale: fr }) : ""; + + const texteRempli = texteAttestation + .replace(/\{\{nomComplet\}\}/g, nomComplet) + .replace(/\{\{nomFormation\}\}/g, formation.nom) + .replace(/\{\{dateDebut\}\}/g, dateDebut) + .replace(/\{\{dateFin\}\}/g, dateFin); + + doc.fontSize(12).font("Helvetica").text(texteRempli, { align: "justify" }); + doc.moveDown(2); + + // Détails de la formation + doc.fontSize(10).font("Helvetica-Bold").text("Détails de la formation :", { underline: true }); + doc.moveDown(0.5); + doc.font("Helvetica"); + doc.text(`Formation : ${formation.nom}`); + doc.text(`Séquence : ${sequence.nom}`); + doc.text(`Lieu : ${sequence.lieu}`); + doc.moveDown(0.5); + doc.text("Dates :"); + dates.forEach((date) => { + const dateStr = format(new Date(date.dateDebut), "dd/MM/yyyy", { locale: fr }); + const heureDebut = format(new Date(date.dateDebut), "HH:mm"); + const heureFin = format(new Date(date.dateFin), "HH:mm"); + doc.text(` • ${dateStr} de ${heureDebut} à ${heureFin}`); + }); + + doc.moveDown(3); + + // Signature + doc.fontSize(10); + doc.text(`Fait le ${format(new Date(), "dd MMMM yyyy", { locale: fr })}`, { align: "right" }); + doc.moveDown(3); + + if (config?.nomSignataire) { + doc.text(config.nomSignataire, { align: "right" }); + } + if (config?.fonctionSignataire) { + doc.text(config.fonctionSignataire, { align: "right" }); + } + + doc.end(); + } catch (error) { + doc.end(); + reject(error); + } + }); +} + +/** + * Enregistre une attestation dans la base de données + */ +export async function enregistrerAttestation( + inscriptionId: number, + apprenantId: number, + sequenceId: number, + s3Key: string, + pdfUrl: string +): Promise { + const db = await getDb(); + if (!db) { + throw new Error("Base de données non disponible"); + } + + const [result] = await db.insert(attestations).values({ + inscriptionId, + apprenantId, + sequenceId, + s3Key, + pdfUrl, + emailEnvoye: false, + }); + + return result.insertId; +} + +/** + * Récupère l'attestation d'un apprenant pour une séquence + */ +export async function getAttestation(apprenantId: number, sequenceId: number) { + const db = await getDb(); + if (!db) return null; + + const [attestation] = await db + .select() + .from(attestations) + .where( + and( + eq(attestations.apprenantId, apprenantId), + eq(attestations.sequenceId, sequenceId) + ) + ) + .limit(1); + + return attestation || null; +} + +/** + * Récupère toutes les attestations d'un apprenant + */ +export async function getAttestationsApprenant(apprenantId: number) { + const db = await getDb(); + if (!db) return []; + + return db + .select({ + attestation: attestations, + sequence: sequences, + formation: formations, + }) + .from(attestations) + .innerJoin(sequences, eq(attestations.sequenceId, sequences.id)) + .innerJoin(formations, eq(sequences.formationId, formations.id)) + .where(eq(attestations.apprenantId, apprenantId)); +} + +/** + * Marque une attestation comme envoyée par email + */ +export async function marquerAttestationEnvoyee(attestationId: number) { + const db = await getDb(); + if (!db) return; + + await db + .update(attestations) + .set({ + emailEnvoye: true, + dateEnvoiEmail: new Date(), + }) + .where(eq(attestations.id, attestationId)); +} + +/** + * Récupère ou crée la configuration des attestations + */ +export async function getOrCreateConfigAttestation() { + const db = await getDb(); + if (!db) return null; + + let [config] = await db.select().from(configAttestation).limit(1); + + if (!config) { + // Créer une configuration par défaut + await db.insert(configAttestation).values({ + texteAttestation: "Nous attestons que {{nomComplet}} a suivi avec assiduité la formation \"{{nomFormation}}\" organisée du {{dateDebut}} au {{dateFin}}.", + }); + + [config] = await db.select().from(configAttestation).limit(1); + } + + return config; +} + +/** + * Met à jour la configuration des attestations + */ +export async function updateConfigAttestation(data: { + logoS3Key?: string; + logoUrl?: string; + signatureS3Key?: string; + signatureUrl?: string; + nomSignataire?: string; + fonctionSignataire?: string; + texteAttestation?: string; +}) { + const db = await getDb(); + if (!db) return; + + const [existing] = await db.select().from(configAttestation).limit(1); + + if (existing) { + await db.update(configAttestation).set(data).where(eq(configAttestation.id, existing.id)); + } else { + await db.insert(configAttestation).values(data); + } +} diff --git a/server/routers.ts b/server/routers.ts index d6dffb0..e0e0bde 100644 --- a/server/routers.ts +++ b/server/routers.ts @@ -1736,6 +1736,98 @@ export const appRouter = router({ }); }), }), + + // Attestations de formation + attestations: router({ + // Générer une attestation pour une inscription + generer: adminProcedure + .input(z.object({ + inscriptionId: z.number(), + })) + .mutation(async ({ input }) => { + const { genererAttestationPDF, enregistrerAttestation, getAttestation } = await import("./attestationService"); + const db = await import("./db").then(m => m.getDb()); + if (!db) throw new Error("Base de données non disponible"); + + // Vérifier si l'attestation existe déjà + const { inscriptions } = await import("../drizzle/schema"); + const { eq } = await import("drizzle-orm"); + const [inscription] = await db.select().from(inscriptions).where(eq(inscriptions.id, input.inscriptionId)).limit(1); + if (!inscription) { + throw new Error("Inscription introuvable"); + } + + const attestationExistante = await getAttestation(inscription.apprenantId, inscription.sequenceId); + if (attestationExistante) { + return { + success: true, + attestation: attestationExistante, + message: "Attestation déjà générée", + }; + } + + // Générer le PDF + const { s3Key, pdfUrl } = await genererAttestationPDF(input.inscriptionId); + + // Enregistrer dans la base + const attestationId = await enregistrerAttestation( + input.inscriptionId, + inscription.apprenantId, + inscription.sequenceId, + s3Key, + pdfUrl + ); + + const attestation = await getAttestation(inscription.apprenantId, inscription.sequenceId); + + return { + success: true, + attestation, + message: "Attestation générée avec succès", + }; + }), + + // Récupérer l'attestation d'un apprenant pour une séquence + get: publicProcedure + .input(z.object({ + apprenantId: z.number(), + sequenceId: z.number(), + })) + .query(async ({ input }) => { + const { getAttestation } = await import("./attestationService"); + return getAttestation(input.apprenantId, input.sequenceId); + }), + + // Récupérer toutes les attestations d'un apprenant + listApprenant: publicProcedure + .input(z.object({ + apprenantId: z.number(), + })) + .query(async ({ input }) => { + const { getAttestationsApprenant } = await import("./attestationService"); + return getAttestationsApprenant(input.apprenantId); + }), + + // Récupérer la configuration des attestations + getConfig: adminProcedure + .query(async () => { + const { getOrCreateConfigAttestation } = await import("./attestationService"); + return getOrCreateConfigAttestation(); + }), + + // Mettre à jour la configuration des attestations + updateConfig: adminProcedure + .input(z.object({ + nomSignataire: z.string().optional(), + fonctionSignataire: z.string().optional(), + texteAttestation: z.string().optional(), + })) + .mutation(async ({ input }) => { + const { updateConfigAttestation } = await import("./attestationService"); + await updateConfigAttestation(input); + return { success: true }; + }), + }), }); export type AppRouter = typeof appRouter; diff --git a/todo.md b/todo.md index ffbb0f5..9ecdf42 100644 --- a/todo.md +++ b/todo.md @@ -442,3 +442,11 @@ - [x] Interface de gestion des emails formateurs dans Configuration - [x] Tableau de bord des notifications avec historique des emails envoyés - [x] Lien vers questionnaire de satisfaction dans l'email de remerciement + +## Réimplémentation attestations (16/12/2025) +- [x] Recréer les tables en base de données +- [x] Recréer le service de génération PDF +- [x] Recréer les procédures tRPC +- [x] Créer la page de configuration +- [x] Intégrer le bouton dans la page de validation des présences +- [x] Tester la génération complète
Chargement...
+ Personnalisez le contenu et la signature des attestations de formation +
{'{{nomComplet}}'}
{'{{nomFormation}}'}
{'{{dateDebut}}'}
{'{{dateFin}}'}