- 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
19 KiB
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.6dans les origines CORS autorisées de manière explicite http://localhostest 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.6dans 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
- Ordre de chargement des chunks: React n'est pas chargé avant zustand/react/shallow
- Cache navigateur: Anciens chunks JS en cache
- 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.6autorisé) - ✅ API répond correctement via HAProxy
- ❌ L'application ne se charge pas à cause de l'erreur React
Causes identifiées:
- Cache navigateur: Anciens chunks JS en cache
- Service Worker: Peut servir d'anciens assets même avec bypass configuré
- Ordre de chargement: React peut ne pas être chargé avant zustand/react/shallow
- 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.6dansCORS_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:
- Modifier
apps/web/src/main.tsxpour ne pas enregistrer le Service Worker - Ou modifier
apps/web/public/sw.jspour ne rien faire - Rebuild et redéployer
Code à modifier:
// 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:
- Vérifier l'ordre dans le build:
curl -k -s https://10.10.10.6/ | grep -E "(script|modulepreload)" | head -15 - Ajouter un preload explicite pour le chunk React dans
index.html - Ou modifier
vite.config.tspour forcer l'ordre viamanualChunks
É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:
- Modifier le build pour ajouter un hash de version
- Ou forcer le rechargement via meta tags
- 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:
- Ouvrir DevTools (F12)
- Application > Storage > Clear site data
- Application > Service Workers > Unregister
- Network > Disable cache (pendant les tests)
- Hard refresh (Ctrl+Shift+R ou Cmd+Shift+R)
Phase 3 - VALIDATION ET TESTS (P1)
Étape 3.1: Tests Complets
- Test CORS preflight
- Test requêtes API depuis navigateur
- Test chargement de l'application
- Vérification des erreurs console
Étape 3.2: Monitoring
- Activer les logs HAProxy (✅ déjà fait)
- Monitorer les erreurs CORS
- Vérifier les logs backend
🔧 CORRECTIONS IMMÉDIATES
Correction 1: Désactiver Service Worker
Fichier: apps/web/src/main.tsx
Modification:
// 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:
// 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:
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):
// 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:
<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:
- ✅ CORS fonctionne: Headers présents, origine autorisée, requêtes API réussissent
- ✅ API fonctionne: Backend répond correctement via HAProxy
- ✅ Frontend accessible: HTML et JS chunks sont servis
- ❌ 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:
- Cache navigateur avec d'anciens chunks qui ont un ordre de chargement différent
- Service Worker qui peut servir d'anciens assets malgré le bypass configuré
- 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.6dansCORS_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:
- Cache navigateur avec anciens chunks
- Service Worker qui sert d'anciens assets
- 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:
- Vérifier que le script
/usr/local/bin/setup-network.shexiste - Vérifier que le service
veza-network-setup.serviceest activé - Tester un redémarrage du container pour vérifier la persistance
- Si nécessaire, améliorer le script de setup réseau
Étape 1.2: Vérifier Apache
Actions:
- Vérifier qu'Apache écoute sur le bon port
- Vérifier les logs Apache pour erreurs
- 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:
- Commenter l'enregistrement du Service Worker
- Rebuild:
./config/incus/build-native.sh web - Redéployer:
./config/incus/deploy-service-native.sh web
Code:
// 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:
- Vérifier que
vendor-react-coreest bien créé - Vérifier l'ordre dans le HTML généré
- Ajouter un preload explicite si nécessaire
Test:
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:
- Ajouter des headers no-cache pour
/js/*.js - Redéployer le frontend
Étape 4: Instructions Cache Navigateur
Action:
- Documenter la procédure complète de vidage de cache
- Fournir un script de test
Étape 5: Test et Validation
Action:
- Tester dans le navigateur avec cache vidé
- Vérifier que l'application charge
- 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:
- Désactiver Service Worker
- Ajouter headers no-cache
- Vider le cache navigateur
- Tester
🎯 CAUSE RACINE FINALE - CONFIRMÉE
Problème Principal: Erreur React.Children
Statut: ❌ BLOQUANT
Cause:
- Cache navigateur avec d'anciens chunks JS qui ont un ordre de chargement différent
- Service Worker qui peut servir d'anciens assets malgré le bypass configuré
- 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:
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:
// 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:
<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
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:
- Ouvrir DevTools (F12)
- Application > Storage > Clear site data
- Application > Service Workers > Unregister
- Network > Disable cache (pendant les tests)
- 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:
- Désactiver Service Worker
- Ajouter headers no-cache pour JS
- Stabiliser réseau container web
- Vider cache navigateur
- Tester
Fin du rapport d'audit