Import initial de Vivier depuis l'hebergement OVH

This commit is contained in:
Yann PILLA committed 2026-10-16 21:52:44 +02:00
commit 839e5e57c5
126 files changed
+22447

No files matched your search

+1
View File
@@ -0,0 +1 @@
Require all denied
+62
View File
@@ -0,0 +1,62 @@
-- Vivier : passage d'une base 1.0 à 1.1
-- À exécuter une seule fois dans phpMyAdmin, sur une base créée avec l'ancien schema.sql.
-- Ensuite, dans Vivier : menu Comptes, bouton « Réindexer tous les profils ».
SET NAMES utf8mb4;
ALTER TABLE candidats
ADD COLUMN niveau_etudes VARCHAR(20) NULL AFTER disponibilite,
ADD COLUMN encadrement TINYINT(1) NULL AFTER niveau_etudes;
-- ---------------------------------------------------------------
-- Mots-clés et métadonnées de recherche
-- Fournis par l'analyse (manuel = 0) ou ajoutés à la main sur la fiche (manuel = 1).
-- ---------------------------------------------------------------
CREATE TABLE mots_cles (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
type ENUM('role','specialite','secteur','mot_cle') NOT NULL,
mot VARCHAR(80) NOT NULL,
manuel TINYINT(1) NOT NULL DEFAULT 0,
UNIQUE KEY uq_mot (candidat_id, type, mot),
CONSTRAINT fk_mot_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Index de recherche : un terme normalisé par ligne, avec son poids.
-- Reconstruit par PHP à chaque import ou modification d'un profil.
-- ---------------------------------------------------------------
CREATE TABLE index_recherche (
candidat_id INT UNSIGNED NOT NULL,
terme VARCHAR(60) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
poids SMALLINT UNSIGNED NOT NULL,
PRIMARY KEY (candidat_id, terme),
KEY idx_terme (terme),
CONSTRAINT fk_index_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Échecs de connexion récents : blocage temporaire après 5 essais
-- ---------------------------------------------------------------
CREATE TABLE tentatives_connexion (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
cle VARCHAR(190) NOT NULL,
moment DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_cle (cle, moment)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO synonymes_recherche (terme, cible_type, cible) VALUES
('développeuse','texte', 'développeur'),
('fullstack','texte', 'full-stack'),
('backend', 'texte', 'back-end'),
('frontend','texte', 'front-end'),
('js', 'texte', 'javascript'),
('ts', 'texte', 'typescript'),
('postgres','texte', 'postgresql'),
('k8s', 'texte', 'kubernetes'),
('po', 'texte', 'product owner'),
('pm', 'texte', 'chef de projet'),
('lead', 'texte', 'technical lead'),
('architect','texte', 'architecte'),
('tester', 'texte', 'testeur'),
('qa', 'texte', 'test');
+11
View File
@@ -0,0 +1,11 @@
-- Vivier : passage d'une base 1.1 à 1.2
-- Connexion par identifiant au lieu de l'adresse email, un seul niveau d'accès aux profils.
-- À exécuter une seule fois dans phpMyAdmin. Les adresses email existantes deviennent les identifiants :
-- le gestionnaire peut ensuite les raccourcir dans le menu Comptes.
SET NAMES utf8mb4;
ALTER TABLE utilisateurs CHANGE email identifiant VARCHAR(190) NOT NULL;
ALTER TABLE utilisateurs RENAME INDEX email TO identifiant;
UPDATE utilisateurs SET role = 'recruteur' WHERE role = 'lecteur';
ALTER TABLE utilisateurs MODIFY role ENUM('admin','recruteur') NOT NULL DEFAULT 'recruteur';
+22
View File
@@ -0,0 +1,22 @@
-- Vivier : passage d'une base 1.2 à 1.3
-- Photos des candidats, langue de l'interface par compte, traductions des profils.
-- À exécuter une seule fois dans phpMyAdmin.
SET NAMES utf8mb4;
ALTER TABLE utilisateurs ADD COLUMN langue CHAR(2) NOT NULL DEFAULT 'fr' AFTER derniere_connexion;
ALTER TABLE candidats ADD COLUMN photo VARCHAR(100) NULL AFTER texte_recherche;
CREATE TABLE traductions (
candidat_id INT UNSIGNED NOT NULL,
langue CHAR(2) NOT NULL,
contenu JSON NOT NULL,
empreinte CHAR(40) CHARACTER SET ascii NOT NULL,
origine ENUM('automatique','fichier') NOT NULL,
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (candidat_id, langue),
CONSTRAINT fk_trad_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE,
CONSTRAINT fk_trad_utilisateur FOREIGN KEY (cree_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+141
View File
@@ -0,0 +1,141 @@
-- Vivier : passage d'une base 1.3 à 1.4
-- Un seul état « Entretiens en cours », archivage, suivi des entretiens, relances, besoins clients,
-- champs commerciaux, consentement, import en lot, sauvegardes.
-- À exécuter une seule fois dans phpMyAdmin.
SET NAMES utf8mb4;
-- Les deux anciens états d'entretien deviennent « entretiens »
ALTER TABLE candidats MODIFY statut ENUM('recu','en_cours','entretien_1_valide','entretien_2_valide','entretiens',
'non_retenu','valide','embauche') NOT NULL DEFAULT 'recu';
UPDATE candidats SET statut = 'entretiens' WHERE statut IN ('entretien_1_valide', 'entretien_2_valide');
ALTER TABLE candidats MODIFY statut ENUM('recu','en_cours','entretiens','non_retenu','valide','embauche') NOT NULL DEFAULT 'recu';
ALTER TABLE candidats
ADD COLUMN disponible_le DATE NULL AFTER disponibilite,
ADD COLUMN tjm SMALLINT UNSIGNED NULL AFTER disponible_le,
ADD COLUMN salaire_souhaite INT UNSIGNED NULL AFTER tjm,
ADD COLUMN mobilite VARCHAR(200) NULL AFTER salaire_souhaite,
ADD COLUMN teletravail ENUM('non','partiel','complet') NULL AFTER mobilite,
ADD COLUMN archive_le DATETIME NULL AFTER motif_refus,
ADD COLUMN archive_par INT UNSIGNED NULL AFTER archive_le,
ADD COLUMN consentement_le DATE NULL AFTER conserver_jusqu_au,
ADD COLUMN consentement_note VARCHAR(200) NULL AFTER consentement_le,
ADD KEY idx_archive (archive_le),
ADD CONSTRAINT fk_candidat_archive_par FOREIGN KEY (archive_par) REFERENCES utilisateurs(id);
-- Le journal accepte de nouvelles actions sans changer la table à chaque version
ALTER TABLE historique MODIFY action VARCHAR(40) NOT NULL;
-- ---------------------------------------------------------------
-- Besoins clients : les missions à pourvoir, et les profils proposés pour chacune
-- ---------------------------------------------------------------
CREATE TABLE besoins (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
client VARCHAR(200) NOT NULL,
intitule VARCHAR(200) NOT NULL,
description TEXT NULL,
technologies VARCHAR(1000) NULL, -- liste séparée par des virgules
seniorite_min ENUM('junior','intermediaire','confirme','expert') NULL,
langues VARCHAR(300) NULL, -- liste séparée par des virgules
lieu VARCHAR(150) NULL,
teletravail ENUM('non','partiel','complet') NULL,
tjm_max SMALLINT UNSIGNED NULL, -- budget journalier du client, en euros
date_debut DATE NULL,
statut ENUM('ouvert','pourvu','ferme') NOT NULL DEFAULT 'ouvert',
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
modifie_le DATETIME NULL,
KEY idx_besoin_statut (statut),
CONSTRAINT fk_besoin_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE besoin_candidat (
besoin_id INT UNSIGNED NOT NULL,
candidat_id INT UNSIGNED NOT NULL,
etat ENUM('propose','presente','retenu','ecarte') NOT NULL DEFAULT 'propose',
note VARCHAR(500) NULL,
ajoute_par INT UNSIGNED NOT NULL,
ajoute_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (besoin_id, candidat_id),
KEY idx_bc_candidat (candidat_id),
CONSTRAINT fk_bc_besoin FOREIGN KEY (besoin_id) REFERENCES besoins(id) ON DELETE CASCADE,
CONSTRAINT fk_bc_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE,
CONSTRAINT fk_bc_utilisateur FOREIGN KEY (ajoute_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Entretiens : un candidat peut en passer plusieurs pendant le statut « Entretiens en cours »
-- ---------------------------------------------------------------
CREATE TABLE entretiens (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
date_entretien DATETIME NOT NULL,
type ENUM('telephone','visio','presentiel','technique','client') NOT NULL,
interlocuteur VARCHAR(150) NULL, -- qui a mené l'entretien
besoin_id INT UNSIGNED NULL, -- besoin client concerné, s'il y en a un
avis ENUM('favorable','reserve','defavorable') NULL,
compte_rendu TEXT NULL,
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_entretien_candidat (candidat_id, date_entretien),
KEY idx_entretien_date (date_entretien),
CONSTRAINT fk_entretien_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE,
CONSTRAINT fk_entretien_besoin FOREIGN KEY (besoin_id) REFERENCES besoins(id) ON DELETE SET NULL,
CONSTRAINT fk_entretien_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Relances : une chose à faire pour un candidat, à une date donnée
-- ---------------------------------------------------------------
CREATE TABLE relances (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
echeance DATE NOT NULL,
objet VARCHAR(200) NOT NULL,
fait_le DATETIME NULL,
fait_par INT UNSIGNED NULL,
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_relance_echeance (fait_le, echeance),
KEY idx_relance_candidat (candidat_id),
CONSTRAINT fk_relance_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE,
CONSTRAINT fk_relance_fait_par FOREIGN KEY (fait_par) REFERENCES utilisateurs(id),
CONSTRAINT fk_relance_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Import en lot : un CV par ligne, en attente d'analyse ou de relecture.
-- La ligne disparaît quand le profil est enregistré.
-- ---------------------------------------------------------------
CREATE TABLE imports_lot (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
jeton CHAR(32) CHARACTER SET ascii NOT NULL, -- nom du dossier temporaire
nom_fichier VARCHAR(255) NOT NULL,
etat ENUM('en_attente','pret','erreur') NOT NULL DEFAULT 'en_attente',
erreur VARCHAR(1000) NULL,
candidat VARCHAR(200) NULL, -- nom lu dans le profil, une fois l'analyse faite
meta JSON NULL, -- fichiers rangés dans le dossier temporaire
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uq_lot_jeton (jeton),
CONSTRAINT fk_lot_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Sauvegardes de la base : une ligne par exécution, réussie ou non
-- ---------------------------------------------------------------
CREATE TABLE sauvegardes (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
origine ENUM('planifiee','manuelle') NOT NULL,
reussie TINYINT(1) NOT NULL DEFAULT 0,
fichier VARCHAR(100) NULL, -- nom du zip dans stockage/sauvegardes, NULL s'il a été supprimé
taille_octets INT UNSIGNED NULL,
profils INT UNSIGNED NULL, -- nombre de profils dans la sauvegarde
envoi ENUM('envoye','sans_piece','echec','non_demande') NOT NULL DEFAULT 'non_demande',
detail VARCHAR(500) NULL,
cree_par INT UNSIGNED NULL, -- NULL : tâche planifiée
KEY idx_sauvegarde_date (cree_le),
CONSTRAINT fk_sauvegarde_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+36
View File
@@ -0,0 +1,36 @@
-- Vivier : passage d'une base 1.4 à 1.5
-- Corbeille des profils (30 jours), demandes de compte à valider, compte du gestionnaire.
-- À exécuter une seule fois dans phpMyAdmin, après une sauvegarde de la base (onglet Exporter).
SET NAMES utf8mb4;
-- ---------------------------------------------------------------
-- Corbeille : un profil supprimé reste 30 jours, puis il est effacé avec ses fichiers
-- ---------------------------------------------------------------
ALTER TABLE candidats
ADD COLUMN supprime_le DATETIME NULL AFTER archive_par,
ADD COLUMN supprime_par INT UNSIGNED NULL AFTER supprime_le,
ADD KEY idx_supprime (supprime_le),
ADD CONSTRAINT fk_candidat_supprime_par FOREIGN KEY (supprime_par) REFERENCES utilisateurs(id);
-- ---------------------------------------------------------------
-- Demandes de compte : la personne s'inscrit, le gestionnaire accepte ou refuse.
-- Un compte en attente a actif = 0 et en_attente = 1 : il ne peut pas se connecter.
-- ---------------------------------------------------------------
ALTER TABLE utilisateurs
ADD COLUMN en_attente TINYINT(1) NOT NULL DEFAULT 0 AFTER actif;
-- ---------------------------------------------------------------
-- Compte du gestionnaire : Yann PILLA, identifiant ypilla.
-- La colonne mot_de_passe contient une empreinte, pas le mot de passe.
-- Si l'identifiant existe déjà, son mot de passe et son rôle sont mis à jour.
-- ---------------------------------------------------------------
UPDATE utilisateurs
SET nom_affiche = 'Yann PILLA', role = 'admin', actif = 1, en_attente = 0,
mot_de_passe = '$2y$12$ENLcXMSR6WlGLW06M5tgtOtGYw5E9o.BgoPlpImStFrk2MWJVEUE.'
WHERE identifiant = 'ypilla';
INSERT INTO utilisateurs (identifiant, nom_affiche, mot_de_passe, role, actif, en_attente)
SELECT 'ypilla', 'Yann PILLA', '$2y$12$ENLcXMSR6WlGLW06M5tgtOtGYw5E9o.BgoPlpImStFrk2MWJVEUE.', 'admin', 1, 0
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM (SELECT id FROM utilisateurs WHERE identifiant = 'ypilla') AS deja);
+9
View File
@@ -0,0 +1,9 @@
-- Vivier : passage d'une base 1.5 à 1.6
-- Noms de famille en majuscules. Aucune table ni colonne ne change.
-- À exécuter une seule fois dans phpMyAdmin, après une sauvegarde de la base (onglet Exporter).
-- Ensuite, dans Vivier : menu Gestion, Comptes, « Réindexer tous les profils ».
SET NAMES utf8mb4;
-- Profils existants : « Tonzar » devient « TONZAR ». Les nouveaux profils sont convertis à l'import.
UPDATE candidats SET nom = UPPER(TRIM(nom));
+5
View File
@@ -0,0 +1,5 @@
-- Vivier : migration 1.6 vers 1.7
-- Les noms de famille passent en capitales, comme Vivier les enregistre désormais à l'import et à la modification.
-- Le prénom ne change pas. À passer une fois, dans phpMyAdmin, onglet SQL.
UPDATE candidats SET nom = UPPER(nom) WHERE nom <> UPPER(nom) COLLATE utf8mb4_bin;
+149
View File
@@ -0,0 +1,149 @@
-- Vivier : migration 1.7 vers 1.8
-- À passer une fois, dans phpMyAdmin, base de Vivier, onglet SQL. Faire d'abord une sauvegarde (onglet Exporter).
--
-- Contenu :
-- 1. Sécurité des accès : double authentification, invitations, sessions, journal des connexions.
-- 2. Profils : disponibilité en liste fixe, nationalités, permis de travail, champs du CV Europass.
-- 3. Traduction des profils dans la langue de l'interface : file d'attente.
-- 4. Reprise des disponibilités déjà saisies.
--
-- Après la migration, chaque compte active la double authentification à sa prochaine connexion.
SET NAMES utf8mb4;
-- ---------------------------------------------------------------
-- 1. Comptes : double authentification, version de session, mot de passe à changer
-- ---------------------------------------------------------------
ALTER TABLE utilisateurs
ADD COLUMN totp_secret VARCHAR(255) NULL AFTER mot_de_passe, -- clé de l'application d'authentification, chiffrée
ADD COLUMN totp_active_le DATETIME NULL AFTER totp_secret, -- NULL : double authentification à activer
ADD COLUMN totp_dernier_pas BIGINT NULL AFTER totp_active_le, -- dernier code accepté : un code ne sert qu'une fois
ADD COLUMN codes_secours TEXT NULL AFTER totp_dernier_pas, -- empreintes des codes de secours restants (JSON)
ADD COLUMN session_version INT UNSIGNED NOT NULL DEFAULT 1 AFTER codes_secours, -- +1 ferme toutes les sessions du compte
ADD COLUMN changer_mot_de_passe TINYINT(1) NOT NULL DEFAULT 0 AFTER session_version; -- mot de passe donné par le gestionnaire
-- Invitations : un lien à usage unique, valable 48 heures, remplace la page publique de demande de compte
CREATE TABLE IF NOT EXISTS invitations (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
jeton CHAR(64) CHARACTER SET ascii NOT NULL, -- empreinte SHA-256 du jeton : le lien lui-même n'est jamais enregistré
nom_affiche VARCHAR(120) NULL, -- nom proposé par le gestionnaire, modifiable par la personne
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
expire_le DATETIME NOT NULL,
utilise_le DATETIME NULL,
annule_le DATETIME NULL,
utilisateur_id INT UNSIGNED NULL, -- compte créé avec ce lien
UNIQUE KEY uq_invitation_jeton (jeton),
CONSTRAINT fk_invitation_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id),
CONSTRAINT fk_invitation_utilisateur FOREIGN KEY (utilisateur_id) REFERENCES utilisateurs(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Journal des connexions : chaque essai, réussi ou non. Gardé 12 mois.
CREATE TABLE IF NOT EXISTS connexions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
moment DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
utilisateur_id INT UNSIGNED NULL,
identifiant VARCHAR(190) NOT NULL,
ip VARCHAR(45) NOT NULL,
reseau VARCHAR(45) NOT NULL, -- réseau de l'adresse (IPv4 /24, IPv6 /48) : sert à repérer un lieu nouveau
navigateur VARCHAR(255) NOT NULL DEFAULT '',
resultat VARCHAR(20) NOT NULL, -- reussie, mot_de_passe, code, bloquee, desactive, attente
KEY idx_connexion_moment (moment),
KEY idx_connexion_compte (utilisateur_id, reseau),
CONSTRAINT fk_connexion_utilisateur FOREIGN KEY (utilisateur_id) REFERENCES utilisateurs(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- 2. Profils
-- ---------------------------------------------------------------
ALTER TABLE candidats
ADD COLUMN disponibilite_code ENUM('immediate','1_mois','2_mois','3_mois','date','a_preciser') NULL AFTER disponibilite,
ADD COLUMN nationalites VARCHAR(60) NULL AFTER pays, -- codes ISO 3166-1 séparés par des virgules : FR,MA
ADD COLUMN hors_ue TINYINT(1) NULL AFTER nationalites, -- 0 : au moins une nationalité UE, EEE ou suisse ; 1 : aucune ; NULL : inconnu
ADD COLUMN permis_travail VARCHAR(300) NULL AFTER hors_ue, -- statut du permis de travail au Luxembourg, texte libre
ADD COLUMN permis_expire_le DATE NULL AFTER permis_travail, -- fin de validité du titre
ADD COLUMN benevolat TEXT NULL AFTER encadrement, -- une activité par ligne (CV Europass)
ADD COLUMN permis_conduire VARCHAR(100) NULL AFTER benevolat, -- catégories : B, A1
ADD KEY idx_hors_ue (hors_ue),
ADD KEY idx_permis_expire (permis_expire_le);
ALTER TABLE experiences
ADD COLUMN projet VARCHAR(200) NULL AFTER client,
ADD COLUMN mission TEXT NULL AFTER projet,
ADD COLUMN charge VARCHAR(300) NULL AFTER mission; -- charge en jours-homme, avec sa répartition
ALTER TABLE formations
ADD COLUMN date_debut VARCHAR(7) CHARACTER SET ascii NULL AFTER etablissement, -- AAAA-MM ou AAAA
ADD COLUMN date_fin VARCHAR(7) CHARACTER SET ascii NULL AFTER date_debut,
ADD COLUMN lieu VARCHAR(150) NULL AFTER date_fin;
-- Niveaux de la grille européenne (CECRL), quand le CV les donne
ALTER TABLE langues
ADD COLUMN ecoute ENUM('A1','A2','B1','B2','C1','C2') NULL AFTER niveau,
ADD COLUMN lecture ENUM('A1','A2','B1','B2','C1','C2') NULL AFTER ecoute,
ADD COLUMN production_orale ENUM('A1','A2','B1','B2','C1','C2') NULL AFTER lecture,
ADD COLUMN interaction_orale ENUM('A1','A2','B1','B2','C1','C2') NULL AFTER production_orale,
ADD COLUMN ecriture ENUM('A1','A2','B1','B2','C1','C2') NULL AFTER interaction_orale;
-- Relance créée par Vivier (renouvellement du titre de séjour) : Vivier la met à jour quand la date change
ALTER TABLE relances
ADD COLUMN auto VARCHAR(20) NULL AFTER objet,
ADD KEY idx_relance_auto (candidat_id, auto);
-- ---------------------------------------------------------------
-- 3. Traductions à faire : profils à traduire dans les langues de l'interface
-- ---------------------------------------------------------------
CREATE TABLE IF NOT EXISTS traductions_a_faire (
candidat_id INT UNSIGNED NOT NULL,
langue CHAR(2) NOT NULL,
ajoute_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
essais TINYINT UNSIGNED NOT NULL DEFAULT 0,
erreur VARCHAR(500) NULL,
verrou_le DATETIME NULL, -- traduction en cours : un seul poste la fait
PRIMARY KEY (candidat_id, langue),
CONSTRAINT fk_afaire_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- 4. Reprise des disponibilités
-- Une date déjà saisie par IT Club devient « Date précise ».
-- Le texte du CV est classé par règles simples ; le reste passe en « À préciser ».
-- Le texte d'origine reste en note sous la valeur, pour être corrigé à la main.
-- « Sous N mois » reçoit une date estimée : date de l'import + N mois.
-- ---------------------------------------------------------------
UPDATE candidats SET disponibilite_code = 'date'
WHERE disponibilite_code IS NULL AND disponible_le IS NOT NULL;
UPDATE candidats
SET disponible_le = STR_TO_DATE(REGEXP_SUBSTR(disponibilite, '[0-9]{2}/[0-9]{2}/[0-9]{4}'), '%d/%m/%Y'),
disponibilite_code = 'date'
WHERE disponibilite_code IS NULL AND disponibilite REGEXP '[0-9]{2}/[0-9]{2}/[0-9]{4}';
UPDATE candidats
SET disponible_le = STR_TO_DATE(REGEXP_SUBSTR(disponibilite, '[0-9]{4}-[0-9]{2}-[0-9]{2}'), '%Y-%m-%d'),
disponibilite_code = 'date'
WHERE disponibilite_code IS NULL AND disponibilite REGEXP '[0-9]{4}-[0-9]{2}-[0-9]{2}';
UPDATE candidats SET disponibilite_code = 'immediate'
WHERE disponibilite_code IS NULL
AND LOWER(disponibilite) REGEXP 'imm.{1,2}diat|tout de suite|sans pr.{1,2}avis|available now|right away|sofort|^ *disponible *\\.? *$';
UPDATE candidats SET disponibilite_code = '1_mois', disponible_le = DATE_ADD(DATE(cree_le), INTERVAL 1 MONTH)
WHERE disponibilite_code IS NULL
AND LOWER(disponibilite) REGEXP '(^|[^0-9])(1|un|one) (mois|month)|4 semaines|4 weeks|30 jours|30 days|1 monat';
UPDATE candidats SET disponibilite_code = '2_mois', disponible_le = DATE_ADD(DATE(cree_le), INTERVAL 2 MONTH)
WHERE disponibilite_code IS NULL
AND LOWER(disponibilite) REGEXP '(^|[^0-9])(2|deux|two) (mois|months)|8 semaines|8 weeks|60 jours|60 days|2 monate';
UPDATE candidats SET disponibilite_code = '3_mois', disponible_le = DATE_ADD(DATE(cree_le), INTERVAL 3 MONTH)
WHERE disponibilite_code IS NULL
AND LOWER(disponibilite) REGEXP '(^|[^0-9])(3|trois|three) (mois|months)|12 semaines|12 weeks|90 jours|90 days|3 monate';
UPDATE candidats SET disponibilite_code = 'a_preciser'
WHERE disponibilite_code IS NULL AND disponibilite IS NOT NULL AND TRIM(disponibilite) <> '';
-- ---------------------------------------------------------------
-- Les demandes de compte encore en attente restent visibles dans Comptes, pour être acceptées ou refusées.
-- Les nouvelles personnes rejoignent Vivier par un lien d'invitation.
-- ---------------------------------------------------------------
+481
View File
@@ -0,0 +1,481 @@
-- Outil de suivi des CV IT Club
-- Schéma MySQL / MariaDB (InnoDB, utf8mb4)
-- Version 1.8 de la base, format de profil cv-profil.schema.json 1.2
-- Base déjà créée : exécuter à la place les fichiers migration-*.sql, dans l'ordre.
SET NAMES utf8mb4;
-- ---------------------------------------------------------------
-- Comptes et rôles
-- ---------------------------------------------------------------
CREATE TABLE utilisateurs (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
identifiant VARCHAR(190) NOT NULL, -- nom de connexion, choisi par le gestionnaire
nom_affiche VARCHAR(120) NOT NULL,
mot_de_passe VARCHAR(255) NOT NULL, -- password_hash() de PHP
totp_secret VARCHAR(255) NULL, -- clé de l'application d'authentification, chiffrée
totp_active_le DATETIME NULL, -- NULL : double authentification à activer
totp_dernier_pas BIGINT NULL, -- dernier code accepté : un code ne sert qu'une fois
codes_secours TEXT NULL, -- empreintes des codes de secours restants (JSON)
session_version INT UNSIGNED NOT NULL DEFAULT 1, -- +1 ferme toutes les sessions du compte
changer_mot_de_passe TINYINT(1) NOT NULL DEFAULT 0, -- mot de passe donné par le gestionnaire : à changer
role ENUM('admin','recruteur') NOT NULL DEFAULT 'recruteur', -- admin : gère aussi les comptes
actif TINYINT(1) NOT NULL DEFAULT 1,
en_attente TINYINT(1) NOT NULL DEFAULT 0, -- demande de compte à valider par le gestionnaire (actif = 0)
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
derniere_connexion DATETIME NULL,
langue CHAR(2) NOT NULL DEFAULT 'fr', -- langue de l'interface pour ce compte
UNIQUE KEY identifiant (identifiant)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Candidats
-- ---------------------------------------------------------------
CREATE TABLE candidats (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
prenom VARCHAR(100) NOT NULL,
nom VARCHAR(100) NOT NULL,
email VARCHAR(190) NULL,
telephone VARCHAR(40) NULL,
rue VARCHAR(200) NULL,
code_postal VARCHAR(20) NULL,
ville VARCHAR(100) NULL,
pays VARCHAR(100) NULL,
nationalites VARCHAR(60) NULL, -- codes ISO 3166-1 séparés par des virgules : FR,MA
hors_ue TINYINT(1) NULL, -- 0 : au moins une nationalité UE, EEE ou suisse ; 1 : aucune ; NULL : inconnu
permis_travail VARCHAR(300) NULL, -- statut du permis de travail au Luxembourg, texte libre
permis_expire_le DATE NULL, -- fin de validité du titre
titre VARCHAR(200) NULL,
resume TEXT NULL,
disponibilite VARCHAR(200) NULL, -- disponibilité telle que le CV l'écrit, gardée en note
disponibilite_code ENUM('immediate','1_mois','2_mois','3_mois','date','a_preciser') NULL,
disponible_le DATE NULL, -- date de disponibilité, quand elle est connue
tjm SMALLINT UNSIGNED NULL, -- taux journalier souhaité, en euros
salaire_souhaite INT UNSIGNED NULL, -- salaire annuel brut souhaité, en euros
mobilite VARCHAR(200) NULL, -- zones acceptées, déplacements
teletravail ENUM('non','partiel','complet') NULL,
niveau_etudes VARCHAR(20) NULL, -- bac, bac+2, bac+3, bac+4, bac+5, doctorat, autre
encadrement TINYINT(1) NULL, -- a encadré une équipe : 1, 0 ou inconnu
benevolat TEXT NULL, -- une activité par ligne (CV Europass)
permis_conduire VARCHAR(100) NULL, -- catégories : B, A1
annees_experience DECIMAL(4,1) NOT NULL DEFAULT 0, -- recalculé par PHP à l'import
seniorite ENUM('junior','intermediaire','confirme','expert') NOT NULL,
statut ENUM('recu','en_cours','entretiens','non_retenu','valide','embauche') NOT NULL DEFAULT 'recu',
motif_refus VARCHAR(500) NULL, -- obligatoire si statut = non_retenu
archive_le DATETIME NULL, -- profil archivé : sorti du Kanban, gardé dans la base
archive_par INT UNSIGNED NULL,
supprime_le DATETIME NULL, -- profil à la corbeille : effacé pour de bon 30 jours après
supprime_par INT UNSIGNED NULL,
position_kanban INT NOT NULL DEFAULT 0, -- ordre dans la colonne
json_source JSON NOT NULL, -- JSON importé, conservé tel quel
schema_version VARCHAR(10) NOT NULL,
texte_recherche MEDIUMTEXT NOT NULL, -- texte complet, pour la recherche de phrases exactes
photo VARCHAR(100) NULL, -- chemin interne de la photo, pour reconnaître le candidat
conserver_jusqu_au DATE NULL, -- échéance de suppression (RGPD)
consentement_le DATE NULL, -- date de l'accord du candidat pour la conservation
consentement_note VARCHAR(200) NULL, -- comment l'accord a été recueilli
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
modifie_par INT UNSIGNED NULL,
modifie_le DATETIME NULL,
UNIQUE KEY uq_candidat_email (email), -- détection des doublons
KEY idx_statut (statut, position_kanban),
KEY idx_seniorite (seniorite),
KEY fk_candidat_cree_par (cree_par),
KEY fk_candidat_modifie_par (modifie_par),
KEY idx_archive (archive_le),
KEY fk_candidat_archive_par (archive_par),
KEY idx_supprime (supprime_le),
KEY idx_hors_ue (hors_ue),
KEY idx_permis_expire (permis_expire_le),
KEY fk_candidat_supprime_par (supprime_par),
FULLTEXT KEY ft_recherche (texte_recherche),
CONSTRAINT fk_candidat_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id),
CONSTRAINT fk_candidat_modifie_par FOREIGN KEY (modifie_par) REFERENCES utilisateurs(id),
CONSTRAINT fk_candidat_archive_par FOREIGN KEY (archive_par) REFERENCES utilisateurs(id),
CONSTRAINT fk_candidat_supprime_par FOREIGN KEY (supprime_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE liens (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
type ENUM('linkedin','github','portfolio','site','autre') NOT NULL,
url VARCHAR(500) NOT NULL,
CONSTRAINT fk_lien_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE experiences (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
poste VARCHAR(200) NOT NULL,
employeur VARCHAR(200) NULL,
client VARCHAR(200) NULL,
projet VARCHAR(200) NULL,
mission TEXT NULL,
charge VARCHAR(300) NULL, -- charge en jours-homme, avec sa répartition
lieu VARCHAR(150) NULL,
type ENUM('emploi','mission','alternance','stage','independant') NOT NULL,
date_debut DATE NOT NULL, -- 1er du mois (ou 1er janvier si mois inconnu)
date_fin DATE NULL, -- NULL = en cours
description TEXT NULL,
technologies VARCHAR(1000) NULL, -- liste séparée par des virgules, pour l'affichage
KEY idx_exp_candidat (candidat_id, date_debut),
CONSTRAINT fk_exp_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE formations (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
diplome VARCHAR(250) NOT NULL,
etablissement VARCHAR(250) NULL,
date_debut VARCHAR(7) CHARACTER SET ascii NULL, -- AAAA-MM ou AAAA
date_fin VARCHAR(7) CHARACTER SET ascii NULL,
lieu VARCHAR(150) NULL,
annee_fin SMALLINT UNSIGNED NULL,
CONSTRAINT fk_formation_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE certifications (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
nom VARCHAR(250) NOT NULL,
organisme VARCHAR(250) NULL,
annee SMALLINT UNSIGNED NULL,
CONSTRAINT fk_certif_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Référentiel des technologies, partagé entre candidats (filtres, statistiques)
CREATE TABLE technologies (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100) NOT NULL UNIQUE,
categorie ENUM('langage','framework','base_de_donnees','outil','cloud','methode','autre') NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE candidat_technologie (
candidat_id INT UNSIGNED NOT NULL,
technologie_id INT UNSIGNED NOT NULL,
annees DECIMAL(4,1) NULL,
PRIMARY KEY (candidat_id, technologie_id),
CONSTRAINT fk_ct_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE,
CONSTRAINT fk_ct_techno FOREIGN KEY (technologie_id) REFERENCES technologies(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE langues (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
langue VARCHAR(60) NOT NULL,
niveau ENUM('A1','A2','B1','B2','C1','C2','natif') NULL,
-- Grille européenne (CECRL), quand le CV la donne
ecoute ENUM('A1','A2','B1','B2','C1','C2') NULL,
lecture ENUM('A1','A2','B1','B2','C1','C2') NULL,
production_orale ENUM('A1','A2','B1','B2','C1','C2') NULL,
interaction_orale ENUM('A1','A2','B1','B2','C1','C2') NULL,
ecriture ENUM('A1','A2','B1','B2','C1','C2') NULL,
CONSTRAINT fk_langue_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Documents attachés (CV d'origine, rapport, lettres, diplômes)
-- Les fichiers sont stockés hors de la racine web ; la base garde le chemin.
-- ---------------------------------------------------------------
CREATE TABLE documents (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
type ENUM('cv_origine','rapport','cv_itclub','cv_anonyme','autre') NOT NULL,
nom_fichier VARCHAR(255) NOT NULL, -- nom affiché
chemin VARCHAR(500) NOT NULL, -- chemin interne, nom aléatoire
type_mime VARCHAR(100) NOT NULL,
taille_octets INT UNSIGNED NOT NULL,
ajoute_par INT UNSIGNED NOT NULL,
ajoute_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_doc_candidat (candidat_id),
CONSTRAINT fk_doc_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE,
CONSTRAINT fk_doc_utilisateur FOREIGN KEY (ajoute_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Commentaires
-- ---------------------------------------------------------------
CREATE TABLE commentaires (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
auteur_id INT UNSIGNED NOT NULL,
texte TEXT NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
modifie_le DATETIME NULL,
KEY idx_com_candidat (candidat_id, cree_le),
CONSTRAINT fk_com_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE,
CONSTRAINT fk_com_auteur FOREIGN KEY (auteur_id) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Journal d'audit : qui a modifié quoi et quand
-- Pas de clé étrangère vers candidats : la trace survit à une suppression.
-- ---------------------------------------------------------------
CREATE TABLE historique (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NULL,
utilisateur_id INT UNSIGNED NOT NULL,
action VARCHAR(40) NOT NULL, -- code de l'action, voir ACTIONS_JOURNAL
champ VARCHAR(100) NULL,
ancienne_valeur TEXT NULL,
nouvelle_valeur TEXT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_hist_candidat (candidat_id, cree_le),
KEY idx_hist_utilisateur (utilisateur_id, cree_le),
CONSTRAINT fk_hist_utilisateur FOREIGN KEY (utilisateur_id) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Mots-clés et métadonnées de recherche
-- Fournis par l'analyse (manuel = 0) ou ajoutés à la main sur la fiche (manuel = 1).
-- ---------------------------------------------------------------
CREATE TABLE mots_cles (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
type ENUM('role','specialite','secteur','mot_cle') NOT NULL,
mot VARCHAR(80) NOT NULL,
manuel TINYINT(1) NOT NULL DEFAULT 0,
UNIQUE KEY uq_mot (candidat_id, type, mot),
CONSTRAINT fk_mot_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Index de recherche : un terme normalisé par ligne, avec son poids.
-- Reconstruit par PHP à chaque import ou modification d'un profil.
-- ---------------------------------------------------------------
CREATE TABLE index_recherche (
candidat_id INT UNSIGNED NOT NULL,
terme VARCHAR(60) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
poids SMALLINT UNSIGNED NOT NULL,
PRIMARY KEY (candidat_id, terme),
KEY idx_terme (terme),
CONSTRAINT fk_index_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Traductions du contenu d'un profil, pour générer le CV dans une autre langue.
-- L'empreinte désigne la version du profil traduite : si le profil change, la traduction est périmée.
-- ---------------------------------------------------------------
CREATE TABLE traductions (
candidat_id INT UNSIGNED NOT NULL,
langue CHAR(2) NOT NULL,
contenu JSON NOT NULL,
empreinte CHAR(40) CHARACTER SET ascii NOT NULL,
origine ENUM('automatique','fichier') NOT NULL,
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (candidat_id, langue),
CONSTRAINT fk_trad_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE,
CONSTRAINT fk_trad_utilisateur FOREIGN KEY (cree_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Profils à traduire dans les langues de l'interface : le navigateur d'un compte connecté les traite un par un
CREATE TABLE traductions_a_faire (
candidat_id INT UNSIGNED NOT NULL,
langue CHAR(2) NOT NULL,
ajoute_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
essais TINYINT UNSIGNED NOT NULL DEFAULT 0,
erreur VARCHAR(500) NULL,
verrou_le DATETIME NULL, -- traduction en cours : un seul poste la fait
PRIMARY KEY (candidat_id, langue),
CONSTRAINT fk_afaire_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Besoins clients : les missions à pourvoir, et les profils proposés pour chacune
-- ---------------------------------------------------------------
CREATE TABLE besoins (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
client VARCHAR(200) NOT NULL,
intitule VARCHAR(200) NOT NULL,
description TEXT NULL,
technologies VARCHAR(1000) NULL, -- liste séparée par des virgules
seniorite_min ENUM('junior','intermediaire','confirme','expert') NULL,
langues VARCHAR(300) NULL, -- liste séparée par des virgules
lieu VARCHAR(150) NULL,
teletravail ENUM('non','partiel','complet') NULL,
tjm_max SMALLINT UNSIGNED NULL, -- budget journalier du client, en euros
date_debut DATE NULL,
statut ENUM('ouvert','pourvu','ferme') NOT NULL DEFAULT 'ouvert',
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
modifie_le DATETIME NULL,
KEY idx_besoin_statut (statut),
CONSTRAINT fk_besoin_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE besoin_candidat (
besoin_id INT UNSIGNED NOT NULL,
candidat_id INT UNSIGNED NOT NULL,
etat ENUM('propose','presente','retenu','ecarte') NOT NULL DEFAULT 'propose',
note VARCHAR(500) NULL,
ajoute_par INT UNSIGNED NOT NULL,
ajoute_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (besoin_id, candidat_id),
KEY idx_bc_candidat (candidat_id),
CONSTRAINT fk_bc_besoin FOREIGN KEY (besoin_id) REFERENCES besoins(id) ON DELETE CASCADE,
CONSTRAINT fk_bc_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE,
CONSTRAINT fk_bc_utilisateur FOREIGN KEY (ajoute_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Entretiens : un candidat peut en passer plusieurs pendant le statut « Entretiens en cours »
-- ---------------------------------------------------------------
CREATE TABLE entretiens (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
date_entretien DATETIME NOT NULL,
type ENUM('telephone','visio','presentiel','technique','client') NOT NULL,
interlocuteur VARCHAR(150) NULL, -- qui a mené l'entretien
besoin_id INT UNSIGNED NULL, -- besoin client concerné, s'il y en a un
avis ENUM('favorable','reserve','defavorable') NULL,
compte_rendu TEXT NULL,
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_entretien_candidat (candidat_id, date_entretien),
KEY idx_entretien_date (date_entretien),
CONSTRAINT fk_entretien_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE,
CONSTRAINT fk_entretien_besoin FOREIGN KEY (besoin_id) REFERENCES besoins(id) ON DELETE SET NULL,
CONSTRAINT fk_entretien_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Relances : une chose à faire pour un candidat, à une date donnée
-- ---------------------------------------------------------------
CREATE TABLE relances (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
candidat_id INT UNSIGNED NOT NULL,
echeance DATE NOT NULL,
objet VARCHAR(200) NOT NULL,
auto VARCHAR(20) NULL, -- relance créée par Vivier (permis) : mise à jour quand la date change
fait_le DATETIME NULL,
fait_par INT UNSIGNED NULL,
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_relance_echeance (fait_le, echeance),
KEY idx_relance_candidat (candidat_id),
KEY idx_relance_auto (candidat_id, auto),
CONSTRAINT fk_relance_candidat FOREIGN KEY (candidat_id) REFERENCES candidats(id) ON DELETE CASCADE,
CONSTRAINT fk_relance_fait_par FOREIGN KEY (fait_par) REFERENCES utilisateurs(id),
CONSTRAINT fk_relance_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Import en lot : un CV par ligne, en attente d'analyse ou de relecture.
-- La ligne disparaît quand le profil est enregistré.
-- ---------------------------------------------------------------
CREATE TABLE imports_lot (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
jeton CHAR(32) CHARACTER SET ascii NOT NULL, -- nom du dossier temporaire
nom_fichier VARCHAR(255) NOT NULL,
etat ENUM('en_attente','pret','erreur') NOT NULL DEFAULT 'en_attente',
erreur VARCHAR(1000) NULL,
candidat VARCHAR(200) NULL, -- nom lu dans le profil, une fois l'analyse faite
meta JSON NULL, -- fichiers rangés dans le dossier temporaire
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uq_lot_jeton (jeton),
CONSTRAINT fk_lot_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Sauvegardes de la base : une ligne par exécution, réussie ou non
-- ---------------------------------------------------------------
CREATE TABLE sauvegardes (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
origine ENUM('planifiee','manuelle') NOT NULL,
reussie TINYINT(1) NOT NULL DEFAULT 0,
fichier VARCHAR(100) NULL, -- nom du zip dans stockage/sauvegardes, NULL s'il a été supprimé
taille_octets INT UNSIGNED NULL,
profils INT UNSIGNED NULL, -- nombre de profils dans la sauvegarde
envoi ENUM('envoye','sans_piece','echec','non_demande') NOT NULL DEFAULT 'non_demande',
detail VARCHAR(500) NULL,
cree_par INT UNSIGNED NULL, -- NULL : tâche planifiée
KEY idx_sauvegarde_date (cree_le),
CONSTRAINT fk_sauvegarde_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Échecs de connexion récents : blocage temporaire (voir src/securite.php)
-- ---------------------------------------------------------------
CREATE TABLE tentatives_connexion (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
cle VARCHAR(190) NOT NULL,
moment DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_cle (cle, moment)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Invitations : un lien à usage unique, valable 48 heures
CREATE TABLE invitations (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
jeton CHAR(64) CHARACTER SET ascii NOT NULL, -- empreinte SHA-256 du jeton : le lien lui-même n'est jamais enregistré
nom_affiche VARCHAR(120) NULL,
cree_par INT UNSIGNED NOT NULL,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
expire_le DATETIME NOT NULL,
utilise_le DATETIME NULL,
annule_le DATETIME NULL,
utilisateur_id INT UNSIGNED NULL,
UNIQUE KEY uq_invitation_jeton (jeton),
CONSTRAINT fk_invitation_cree_par FOREIGN KEY (cree_par) REFERENCES utilisateurs(id),
CONSTRAINT fk_invitation_utilisateur FOREIGN KEY (utilisateur_id) REFERENCES utilisateurs(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Journal des connexions : chaque essai, réussi ou non. Gardé 12 mois.
CREATE TABLE connexions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
moment DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
utilisateur_id INT UNSIGNED NULL,
identifiant VARCHAR(190) NOT NULL,
ip VARCHAR(45) NOT NULL,
reseau VARCHAR(45) NOT NULL, -- réseau de l'adresse (IPv4 /24, IPv6 /48)
navigateur VARCHAR(255) NOT NULL DEFAULT '',
resultat VARCHAR(20) NOT NULL, -- reussie, mot_de_passe, code, bloquee, desactive, attente
KEY idx_connexion_moment (moment),
KEY idx_connexion_compte (utilisateur_id, reseau),
CONSTRAINT fk_connexion_utilisateur FOREIGN KEY (utilisateur_id) REFERENCES utilisateurs(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------
-- Synonymes de recherche : traduit un mot tapé en filtre ou en termes
-- ---------------------------------------------------------------
CREATE TABLE synonymes_recherche (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
terme VARCHAR(100) NOT NULL,
cible_type ENUM('seniorite','texte') NOT NULL,
cible VARCHAR(100) NOT NULL,
KEY idx_terme (terme)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO synonymes_recherche (terme, cible_type, cible) VALUES
('senior', 'seniorite', 'confirme'),
('senior', 'seniorite', 'expert'),
('sénior', 'seniorite', 'confirme'),
('sénior', 'seniorite', 'expert'),
('junior', 'seniorite', 'junior'),
('confirmé','seniorite', 'confirme'),
('expert', 'seniorite', 'expert'),
('intermédiaire', 'seniorite', 'intermediaire'),
('dev', 'texte', 'développeur'),
('developer','texte', 'développeur'),
('développeuse','texte', 'développeur'),
('fullstack','texte', 'full-stack'),
('backend', 'texte', 'back-end'),
('frontend','texte', 'front-end'),
('js', 'texte', 'javascript'),
('ts', 'texte', 'typescript'),
('postgres','texte', 'postgresql'),
('k8s', 'texte', 'kubernetes'),
('po', 'texte', 'product owner'),
('pm', 'texte', 'chef de projet'),
('lead', 'texte', 'technical lead'),
('architect','texte', 'architecte'),
('tester', 'texte', 'testeur'),
('qa', 'texte', 'test');