veza/config/incus/AUDIT_BARE_METAL_VS_INCUS.md
senke f0ba7de543 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

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

É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:

// 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:
    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:

// 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:

  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:

// 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:

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:

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:

  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