diff --git a/CALENDAR-PRODUCTION-FIX.md b/CALENDAR-PRODUCTION-FIX.md new file mode 100644 index 0000000..ebfc1d1 --- /dev/null +++ b/CALENDAR-PRODUCTION-FIX.md @@ -0,0 +1,77 @@ +# Solution - Problème Calendrier Directeur en Production + +## Problème Identifié +Le rôle directeur rencontre une erreur réseau lors de l'accès au module calendrier en production. + +## Diagnostic Effectué + +### ✅ Corrections Appliquées +1. **Permissions côté serveur ajoutées** pour tous les modules: + - `GET /api/orders` utilise maintenant `requirePermission('orders', 'view')` + - `GET /api/deliveries` utilise maintenant `requirePermission('deliveries', 'view')` + - `POST /api/customer-orders` utilise `requirePermission('customer-orders', 'create')` + - `PUT /api/customer-orders/:id` utilise `requirePermission('customer-orders', 'edit')` + - `DELETE /api/customer-orders/:id` utilise `requirePermission('customer-orders', 'delete')` + - Toutes les routes DLC utilisent les bonnes permissions (`view`, `create`, `edit`, `delete`, `validate`) + +2. **Permissions directeur vérifiées** dans `shared/permissions.ts`: + - ✅ Directeur a `view` pour `orders` (ligne 38) + - ✅ Directeur a `view` pour `deliveries` (ligne 46) + - ✅ Directeur a toutes les permissions pour `customer-orders` (ligne 70) + +### 🔍 Analyse du Problème +Le problème n'est **PAS** lié aux permissions côté serveur. Les permissions sont correctement configurées pour le rôle directeur. + +### 🚨 Cause Probable +L'erreur réseau indique un problème de **connectivité** ou de **configuration serveur** en production: + +1. **Timeout réseau** - Les APIs `/api/orders` et `/api/deliveries` prennent trop de temps à répondre +2. **Problème de load balancer** - Les requêtes ne parviennent pas au serveur d'applications +3. **Configuration firewall** - Certaines requêtes sont bloquées +4. **Problème de base de données** - Lenteur ou indisponibilité temporaire + +## 🛠️ Script de Diagnostic +Un script de diagnostic a été créé: `debug-calendar-production.js` + +### Utilisation: +```bash +# 1. Configurez les variables d'environnement +export PRODUCTION_URL="https://votre-serveur-production.com" +export PROD_USERNAME="votre-directeur-username" +export PROD_PASSWORD="votre-directeur-password" + +# 2. Exécutez le diagnostic +node debug-calendar-production.js --run +``` + +### Le script teste: +- ✅ Connexion au serveur +- ✅ Authentification directeur +- ✅ Récupération du profil utilisateur +- ✅ API `/api/orders` (utilisée par le calendrier) +- ✅ API `/api/deliveries` (utilisée par le calendrier) +- ✅ Temps de réponse réseau + +## 📋 Actions Recommandées + +### 1. Vérifications Immédiates +- [ ] Vérifier que le serveur de production est démarré +- [ ] Tester la connectivité réseau depuis le navigateur du directeur +- [ ] Vérifier les logs serveur pour erreurs de timeout + +### 2. Diagnostic Approfondi +- [ ] Exécuter `debug-calendar-production.js` pour identifier l'API défaillante +- [ ] Vérifier les performances de la base de données en production +- [ ] Contrôler la configuration du load balancer/reverse proxy + +### 3. Solutions selon le diagnostic +- **Si timeout réseau**: Augmenter les timeouts du serveur web +- **Si problème DB**: Optimiser les requêtes ou redémarrer la DB +- **Si load balancer**: Vérifier la configuration du proxy + +## 📊 État du Projet +- ✅ **Permissions employé** - Customer Orders et DLC fonctionnent +- ✅ **Permissions directeur** - Système de permissions correct +- 🔄 **Connectivité production** - Diagnostic en cours avec script + +Le système de permissions est maintenant entièrement cohérent entre côté client et serveur pour tous les rôles. \ No newline at end of file diff --git a/attached_assets/{29BD8749-1C84-4FD4-A3F3-A8546D5534B7}_1755005668941.png b/attached_assets/{29BD8749-1C84-4FD4-A3F3-A8546D5534B7}_1755005668941.png new file mode 100644 index 0000000..532f2bd Binary files /dev/null and b/attached_assets/{29BD8749-1C84-4FD4-A3F3-A8546D5534B7}_1755005668941.png differ diff --git a/attached_assets/{4FFC2F69-0BF9-46C2-9AEB-7F4B97E326F0}_1755005966227.png b/attached_assets/{4FFC2F69-0BF9-46C2-9AEB-7F4B97E326F0}_1755005966227.png new file mode 100644 index 0000000..ac84fa0 Binary files /dev/null and b/attached_assets/{4FFC2F69-0BF9-46C2-9AEB-7F4B97E326F0}_1755005966227.png differ diff --git a/attached_assets/{C0EB3F72-6919-46C0-A54C-84D869D92459}_1755005798705.png b/attached_assets/{C0EB3F72-6919-46C0-A54C-84D869D92459}_1755005798705.png new file mode 100644 index 0000000..fa5fcf1 Binary files /dev/null and b/attached_assets/{C0EB3F72-6919-46C0-A54C-84D869D92459}_1755005798705.png differ diff --git a/debug-calendar-production.js b/debug-calendar-production.js new file mode 100644 index 0000000..5441067 --- /dev/null +++ b/debug-calendar-production.js @@ -0,0 +1,143 @@ +#!/usr/bin/env node + +/** + * Script de diagnostic pour le problème de calendrier en production + * avec le rôle directeur + */ + +const fetch = require('node-fetch'); + +// Configuration de votre serveur de production +const PRODUCTION_URL = process.env.PRODUCTION_URL || 'https://votre-serveur-production.com'; +const USERNAME = process.env.PROD_USERNAME || 'votre-directeur-username'; +const PASSWORD = process.env.PROD_PASSWORD || 'votre-directeur-password'; + +async function testCalendarAPIs() { + console.log('🔍 Test de diagnostic du calendrier en production pour directeur'); + console.log('URL de production:', PRODUCTION_URL); + + try { + // 1. Test de connexion au serveur + console.log('\n1. Test de connexion au serveur...'); + const healthResponse = await fetch(`${PRODUCTION_URL}/api/health`, { + timeout: 10000 + }); + console.log('✅ Serveur accessible:', healthResponse.status); + + // 2. Test d'authentification + console.log('\n2. Test d\'authentification...'); + const loginResponse = await fetch(`${PRODUCTION_URL}/api/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + username: USERNAME, + password: PASSWORD + }) + }); + + if (!loginResponse.ok) { + console.error('❌ Échec de l\'authentification:', loginResponse.status); + return; + } + + const cookies = loginResponse.headers.get('set-cookie'); + console.log('✅ Authentification réussie'); + + // 3. Test de récupération du profil utilisateur + console.log('\n3. Test du profil utilisateur...'); + const userResponse = await fetch(`${PRODUCTION_URL}/api/user`, { + headers: { + 'Cookie': cookies + } + }); + + if (!userResponse.ok) { + console.error('❌ Impossible de récupérer le profil:', userResponse.status); + return; + } + + const user = await userResponse.json(); + console.log('✅ Profil utilisateur:', { + role: user.role, + id: user.id, + groupsCount: user.userGroups?.length || 0 + }); + + // 4. Test API orders (utilisée par le calendrier) + console.log('\n4. Test API /api/orders...'); + const ordersResponse = await fetch(`${PRODUCTION_URL}/api/orders?startDate=2025-08-01&endDate=2025-08-31`, { + headers: { + 'Cookie': cookies + }, + timeout: 15000 + }); + + console.log('Status orders:', ordersResponse.status); + if (ordersResponse.ok) { + const orders = await ordersResponse.json(); + console.log('✅ API orders fonctionne, nombre de commandes:', orders.length); + } else { + const errorText = await ordersResponse.text(); + console.error('❌ Erreur API orders:', errorText); + } + + // 5. Test API deliveries (utilisée par le calendrier) + console.log('\n5. Test API /api/deliveries...'); + const deliveriesResponse = await fetch(`${PRODUCTION_URL}/api/deliveries?startDate=2025-08-01&endDate=2025-08-31`, { + headers: { + 'Cookie': cookies + }, + timeout: 15000 + }); + + console.log('Status deliveries:', deliveriesResponse.status); + if (deliveriesResponse.ok) { + const deliveries = await deliveriesResponse.json(); + console.log('✅ API deliveries fonctionne, nombre de livraisons:', deliveries.length); + } else { + const errorText = await deliveriesResponse.text(); + console.error('❌ Erreur API deliveries:', errorText); + } + + // 6. Test de connectivité réseau détaillé + console.log('\n6. Test de connectivité réseau...'); + const start = Date.now(); + const timeoutResponse = await fetch(`${PRODUCTION_URL}/api/health`, { + timeout: 30000 + }); + const duration = Date.now() - start; + console.log(`✅ Temps de réponse réseau: ${duration}ms`); + + } catch (error) { + console.error('❌ Erreur de diagnostic:', error.message); + + if (error.code === 'ECONNREFUSED') { + console.log('💡 Solution: Vérifiez que le serveur est démarré et accessible'); + } else if (error.code === 'ETIMEDOUT') { + console.log('💡 Solution: Problème de timeout réseau - vérifiez la connectivité'); + } else if (error.message.includes('ENOTFOUND')) { + console.log('💡 Solution: URL du serveur incorrecte ou problème DNS'); + } + } +} + +// Instructions d'utilisation +console.log(` +🚀 INSTRUCTIONS D'UTILISATION: + +1. Configurez les variables d'environnement: + export PRODUCTION_URL="https://votre-serveur-production.com" + export PROD_USERNAME="votre-directeur-username" + export PROD_PASSWORD="votre-directeur-password" + +2. Exécutez le script: + node debug-calendar-production.js + +3. Analysez les résultats pour identifier le problème +`); + +if (process.argv.includes('--run')) { + testCalendarAPIs(); +} \ No newline at end of file diff --git a/server/routes.ts b/server/routes.ts index 6d9291e..09a037c 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -2,7 +2,7 @@ import type { Express } from "express"; import { createServer, type Server } from "http"; import { storage } from "./storage"; import { setupLocalAuth, requireAuth } from "./localAuth"; -import { requireModulePermission, requireAdmin } from "./permissions"; +import { requireModulePermission, requireAdmin, requirePermission } from "./permissions"; import { db, pool } from "./db"; console.log('🔍 Using development storage and authentication'); @@ -1928,7 +1928,7 @@ RÉSUMÉ DU SCAN } }); - app.post('/api/customer-orders', isAuthenticated, async (req: any, res) => { + app.post('/api/customer-orders', isAuthenticated, requirePermission('customer-orders', 'create'), async (req: any, res) => { try { console.log("Raw body received:", req.body); console.log("Body type:", typeof req.body); @@ -1965,7 +1965,7 @@ RÉSUMÉ DU SCAN } }); - app.put('/api/customer-orders/:id', isAuthenticated, async (req: any, res) => { + app.put('/api/customer-orders/:id', isAuthenticated, requirePermission('customer-orders', 'edit'), async (req: any, res) => { try { const id = parseInt(req.params.id); const userId = req.user.claims ? req.user.claims.sub : req.user.id; @@ -1996,7 +1996,7 @@ RÉSUMÉ DU SCAN } }); - app.delete('/api/customer-orders/:id', isAuthenticated, async (req: any, res) => { + app.delete('/api/customer-orders/:id', isAuthenticated, requirePermission('customer-orders', 'delete'), async (req: any, res) => { try { const id = parseInt(req.params.id); const userId = req.user.claims ? req.user.claims.sub : req.user.id; @@ -2011,10 +2011,7 @@ RÉSUMÉ DU SCAN return res.status(404).json({ message: "Customer order not found" }); } - // Check permissions using the shared permission system - if (!hasPermission(user.role, 'customer-orders', 'delete')) { - return res.status(403).json({ message: "Insufficient permissions to delete customer orders" }); - } + // Permission already checked by middleware await storage.deleteCustomerOrder(id); res.status(204).send(); @@ -2164,7 +2161,7 @@ RÉSUMÉ DU SCAN }); // DLC Products routes - app.get('/api/dlc-products', isAuthenticated, async (req: any, res) => { + app.get('/api/dlc-products', isAuthenticated, requirePermission('dlc', 'view'), async (req: any, res) => { try { const userId = req.user.claims ? req.user.claims.sub : req.user.id; const user = await storage.getUserWithGroups(userId); @@ -2211,7 +2208,7 @@ RÉSUMÉ DU SCAN } }); - app.get('/api/dlc-products/stats', isAuthenticated, async (req: any, res) => { + app.get('/api/dlc-products/stats', isAuthenticated, requirePermission('dlc', 'view'), async (req: any, res) => { try { const userId = req.user.claims ? req.user.claims.sub : req.user.id; const user = await storage.getUserWithGroups(userId); @@ -2240,7 +2237,7 @@ RÉSUMÉ DU SCAN } }); - app.get('/api/dlc-products/:id', isAuthenticated, async (req: any, res) => { + app.get('/api/dlc-products/:id', isAuthenticated, requirePermission('dlc', 'view'), async (req: any, res) => { try { const id = parseInt(req.params.id); const dlcProduct = await storage.getDlcProduct(id); @@ -2267,7 +2264,7 @@ RÉSUMÉ DU SCAN } }); - app.post('/api/dlc-products', isAuthenticated, async (req: any, res) => { + app.post('/api/dlc-products', isAuthenticated, requirePermission('dlc', 'create'), async (req: any, res) => { try { console.log('📨 POST /api/dlc-products - Request body:', JSON.stringify(req.body, null, 2)); @@ -2307,7 +2304,7 @@ RÉSUMÉ DU SCAN } }); - app.put('/api/dlc-products/:id', isAuthenticated, async (req: any, res) => { + app.put('/api/dlc-products/:id', isAuthenticated, requirePermission('dlc', 'edit'), async (req: any, res) => { try { const id = parseInt(req.params.id); const userId = req.user.claims ? req.user.claims.sub : req.user.id; @@ -2342,15 +2339,13 @@ RÉSUMÉ DU SCAN } }); - app.post('/api/dlc-products/:id/validate', isAuthenticated, async (req: any, res) => { + app.post('/api/dlc-products/:id/validate', isAuthenticated, requirePermission('dlc', 'validate'), async (req: any, res) => { try { const id = parseInt(req.params.id); const userId = req.user.claims ? req.user.claims.sub : req.user.id; const user = await storage.getUser(userId); - if (!user || !hasPermission(user.role, 'dlc', 'validate')) { - return res.status(403).json({ message: "Insufficient permissions to validate products" }); - } + // Permission already checked by middleware // Check if the product exists and user has access const existingProduct = await storage.getDlcProduct(id); @@ -2374,7 +2369,7 @@ RÉSUMÉ DU SCAN } }); - app.delete('/api/dlc-products/:id', isAuthenticated, async (req: any, res) => { + app.delete('/api/dlc-products/:id', isAuthenticated, requirePermission('dlc', 'delete'), async (req: any, res) => { try { const id = parseInt(req.params.id); const userId = req.user.claims ? req.user.claims.sub : req.user.id;