Fiabilité des données
- Contrôle de plausibilité avant d'écrire le cache (lib/qlik-validation.ts) :
extraction refusée, cache inchangé, si le dernier mois pèse moins de 40 %
des 3 précédents dans les 10 premiers jours du mois (mois pas encore
chargé dans Qlik), ou si plus de la moitié des séries vendues ont la même
valeur 12 mois (mesure insensible au mois).
- Valeurs impossibles corrigées (NaN, infini, nombre de magasins négatif).
Récupération
- Chromium relancé s'il est tombé : un navigateur déconnecté faisait échouer
toutes les extractions jusqu'au redémarrage du serveur.
- Une seule session Qlik à la fois (extraction de nuit, synchro manuelle,
recherche produit) : en parallèle, le serveur Qlik abandonnait les deux.
- Planificateur : un échec est retenté la nuit suivante (au lieu de 7 jours)
et les données d'avant le mois en cours sont rafraîchies sans attendre le
délai de fraîcheur. Page Synchronisation mise à jour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015MouZgPPAuEZjHXXifW7bm
Grille (navigateur)
- « Rafraîchir » ne passe plus par l'URL : le paramètre _refresh restait
mémorisé et chaque retour par le menu forçait un recalcul serveur complet
(migration du store pour nettoyer les valeurs déjà enregistrées).
- Lignes reçues regroupées toutes les 300 ms au lieu de reconstruire tout le
tableau à chaque paquet de 150 (chargement quadratique).
- Sélection indexée par code article (getRowId) : après un filtre, l'action
groupée visait d'autres produits. Seules les lignes affichées comptent.
- Recherche : un passage par ligne au lieu d'un par colonne ; formateurs de
nombres partagés (lib/format.ts) ; colonnes mensuelles mémorisées ;
plus de transition-all sur les lignes positionnées par transform.
- exceljs, jspdf et xlsx chargés au clic seulement.
Grille (serveur)
- Requêtes Qlik et snapshot lancées en parallèle de la phase SQL.
- Cache mémoire borné (LRU) ; calcul en cours réutilisé même en forcé ;
flux interrompu quand le client part.
- Après un enregistrement, les gammes sont reportées dans le cache et dans
grid_rows au lieu d'invalider (recalcul de ~40 s évité).
Données et API
- lib/ff-cache.ts : cache mémoire 30 min des lectures FF (stock, hit-parade,
CA mensuel, fournisseurs, dernière réception, publicités), vidé en fin de
synchro nocturne ; erreurs jamais gardées.
- Pool PostgreSQL unique (globalThis), réglage sans workers parallèles posé
une fois par connexion au lieu d'une transaction autour de chaque requête.
- Délai maximal sur tous les appels à l'API FF.
- Index session_snapshots ; commandes : plus de double rechargement ;
synchro : saisies regroupées ; paramètres : configuration lue une fois ;
journal de capture en ajout seul, rien de formaté sans capture ouverte.
Corrections
- Historique : l'échec de chargement s'affiche (au lieu de « Aucun snapshot »).
- Sessions et validations enregistrent le magasin affiché, plus « TOTAL ».
- Publicités : libellé du statut « passées ».
Plan complet : docs/plan-optimisation-webui.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AcA129WzGTH6zxPHFBGWmn
Page /admin/synchronisation : choisir quels fournisseurs sont cadencés, pour
quelle source, et suivre l'avancement.
ORDRE DE PASSAGE. La file est « le plus anciennement synchronisé d'abord », en
ignorant ceux déjà traités depuis l'ouverture de la fenêtre. Il en découle,
sans curseur ni compteur de tour : la nuit 2 reprend là où la nuit 1 s'est
arrêtée, le tour recommence quand tout le monde est passé, et un fournisseur
en échec garde une date ancienne donc repasse en tête.
DEUX FILES. SQL (~43 s sur le plus gros) et Qlik (jusqu'à 8 min, sur un serveur
qui abandonne quand on le sollicite trop) ont leur propre activation et leur
propre rythme. Une extraction Qlik est intercalée tous les N fournisseurs SQL,
sinon elle ne démarrerait jamais avant que la file SQL soit vide. Un plafond
par nuit et un âge minimal évitent de refaire chaque nuit des agrégats
mensuels.
Détails qui comptent :
- La fenêtre signifie « ne plus DÉMARRER après l'heure de fin » : une
extraction en cours n'est jamais coupée. Le passage par minuit est géré.
- L'horodatage est écrit même en cas d'échec, sans quoi le fournisseur fautif
bloquerait la file derrière lui.
- Garde anti-boucle : l'avancement repose sur cette écriture, volontairement
non bloquante ; si elle échoue, le round s'arrête au lieu de reprendre le
même fournisseur indéfiniment.
- Un fournisseur sans article est désactivé automatiquement, motif affiché,
réactivable — plutôt que réessayé chaque nuit.
- Désactivé par défaut : un déploiement ne doit pas se mettre à solliciter
Qlik la nuit suivante sans décision explicite.
Déclenchement par minuteur interne (instrumentation.ts), battement d'une
minute. Aucune configuration côté hôte, se réarme au démarrage ; en
contrepartie rien ne tourne si l'application est arrêtée.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y26nRZxTR57K7h8yqsF675
La section « IA Copilot — OpenRouter » annonçait « pour les analyses de
gammes », mais aucun code ne consommait cette clé : elle était décorative.
Supprimée, ainsi que les routes devenues orphelines /api/admin/ai-config,
/api/google-ai/models et /api/openrouter/models.
Nettoyage de l'état correspondant dans la page : clé, liste de modèles,
fournisseur d'IA et modèle Google ne faisaient plus qu'un aller-retour entre le
chargement et l'enregistrement, sans aucune interface pour les modifier.
handleSave n'enregistre donc plus que l'URL de la base.
La règle set-state-in-effect s'est mise à signaler le `setIsMounted` du montage,
inchangé mais devenu analysable une fois le code IA retiré : dérogation locale,
comme dans api-connection-info.tsx, puisque poser l'indicateur au montage est
précisément ce qui évite l'écart d'hydratation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y26nRZxTR57K7h8yqsF675