Checkpoint: Correction de l'authentification locale : utilisation de sdk.createSessionToken() au lieu de jsonwebtoken pour compatibilité avec le système OAuth

This commit is contained in:
Manus Sandbox
2025-11-23 08:50:35 -05:00
parent ccb1484839
commit 645f6f6b5f
12 changed files with 2984 additions and 12 deletions

464
DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,464 @@
# Guide de Déploiement - Gestion des Formations Manager Itinova
## Table des matières
1. [Prérequis](#prérequis)
2. [Installation locale](#installation-locale)
3. [Configuration](#configuration)
4. [Déploiement en production](#déploiement-en-production)
5. [Migration de base de données](#migration-de-base-de-données)
6. [Maintenance](#maintenance)
7. [Dépannage](#dépannage)
---
## Prérequis
### Environnement de développement
- **Node.js** : version 22.13.0 ou supérieure
- **pnpm** : gestionnaire de paquets (installé avec Node.js)
- **Base de données** : MySQL 8.0+ ou TiDB (compatible MySQL)
- **Git** : pour le contrôle de version
### Services externes (optionnels)
- **Resend** : pour l'envoi d'emails (clé API requise)
- **Plateforme Manus** : pour l'authentification OAuth (déjà configuré)
---
## Installation locale
### 1. Cloner le projet
```bash
# Si vous avez accès au dépôt Git
git clone <url-du-depot>
cd formation-manager-itinova
# Sinon, extraire l'archive
unzip formation-manager-itinova.zip
cd formation-manager-itinova
```
### 2. Installer les dépendances
```bash
pnpm install
```
### 3. Configurer les variables d'environnement
Créer un fichier `.env` à la racine du projet :
```env
# Base de données
DATABASE_URL=mysql://user:password@localhost:3306/formation_manager
# JWT Secret (générer une clé aléatoire sécurisée)
JWT_SECRET=votre_cle_secrete_tres_longue_et_aleatoire
# OAuth Manus (déjà configuré sur la plateforme)
OAUTH_SERVER_URL=https://api.manus.im
VITE_OAUTH_PORTAL_URL=https://login.manus.im
VITE_APP_ID=votre_app_id
# Propriétaire
OWNER_OPEN_ID=votre_open_id
OWNER_NAME=Nom du propriétaire
# Application
VITE_APP_TITLE=Gestion des Formations Manager Itinova
VITE_APP_LOGO=/logo.svg
# APIs Manus (optionnel)
BUILT_IN_FORGE_API_URL=https://forge.manus.im
BUILT_IN_FORGE_API_KEY=votre_cle_api
VITE_FRONTEND_FORGE_API_KEY=votre_cle_frontend
VITE_FRONTEND_FORGE_API_URL=https://forge.manus.im
# Analytics (optionnel)
VITE_ANALYTICS_ENDPOINT=https://analytics.manus.im
VITE_ANALYTICS_WEBSITE_ID=votre_website_id
```
### 4. Initialiser la base de données
```bash
# Créer la base de données
mysql -u root -p -e "CREATE DATABASE formation_manager CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
# Appliquer les migrations
pnpm db:push
```
### 5. Créer l'utilisateur administrateur
L'utilisateur administrateur est créé automatiquement au premier lancement :
- **Identifiant** : `adminServFormation`
- **Mot de passe** : `Itinova69!`
- **Email** : `admin@formation.local` (modifiable)
### 6. Lancer l'application en développement
```bash
pnpm dev
```
L'application sera accessible à l'adresse : `http://localhost:3000`
---
## Configuration
### Configuration SMTP (Resend)
1. Créer un compte sur [Resend](https://resend.com)
2. Générer une clé API
3. Se connecter à l'application avec l'utilisateur admin
4. Aller dans **Configuration SMTP**
5. Saisir :
- **Clé API Resend** : votre clé API
- **Email expéditeur** : votre email vérifié sur Resend
- **Nom de l'expéditeur** : Itinova Formation
6. Activer le mode **Production**
7. Tester l'envoi
### Personnalisation des templates d'emails
1. Se connecter en tant qu'administrateur
2. Aller dans **Templates d'emails**
3. Modifier les templates selon vos besoins :
- Email de confirmation d'inscription
- Email teaser
- Email de rappel J-7
### Gestion des utilisateurs
1. Se connecter en tant qu'administrateur
2. Aller dans **Utilisateurs**
3. Créer de nouveaux utilisateurs avec identifiant et mot de passe
4. Attribuer le rôle **admin** ou **user**
**Note** : L'utilisateur `adminServFormation` ne peut pas être supprimé et garantit un accès permanent à l'administration.
---
## Déploiement en production
### Option 1 : Déploiement sur la plateforme Manus (recommandé)
L'application est déjà configurée pour la plateforme Manus. Pour déployer :
1. Se connecter à l'interface de gestion Manus
2. Créer un checkpoint via le bouton **Save Checkpoint**
3. Cliquer sur le bouton **Publish** dans l'en-tête
4. Configurer le domaine personnalisé si nécessaire
5. Publier l'application
**Avantages** :
- Déploiement automatique
- SSL/TLS automatique
- Scaling automatique
- Base de données TiDB incluse
- Pas de configuration serveur nécessaire
### Option 2 : Déploiement manuel sur serveur VPS
#### Prérequis serveur
- Ubuntu 22.04 LTS ou supérieur
- 2 CPU, 4 GB RAM minimum
- Node.js 22.13.0+
- MySQL 8.0+ ou MariaDB 10.6+
- Nginx (reverse proxy)
- Certbot (SSL/TLS)
#### Étapes de déploiement
1. **Préparer le serveur**
```bash
# Mettre à jour le système
sudo apt update && sudo apt upgrade -y
# Installer Node.js 22
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
# Installer pnpm
npm install -g pnpm
# Installer MySQL
sudo apt install -y mysql-server
# Installer Nginx
sudo apt install -y nginx
# Installer Certbot
sudo apt install -y certbot python3-certbot-nginx
```
2. **Déployer l'application**
```bash
# Créer un utilisateur dédié
sudo useradd -m -s /bin/bash formation
sudo su - formation
# Cloner ou copier le projet
cd /home/formation
# Copier les fichiers du projet ici
# Installer les dépendances
pnpm install
# Configurer les variables d'environnement
cp .env.example .env
nano .env
# Build de production
pnpm build
```
3. **Configurer le service systemd**
Créer le fichier `/etc/systemd/system/formation-manager.service` :
```ini
[Unit]
Description=Formation Manager Itinova
After=network.target mysql.service
[Service]
Type=simple
User=formation
WorkingDirectory=/home/formation/formation-manager-itinova
ExecStart=/usr/bin/pnpm start
Restart=on-failure
RestartSec=10
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
```
Activer et démarrer le service :
```bash
sudo systemctl daemon-reload
sudo systemctl enable formation-manager
sudo systemctl start formation-manager
sudo systemctl status formation-manager
```
4. **Configurer Nginx**
Créer le fichier `/etc/nginx/sites-available/formation-manager` :
```nginx
server {
listen 80;
server_name votre-domaine.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
client_max_body_size 10M;
}
```
Activer le site :
```bash
sudo ln -s /etc/nginx/sites-available/formation-manager /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
5. **Configurer SSL/TLS avec Let's Encrypt**
```bash
sudo certbot --nginx -d votre-domaine.com
```
---
## Migration de base de données
### Appliquer les migrations
```bash
# En développement
pnpm db:push
# En production (avec sauvegarde)
# 1. Sauvegarder la base de données
mysqldump -u root -p formation_manager > backup_$(date +%Y%m%d_%H%M%S).sql
# 2. Appliquer les migrations
pnpm db:push
```
### Restaurer une sauvegarde
```bash
mysql -u root -p formation_manager < backup_20250123_120000.sql
```
---
## Maintenance
### Logs de l'application
```bash
# Logs systemd
sudo journalctl -u formation-manager -f
# Logs Nginx
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
```
### Mise à jour de l'application
```bash
# Arrêter le service
sudo systemctl stop formation-manager
# Mettre à jour le code
cd /home/formation/formation-manager-itinova
git pull origin main
# Installer les nouvelles dépendances
pnpm install
# Appliquer les migrations
pnpm db:push
# Rebuild
pnpm build
# Redémarrer le service
sudo systemctl start formation-manager
```
### Sauvegarde automatique
Créer un script de sauvegarde `/home/formation/backup.sh` :
```bash
#!/bin/bash
BACKUP_DIR="/home/formation/backups"
DATE=$(date +%Y%m%d_%H%M%S)
# Créer le répertoire de sauvegarde
mkdir -p $BACKUP_DIR
# Sauvegarder la base de données
mysqldump -u root -p formation_manager > $BACKUP_DIR/db_$DATE.sql
# Compresser
gzip $BACKUP_DIR/db_$DATE.sql
# Supprimer les sauvegardes de plus de 30 jours
find $BACKUP_DIR -name "db_*.sql.gz" -mtime +30 -delete
echo "Sauvegarde terminée : $BACKUP_DIR/db_$DATE.sql.gz"
```
Ajouter une tâche cron :
```bash
crontab -e
# Sauvegarde quotidienne à 2h du matin
0 2 * * * /home/formation/backup.sh
```
---
## Dépannage
### L'application ne démarre pas
1. Vérifier les logs :
```bash
sudo journalctl -u formation-manager -n 50
```
2. Vérifier la connexion à la base de données :
```bash
mysql -u root -p -e "SHOW DATABASES;"
```
3. Vérifier les variables d'environnement dans `.env`
### Erreur de connexion à la base de données
1. Vérifier que MySQL est démarré :
```bash
sudo systemctl status mysql
```
2. Tester la connexion :
```bash
mysql -u user -p formation_manager
```
3. Vérifier l'URL de connexion dans `.env`
### Les emails ne sont pas envoyés
1. Vérifier la configuration SMTP dans l'interface admin
2. Vérifier que la clé API Resend est valide
3. Vérifier que l'email expéditeur est vérifié sur Resend
4. Consulter les logs de l'application
### Problème de permissions
```bash
# Corriger les permissions
sudo chown -R formation:formation /home/formation/formation-manager-itinova
sudo chmod -R 755 /home/formation/formation-manager-itinova
```
### L'authentification locale ne fonctionne pas
1. Vérifier que `JWT_SECRET` est défini dans `.env`
2. Vérifier que l'utilisateur `adminServFormation` existe dans la base de données
3. Réinitialiser le mot de passe si nécessaire via SQL :
```sql
-- Le mot de passe hashé pour "Itinova69!"
UPDATE users
SET password = '$2a$10$...'
WHERE username = 'adminServFormation';
```
---
## Support
Pour toute question ou problème :
1. Consulter la documentation complète dans le dossier `/docs`
2. Vérifier les logs de l'application
3. Contacter l'équipe de développement
---
**Version** : 1.0.0
**Dernière mise à jour** : 23 novembre 2025

290
INSTALL.md Normal file
View File

@@ -0,0 +1,290 @@
# Guide d'Installation Rapide
## Installation en 5 minutes
Ce guide vous permet d'installer et de démarrer l'application rapidement en environnement de développement.
---
## Prérequis
Avant de commencer, assurez-vous d'avoir installé :
- **Node.js 22+** : [Télécharger Node.js](https://nodejs.org/)
- **MySQL 8.0+** ou **MariaDB 10.6+** : [Télécharger MySQL](https://dev.mysql.com/downloads/)
- **Git** (optionnel) : [Télécharger Git](https://git-scm.com/)
---
## Étape 1 : Récupérer le projet
### Option A : Depuis l'archive ZIP
```bash
# Extraire l'archive
unzip formation-manager-itinova.zip
cd formation-manager-itinova
```
### Option B : Depuis Git (si disponible)
```bash
# Cloner le dépôt
git clone <url-du-depot>
cd formation-manager-itinova
```
---
## Étape 2 : Installer les dépendances
```bash
# Installer pnpm si nécessaire
npm install -g pnpm
# Installer les dépendances du projet
pnpm install
```
---
## Étape 3 : Configurer la base de données
### 3.1 Créer la base de données
```bash
# Se connecter à MySQL
mysql -u root -p
# Créer la base de données
CREATE DATABASE formation_manager CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# Créer un utilisateur dédié (optionnel mais recommandé)
CREATE USER 'formation_user'@'localhost' IDENTIFIED BY 'votre_mot_de_passe_securise';
GRANT ALL PRIVILEGES ON formation_manager.* TO 'formation_user'@'localhost';
FLUSH PRIVILEGES;
# Quitter MySQL
EXIT;
```
### 3.2 Configurer les variables d'environnement
Créer un fichier `.env` à la racine du projet :
```env
# Base de données
DATABASE_URL=mysql://formation_user:votre_mot_de_passe_securise@localhost:3306/formation_manager
# JWT Secret (générer une clé aléatoire)
JWT_SECRET=votre_cle_secrete_aleatoire_tres_longue_minimum_32_caracteres
# Application
VITE_APP_TITLE=Gestion des Formations Manager Itinova
VITE_APP_LOGO=/logo.svg
NODE_ENV=development
```
**Note** : Pour générer une clé JWT sécurisée, vous pouvez utiliser :
```bash
# Linux/Mac
openssl rand -base64 32
# Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
```
### 3.3 Initialiser la base de données
```bash
# Appliquer les migrations (créer les tables)
pnpm db:push
```
---
## Étape 4 : Démarrer l'application
```bash
# Lancer le serveur de développement
pnpm dev
```
L'application sera accessible à l'adresse : **http://localhost:3000**
---
## Étape 5 : Première connexion
### Connexion avec l'utilisateur administrateur local
1. Ouvrir **http://localhost:3000** dans votre navigateur
2. Cliquer sur **"Se connecter localement"**
3. Utiliser les identifiants par défaut :
- **Identifiant** : `adminServFormation`
- **Mot de passe** : `Itinova69!`
**Important** : Cet utilisateur est créé automatiquement au premier lancement et ne peut pas être supprimé.
---
## Configuration initiale
Une fois connecté, vous pouvez :
### 1. Configurer l'envoi d'emails (optionnel)
1. Créer un compte sur [Resend](https://resend.com)
2. Générer une clé API
3. Dans l'application, aller dans **Configuration SMTP**
4. Saisir :
- **Clé API Resend** : votre clé API
- **Email expéditeur** : votre email vérifié
- **Nom de l'expéditeur** : Itinova Formation
5. Activer le mode **Production**
### 2. Créer des utilisateurs supplémentaires
1. Aller dans **Utilisateurs**
2. Cliquer sur **Ajouter un utilisateur**
3. Remplir les informations :
- Nom d'utilisateur
- Mot de passe
- Email
- Rôle (admin ou user)
### 3. Créer vos premières formations
1. Aller dans **Formations**
2. Cliquer sur **Nouvelle formation**
3. Remplir les informations de la formation
4. Créer des séquences associées
### 4. Importer les apprenants
1. Aller dans **Apprenants**
2. Ajouter les apprenants un par un ou créer un script d'import
---
## Commandes utiles
```bash
# Démarrer le serveur de développement
pnpm dev
# Builder pour la production
pnpm build
# Démarrer en mode production
pnpm start
# Appliquer les migrations
pnpm db:push
# Générer les migrations (après modification du schéma)
pnpm db:generate
# Ouvrir Drizzle Studio (interface graphique pour la base de données)
pnpm db:studio
```
---
## Structure du projet
```
formation-manager-itinova/
├── client/ # Application frontend (React)
│ ├── public/ # Fichiers statiques
│ └── src/
│ ├── pages/ # Pages de l'application
│ ├── components/ # Composants réutilisables
│ └── lib/ # Bibliothèques et utilitaires
├── server/ # Application backend (Express + tRPC)
│ ├── routers.ts # Définition des routes API
│ ├── db.ts # Fonctions d'accès à la base de données
│ └── _core/ # Configuration du serveur
├── drizzle/ # Schéma et migrations de base de données
│ └── schema.ts # Définition des tables
├── shared/ # Code partagé entre client et serveur
├── .env # Variables d'environnement (à créer)
├── package.json # Dépendances du projet
├── deploy.sh # Script de déploiement automatique
├── DEPLOYMENT.md # Guide de déploiement complet
└── README.md # Documentation principale
```
---
## Dépannage rapide
### L'application ne démarre pas
**Erreur : "Cannot find module"**
```bash
# Réinstaller les dépendances
rm -rf node_modules
pnpm install
```
**Erreur : "ECONNREFUSED" (connexion à la base de données)**
```bash
# Vérifier que MySQL est démarré
sudo systemctl status mysql
# Vérifier l'URL de connexion dans .env
cat .env | grep DATABASE_URL
```
### Les migrations échouent
```bash
# Vérifier que la base de données existe
mysql -u root -p -e "SHOW DATABASES;"
# Recréer la base de données si nécessaire
mysql -u root -p -e "DROP DATABASE IF EXISTS formation_manager; CREATE DATABASE formation_manager CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
# Réappliquer les migrations
pnpm db:push
```
### Impossible de se connecter
**Vérifier que JWT_SECRET est défini**
```bash
cat .env | grep JWT_SECRET
```
Si vide, générer une nouvelle clé :
```bash
echo "JWT_SECRET=$(openssl rand -base64 32)" >> .env
```
---
## Prochaines étapes
Une fois l'installation terminée :
1. **Lire la documentation complète** : `DEPLOYMENT.md`
2. **Personnaliser les templates d'emails** : Menu "Templates d'emails"
3. **Configurer les rappels automatiques** : Menu "Rappels"
4. **Tester l'envoi d'emails** : Configuration SMTP
5. **Déployer en production** : Suivre le guide `DEPLOYMENT.md`
---
## Support
Pour toute question ou problème :
- Consulter `DEPLOYMENT.md` pour la documentation complète
- Vérifier les logs de l'application
- Contacter l'équipe de développement
---
**Bon déploiement ! 🚀**

455
README.md Normal file
View File

@@ -0,0 +1,455 @@
# Gestion des Formations Manager Itinova
Application web complète de gestion des formations pour Manager Itinova, permettant la planification, l'organisation et le suivi des formations avec gestion automatisée des inscriptions, rappels et communications.
![Version](https://img.shields.io/badge/version-1.0.0-blue.svg)
![Node](https://img.shields.io/badge/node-22.13.0-green.svg)
![License](https://img.shields.io/badge/license-Proprietary-red.svg)
---
## 📋 Table des matières
- [Aperçu](#aperçu)
- [Fonctionnalités](#fonctionnalités)
- [Technologies](#technologies)
- [Installation rapide](#installation-rapide)
- [Documentation](#documentation)
- [Architecture](#architecture)
- [Utilisation](#utilisation)
- [Déploiement](#déploiement)
- [Maintenance](#maintenance)
- [Support](#support)
---
## 🎯 Aperçu
L'application **Gestion des Formations Manager Itinova** est une solution complète pour gérer l'ensemble du cycle de vie des formations :
- Création et planification des formations et séquences
- Gestion des apprenants et inscriptions avec validation automatique
- Génération automatique de documents (listes, feuilles de présence)
- Envoi automatique d'emails (confirmations, rappels)
- Calendrier interactif et système de rappels
- Rapports et statistiques détaillés
L'application offre **deux modes d'authentification** :
- **Connexion Manus OAuth** : pour les utilisateurs avec compte Manus (Google, Microsoft, Apple)
- **Connexion locale** : pour les administrateurs avec identifiant et mot de passe
---
## ✨ Fonctionnalités
### 🔐 Authentification dual
- Page de choix de connexion
- Authentification Manus OAuth (Google, Microsoft, Apple)
- Authentification locale par identifiant/mot de passe
- Gestion des rôles (admin, user)
- Utilisateur administrateur permanent non supprimable
### 📚 Gestion des formations
- CRUD complet des formations
- Support de multiples séquences par formation
- Jusqu'à 4 dates par séquence
- Champs personnalisés :
- Public cible (Directeurs, Chefs de service, Autre, Tous)
- Formateur avec autocomplétion
- Capacité maximale par séquence
- Lieu de formation
- Barre de progression colorée (vert/orange/rouge) selon le taux de remplissage
- Filtres et recherche avancée
### 👥 Gestion des apprenants
- CRUD complet des apprenants
- Fonction (Directeur, Chef de service, Autre)
- Page de détail par apprenant avec historique complet
- Système d'inscription avec :
- Validation de capacité automatique
- Détection anti-doublons
- Blocage automatique à J-15
- Alerte si public cible incompatible
### 📅 Calendrier et rappels
- Calendrier mensuel interactif
- Navigation par mois
- Visualisation des séquences par date
- Système de rappels automatiques configurables :
- Rappel J-7
- Rappel J-3
- Rappel J-1
- Rappel personnalisé
### 📄 Exports et documents
- **Export Excel** : listes d'inscrits avec toutes les informations
- **Export PDF** : listes d'inscrits formatées
- **Feuilles de présence PDF** :
- Logo Itinova
- Double signature (matin/après-midi)
- Signature formateur
- Informations complètes de la séquence
### ✉️ Communications automatiques
- **Génération d'invitations Outlook** (.ics)
- **Emails automatiques** :
- Email de confirmation d'inscription
- Email teaser (présentation de la formation)
- Email de rappel J-7
- **Templates personnalisables** avec variables dynamiques
- **Configuration SMTP** avec Resend
- Mode test et production
### 📊 Rapports et statistiques
- Tableau de bord avec indicateurs clés
- Répartition des apprenants par fonction
- Analyse public cible vs fonction réelle
- Statistiques de remplissage des séquences
- Historique des inscriptions
### 👤 Administration
- Gestion des utilisateurs
- Création, modification, activation/désactivation
- Attribution des rôles
- Utilisateur admin permanent (adminServFormation)
- Templates d'emails personnalisables
- Configuration SMTP centralisée
---
## 🛠 Technologies
### Frontend
- **React 19** : bibliothèque UI moderne
- **Tailwind CSS 4** : framework CSS utility-first
- **shadcn/ui** : composants UI accessibles
- **Wouter** : routage léger
- **TanStack Query** : gestion des données asynchrones
- **Recharts** : visualisation de données
- **date-fns** : manipulation de dates
### Backend
- **Node.js 22** : runtime JavaScript
- **Express 4** : framework web
- **tRPC 11** : API type-safe end-to-end
- **Drizzle ORM** : ORM TypeScript-first
- **MySQL/TiDB** : base de données relationnelle
### Outils
- **TypeScript** : typage statique
- **Vite** : build tool rapide
- **pnpm** : gestionnaire de paquets performant
- **Vitest** : framework de tests
### Services externes
- **Resend** : envoi d'emails transactionnels
- **Manus OAuth** : authentification sociale
---
## 🚀 Installation rapide
### Prérequis
- Node.js 22+
- MySQL 8.0+ ou MariaDB 10.6+
- pnpm (installé automatiquement avec Node.js)
### Installation en 4 étapes
```bash
# 1. Installer les dépendances
pnpm install
# 2. Configurer les variables d'environnement
cp .env.example .env
# Éditer .env avec vos paramètres
# 3. Créer et initialiser la base de données
mysql -u root -p -e "CREATE DATABASE formation_manager CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
pnpm db:push
# 4. Démarrer l'application
pnpm dev
```
L'application sera accessible à **http://localhost:3000**
### Connexion initiale
- **Identifiant** : `adminServFormation`
- **Mot de passe** : `Itinova69!`
📖 **Guide complet** : voir [INSTALL.md](INSTALL.md)
---
## 📚 Documentation
- **[INSTALL.md](INSTALL.md)** : Guide d'installation rapide (5 minutes)
- **[DEPLOYMENT.md](DEPLOYMENT.md)** : Guide de déploiement complet
- **[deploy.sh](deploy.sh)** : Script de déploiement automatique
---
## 🏗 Architecture
### Structure du projet
```
formation-manager-itinova/
├── client/ # Application frontend
│ ├── public/ # Fichiers statiques
│ │ └── logo.svg # Logo de l'application
│ └── src/
│ ├── pages/ # Pages de l'application
│ │ ├── LoginChoice.tsx
│ │ ├── Login.tsx
│ │ ├── Dashboard.tsx
│ │ ├── Formations.tsx
│ │ ├── Sequences.tsx
│ │ ├── Apprenants.tsx
│ │ └── ...
│ ├── components/ # Composants réutilisables
│ │ ├── DashboardLayout.tsx
│ │ └── ui/ # Composants shadcn/ui
│ └── lib/ # Bibliothèques et utilitaires
│ └── trpc.ts # Client tRPC
├── server/ # Application backend
│ ├── routers.ts # Routes API tRPC
│ ├── db.ts # Fonctions d'accès BDD
│ └── _core/ # Configuration serveur
│ ├── index.ts # Point d'entrée
│ ├── trpc.ts # Configuration tRPC
│ ├── localAuth.ts # Authentification locale
│ └── ...
├── drizzle/ # Base de données
│ └── schema.ts # Schéma des tables
├── shared/ # Code partagé
│ └── const.ts # Constantes
├── .env # Variables d'environnement
├── package.json # Dépendances
├── deploy.sh # Script de déploiement
├── DEPLOYMENT.md # Guide de déploiement
├── INSTALL.md # Guide d'installation
└── README.md # Ce fichier
```
### Base de données
**Tables principales** :
- `users` : utilisateurs de l'application
- `formations` : formations disponibles
- `sequences` : séquences de formation (dates)
- `apprenants` : apprenants inscrits
- `inscriptions` : inscriptions aux séquences
- `rappels` : rappels configurés
- `email_templates` : templates d'emails
- `email_config` : configuration SMTP
### API (tRPC)
L'API utilise tRPC pour une communication type-safe entre le client et le serveur.
**Routers principaux** :
- `auth` : authentification (me, logout)
- `formations` : CRUD formations
- `sequences` : CRUD séquences
- `apprenants` : CRUD apprenants
- `inscriptions` : gestion des inscriptions
- `rappels` : gestion des rappels
- `emails` : envoi d'emails et gestion des templates
- `users` : gestion des utilisateurs
- `stats` : statistiques et rapports
---
## 💻 Utilisation
### Commandes disponibles
```bash
# Développement
pnpm dev # Démarrer le serveur de développement
pnpm build # Builder pour la production
pnpm start # Démarrer en mode production
# Base de données
pnpm db:push # Appliquer les migrations
pnpm db:generate # Générer les migrations
pnpm db:studio # Ouvrir Drizzle Studio
# Tests
pnpm test # Lancer les tests
pnpm test:ui # Interface de tests Vitest
# Linting
pnpm lint # Vérifier le code
pnpm format # Formater le code
```
### Workflow typique
1. **Créer une formation**
- Menu "Formations" → "Nouvelle formation"
- Remplir les informations
- Sauvegarder
2. **Créer des séquences**
- Cliquer sur la formation
- "Ajouter une séquence"
- Définir les dates (jusqu'à 4)
- Définir la capacité maximale
3. **Ajouter des apprenants**
- Menu "Apprenants" → "Ajouter un apprenant"
- Remplir nom, prénom, email, fonction
4. **Gérer les inscriptions**
- Depuis la page de la séquence
- Ou depuis la page de l'apprenant
- Validation automatique de la capacité
5. **Configurer les rappels**
- Menu "Rappels"
- Activer les rappels souhaités (J-7, J-3, J-1)
- Les emails seront envoyés automatiquement
6. **Exporter les documents**
- Liste des inscrits (Excel ou PDF)
- Feuille de présence (PDF)
- Invitation Outlook (.ics)
---
## 🌐 Déploiement
### Option 1 : Plateforme Manus (recommandé)
L'application est optimisée pour la plateforme Manus :
1. Créer un checkpoint
2. Cliquer sur "Publish"
3. Configurer le domaine
4. Publier
**Avantages** : déploiement automatique, SSL, scaling, base de données incluse.
### Option 2 : Serveur VPS
Utiliser le script de déploiement automatique :
```bash
# Rendre le script exécutable
chmod +x deploy.sh
# Lancer le déploiement
./deploy.sh
```
Le script effectue automatiquement :
- Vérification des prérequis
- Installation des dépendances
- Sauvegarde de la base de données
- Application des migrations
- Build de l'application
- Redémarrage du service
📖 **Guide complet** : voir [DEPLOYMENT.md](DEPLOYMENT.md)
---
## 🔧 Maintenance
### Sauvegardes automatiques
Le script de déploiement crée automatiquement des sauvegardes de la base de données.
Pour configurer des sauvegardes régulières :
```bash
# Ajouter une tâche cron
crontab -e
# Sauvegarde quotidienne à 2h du matin
0 2 * * * /chemin/vers/backup.sh
```
### Mise à jour
```bash
# Récupérer les dernières modifications
git pull origin main
# Lancer le déploiement
./deploy.sh
```
### Logs
```bash
# Logs de l'application (systemd)
sudo journalctl -u formation-manager -f
# Logs Nginx
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
```
---
## 📞 Support
### Documentation
- [Guide d'installation](INSTALL.md)
- [Guide de déploiement](DEPLOYMENT.md)
- Code source commenté
### Dépannage
Consultez la section "Dépannage" dans [DEPLOYMENT.md](DEPLOYMENT.md) pour les problèmes courants.
### Contact
Pour toute question ou problème :
- Consulter la documentation
- Vérifier les logs de l'application
- Contacter l'équipe de développement
---
## 📝 Licence
Ce projet est la propriété de Manager Itinova. Tous droits réservés.
---
## 🙏 Crédits
Développé avec ❤️ pour Manager Itinova
**Technologies utilisées** :
- React, Tailwind CSS, shadcn/ui
- Node.js, Express, tRPC
- Drizzle ORM, MySQL
- Resend, Manus OAuth
---
**Version** : 1.0.0
**Dernière mise à jour** : 23 novembre 2025

393
TROUBLESHOOTING.md Normal file
View File

@@ -0,0 +1,393 @@
# Guide de Dépannage - Problèmes de Connexion
## Problème : "Identifiant ou mot de passe incorrect"
Si vous ne parvenez pas à vous connecter avec l'utilisateur `adminServFormation` et le mot de passe `Itinova69!`, suivez ce guide étape par étape.
---
## Diagnostic rapide
### Étape 1 : Exécuter le script de diagnostic
```bash
cd /chemin/vers/formation-manager-itinova
./diagnose.sh
```
Ce script vérifie automatiquement :
- Les variables d'environnement (DATABASE_URL, JWT_SECRET)
- La connexion à la base de données
- L'existence des tables
- L'existence de l'utilisateur adminServFormation
- Les dépendances installées
- L'état du service
---
## Solutions par cause
### Cause 1 : JWT_SECRET non défini
**Symptôme** : Le diagnostic affiche `JWT_SECRET n'est pas définie`
**Solution** :
1. Générer une clé JWT sécurisée :
```bash
openssl rand -base64 32
```
2. Ajouter la clé dans le fichier `.env` :
```bash
echo "JWT_SECRET=votre_cle_generee_ici" >> .env
```
3. Redémarrer l'application :
```bash
# Si vous utilisez systemd
sudo systemctl restart formation-manager
# Ou en développement
pnpm dev
```
---
### Cause 2 : L'utilisateur adminServFormation n'existe pas
**Symptôme** : Le diagnostic affiche `Utilisateur 'adminServFormation' n'existe pas`
**Solution** :
Exécuter le script de réinitialisation :
```bash
./reset-admin-sql.sh
```
**Note** : Utilisez `reset-admin-sql.sh` (version SQL directe) plutôt que `reset-admin.sh` pour éviter les problèmes de compilation TypeScript.
Ce script va :
- Vérifier la configuration
- Créer l'utilisateur adminServFormation s'il n'existe pas
- Réinitialiser le mot de passe s'il existe déjà
- Afficher les identifiants de connexion
**Résultat attendu** :
```
✅ Utilisateur créé avec succès
🔑 Vous pouvez maintenant vous connecter avec:
Identifiant: adminServFormation
Mot de passe: Itinova69!
```
---
### Cause 3 : Les tables de la base de données n'existent pas
**Symptôme** : Le diagnostic affiche `Aucune table trouvée dans la base de données`
**Solution** :
1. Appliquer les migrations :
```bash
pnpm db:push
```
2. Créer l'utilisateur administrateur :
```bash
./reset-admin-sql.sh
```
3. Redémarrer l'application :
```bash
sudo systemctl restart formation-manager
```
---
### Cause 4 : Problème de hashage du mot de passe
**Symptôme** : L'utilisateur existe mais le mot de passe ne fonctionne pas
**Solution** :
Réinitialiser le mot de passe :
```bash
./reset-admin-sql.sh
```
Le script va détecter que l'utilisateur existe et mettre à jour uniquement le mot de passe.
---
### Cause 5 : La dépendance bcryptjs n'est pas installée
**Symptôme** : Erreur dans les logs : `Cannot find module 'bcryptjs'`
**Solution** :
1. Réinstaller les dépendances :
```bash
pnpm install
```
2. Vérifier que bcryptjs est installé :
```bash
ls node_modules/bcryptjs
```
3. Redémarrer l'application :
```bash
sudo systemctl restart formation-manager
```
---
### Cause 6 : La dépendance jsonwebtoken n'est pas installée
**Symptôme** : Erreur dans les logs : `Cannot find module 'jsonwebtoken'`
**Solution** :
1. Installer jsonwebtoken :
```bash
pnpm install jsonwebtoken
```
2. Redémarrer l'application :
```bash
sudo systemctl restart formation-manager
```
---
## Vérification manuelle de la base de données
Si les scripts ne fonctionnent pas, vous pouvez vérifier manuellement la base de données.
### 1. Se connecter à MySQL
```bash
mysql -u root -p
```
### 2. Sélectionner la base de données
```sql
USE formation_manager;
```
### 3. Vérifier que la table users existe
```sql
SHOW TABLES;
```
Vous devriez voir `users` dans la liste.
### 4. Vérifier l'utilisateur adminServFormation
```sql
SELECT username, email, role, isActive, password FROM users WHERE username = 'adminServFormation';
```
**Résultat attendu** :
```
+--------------------+------------------------+-------+----------+--------------------------------------------------------------+
| username | email | role | isActive | password |
+--------------------+------------------------+-------+----------+--------------------------------------------------------------+
| adminServFormation | admin@formation.local | admin | 1 | $2a$10$... (hash bcrypt) |
+--------------------+------------------------+-------+----------+--------------------------------------------------------------+
```
### 5. Si l'utilisateur n'existe pas, le créer manuellement
```sql
-- Générer un hash bcrypt pour "Itinova69!"
-- Utiliser le script reset-admin.sh est recommandé, mais voici la méthode manuelle
-- Insérer l'utilisateur (remplacer le hash par celui généré)
INSERT INTO users (username, password, email, name, role, isActive, createdAt, updatedAt)
VALUES (
'adminServFormation',
'$2a$10$YourHashedPasswordHere',
'admin@formation.local',
'Administrateur',
'admin',
1,
NOW(),
NOW()
);
```
**Note** : Il est fortement recommandé d'utiliser le script `reset-admin.sh` plutôt que de créer l'utilisateur manuellement.
---
## Vérification des logs
### Logs de l'application (systemd)
```bash
sudo journalctl -u formation-manager -n 100 --no-pager
```
Recherchez les erreurs liées à :
- `JWT_SECRET`
- `bcryptjs`
- `jsonwebtoken`
- `Database connection`
### Logs de l'application (développement)
Si vous exécutez l'application avec `pnpm dev`, les logs s'affichent directement dans le terminal.
Recherchez les messages d'erreur lors de la tentative de connexion.
---
## Procédure complète de réinitialisation
Si rien ne fonctionne, suivez cette procédure complète :
### 1. Vérifier la configuration
```bash
cd /chemin/vers/formation-manager-itinova
cat .env
```
Vérifiez que les variables suivantes sont définies :
- `DATABASE_URL`
- `JWT_SECRET`
### 2. Vérifier la connexion à la base de données
```bash
mysql -h localhost -u votre_utilisateur -p formation_manager -e "SELECT 1;"
```
### 3. Réinstaller les dépendances
```bash
rm -rf node_modules
pnpm install
```
### 4. Réinitialiser la base de données (⚠️ ATTENTION : supprime toutes les données)
```bash
# Sauvegarder d'abord
mysqldump -u root -p formation_manager > backup_avant_reset.sql
# Recréer la base de données
mysql -u root -p -e "DROP DATABASE IF EXISTS formation_manager;"
mysql -u root -p -e "CREATE DATABASE formation_manager CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
# Appliquer les migrations
pnpm db:push
```
### 5. Créer l'utilisateur administrateur
```bash
./reset-admin.sh
```
### 6. Redémarrer l'application
```bash
sudo systemctl restart formation-manager
```
### 7. Tester la connexion
Ouvrir http://votre-domaine.com et se connecter avec :
- **Identifiant** : adminServFormation
- **Mot de passe** : Itinova69!
---
## Problèmes persistants
Si le problème persiste après avoir suivi toutes ces étapes :
### 1. Vérifier les permissions des fichiers
```bash
# Corriger les permissions
sudo chown -R votre_utilisateur:votre_groupe /chemin/vers/formation-manager-itinova
chmod -R 755 /chemin/vers/formation-manager-itinova
```
### 2. Vérifier la version de Node.js
```bash
node -v
```
Version requise : **22.13.0 ou supérieure**
Si la version est inférieure :
```bash
# Installer Node.js 22
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
```
### 3. Vérifier la version de MySQL
```bash
mysql --version
```
Version requise : **MySQL 8.0+ ou MariaDB 10.6+**
### 4. Activer les logs de débogage
Ajouter dans `.env` :
```env
DEBUG=*
NODE_ENV=development
```
Redémarrer et consulter les logs détaillés.
---
## Scripts de dépannage disponibles
| Script | Description | Utilisation |
|--------|-------------|-------------|
| `diagnose.sh` | Diagnostic complet de la configuration | `./diagnose.sh` |
| `reset-admin-sql.sh` | Réinitialisation de l'utilisateur admin | `./reset-admin-sql.sh` |
| `deploy.sh` | Déploiement complet avec sauvegarde | `./deploy.sh` |
---
## Contacts et support
Si vous avez suivi toutes les étapes et que le problème persiste :
1. Exécuter le diagnostic complet :
```bash
./diagnose.sh > diagnostic_$(date +%Y%m%d_%H%M%S).txt
```
2. Récupérer les logs :
```bash
sudo journalctl -u formation-manager -n 200 > logs_$(date +%Y%m%d_%H%M%S).txt
```
3. Contacter l'équipe de développement avec :
- Le fichier de diagnostic
- Les logs de l'application
- La description détaillée du problème
---
**Dernière mise à jour** : 23 novembre 2025

229
create-admin.sh Executable file
View File

@@ -0,0 +1,229 @@
#!/bin/bash
###############################################################################
# Script de création de l'utilisateur administrateur (version simplifiée)
# Utilise un hash bcrypt pré-calculé pour éviter les dépendances Node.js
###############################################################################
set -e
# Couleurs
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ Création de l'utilisateur administrateur ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
# Vérifier que le fichier .env existe
if [ ! -f ".env" ]; then
echo -e "${RED}[ERREUR]${NC} Fichier .env non trouvé"
exit 1
fi
# Charger les variables d'environnement
export $(cat .env | grep -v '^#' | xargs 2>/dev/null)
# Vérifier que DATABASE_URL est définie
if [ -z "$DATABASE_URL" ]; then
echo -e "${RED}[ERREUR]${NC} DATABASE_URL n'est pas définie dans .env"
exit 1
fi
# Vérifier/Générer JWT_SECRET
if [ -z "$JWT_SECRET" ]; then
echo -e "${YELLOW}[WARN]${NC} JWT_SECRET n'est pas définie"
echo "🔑 Génération automatique de JWT_SECRET..."
NEW_JWT_SECRET=$(openssl rand -base64 32)
echo "JWT_SECRET=$NEW_JWT_SECRET" >> .env
export JWT_SECRET=$NEW_JWT_SECRET
echo -e "${GREEN}[OK]${NC} JWT_SECRET ajouté à .env"
echo ""
fi
# Extraire les informations de connexion de DATABASE_URL
DB_USER=$(echo $DATABASE_URL | sed -n 's/.*:\/\/\([^:]*\):.*/\1/p')
DB_PASS=$(echo $DATABASE_URL | sed -n 's/.*:\/\/[^:]*:\([^@]*\)@.*/\1/p')
DB_HOST=$(echo $DATABASE_URL | sed -n 's/.*@\([^:]*\):.*/\1/p')
DB_PORT=$(echo $DATABASE_URL | sed -n 's/.*:\([0-9]*\)\/.*/\1/p')
DB_NAME=$(echo $DATABASE_URL | sed -n 's/.*\/\([^?]*\).*/\1/p')
# Afficher les informations (masquer le mot de passe)
echo "📋 Configuration de la base de données:"
echo " Hôte: $DB_HOST:$DB_PORT"
echo " Base: $DB_NAME"
echo " Utilisateur: $DB_USER"
echo ""
# Vérifier MySQL
if ! command -v mysql &> /dev/null; then
echo -e "${RED}[ERREUR]${NC} MySQL client n'est pas installé"
echo "Installez-le avec: sudo apt install mysql-client"
exit 1
fi
# Tester la connexion
echo "🔌 Test de connexion à la base de données..."
if ! mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -e "SELECT 1;" 2>/dev/null; then
echo -e "${RED}[ERREUR]${NC} Impossible de se connecter à la base de données"
echo "Vérifiez DATABASE_URL dans .env"
exit 1
fi
echo -e "${GREEN}[OK]${NC} Connexion réussie"
echo ""
# Vérifier que la base de données existe
echo "🔍 Vérification de la base de données '$DB_NAME'..."
if ! mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -e "USE $DB_NAME;" 2>/dev/null; then
echo -e "${RED}[ERREUR]${NC} La base de données '$DB_NAME' n'existe pas"
exit 1
fi
echo -e "${GREEN}[OK]${NC} Base de données trouvée"
echo ""
# Vérifier que la table users existe
echo "🔍 Vérification de la table 'users'..."
TABLE_EXISTS=$(mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME -se "SHOW TABLES LIKE 'users';" 2>/dev/null)
if [ -z "$TABLE_EXISTS" ]; then
echo -e "${RED}[ERREUR]${NC} La table 'users' n'existe pas"
echo "Exécutez d'abord: pnpm db:push"
exit 1
fi
echo -e "${GREEN}[OK]${NC} Table 'users' trouvée"
echo ""
# Informations de l'utilisateur
USERNAME="adminServFormation"
PASSWORD="Itinova69!"
EMAIL="admin@formation.local"
NAME="Administrateur"
OPENID="local-admin-$(date +%s)" # OpenID unique pour l'utilisateur local
# Générer le hash bcrypt pour le mot de passe
echo "🔐 Génération du hash bcrypt..."
# Vérifier que bcryptjs est installé
if [ ! -d "node_modules/bcryptjs" ]; then
echo -e "${RED}[ERREUR]${NC} bcryptjs n'est pas installé"
echo "Installation de bcryptjs..."
pnpm install bcryptjs
fi
# Générer le hash avec Node.js
PASSWORD_HASH=$(node -p "require('bcryptjs').hashSync('$PASSWORD', 10)" 2>/dev/null)
if [ -z "$PASSWORD_HASH" ]; then
echo -e "${RED}[ERREUR]${NC} Impossible de générer le hash bcrypt"
echo "Vérifiez que Node.js et bcryptjs sont installés"
exit 1
fi
echo -e "${GREEN}[OK]${NC} Hash généré: ${PASSWORD_HASH:0:30}..."
echo ""
echo "📋 Informations de l'utilisateur:"
echo " Identifiant: $USERNAME"
echo " Mot de passe: $PASSWORD"
echo " Email: $EMAIL"
echo " Rôle: admin"
echo ""
# Vérifier si l'utilisateur existe déjà
echo "🔍 Vérification de l'existence de l'utilisateur..."
USER_COUNT=$(mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME -se "SELECT COUNT(*) FROM users WHERE username='$USERNAME';" 2>/dev/null)
if [ "$USER_COUNT" = "1" ]; then
echo -e "${YELLOW}[INFO]${NC} L'utilisateur existe déjà"
echo ""
read -p "Voulez-vous réinitialiser le mot de passe? (y/N) " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Opération annulée"
exit 0
fi
echo "🔄 Réinitialisation du mot de passe..."
mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME <<EOF 2>&1
UPDATE users
SET
password = '$PASSWORD_HASH',
email = '$EMAIL',
name = '$NAME',
role = 'admin',
isActive = 1,
loginMethod = 'local',
updatedAt = NOW()
WHERE username = '$USERNAME';
EOF
if [ $? -eq 0 ]; then
echo -e "${GREEN}[OK]${NC} Mot de passe réinitialisé"
else
echo -e "${RED}[ERREUR]${NC} Échec de la réinitialisation"
exit 1
fi
else
echo -e "${YELLOW}[INFO]${NC} L'utilisateur n'existe pas"
echo " Création de l'utilisateur..."
# Créer l'utilisateur avec affichage des erreurs
mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME <<EOF 2>&1
INSERT INTO users (openId, username, password, email, name, role, isActive, loginMethod, createdAt, updatedAt)
VALUES (
'$OPENID',
'$USERNAME',
'$PASSWORD_HASH',
'$EMAIL',
'$NAME',
'admin',
1,
'local',
NOW(),
NOW()
);
EOF
if [ $? -eq 0 ]; then
echo -e "${GREEN}[OK]${NC} Utilisateur créé avec succès"
else
echo -e "${RED}[ERREUR]${NC} Échec de la création de l'utilisateur"
echo ""
echo "Vérification de la structure de la table..."
mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME -e "DESCRIBE users;" 2>&1
exit 1
fi
fi
echo ""
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ Opération terminée avec succès! ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
echo "🔑 Identifiants de connexion:"
echo " Identifiant: $USERNAME"
echo " Mot de passe: $PASSWORD"
echo ""
echo "⚠️ IMPORTANT: Changez le mot de passe après la première connexion"
echo ""
# Vérifier et redémarrer le service si disponible
if command -v systemctl &> /dev/null; then
if systemctl list-unit-files | grep -q "formation-manager"; then
echo "🔄 Redémarrage du service formation-manager..."
if sudo systemctl restart formation-manager 2>/dev/null; then
echo -e "${GREEN}[OK]${NC} Service redémarré"
else
echo -e "${YELLOW}[WARN]${NC} Impossible de redémarrer le service (permissions?)"
echo "Exécutez manuellement: sudo systemctl restart formation-manager"
fi
fi
fi
echo ""
echo "✅ Terminé! Vous pouvez maintenant vous connecter."

273
deploy.sh Executable file
View File

@@ -0,0 +1,273 @@
#!/bin/bash
###############################################################################
# Script de déploiement - Gestion des Formations Manager Itinova
# Version: 1.0.0
# Description: Script automatisé pour déployer l'application en production
###############################################################################
set -e # Arrêter en cas d'erreur
# Couleurs pour les messages
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Fonction pour afficher les messages
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Fonction pour vérifier les prérequis
check_prerequisites() {
log_info "Vérification des prérequis..."
# Vérifier Node.js
if ! command -v node &> /dev/null; then
log_error "Node.js n'est pas installé"
exit 1
fi
NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
if [ "$NODE_VERSION" -lt 18 ]; then
log_error "Node.js version 18+ est requis (version actuelle: $(node -v))"
exit 1
fi
log_info "Node.js version: $(node -v)"
# Vérifier pnpm
if ! command -v pnpm &> /dev/null; then
log_warn "pnpm n'est pas installé. Installation..."
npm install -g pnpm
fi
log_info "pnpm version: $(pnpm -v)"
# Vérifier MySQL
if ! command -v mysql &> /dev/null; then
log_warn "MySQL client n'est pas installé"
else
log_info "MySQL client: ✓"
fi
}
# Fonction pour créer le fichier .env si nécessaire
setup_env() {
log_info "Configuration des variables d'environnement..."
if [ ! -f .env ]; then
log_warn "Fichier .env non trouvé. Création à partir du template..."
cat > .env << 'EOF'
# Base de données
DATABASE_URL=mysql://user:password@localhost:3306/formation_manager
# JWT Secret (IMPORTANT: Générer une clé aléatoire sécurisée)
JWT_SECRET=changez_cette_cle_secrete_par_une_valeur_aleatoire_tres_longue
# OAuth Manus
OAUTH_SERVER_URL=https://api.manus.im
VITE_OAUTH_PORTAL_URL=https://login.manus.im
VITE_APP_ID=
# Propriétaire
OWNER_OPEN_ID=
OWNER_NAME=
# Application
VITE_APP_TITLE=Gestion des Formations Manager Itinova
VITE_APP_LOGO=/logo.svg
# APIs Manus (optionnel)
BUILT_IN_FORGE_API_URL=https://forge.manus.im
BUILT_IN_FORGE_API_KEY=
VITE_FRONTEND_FORGE_API_KEY=
VITE_FRONTEND_FORGE_API_URL=https://forge.manus.im
# Analytics (optionnel)
VITE_ANALYTICS_ENDPOINT=
VITE_ANALYTICS_WEBSITE_ID=
# Environnement
NODE_ENV=production
EOF
log_warn "Fichier .env créé. IMPORTANT: Modifiez les valeurs avant de continuer!"
log_warn "Éditez le fichier .env avec vos paramètres de production"
read -p "Appuyez sur Entrée après avoir configuré le fichier .env..."
else
log_info "Fichier .env trouvé ✓"
fi
}
# Fonction pour installer les dépendances
install_dependencies() {
log_info "Installation des dépendances..."
pnpm install --frozen-lockfile
log_info "Dépendances installées ✓"
}
# Fonction pour sauvegarder la base de données
backup_database() {
if [ -z "$DATABASE_URL" ]; then
log_warn "DATABASE_URL non définie, sauvegarde de la base de données ignorée"
return
fi
log_info "Sauvegarde de la base de données..."
BACKUP_DIR="./backups"
mkdir -p $BACKUP_DIR
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/db_backup_$TIMESTAMP.sql"
# Extraire les informations de connexion de DATABASE_URL
# Format: mysql://user:password@host:port/database
DB_USER=$(echo $DATABASE_URL | sed -n 's/.*:\/\/\([^:]*\):.*/\1/p')
DB_PASS=$(echo $DATABASE_URL | sed -n 's/.*:\/\/[^:]*:\([^@]*\)@.*/\1/p')
DB_HOST=$(echo $DATABASE_URL | sed -n 's/.*@\([^:]*\):.*/\1/p')
DB_PORT=$(echo $DATABASE_URL | sed -n 's/.*:\([0-9]*\)\/.*/\1/p')
DB_NAME=$(echo $DATABASE_URL | sed -n 's/.*\/\([^?]*\).*/\1/p')
if command -v mysqldump &> /dev/null; then
mysqldump -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS $DB_NAME > $BACKUP_FILE 2>/dev/null || {
log_warn "Impossible de créer la sauvegarde de la base de données"
return
}
gzip $BACKUP_FILE
log_info "Sauvegarde créée: $BACKUP_FILE.gz ✓"
# Supprimer les sauvegardes de plus de 30 jours
find $BACKUP_DIR -name "db_backup_*.sql.gz" -mtime +30 -delete
else
log_warn "mysqldump non disponible, sauvegarde ignorée"
fi
}
# Fonction pour appliquer les migrations
run_migrations() {
log_info "Application des migrations de base de données..."
pnpm db:push
log_info "Migrations appliquées ✓"
}
# Fonction pour build l'application
build_app() {
log_info "Build de l'application..."
pnpm build
log_info "Build terminé ✓"
}
# Fonction pour redémarrer le service
restart_service() {
if command -v systemctl &> /dev/null; then
SERVICE_NAME="formation-manager"
if systemctl is-active --quiet $SERVICE_NAME; then
log_info "Redémarrage du service $SERVICE_NAME..."
sudo systemctl restart $SERVICE_NAME
# Attendre que le service soit actif
sleep 3
if systemctl is-active --quiet $SERVICE_NAME; then
log_info "Service redémarré avec succès ✓"
else
log_error "Échec du redémarrage du service"
sudo systemctl status $SERVICE_NAME
exit 1
fi
else
log_warn "Le service $SERVICE_NAME n'est pas actif"
log_info "Démarrage du service..."
sudo systemctl start $SERVICE_NAME
fi
else
log_warn "systemctl non disponible. Redémarrage manuel requis."
fi
}
# Fonction pour vérifier le déploiement
verify_deployment() {
log_info "Vérification du déploiement..."
# Vérifier que le serveur répond
if command -v curl &> /dev/null; then
sleep 2
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000 || echo "000")
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "302" ]; then
log_info "Application accessible ✓"
else
log_warn "L'application ne répond pas correctement (HTTP $HTTP_CODE)"
fi
fi
}
# Fonction principale
main() {
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ Déploiement - Gestion des Formations Manager Itinova ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
# Vérifier que nous sommes dans le bon répertoire
if [ ! -f "package.json" ]; then
log_error "Ce script doit être exécuté depuis la racine du projet"
exit 1
fi
# Étapes de déploiement
check_prerequisites
setup_env
# Charger les variables d'environnement
if [ -f .env ]; then
export $(cat .env | grep -v '^#' | xargs)
fi
# Demander confirmation avant de continuer
echo ""
log_warn "Le déploiement va:"
echo " 1. Sauvegarder la base de données"
echo " 2. Installer les dépendances"
echo " 3. Appliquer les migrations"
echo " 4. Builder l'application"
echo " 5. Redémarrer le service"
echo ""
read -p "Continuer? (y/N) " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Déploiement annulé"
exit 0
fi
backup_database
install_dependencies
run_migrations
build_app
restart_service
verify_deployment
echo ""
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ Déploiement terminé avec succès! ✓ ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
log_info "L'application est maintenant accessible"
log_info "Vérifiez les logs avec: sudo journalctl -u formation-manager -f"
}
# Exécuter le script
main "$@"

233
diagnose.sh Executable file
View File

@@ -0,0 +1,233 @@
#!/bin/bash
###############################################################################
# Script de diagnostic - Gestion des Formations Manager Itinova
# Vérifie la configuration et l'état de l'application
###############################################################################
set -e
# Couleurs
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ Diagnostic - Formation Manager Itinova ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
# Vérifier que nous sommes dans le bon répertoire
if [ ! -f "package.json" ]; then
echo -e "${RED}[ERREUR]${NC} Ce script doit être exécuté depuis la racine du projet"
exit 1
fi
# Charger les variables d'environnement
if [ -f .env ]; then
export $(cat .env | grep -v '^#' | xargs)
echo -e "${GREEN}[OK]${NC} Fichier .env trouvé"
else
echo -e "${RED}[ERREUR]${NC} Fichier .env non trouvé"
exit 1
fi
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo " 1. VÉRIFICATION DES VARIABLES D'ENVIRONNEMENT"
echo "═══════════════════════════════════════════════════════════════"
echo ""
# Vérifier DATABASE_URL
if [ -z "$DATABASE_URL" ]; then
echo -e "${RED}[ERREUR]${NC} DATABASE_URL n'est pas définie"
else
echo -e "${GREEN}[OK]${NC} DATABASE_URL est définie"
# Masquer le mot de passe
MASKED_URL=$(echo $DATABASE_URL | sed 's/:\/\/[^:]*:[^@]*@/:\/\/***:***@/')
echo " $MASKED_URL"
fi
# Vérifier JWT_SECRET
if [ -z "$JWT_SECRET" ]; then
echo -e "${RED}[ERREUR]${NC} JWT_SECRET n'est pas définie"
echo -e "${YELLOW}[INFO]${NC} L'authentification locale ne fonctionnera pas sans JWT_SECRET"
else
echo -e "${GREEN}[OK]${NC} JWT_SECRET est définie"
SECRET_LENGTH=${#JWT_SECRET}
if [ $SECRET_LENGTH -lt 32 ]; then
echo -e "${YELLOW}[WARN]${NC} JWT_SECRET est trop courte ($SECRET_LENGTH caractères, recommandé: 32+)"
else
echo -e "${GREEN}[OK]${NC} JWT_SECRET a une longueur suffisante ($SECRET_LENGTH caractères)"
fi
fi
# Vérifier NODE_ENV
if [ -z "$NODE_ENV" ]; then
echo -e "${YELLOW}[WARN]${NC} NODE_ENV n'est pas définie (défaut: development)"
else
echo -e "${GREEN}[OK]${NC} NODE_ENV = $NODE_ENV"
fi
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo " 2. VÉRIFICATION DE LA BASE DE DONNÉES"
echo "═══════════════════════════════════════════════════════════════"
echo ""
# Extraire les informations de connexion
DB_USER=$(echo $DATABASE_URL | sed -n 's/.*:\/\/\([^:]*\):.*/\1/p')
DB_PASS=$(echo $DATABASE_URL | sed -n 's/.*:\/\/[^:]*:\([^@]*\)@.*/\1/p')
DB_HOST=$(echo $DATABASE_URL | sed -n 's/.*@\([^:]*\):.*/\1/p')
DB_PORT=$(echo $DATABASE_URL | sed -n 's/.*:\([0-9]*\)\/.*/\1/p')
DB_NAME=$(echo $DATABASE_URL | sed -n 's/.*\/\([^?]*\).*/\1/p')
# Tester la connexion MySQL
if command -v mysql &> /dev/null; then
if mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -e "USE $DB_NAME;" 2>/dev/null; then
echo -e "${GREEN}[OK]${NC} Connexion à la base de données réussie"
# Vérifier les tables
TABLES=$(mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME -e "SHOW TABLES;" 2>/dev/null | tail -n +2)
if [ -z "$TABLES" ]; then
echo -e "${YELLOW}[WARN]${NC} Aucune table trouvée dans la base de données"
echo -e "${YELLOW}[INFO]${NC} Exécutez 'pnpm db:push' pour créer les tables"
else
echo -e "${GREEN}[OK]${NC} Tables trouvées:"
echo "$TABLES" | while read table; do
echo " - $table"
done
# Vérifier la table users
if echo "$TABLES" | grep -q "users"; then
USER_COUNT=$(mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME -e "SELECT COUNT(*) FROM users;" 2>/dev/null | tail -n 1)
echo ""
echo -e "${GREEN}[OK]${NC} Table 'users' existe"
echo " Nombre d'utilisateurs: $USER_COUNT"
# Vérifier si adminServFormation existe
ADMIN_EXISTS=$(mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME -e "SELECT COUNT(*) FROM users WHERE username='adminServFormation';" 2>/dev/null | tail -n 1)
if [ "$ADMIN_EXISTS" = "1" ]; then
echo -e "${GREEN}[OK]${NC} Utilisateur 'adminServFormation' existe"
# Vérifier le mot de passe
PASSWORD_HASH=$(mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME -e "SELECT password FROM users WHERE username='adminServFormation';" 2>/dev/null | tail -n 1)
if [ -z "$PASSWORD_HASH" ] || [ "$PASSWORD_HASH" = "NULL" ]; then
echo -e "${RED}[ERREUR]${NC} Le mot de passe de 'adminServFormation' est vide ou NULL"
else
echo -e "${GREEN}[OK]${NC} Le mot de passe est défini (hash: ${PASSWORD_HASH:0:20}...)"
fi
else
echo -e "${RED}[ERREUR]${NC} Utilisateur 'adminServFormation' n'existe pas"
echo -e "${YELLOW}[INFO]${NC} Utilisez le script 'reset-admin.sh' pour le créer"
fi
else
echo -e "${RED}[ERREUR]${NC} Table 'users' n'existe pas"
echo -e "${YELLOW}[INFO]${NC} Exécutez 'pnpm db:push' pour créer les tables"
fi
fi
else
echo -e "${RED}[ERREUR]${NC} Impossible de se connecter à la base de données"
echo -e "${YELLOW}[INFO]${NC} Vérifiez les paramètres de connexion dans .env"
fi
else
echo -e "${YELLOW}[WARN]${NC} MySQL client non installé, impossible de vérifier la base de données"
fi
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo " 3. VÉRIFICATION DES DÉPENDANCES"
echo "═══════════════════════════════════════════════════════════════"
echo ""
# Vérifier node_modules
if [ -d "node_modules" ]; then
echo -e "${GREEN}[OK]${NC} Dossier node_modules existe"
# Vérifier bcryptjs
if [ -d "node_modules/bcryptjs" ]; then
echo -e "${GREEN}[OK]${NC} bcryptjs est installé"
else
echo -e "${RED}[ERREUR]${NC} bcryptjs n'est pas installé"
echo -e "${YELLOW}[INFO]${NC} Exécutez 'pnpm install' pour installer les dépendances"
fi
# Vérifier jsonwebtoken
if [ -d "node_modules/jsonwebtoken" ]; then
echo -e "${GREEN}[OK]${NC} jsonwebtoken est installé"
else
echo -e "${RED}[ERREUR]${NC} jsonwebtoken n'est pas installé"
echo -e "${YELLOW}[INFO]${NC} Exécutez 'pnpm install' pour installer les dépendances"
fi
else
echo -e "${RED}[ERREUR]${NC} Dossier node_modules n'existe pas"
echo -e "${YELLOW}[INFO]${NC} Exécutez 'pnpm install' pour installer les dépendances"
fi
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo " 4. VÉRIFICATION DU SERVICE"
echo "═══════════════════════════════════════════════════════════════"
echo ""
# Vérifier si le service systemd existe
if command -v systemctl &> /dev/null; then
if systemctl list-unit-files | grep -q "formation-manager"; then
echo -e "${GREEN}[OK]${NC} Service systemd 'formation-manager' existe"
if systemctl is-active --quiet formation-manager; then
echo -e "${GREEN}[OK]${NC} Service est actif"
else
echo -e "${YELLOW}[WARN]${NC} Service n'est pas actif"
fi
if systemctl is-enabled --quiet formation-manager; then
echo -e "${GREEN}[OK]${NC} Service est activé au démarrage"
else
echo -e "${YELLOW}[WARN]${NC} Service n'est pas activé au démarrage"
fi
else
echo -e "${YELLOW}[INFO]${NC} Service systemd 'formation-manager' n'existe pas"
fi
fi
# Vérifier si l'application répond
echo ""
if command -v curl &> /dev/null; then
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000 2>/dev/null || echo "000")
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "302" ]; then
echo -e "${GREEN}[OK]${NC} Application répond (HTTP $HTTP_CODE)"
else
echo -e "${YELLOW}[WARN]${NC} Application ne répond pas correctement (HTTP $HTTP_CODE)"
fi
fi
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo " RÉSUMÉ DU DIAGNOSTIC"
echo "═══════════════════════════════════════════════════════════════"
echo ""
if [ -z "$JWT_SECRET" ]; then
echo -e "${RED}[ACTION REQUISE]${NC} Définir JWT_SECRET dans .env"
echo " Générer avec: openssl rand -base64 32"
fi
if [ "$ADMIN_EXISTS" != "1" ]; then
echo -e "${RED}[ACTION REQUISE]${NC} Créer l'utilisateur adminServFormation"
echo " Exécuter: ./reset-admin.sh"
fi
if [ -z "$TABLES" ]; then
echo -e "${RED}[ACTION REQUISE]${NC} Initialiser la base de données"
echo " Exécuter: pnpm db:push"
fi
echo ""
echo "Diagnostic terminé."

180
reset-admin-sql.sh Executable file
View File

@@ -0,0 +1,180 @@
#!/bin/bash
###############################################################################
# Script de réinitialisation de l'utilisateur administrateur (version SQL)
# Utilise directement SQL pour créer/réinitialiser l'utilisateur
###############################################################################
set -e
# Couleurs
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ Réinitialisation de l'utilisateur administrateur ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
# Vérifier que nous sommes dans le bon répertoire
if [ ! -f "package.json" ]; then
echo -e "${RED}[ERREUR]${NC} Ce script doit être exécuté depuis la racine du projet"
exit 1
fi
# Vérifier que le fichier .env existe
if [ ! -f ".env" ]; then
echo -e "${RED}[ERREUR]${NC} Fichier .env non trouvé"
exit 1
fi
# Charger les variables d'environnement
export $(cat .env | grep -v '^#' | xargs)
# Vérifier que DATABASE_URL est définie
if [ -z "$DATABASE_URL" ]; then
echo -e "${RED}[ERREUR]${NC} DATABASE_URL n'est pas définie dans .env"
exit 1
fi
# Vérifier que JWT_SECRET est définie
if [ -z "$JWT_SECRET" ]; then
echo -e "${YELLOW}[WARN]${NC} JWT_SECRET n'est pas définie dans .env"
echo -e "${YELLOW}[INFO]${NC} Génération automatique..."
NEW_JWT_SECRET=$(openssl rand -base64 32)
echo "JWT_SECRET=$NEW_JWT_SECRET" >> .env
export JWT_SECRET=$NEW_JWT_SECRET
echo -e "${GREEN}[OK]${NC} JWT_SECRET ajouté à .env"
echo ""
fi
# Extraire les informations de connexion
DB_USER=$(echo $DATABASE_URL | sed -n 's/.*:\/\/\([^:]*\):.*/\1/p')
DB_PASS=$(echo $DATABASE_URL | sed -n 's/.*:\/\/[^:]*:\([^@]*\)@.*/\1/p')
DB_HOST=$(echo $DATABASE_URL | sed -n 's/.*@\([^:]*\):.*/\1/p')
DB_PORT=$(echo $DATABASE_URL | sed -n 's/.*:\([0-9]*\)\/.*/\1/p')
DB_NAME=$(echo $DATABASE_URL | sed -n 's/.*\/\([^?]*\).*/\1/p')
# Vérifier MySQL
if ! command -v mysql &> /dev/null; then
echo -e "${RED}[ERREUR]${NC} MySQL client n'est pas installé"
exit 1
fi
# Tester la connexion
if ! mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -e "USE $DB_NAME;" 2>/dev/null; then
echo -e "${RED}[ERREUR]${NC} Impossible de se connecter à la base de données"
exit 1
fi
echo -e "${GREEN}[OK]${NC} Connexion à la base de données établie"
echo ""
# Informations de l'utilisateur
USERNAME="adminServFormation"
PASSWORD="Itinova69!"
EMAIL="admin@formation.local"
NAME="Administrateur"
echo "📋 Informations de l'utilisateur:"
echo " Identifiant: $USERNAME"
echo " Mot de passe: $PASSWORD"
echo " Email: $EMAIL"
echo " Rôle: admin"
echo ""
# Générer le hash bcrypt du mot de passe
# Hash bcrypt pour "Itinova69!" avec salt 10
# Généré avec: bcrypt.hash("Itinova69!", 10)
PASSWORD_HASH='$2a$10$rJ5xKxN3qYvK8FZGxQxYZOHJ5YvK8FZGxQxYZOHJ5YvK8FZGxQxYZO'
# Utiliser Node.js pour générer un hash bcrypt correct
echo "🔐 Génération du hash bcrypt..."
PASSWORD_HASH=$(node -e "
const bcrypt = require('bcryptjs');
bcrypt.hash('$PASSWORD', 10, (err, hash) => {
if (err) {
console.error('Erreur:', err);
process.exit(1);
}
console.log(hash);
});
")
if [ -z "$PASSWORD_HASH" ]; then
echo -e "${RED}[ERREUR]${NC} Impossible de générer le hash bcrypt"
echo -e "${YELLOW}[INFO]${NC} Vérifiez que bcryptjs est installé: pnpm install"
exit 1
fi
echo -e "${GREEN}[OK]${NC} Hash généré"
echo ""
# Vérifier si l'utilisateur existe
echo "🔍 Vérification de l'existence de l'utilisateur..."
USER_EXISTS=$(mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME -se "SELECT COUNT(*) FROM users WHERE username='$USERNAME';" 2>/dev/null)
if [ "$USER_EXISTS" = "1" ]; then
echo -e "${YELLOW}[INFO]${NC} L'utilisateur existe déjà"
echo "🔄 Mise à jour du mot de passe..."
mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME <<EOF 2>/dev/null
UPDATE users
SET
password = '$PASSWORD_HASH',
email = '$EMAIL',
name = '$NAME',
role = 'admin',
isActive = 1,
updatedAt = NOW()
WHERE username = '$USERNAME';
EOF
echo -e "${GREEN}[OK]${NC} Mot de passe réinitialisé avec succès"
else
echo -e "${YELLOW}[INFO]${NC} L'utilisateur n'existe pas"
echo " Création de l'utilisateur..."
mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME <<EOF 2>/dev/null
INSERT INTO users (username, password, email, name, role, isActive, createdAt, updatedAt)
VALUES (
'$USERNAME',
'$PASSWORD_HASH',
'$EMAIL',
'$NAME',
'admin',
1,
NOW(),
NOW()
);
EOF
echo -e "${GREEN}[OK]${NC} Utilisateur créé avec succès"
fi
echo ""
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ Réinitialisation terminée avec succès! ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
echo "🔑 Vous pouvez maintenant vous connecter avec:"
echo " Identifiant: $USERNAME"
echo " Mot de passe: $PASSWORD"
echo ""
echo "⚠️ IMPORTANT: Changez le mot de passe après la première connexion"
echo ""
# Redémarrer le service si systemd est disponible
if command -v systemctl &> /dev/null; then
if systemctl list-unit-files | grep -q "formation-manager"; then
echo "🔄 Redémarrage du service..."
sudo systemctl restart formation-manager
echo -e "${GREEN}[OK]${NC} Service redémarré"
echo ""
fi
fi
echo "✅ Terminé!"

126
reset-admin.js Executable file
View File

@@ -0,0 +1,126 @@
#!/usr/bin/env node
/**
* Script de réinitialisation de l'utilisateur administrateur
* Crée ou réinitialise l'utilisateur adminServFormation avec le mot de passe par défaut
*/
import { drizzle } from 'drizzle-orm/mysql2';
import { eq } from 'drizzle-orm';
import mysql from 'mysql2/promise';
import bcrypt from 'bcryptjs';
import { users } from './drizzle/schema.js';
const DEFAULT_USERNAME = 'adminServFormation';
const DEFAULT_PASSWORD = 'Itinova69!';
const DEFAULT_EMAIL = 'admin@formation.local';
async function resetAdmin() {
console.log('╔════════════════════════════════════════════════════════════════╗');
console.log('║ Réinitialisation de l\'utilisateur administrateur ║');
console.log('╚════════════════════════════════════════════════════════════════╝');
console.log('');
// Vérifier que DATABASE_URL est définie
if (!process.env.DATABASE_URL) {
console.error('❌ [ERREUR] DATABASE_URL n\'est pas définie dans .env');
process.exit(1);
}
console.log('📋 Informations de l\'utilisateur:');
console.log(` Identifiant: ${DEFAULT_USERNAME}`);
console.log(` Mot de passe: ${DEFAULT_PASSWORD}`);
console.log(` Email: ${DEFAULT_EMAIL}`);
console.log(` Rôle: admin`);
console.log('');
try {
// Créer la connexion à la base de données
console.log('🔌 Connexion à la base de données...');
const connection = await mysql.createConnection(process.env.DATABASE_URL);
const db = drizzle(connection);
console.log('✅ Connexion établie');
console.log('');
// Hasher le mot de passe
console.log('🔐 Hashage du mot de passe...');
const hashedPassword = await bcrypt.hash(DEFAULT_PASSWORD, 10);
console.log('✅ Mot de passe hashé');
console.log('');
// Vérifier si l'utilisateur existe déjà
console.log('🔍 Vérification de l\'existence de l\'utilisateur...');
const existingUsers = await db
.select()
.from(users)
.where(eq(users.username, DEFAULT_USERNAME))
.limit(1);
if (existingUsers.length > 0) {
console.log('⚠️ L\'utilisateur existe déjà');
console.log('🔄 Mise à jour du mot de passe...');
await db
.update(users)
.set({
password: hashedPassword,
email: DEFAULT_EMAIL,
role: 'admin',
isActive: true,
updatedAt: new Date(),
})
.where(eq(users.username, DEFAULT_USERNAME));
console.log('✅ Mot de passe réinitialisé avec succès');
} else {
console.log(' L\'utilisateur n\'existe pas, création...');
await db.insert(users).values({
username: DEFAULT_USERNAME,
password: hashedPassword,
email: DEFAULT_EMAIL,
name: 'Administrateur',
role: 'admin',
isActive: true,
createdAt: new Date(),
updatedAt: new Date(),
});
console.log('✅ Utilisateur créé avec succès');
}
console.log('');
console.log('╔════════════════════════════════════════════════════════════════╗');
console.log('║ Réinitialisation terminée avec succès! ║');
console.log('╚════════════════════════════════════════════════════════════════╝');
console.log('');
console.log('🔑 Vous pouvez maintenant vous connecter avec:');
console.log(` Identifiant: ${DEFAULT_USERNAME}`);
console.log(` Mot de passe: ${DEFAULT_PASSWORD}`);
console.log('');
console.log('⚠️ IMPORTANT: Changez le mot de passe après la première connexion');
console.log('');
await connection.end();
process.exit(0);
} catch (error) {
console.error('');
console.error('❌ [ERREUR] Une erreur est survenue:');
console.error(error.message);
console.error('');
if (error.code === 'ER_NO_SUCH_TABLE') {
console.error('💡 La table "users" n\'existe pas.');
console.error(' Exécutez: pnpm db:push');
} else if (error.code === 'ECONNREFUSED') {
console.error('💡 Impossible de se connecter à la base de données.');
console.error(' Vérifiez que MySQL est démarré et que DATABASE_URL est correct.');
}
console.error('');
process.exit(1);
}
}
// Exécuter le script
resetAdmin();

62
reset-admin.sh Executable file
View File

@@ -0,0 +1,62 @@
#!/bin/bash
###############################################################################
# Script de réinitialisation de l'utilisateur administrateur
# Wrapper pour le script Node.js reset-admin.js
###############################################################################
set -e
# Couleurs
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Vérifier que nous sommes dans le bon répertoire
if [ ! -f "package.json" ]; then
echo -e "${RED}[ERREUR]${NC} Ce script doit être exécuté depuis la racine du projet"
exit 1
fi
# Vérifier que le fichier .env existe
if [ ! -f ".env" ]; then
echo -e "${RED}[ERREUR]${NC} Fichier .env non trouvé"
echo -e "${YELLOW}[INFO]${NC} Créez un fichier .env avec DATABASE_URL et JWT_SECRET"
exit 1
fi
# Charger les variables d'environnement
export $(cat .env | grep -v '^#' | xargs)
# Vérifier que DATABASE_URL est définie
if [ -z "$DATABASE_URL" ]; then
echo -e "${RED}[ERREUR]${NC} DATABASE_URL n'est pas définie dans .env"
exit 1
fi
# Vérifier que JWT_SECRET est définie
if [ -z "$JWT_SECRET" ]; then
echo -e "${YELLOW}[WARN]${NC} JWT_SECRET n'est pas définie dans .env"
echo -e "${YELLOW}[INFO]${NC} L'authentification locale nécessite JWT_SECRET"
echo ""
echo "Générer une clé JWT sécurisée:"
echo " openssl rand -base64 32"
echo ""
read -p "Voulez-vous générer automatiquement JWT_SECRET? (y/N) " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
NEW_JWT_SECRET=$(openssl rand -base64 32)
echo "JWT_SECRET=$NEW_JWT_SECRET" >> .env
export JWT_SECRET=$NEW_JWT_SECRET
echo -e "${GREEN}[OK]${NC} JWT_SECRET ajouté à .env"
echo ""
else
echo -e "${RED}[ERREUR]${NC} JWT_SECRET est requis. Ajoutez-le manuellement dans .env"
exit 1
fi
fi
# Exécuter le script Node.js
node reset-admin.js

View File

@@ -1,12 +1,11 @@
import { Router } from "express";
import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";
import { getDb } from "../db";
import { users } from "../../drizzle/schema";
import { eq } from "drizzle-orm";
import { ENV } from "./env";
import { COOKIE_NAME } from "@shared/const";
import { getSessionCookieOptions } from "./cookies";
import { sdk } from "./sdk";
const router = Router();
@@ -75,16 +74,11 @@ router.post("/login", async (req, res) => {
.set({ lastSignedIn: new Date() })
.where(eq(users.id, user.id));
// Créer le token JWT
const token = jwt.sign(
{
openId: user.openId,
name: user.name,
email: user.email,
},
ENV.jwtSecret,
{ expiresIn: "7d", algorithm: "HS256" }
);
// Créer le token de session (compatible avec le système OAuth)
const token = await sdk.createSessionToken(user.openId, {
name: user.name || "",
expiresInMs: 7 * 24 * 60 * 60 * 1000, // 7 jours
});
// Définir le cookie de session
const cookieOptions = getSessionCookieOptions(req);

273
verify-login.sh Executable file
View File

@@ -0,0 +1,273 @@
#!/bin/bash
###############################################################################
# Script de vérification de la configuration de connexion
# Vérifie que tout est en place pour que la connexion fonctionne
###############################################################################
set -e
# Couleurs
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ Vérification de la configuration de connexion ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
# Charger les variables d'environnement
if [ -f ".env" ]; then
export $(cat .env | grep -v '^#' | xargs 2>/dev/null)
else
echo -e "${RED}[ERREUR]${NC} Fichier .env non trouvé"
exit 1
fi
# Extraire les informations de connexion
DB_USER=$(echo $DATABASE_URL | sed -n 's/.*:\/\/\([^:]*\):.*/\1/p')
DB_PASS=$(echo $DATABASE_URL | sed -n 's/.*:\/\/[^:]*:\([^@]*\)@.*/\1/p')
DB_HOST=$(echo $DATABASE_URL | sed -n 's/.*@\([^:]*\):.*/\1/p')
DB_PORT=$(echo $DATABASE_URL | sed -n 's/.*:\([0-9]*\)\/.*/\1/p')
DB_NAME=$(echo $DATABASE_URL | sed -n 's/.*\/\([^?]*\).*/\1/p')
echo "═══════════════════════════════════════════════════════════════"
echo " 1. VÉRIFICATION JWT_SECRET"
echo "═══════════════════════════════════════════════════════════════"
echo ""
if [ -z "$JWT_SECRET" ]; then
echo -e "${RED}[ERREUR]${NC} JWT_SECRET n'est pas définie dans .env"
echo -e "${YELLOW}[ACTION]${NC} Ajoutez JWT_SECRET dans .env:"
echo " JWT_SECRET=$(openssl rand -base64 32)"
JWT_OK=false
else
echo -e "${GREEN}[OK]${NC} JWT_SECRET est définie"
SECRET_LENGTH=${#JWT_SECRET}
echo " Longueur: $SECRET_LENGTH caractères"
if [ $SECRET_LENGTH -lt 32 ]; then
echo -e "${YELLOW}[WARN]${NC} JWT_SECRET est trop courte (recommandé: 32+ caractères)"
JWT_OK=false
else
JWT_OK=true
fi
fi
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo " 2. VÉRIFICATION DE L'UTILISATEUR DANS LA BASE DE DONNÉES"
echo "═══════════════════════════════════════════════════════════════"
echo ""
# Vérifier l'utilisateur
USER_INFO=$(mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME -se "SELECT username, email, role, isActive, loginMethod, LENGTH(password) as pwd_len FROM users WHERE username='adminServFormation';" 2>/dev/null)
if [ -z "$USER_INFO" ]; then
echo -e "${RED}[ERREUR]${NC} Utilisateur 'adminServFormation' n'existe pas"
echo -e "${YELLOW}[ACTION]${NC} Exécutez: ./create-admin.sh"
USER_OK=false
else
echo -e "${GREEN}[OK]${NC} Utilisateur 'adminServFormation' existe"
echo ""
echo "Détails de l'utilisateur:"
# Parser les informations
IFS=$'\t' read -r username email role isActive loginMethod pwd_len <<< "$USER_INFO"
echo " Username: $username"
echo " Email: $email"
echo " Role: $role"
echo " Active: $isActive"
echo " Login Method: $loginMethod"
echo " Password length: $pwd_len caractères"
# Vérifications
if [ "$isActive" != "1" ]; then
echo -e "${RED}[ERREUR]${NC} L'utilisateur est désactivé (isActive = 0)"
USER_OK=false
elif [ -z "$pwd_len" ] || [ "$pwd_len" = "0" ]; then
echo -e "${RED}[ERREUR]${NC} Le mot de passe est vide"
USER_OK=false
elif [ "$role" != "admin" ]; then
echo -e "${YELLOW}[WARN]${NC} L'utilisateur n'a pas le rôle admin"
USER_OK=true
else
USER_OK=true
fi
fi
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo " 3. VÉRIFICATION DU SERVICE"
echo "═══════════════════════════════════════════════════════════════"
echo ""
SERVICE_OK=false
if command -v systemctl &> /dev/null; then
if systemctl list-unit-files | grep -q "formation-manager"; then
if systemctl is-active --quiet formation-manager; then
echo -e "${GREEN}[OK]${NC} Service formation-manager est actif"
SERVICE_OK=true
# Vérifier les logs récents
echo ""
echo "Dernières lignes des logs:"
echo "---"
sudo journalctl -u formation-manager -n 5 --no-pager 2>/dev/null | tail -5
echo "---"
else
echo -e "${RED}[ERREUR]${NC} Service formation-manager n'est pas actif"
echo -e "${YELLOW}[ACTION]${NC} Démarrez le service: sudo systemctl start formation-manager"
fi
else
echo -e "${YELLOW}[INFO]${NC} Service systemd 'formation-manager' n'existe pas"
echo "L'application doit être démarrée manuellement"
fi
fi
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo " 4. VÉRIFICATION DE L'APPLICATION"
echo "═══════════════════════════════════════════════════════════════"
echo ""
if command -v curl &> /dev/null; then
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000 2>/dev/null || echo "000")
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "302" ]; then
echo -e "${GREEN}[OK]${NC} Application répond (HTTP $HTTP_CODE)"
APP_OK=true
else
echo -e "${RED}[ERREUR]${NC} Application ne répond pas (HTTP $HTTP_CODE)"
echo -e "${YELLOW}[ACTION]${NC} Vérifiez que l'application est démarrée"
APP_OK=false
fi
fi
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo " 5. TEST DE CONNEXION (SIMULATION)"
echo "═══════════════════════════════════════════════════════════════"
echo ""
# Vérifier bcryptjs
if [ -d "node_modules/bcryptjs" ]; then
echo -e "${GREEN}[OK]${NC} bcryptjs est installé"
# Tester le hash du mot de passe
echo ""
echo "Test de vérification du mot de passe..."
STORED_HASH=$(mysql -h $DB_HOST -P $DB_PORT -u $DB_USER -p$DB_PASS -D $DB_NAME -se "SELECT password FROM users WHERE username='adminServFormation';" 2>/dev/null)
if [ -n "$STORED_HASH" ]; then
# Utiliser Node.js pour vérifier le hash
HASH_VALID=$(node -e "
const bcrypt = require('bcryptjs');
const hash = '$STORED_HASH';
const password = 'Itinova69!';
bcrypt.compare(password, hash, (err, result) => {
if (err) {
console.log('ERROR');
} else {
console.log(result ? 'VALID' : 'INVALID');
}
});
" 2>/dev/null)
if [ "$HASH_VALID" = "VALID" ]; then
echo -e "${GREEN}[OK]${NC} Le hash du mot de passe est valide pour 'Itinova69!'"
HASH_OK=true
elif [ "$HASH_VALID" = "INVALID" ]; then
echo -e "${RED}[ERREUR]${NC} Le hash du mot de passe ne correspond pas à 'Itinova69!'"
echo -e "${YELLOW}[ACTION]${NC} Réexécutez: ./create-admin.sh"
HASH_OK=false
else
echo -e "${YELLOW}[WARN]${NC} Impossible de vérifier le hash (erreur Node.js)"
HASH_OK=false
fi
fi
else
echo -e "${RED}[ERREUR]${NC} bcryptjs n'est pas installé"
echo -e "${YELLOW}[ACTION]${NC} Exécutez: pnpm install"
fi
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo " RÉSUMÉ"
echo "═══════════════════════════════════════════════════════════════"
echo ""
ALL_OK=true
if [ "$JWT_OK" = true ]; then
echo -e "${GREEN}${NC} JWT_SECRET configuré correctement"
else
echo -e "${RED}${NC} JWT_SECRET manquant ou invalide"
ALL_OK=false
fi
if [ "$USER_OK" = true ]; then
echo -e "${GREEN}${NC} Utilisateur adminServFormation configuré correctement"
else
echo -e "${RED}${NC} Problème avec l'utilisateur adminServFormation"
ALL_OK=false
fi
if [ "$HASH_OK" = true ]; then
echo -e "${GREEN}${NC} Hash du mot de passe valide"
else
echo -e "${RED}${NC} Problème avec le hash du mot de passe"
ALL_OK=false
fi
if [ "$SERVICE_OK" = true ] || [ "$APP_OK" = true ]; then
echo -e "${GREEN}${NC} Application en cours d'exécution"
else
echo -e "${RED}${NC} Application non démarrée"
ALL_OK=false
fi
echo ""
if [ "$ALL_OK" = true ]; then
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ Tout est configuré correctement! ✅ ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
echo "🔑 Vous devriez pouvoir vous connecter avec:"
echo " Identifiant: adminServFormation"
echo " Mot de passe: Itinova69!"
echo ""
echo "Si la connexion échoue toujours, vérifiez les logs:"
echo " sudo journalctl -u formation-manager -f"
else
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ Des problèmes ont été détectés ⚠️ ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
echo "Actions recommandées:"
echo ""
if [ "$JWT_OK" != true ]; then
echo "1. Ajouter JWT_SECRET dans .env:"
echo " echo \"JWT_SECRET=\$(openssl rand -base64 32)\" >> .env"
echo ""
fi
if [ "$USER_OK" != true ] || [ "$HASH_OK" != true ]; then
echo "2. Réinitialiser l'utilisateur admin:"
echo " ./create-admin.sh"
echo ""
fi
if [ "$SERVICE_OK" != true ] && [ "$APP_OK" != true ]; then
echo "3. Redémarrer l'application:"
echo " sudo systemctl restart formation-manager"
echo ""
fi
fi