291 lines
8.0 KiB
Markdown
291 lines
8.0 KiB
Markdown
# Corrections Appliquées pour la Production
|
|
|
|
Ce document liste les corrections critiques appliquées suite à l'analyse de performance et de préparation à la production.
|
|
|
|
## ✅ Corrections Appliquées
|
|
|
|
### 1. Utilitaire fetchWithTimeout
|
|
|
|
**Fichier créé:** `lib/utils/fetch-with-timeout.ts`
|
|
|
|
**Problème résolu:** Requêtes HTTP sans timeout pouvant bloquer indéfiniment.
|
|
|
|
**Utilisation:**
|
|
```typescript
|
|
import { fetchWithTimeout, fetchJsonWithTimeout } from '@/lib/utils/fetch-with-timeout';
|
|
|
|
// Exemple 1: Fetch simple avec timeout
|
|
const response = await fetchWithTimeout('https://api.example.com/data', {
|
|
method: 'GET',
|
|
timeout: 10000, // 10 secondes
|
|
headers: { 'Authorization': 'Bearer token' }
|
|
});
|
|
|
|
// Exemple 2: Fetch avec parsing JSON automatique
|
|
const data = await fetchJsonWithTimeout<MyType>('https://api.example.com/data', {
|
|
method: 'POST',
|
|
timeout: 30000, // 30 secondes
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(payload)
|
|
});
|
|
```
|
|
|
|
**Migration recommandée:**
|
|
Remplacer tous les `fetch()` dans:
|
|
- `lib/services/n8n-service.ts`
|
|
- `app/api/missions/[missionId]/generate-plan/route.ts`
|
|
- `app/api/users/[userId]/route.ts`
|
|
- `app/api/leantime/tasks/route.ts`
|
|
- `app/api/rocket-chat/messages/route.ts`
|
|
|
|
### 2. Correction Dockerfile
|
|
|
|
**Fichier modifié:** `Dockerfile`
|
|
|
|
**Problème résolu:** Utilisation de `migrate dev` en production (créerait de nouvelles migrations).
|
|
|
|
**Changement:**
|
|
```dockerfile
|
|
# ❌ AVANT
|
|
RUN npx prisma migrate dev --name init
|
|
|
|
# ✅ APRÈS
|
|
# NOTE: Migrations should be run separately before deployment
|
|
# DO NOT use 'migrate dev' in production
|
|
# Use 'prisma migrate deploy' instead, run separately before container start
|
|
```
|
|
|
|
**Action requise:** Utiliser `Dockerfile.prod` pour la production, qui est déjà correctement configuré.
|
|
|
|
### 3. Script de Validation d'Environnement
|
|
|
|
**Fichier créé:** `scripts/validate-env.ts`
|
|
|
|
**Problème résolu:** Variables d'environnement manquantes non détectées avant déploiement.
|
|
|
|
**Utilisation:**
|
|
```bash
|
|
# Valider les variables d'environnement
|
|
npm run validate:env
|
|
|
|
# Ou directement
|
|
ts-node scripts/validate-env.ts
|
|
```
|
|
|
|
**Fonctionnalités:**
|
|
- ✅ Vérifie toutes les variables requises
|
|
- ✅ Valide le format des URLs
|
|
- ✅ Vérifie la force de NEXTAUTH_SECRET
|
|
- ✅ Recommande les paramètres de pool DB
|
|
- ✅ Affiche des warnings pour les variables optionnelles
|
|
|
|
**Ajouté dans package.json:**
|
|
```json
|
|
"validate:env": "ts-node scripts/validate-env.ts"
|
|
```
|
|
|
|
## 🔄 Migrations à Effectuer
|
|
|
|
### Priorité 1 - CRITIQUE
|
|
|
|
#### 1. Remplacer fetch() par fetchWithTimeout()
|
|
|
|
**Fichiers à modifier:**
|
|
|
|
1. **lib/services/n8n-service.ts**
|
|
```typescript
|
|
// ❌ AVANT
|
|
const response = await fetch(this.webhookUrl, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', 'x-api-key': this.apiKey },
|
|
body: JSON.stringify(cleanData),
|
|
});
|
|
|
|
// ✅ APRÈS
|
|
import { fetchWithTimeout } from '@/lib/utils/fetch-with-timeout';
|
|
|
|
const response = await fetchWithTimeout(this.webhookUrl, {
|
|
method: 'POST',
|
|
timeout: 30000, // 30 secondes
|
|
headers: { 'Content-Type': 'application/json', 'x-api-key': this.apiKey },
|
|
body: JSON.stringify(cleanData),
|
|
});
|
|
```
|
|
|
|
2. **app/api/missions/[missionId]/generate-plan/route.ts**
|
|
```typescript
|
|
// ❌ AVANT
|
|
const response = await fetch(webhookUrl, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey },
|
|
body: JSON.stringify(webhookData),
|
|
});
|
|
|
|
// ✅ APRÈS
|
|
import { fetchWithTimeout } from '@/lib/utils/fetch-with-timeout';
|
|
|
|
const response = await fetchWithTimeout(webhookUrl, {
|
|
method: 'POST',
|
|
timeout: 30000,
|
|
headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey },
|
|
body: JSON.stringify(webhookData),
|
|
});
|
|
```
|
|
|
|
3. **app/api/users/[userId]/route.ts** (getLeantimeUserId)
|
|
```typescript
|
|
// ❌ AVANT
|
|
const userResponse = await fetch('https://agilite.slm-lab.net/api/jsonrpc', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', 'X-API-Key': process.env.LEANTIME_TOKEN || '' },
|
|
body: JSON.stringify({ ... }),
|
|
});
|
|
|
|
// ✅ APRÈS
|
|
import { fetchJsonWithTimeout } from '@/lib/utils/fetch-with-timeout';
|
|
|
|
const userData = await fetchJsonWithTimeout('https://agilite.slm-lab.net/api/jsonrpc', {
|
|
method: 'POST',
|
|
timeout: 10000, // 10 secondes
|
|
headers: { 'Content-Type': 'application/json', 'X-API-Key': process.env.LEANTIME_TOKEN || '' },
|
|
body: JSON.stringify({ ... }),
|
|
});
|
|
```
|
|
|
|
#### 2. Configurer le Pool de Connexions Prisma
|
|
|
|
**Action:** Modifier `DATABASE_URL` dans les variables d'environnement:
|
|
|
|
```bash
|
|
# ❌ AVANT
|
|
DATABASE_URL=postgresql://user:pass@host:5432/db
|
|
|
|
# ✅ APRÈS
|
|
DATABASE_URL=postgresql://user:pass@host:5432/db?connection_limit=10&pool_timeout=20&connect_timeout=10
|
|
```
|
|
|
|
**Paramètres recommandés:**
|
|
- `connection_limit=10` - Limite le nombre de connexions simultanées
|
|
- `pool_timeout=20` - Timeout pour obtenir une connexion du pool (secondes)
|
|
- `connect_timeout=10` - Timeout pour établir une connexion (secondes)
|
|
|
|
**Note:** Ajuster `connection_limit` selon la charge attendue et les limites du serveur PostgreSQL.
|
|
|
|
#### 3. Remplacer console.log par logger
|
|
|
|
**Script de migration:**
|
|
```bash
|
|
# Créer scripts/migrate-console-logs.sh
|
|
#!/bin/bash
|
|
|
|
find lib/services app/api -name "*.ts" -type f | while read file; do
|
|
# Sauvegarder d'abord
|
|
cp "$file" "$file.bak"
|
|
|
|
# Remplacer
|
|
sed -i '' 's/console\.log(/logger.debug(/g' "$file"
|
|
sed -i '' 's/console\.error(/logger.error(/g' "$file"
|
|
sed -i '' 's/console\.warn(/logger.warn(/g' "$file"
|
|
sed -i '' 's/console\.debug(/logger.debug(/g' "$file"
|
|
|
|
# Vérifier que logger est importé
|
|
if ! grep -q "import.*logger" "$file" && grep -q "logger\." "$file"; then
|
|
# Ajouter l'import en haut du fichier
|
|
sed -i '' '1i\
|
|
import { logger } from '\''@/lib/logger'\'';
|
|
' "$file"
|
|
fi
|
|
done
|
|
|
|
echo "✅ Console logs migrated to logger"
|
|
echo "⚠️ Review changes and remove .bak files after verification"
|
|
```
|
|
|
|
**Fichiers prioritaires:**
|
|
- `lib/services/rocketchat-call-listener.ts` (35 occurrences)
|
|
- `lib/services/refresh-manager.ts` (19 occurrences)
|
|
- `lib/services/prefetch-service.ts` (17 occurrences)
|
|
|
|
### Priorité 2 - HAUTE
|
|
|
|
#### 4. Activer l'Optimisation d'Images Next.js
|
|
|
|
**Fichier:** `next.config.mjs`
|
|
|
|
```javascript
|
|
// ❌ AVANT
|
|
images: {
|
|
unoptimized: true,
|
|
},
|
|
|
|
// ✅ APRÈS
|
|
images: {
|
|
unoptimized: false,
|
|
formats: ['image/avif', 'image/webp'],
|
|
deviceSizes: [640, 750, 828, 1080, 1200],
|
|
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
|
|
},
|
|
```
|
|
|
|
#### 5. Implémenter Circuit Breaker
|
|
|
|
Créer `lib/utils/circuit-breaker.ts` (voir exemple dans `PERFORMANCE_AND_PRODUCTION_ANALYSIS.md`).
|
|
|
|
**Services à protéger:**
|
|
- N8N webhooks
|
|
- Leantime API
|
|
- RocketChat API
|
|
|
|
## 📋 Checklist de Migration
|
|
|
|
- [ ] Remplacer tous les `fetch()` par `fetchWithTimeout()` dans les fichiers listés
|
|
- [ ] Configurer `DATABASE_URL` avec les paramètres de pool
|
|
- [ ] Exécuter le script de migration console.log
|
|
- [ ] Vérifier que tous les fichiers utilisent `logger` au lieu de `console`
|
|
- [ ] Activer l'optimisation d'images dans `next.config.mjs`
|
|
- [ ] Tester toutes les fonctionnalités après les changements
|
|
- [ ] Valider l'environnement avec `npm run validate:env`
|
|
- [ ] Déployer en staging et tester
|
|
- [ ] Monitorer les performances après déploiement
|
|
|
|
## 🧪 Tests Recommandés
|
|
|
|
### Test de Timeout
|
|
```typescript
|
|
// Test que les timeouts fonctionnent
|
|
const start = Date.now();
|
|
try {
|
|
await fetchWithTimeout('https://httpstat.us/200?sleep=5000', {
|
|
timeout: 2000, // 2 secondes
|
|
});
|
|
} catch (error) {
|
|
const duration = Date.now() - start;
|
|
console.assert(duration < 3000, 'Timeout should occur before 3 seconds');
|
|
console.assert(error.message.includes('timeout'), 'Error should mention timeout');
|
|
}
|
|
```
|
|
|
|
### Test de Validation d'Environnement
|
|
```bash
|
|
# Tester avec variables manquantes
|
|
unset DATABASE_URL
|
|
npm run validate:env
|
|
# Devrait échouer avec message clair
|
|
|
|
# Tester avec toutes les variables
|
|
# Devrait réussir
|
|
npm run validate:env
|
|
```
|
|
|
|
## 📚 Documentation
|
|
|
|
Voir `PERFORMANCE_AND_PRODUCTION_ANALYSIS.md` pour:
|
|
- Analyse complète des problèmes
|
|
- Recommandations détaillées
|
|
- Métriques de succès
|
|
- Checklist complète de mise en production
|
|
|
|
---
|
|
|
|
**Dernière mise à jour:** $(date)
|