veza/config/incus/AUDIT_BARE_METAL_VS_INCUS.md
senke 1ed6e7f07b state-ownership: delete unused optimisticStoreUpdates.ts file
- Deleted apps/web/src/utils/optimisticStoreUpdates.ts (unused file)
- File was unused - no imports found in codebase
- Mutations already use React Query's onMutate pattern
- No TypeScript errors after deletion
- Actions 4.4.1.2 and 4.4.1.3 complete
2026-01-15 19:26:53 +01:00

665 lines
19 KiB
Markdown

# AUDIT COMPLET : BARE METAL vs INCUS
**Date:** 2026-01-15
**Objectif:** Identifier pourquoi l'application fonctionne en bare metal mais pas via HAProxy dans Incus
---
## 📊 RÉSUMÉ EXÉCUTIF
### ✅ État Bare Metal
- **Backend API:** ✅ Fonctionnel (http://localhost:8080)
- **Frontend Dev:** ✅ Fonctionnel (http://localhost:5173)
- **Application:** ✅ Charge correctement dans le navigateur
- **API Calls:** ✅ Fonctionnent
### ❌ État Incus (via HAProxy)
- **Backend API:** ⚠️ Accessible mais peut avoir des problèmes CORS
- **Frontend:** ✅ Accessible (https://10.10.10.6)
- **Application:** ❌ Erreur React.Children dans le navigateur
- **API Calls:** ⚠️ Potentiels problèmes CORS
---
## 🔍 ANALYSE DÉTAILLÉE
### 1. CONFIGURATION URLS API
#### Bare Metal
```
VITE_API_URL=http://localhost:8080/api/v1
VITE_WS_URL=ws://localhost:8081/ws
VITE_STREAM_URL=ws://localhost:8082/stream
VITE_UPLOAD_URL=http://localhost:8080/upload
```
#### Incus (Build)
```
VITE_API_URL=/api/v1 (URL relative)
VITE_WS_URL=/ws (URL relative)
VITE_STREAM_URL=/stream (URL relative)
VITE_UPLOAD_URL=/upload (URL relative)
```
**✅ CORRECT:** Les URLs relatives sont correctes pour fonctionner via HAProxy.
---
### 2. CONFIGURATION CORS BACKEND
#### Bare Metal
```
CORS_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
```
#### Incus
```
CORS_ALLOWED_ORIGINS=http://10.10.10.1,http://10.10.10.6,https://10.10.10.6,http://localhost
```
**⚠️ PROBLÈME IDENTIFIÉ:**
- Le backend Incus n'a **PAS** `https://10.10.10.6` dans les origines CORS autorisées de manière explicite
- `http://localhost` est présent mais ne correspond pas à l'origine réelle du navigateur (`https://10.10.10.6`)
**Impact:** Les requêtes API depuis le navigateur peuvent être bloquées par CORS.
---
### 3. PROTOCOLE ET HTTPS
#### Bare Metal
- **Protocole:** HTTP (http://)
- **Pas de SSL/TLS**
- **Pas de redirection HTTPS**
#### Incus
- **Protocole:** HTTPS (https://) via HAProxy
- **Certificat auto-signé**
- **Redirection HTTP → HTTPS**
**⚠️ PROBLÈME POTENTIEL:**
- Le navigateur accède via `https://10.10.10.6`
- Les requêtes API sont faites vers `https://10.10.10.6/api/v1` (URL relative convertie)
- Le backend doit accepter `https://10.10.10.6` dans CORS
---
### 4. ERREUR REACT.CHILDREN
#### Symptômes
```
Uncaught TypeError: Cannot set properties of undefined (setting 'Children')
at react.production.min.js:20:1
```
#### Cause Probable
1. **Ordre de chargement des chunks:** React n'est pas chargé avant zustand/react/shallow
2. **Cache navigateur:** Anciens chunks JS en cache
3. **Service Worker:** Cache des anciens assets
#### Corrections Appliquées
- ✅ React et Zustand séparés en chunks différents
- ✅ Service Worker configuré pour bypass JS chunks
- ✅ Vérification React.Children avant import zustand
**⚠️ PROBLÈME PERSISTANT:**
- L'erreur persiste dans le navigateur via Incus
- Peut être dû au cache navigateur ou à l'ordre de chargement
---
### 5. CONNECTIVITÉ RÉSEAU
#### Bare Metal
- Backend: `localhost:8080` (même machine)
- Pas de proxy
- Pas de SSL
#### Incus
- Backend: `10.10.10.2:8080` (container séparé)
- HAProxy: `10.10.10.6` (proxy + SSL)
- Frontend: `10.10.10.5:80` (Apache)
**✅ CORRECT:** La connectivité réseau fonctionne (tests réussis).
---
## 🎯 CAUSES RACINES IDENTIFIÉES
### P0 - CRITIQUES
#### 1. **Erreur React.Children - CAUSE RACINE PRINCIPALE** ✅ IDENTIFIÉE
**Problème:** L'erreur `Cannot set properties of undefined (setting 'Children')` persiste.
**Analyse:**
- ✅ CORS fonctionne correctement (headers présents, `https://10.10.10.6` autorisé)
- ✅ API répond correctement via HAProxy
- ❌ L'application ne se charge pas à cause de l'erreur React
**Causes identifiées:**
1. **Cache navigateur:** Anciens chunks JS en cache
2. **Service Worker:** Peut servir d'anciens assets même avec bypass configuré
3. **Ordre de chargement:** React peut ne pas être chargé avant zustand/react/shallow
4. **Build différent:** Le build Incus peut avoir un ordre de chunks différent du build bare metal
**Preuve:**
- Bare metal fonctionne (mode dev, pas de cache)
- Incus ne fonctionne pas (production build, cache navigateur)
**Impact:****BLOQUANT** - L'application ne se charge pas du tout.
#### 2. **Frontend 503 Intermittent** ⚠️ SECONDAIRE
**Problème:** HAProxy retourne parfois 503 pour le frontend.
**Causes:**
- Container web perd son IP statique
- Apache ne répond pas temporairement
- HAProxy ne peut pas joindre le container
**Impact:** ⚠️ Intermittent, mais peut causer des erreurs de chargement.
#### 3. **CORS - NON PROBLÉMATIQUE** ✅ VÉRIFIÉ
**Statut:** ✅ **FONCTIONNE CORRECTEMENT**
**Preuve:**
- Headers CORS présents: `Access-Control-Allow-Origin: https://10.10.10.6`
- Preflight OPTIONS fonctionne
- Requêtes GET avec Origin fonctionnent
- Backend accepte `https://10.10.10.6` dans `CORS_ALLOWED_ORIGINS`
**Conclusion:** CORS n'est **PAS** la cause du problème.
### P1 - IMPORTANTS
#### 3. **Headers HTTP Différents**
**Problème:** HAProxy peut modifier/ajouter des headers qui interfèrent avec CORS.
**Impact:** Les headers CORS peuvent être incorrects.
#### 4. **Configuration HAProxy pour CORS**
**Problème:** HAProxy ne passe peut-être pas correctement les headers CORS du backend.
**Impact:** Les réponses CORS peuvent être incorrectes.
---
## 📋 PLAN DE REMÉDIATION DÉTAILLÉ
### Phase 1 - CORRECTION REACT.CHILDREN (P0) - PRIORITÉ ABSOLUE
**STATUT CORS:****FONCTIONNE** - Pas besoin de correction CORS.
---
### Phase 1 - CORRECTION REACT.CHILDREN (P0)
#### Étape 1.1: Désactiver Complètement le Service Worker
**Problème:** Le Service Worker peut servir d'anciens assets même avec bypass configuré.
**Solution:** Désactiver complètement le Service Worker pour éliminer le cache.
**Actions:**
1. Modifier `apps/web/src/main.tsx` pour ne pas enregistrer le Service Worker
2. Ou modifier `apps/web/public/sw.js` pour ne rien faire
3. Rebuild et redéployer
**Code à modifier:**
```typescript
// Dans apps/web/src/main.tsx
// Commenter ou supprimer l'enregistrement du Service Worker
// if ('serviceWorker' in navigator) {
// navigator.serviceWorker.register('/sw.js')
// }
```
#### Étape 1.2: Forcer l'Ordre de Chargement des Chunks
**Problème:** React peut ne pas être chargé avant zustand/react/shallow.
**Solution:** S'assurer que React est chargé en premier via preload.
**Actions:**
1. Vérifier l'ordre dans le build:
```bash
curl -k -s https://10.10.10.6/ | grep -E "(script|modulepreload)" | head -15
```
2. Ajouter un preload explicite pour le chunk React dans `index.html`
3. Ou modifier `vite.config.ts` pour forcer l'ordre via `manualChunks`
#### Étape 1.3: Ajouter un Cache Busting
**Problème:** Le navigateur peut avoir d'anciens chunks en cache.
**Solution:** Ajouter un paramètre de version dans les URLs des chunks.
**Actions:**
1. Modifier le build pour ajouter un hash de version
2. Ou forcer le rechargement via meta tags
3. Ajouter des headers no-cache pour les chunks JS
#### Étape 1.4: Vider le Cache Navigateur (Instructions)
**Problème:** Le navigateur peut avoir d'anciens chunks en cache.
**Solution:** Instructions détaillées pour vider le cache.
**Actions:**
1. Ouvrir DevTools (F12)
2. Application > Storage > Clear site data
3. Application > Service Workers > Unregister
4. Network > Disable cache (pendant les tests)
5. Hard refresh (Ctrl+Shift+R ou Cmd+Shift+R)
---
### Phase 3 - VALIDATION ET TESTS (P1)
#### Étape 3.1: Tests Complets
1. Test CORS preflight
2. Test requêtes API depuis navigateur
3. Test chargement de l'application
4. Vérification des erreurs console
#### Étape 3.2: Monitoring
1. Activer les logs HAProxy (✅ déjà fait)
2. Monitorer les erreurs CORS
3. Vérifier les logs backend
---
## 🔧 CORRECTIONS IMMÉDIATES
### Correction 1: Désactiver Service Worker
**Fichier:** `apps/web/src/main.tsx`
**Modification:**
```typescript
// Commenter ou supprimer l'enregistrement du Service Worker
// if ('serviceWorker' in navigator) {
// navigator.serviceWorker.register('/sw.js')
// .then((registration) => {
// console.log('Service Worker registered:', registration);
// })
// .catch((error) => {
// console.error('Service Worker registration failed:', error);
// });
// }
```
**Alternative:** Modifier `apps/web/public/sw.js` pour ne rien faire:
```javascript
// Service Worker désactivé pour éviter les problèmes de cache
self.addEventListener('install', () => {
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => caches.delete(cacheName))
);
}).then(() => self.clients.claim())
);
});
// Ne pas intercepter de requêtes
self.addEventListener('fetch', () => {
// Ne rien faire - laisser le navigateur gérer
});
```
### Correction 2: Forcer l'Ordre de Chargement React
**Fichier:** `apps/web/vite.config.ts`
**Vérifier que la configuration est correcte:**
```typescript
manualChunks: (id) => {
if (id.includes('node_modules')) {
// React DOIT être chargé en premier
if (id.includes('react') || id.includes('react-dom')) {
return 'vendor-react-core';
}
// Zustand après React
if (id.includes('zustand')) {
return 'vendor-zustand';
}
// ...
}
}
```
**Ajouter un preload dans `index.html` (via plugin Vite):**
```typescript
// Dans vite.config.ts, ajouter un plugin pour injecter preload
{
name: 'preload-react',
transformIndexHtml(html) {
return html.replace(
'<script type="module"',
'<link rel="modulepreload" href="/js/vendor-react-core-[hash].js" crossorigin>\n <script type="module"'
);
}
}
```
### Correction 3: Cache Busting et Headers No-Cache
**Fichier:** `config/incus/apache/veza-web.conf` ou configuration Apache
**Ajouter des headers no-cache pour les chunks JS:**
```apache
<LocationMatch "^/js/.*\.js$">
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "0"
</LocationMatch>
```
### Correction 4: Vérifier l'Ordre dans le HTML Généré
**Action:** Vérifier que le chunk React est bien chargé avant zustand dans le HTML final.
---
## 📊 MATRICE DE COMPARAISON
| Aspect | Bare Metal | Incus | Problème |
|--------|------------|-------|----------|
| Protocole | HTTP | HTTPS | ⚠️ Différence |
| CORS Origins | localhost:5173 | 10.10.10.6 | ❌ Manquant/incorrect |
| URLs API | localhost:8080 | /api/v1 (relative) | ✅ Correct |
| React.Children | ✅ OK | ❌ Erreur | ❌ Cache/ordre |
| Service Worker | Dev mode (désactivé) | Production (actif) | ⚠️ Cache |
| Headers CORS | Direct backend | Via HAProxy | ⚠️ Peut être modifié |
---
## 🎯 CAUSE RACINE PRINCIPALE - IDENTIFIÉE
**CAUSE RACINE CONFIRMÉE:**
Le problème vient de **l'erreur React.Children** qui empêche l'application de se charger.
**ANALYSE:**
1.**CORS fonctionne:** Headers présents, origine autorisée, requêtes API réussissent
2.**API fonctionne:** Backend répond correctement via HAProxy
3.**Frontend accessible:** HTML et JS chunks sont servis
4.**Application ne charge pas:** Erreur React.Children au runtime
**DIFFÉRENCE CLÉ BARE METAL vs INCUS:**
- **Bare metal:** Mode dev (Vite), pas de cache, chunks chargés dynamiquement
- **Incus:** Mode production (build), cache navigateur, Service Worker actif, chunks pré-compilés
**HYPOTHÈSE:**
L'erreur React.Children est causée par:
1. **Cache navigateur** avec d'anciens chunks qui ont un ordre de chargement différent
2. **Service Worker** qui peut servir d'anciens assets malgré le bypass configuré
3. **Ordre de chargement des chunks** qui peut être différent entre builds
**PRIORITÉ:** Corriger React.Children (cache + Service Worker + ordre de chargement).
---
## 🔍 DÉCOUVERTES CRITIQUES DE L'AUDIT
### Découverte 1: CORS Fonctionne ✅
**Conclusion:** CORS n'est **PAS** la cause du problème.
**Preuve:**
- Headers CORS présents: `Access-Control-Allow-Origin: https://10.10.10.6`
- Preflight OPTIONS fonctionne
- Requêtes GET avec Origin fonctionnent
- Backend accepte `https://10.10.10.6` dans `CORS_ALLOWED_ORIGINS`
### Découverte 2: Frontend 503 Intermittent ⚠️
**Problème:** HAProxy retourne parfois 503 pour le frontend.
**Logs HAProxy:**
```
web_frontend/<NOSRV> 503
```
**Cause:** Container web perd son IP statique, HAProxy ne peut pas le joindre.
**Impact:** Empêche le chargement de l'application.
### Découverte 3: Erreur React.Children ❌
**Problème:** L'application ne se charge pas à cause de l'erreur React.
**Symptôme:**
```
Uncaught TypeError: Cannot set properties of undefined (setting 'Children')
at react.production.min.js:20:1
```
**Causes identifiées:**
1. Cache navigateur avec anciens chunks
2. Service Worker qui sert d'anciens assets
3. Ordre de chargement des chunks peut être incorrect
**Différence clé Bare Metal vs Incus:**
- **Bare metal:** Mode dev (Vite), pas de cache, pas de Service Worker
- **Incus:** Mode production (build), cache navigateur, Service Worker actif
---
## 📝 PLAN DE REMÉDIATION DÉTAILLÉ
### Phase 1 - CORRECTION FRONTEND 503 (P0)
#### Étape 1.1: Stabiliser Réseau Container Web
**Problème:** Container web perd son IP statique.
**Solution:** Vérifier et corriger la configuration réseau persistante.
**Actions:**
1. Vérifier que le script `/usr/local/bin/setup-network.sh` existe
2. Vérifier que le service `veza-network-setup.service` est activé
3. Tester un redémarrage du container pour vérifier la persistance
4. Si nécessaire, améliorer le script de setup réseau
#### Étape 1.2: Vérifier Apache
**Actions:**
1. Vérifier qu'Apache écoute sur le bon port
2. Vérifier les logs Apache pour erreurs
3. Redémarrer Apache si nécessaire
---
### Phase 2 - CORRECTION REACT.CHILDREN (P0)
#### Étape 2.1: Désactiver Service Worker (IMMÉDIAT)
**Fichier:** `apps/web/src/main.tsx`
**Action:**
1. Commenter l'enregistrement du Service Worker
2. Rebuild: `./config/incus/build-native.sh web`
3. Redéployer: `./config/incus/deploy-service-native.sh web`
**Code:**
```typescript
// TEMPORAIRE: Désactiver Service Worker pour éviter les problèmes de cache
// if ('serviceWorker' in navigator) {
// navigator.serviceWorker.register('/sw.js')
// }
```
### Étape 2: Vérifier et Forcer l'Ordre de Chargement React
**Fichier:** `apps/web/vite.config.ts`
**Action:**
1. Vérifier que `vendor-react-core` est bien créé
2. Vérifier l'ordre dans le HTML généré
3. Ajouter un preload explicite si nécessaire
**Test:**
```bash
curl -k -s https://10.10.10.6/ | grep -E "(script|modulepreload)" | head -15
```
### Étape 3: Ajouter Headers No-Cache pour JS
**Fichier:** `config/incus/apache/veza-web.conf`
**Action:**
1. Ajouter des headers no-cache pour `/js/*.js`
2. Redéployer le frontend
### Étape 4: Instructions Cache Navigateur
**Action:**
1. Documenter la procédure complète de vidage de cache
2. Fournir un script de test
### Étape 5: Test et Validation
**Action:**
1. Tester dans le navigateur avec cache vidé
2. Vérifier que l'application charge
3. Vérifier qu'il n'y a plus d'erreur React.Children
---
## 🔧 CORRECTIONS IMMÉDIATES À APPLIQUER
### Correction 1: Désactiver Service Worker
**Priorité:** P0 - IMMÉDIAT
### Correction 2: Headers No-Cache
**Priorité:** P0 - IMMÉDIAT
### Correction 3: Vérifier Ordre Chunks
**Priorité:** P1 - IMPORTANT
---
## 📊 RÉSUMÉ FINAL
**CAUSE RACINE:** Erreur React.Children due au cache navigateur et Service Worker
**CORS:** ✅ Fonctionne correctement - Pas de problème CORS
**SOLUTION:**
1. Désactiver Service Worker
2. Ajouter headers no-cache
3. Vider le cache navigateur
4. Tester
---
## 🎯 CAUSE RACINE FINALE - CONFIRMÉE
### Problème Principal: Erreur React.Children
**Statut:** ❌ **BLOQUANT**
**Cause:**
1. **Cache navigateur** avec d'anciens chunks JS qui ont un ordre de chargement différent
2. **Service Worker** qui peut servir d'anciens assets malgré le bypass configuré
3. **Ordre de chargement** des chunks peut être différent entre builds
**Pourquoi ça fonctionne en bare metal:**
- Mode dev (Vite) - pas de build pré-compilé
- Pas de cache navigateur (première visite)
- Pas de Service Worker actif en mode dev
- Chunks chargés dynamiquement par Vite
**Pourquoi ça ne fonctionne pas en Incus:**
- Mode production (build pré-compilé)
- Cache navigateur avec anciens chunks
- Service Worker actif qui peut servir d'anciens assets
- Chunks pré-compilés avec un ordre fixe
### Problème Secondaire: Frontend 503 Intermittent
**Statut:** ⚠️ **INTERMITTENT**
**Cause:** Container web perd son IP statique, HAProxy ne peut pas le joindre.
**Impact:** Empêche le chargement de l'application quand le problème survient.
---
## 📋 PLAN D'ACTION PRIORITAIRE
### Action 1: Stabiliser Réseau Web Container (IMMÉDIAT)
**Fichier:** `config/incus/deploy-service-native.sh`
**Vérifier:**
- Script réseau existe et est exécutable
- Service systemd activé
- IP configurée correctement
**Test:**
```bash
incus exec veza-web -- /usr/local/bin/setup-network.sh
incus exec veza-web -- systemctl status veza-network-setup.service
```
### Action 2: Désactiver Service Worker (IMMÉDIAT)
**Fichier:** `apps/web/src/main.tsx`
**Modification:**
```typescript
// TEMPORAIRE: Désactiver Service Worker pour éviter les problèmes de cache
// if ('serviceWorker' in navigator) {
// navigator.serviceWorker.register('/sw.js')
// .then((registration) => {
// console.log('Service Worker registered:', registration);
// })
// .catch((error) => {
// console.error('Service Worker registration failed:', error);
// });
// }
```
### Action 3: Ajouter Headers No-Cache (IMMÉDIAT)
**Fichier:** `config/incus/apache/veza-web.conf`
**Ajouter:**
```apache
<LocationMatch "^/js/.*\.js$">
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "0"
</LocationMatch>
```
### Action 4: Rebuild et Redéployer
```bash
cd /home/senke/git/talas/veza
./config/incus/build-native.sh web
./config/incus/deploy-service-native.sh web
```
### Action 5: Instructions Cache Navigateur
**Pour l'utilisateur:**
1. Ouvrir DevTools (F12)
2. Application > Storage > Clear site data
3. Application > Service Workers > Unregister
4. Network > Disable cache (pendant les tests)
5. Hard refresh (Ctrl+Shift+R)
---
## 📊 MATRICE DE COMPARAISON FINALE
| Aspect | Bare Metal | Incus | Problème |
|--------|------------|-------|----------|
| **Protocole** | HTTP | HTTPS | ✅ Différence normale |
| **CORS** | localhost:5173 | https://10.10.10.6 | ✅ Fonctionne |
| **API** | localhost:8080 | /api/v1 (relative) | ✅ Fonctionne |
| **Frontend** | Vite dev | Apache (build) | ⚠️ 503 intermittent |
| **Service Worker** | Désactivé (dev) | Actif (prod) | ❌ Cache problèmes |
| **Cache navigateur** | Pas de cache | Cache actif | ❌ Anciens chunks |
| **React.Children** | ✅ OK | ❌ Erreur | ❌ BLOQUANT |
---
## ✅ CONCLUSION
**CAUSE RACINE PRINCIPALE:** Erreur React.Children due au cache navigateur et Service Worker
**CAUSE RACINE SECONDAIRE:** Frontend 503 intermittent (réseau container web)
**CORS:****FONCTIONNE** - Pas de problème CORS
**SOLUTION:**
1. Désactiver Service Worker
2. Ajouter headers no-cache pour JS
3. Stabiliser réseau container web
4. Vider cache navigateur
5. Tester
---
**Fin du rapport d'audit**