Aller au contenu principal

Stratégie TanStack Query

Ce document décrit comment TanStack Query peut être introduit dans l'écosystème Rilindra sans fragiliser les applications déjà migrées vers le VPS.

L'objectif n'est pas de déplacer la logique métier côté navigateur. L'objectif est de mieux gérer le server state dans les interfaces React : cache, rafraîchissement, mutations, invalidation et états de chargement.

Décision proposée

TanStack Query est pertinent pour Staff Manager en priorité.

Il peut ensuite être étendu à Commu Rilindra si les parcours quiz, leaderboard, rewards et profil joueur ont besoin d'une meilleure synchronisation côté client.

Il ne concerne pas directement bot-rilindra, car le bot est un service runtime Node.js sans interface React. Le bot reste consommé via ses routes internes, ses webhooks, Discord, PostgreSQL et MinIO.

Pourquoi l'ajouter

Staff Manager a beaucoup d'écrans qui manipulent des données serveur :

  • tâches staff ;
  • utilisateurs et permissions ;
  • enchères ;
  • VIP ;
  • coffres ;
  • box de stockage ;
  • logs Discord ;
  • templates webhook ;
  • backups ;
  • dashboard bot ;
  • grille tarifaire ;
  • formulaires publics ;
  • données Discord enrichies.

Aujourd'hui, ces vues ont tendance à gérer elles-mêmes :

  • les états loading ;
  • les erreurs ;
  • les rechargements manuels ;
  • les données obsolètes après mutation ;
  • les synchronisations entre plusieurs boutons ou modales ;
  • les appels API répétés quand plusieurs composants lisent la même ressource.

TanStack Query apporte une couche standard pour ces problèmes, sans changer la source de vérité.

Source de vérité

La source de vérité reste :

PostgreSQL VPS
API routes Next.js
services serveur
bot Discord
MinIO
Infisical
Coolify

TanStack Query ne doit jamais devenir une source de vérité métier.

Il sert uniquement à synchroniser l'interface avec les données serveur.

Règle centrale

Le navigateur ne parle jamais directement à PostgreSQL, Discord, MinIO ou Infisical.
Le navigateur parle aux routes API.
TanStack Query orchestre les appels API côté client.

Périmètre recommandé

Staff Manager

Staff Manager est la meilleure cible initiale.

Raisons :

  • beaucoup de pages sont interactives ;
  • beaucoup d'actions modifient des données ;
  • plusieurs pages ont besoin de refetch après mutation ;
  • les admins doivent avoir une interface stable et prévisible ;
  • l'app utilise déjà NextAuth et des routes API internes ;
  • les données sont sensibles, donc la logique doit rester côté serveur.

Commu Rilindra

Commu peut bénéficier de TanStack Query dans un second temps.

Cibles possibles :

  • session joueur enrichie ;
  • quiz disponibles ;
  • résultat du dernier quiz ;
  • leaderboard ;
  • rewards ;
  • transactions ;
  • profil Discord ;
  • historique d'activité.

La migration de Commu doit rester séparée de Staff Manager pour éviter de mélanger deux chantiers.

Bot Rilindra

Le bot n'a pas besoin de TanStack Query.

Les interfaces qui pilotent le bot depuis Staff Manager peuvent utiliser TanStack Query, par exemple :

  • état runtime du bot ;
  • start / stop / restart ;
  • historique backups ;
  • logs bot ;
  • templates messages ;
  • notifications test ;
  • queue snapshots ;
  • statut Coolify.

Mais le bot lui-même reste indépendant.

Ce que TanStack Query résout

Cache client

Quand plusieurs composants lisent la même donnée, TanStack Query peut partager le résultat au lieu de refaire l'appel.

Exemples :

  • profil staff courant ;
  • permissions ;
  • liste des utilisateurs ;
  • état runtime du bot ;
  • compteurs du dashboard ;
  • catalogue de la grille tarifaire.

Invalidation après mutation

Après une action, l'interface doit savoir quelles données relire.

Exemples :

  • créer une tâche invalide tasks ;
  • valider une tâche invalide tasks et éventuellement dashboard;
  • modifier un rôle invalide users et permissions;
  • lancer une sauvegarde invalide botBackups;
  • modifier un template invalide discordTemplates;
  • annuler une enchère invalide auctions;
  • attribuer un coffre invalide vaults, vip et logs.

Etats réseau cohérents

Chaque écran peut exposer les mêmes états :

  • chargement initial ;
  • rechargement silencieux ;
  • erreur récupérable ;
  • retry ;
  • mutation en cours ;
  • mutation réussie ;
  • mutation échouée.

Moins de logique dupliquée

Les appels fetch, les toasts d'erreur, les refreshs et les invalidations peuvent être factorisés dans des hooks.

Ce que TanStack Query ne résout pas

TanStack Query ne remplace pas :

  • PostgreSQL ;
  • NextAuth ;
  • les routes API ;
  • les validations serveur ;
  • les permissions ;
  • les transactions SQL ;
  • les logs métier ;
  • les backups ;
  • la sécurité des secrets ;
  • la gestion Coolify ;
  • la logique Discord du bot.

Une mutation TanStack Query n'est pas une transaction métier. La transaction reste côté serveur.

Architecture cible

Provider recommandé

D'après la documentation TanStack Query v5, une application React doit être enveloppée dans un QueryClientProvider.

Dans Next.js App Router, le provider doit être un composant client.

Configuration de départ recommandée pour Rilindra :

staleTime global : 30s à 60s
retry global : limité, par exemple 1 ou 2
refetchOnWindowFocus : désactivé par défaut pour les interfaces admin sensibles
gcTime : valeur par défaut ou ajustée selon les pages

Raison :

  • éviter les refetch immédiats après hydratation ;
  • éviter de surcharger les API internes ;
  • garder une interface admin prévisible ;
  • rafraîchir explicitement les données après mutation.

Règles pour les query keys

Les query keys doivent être stables, lisibles et hiérarchiques.

Convention proposée :

["staff", "me"]
["staff", "permissions"]
["users", "list", filters]
["tasks", "list", filters]
["tasks", "calendar", month]
["auctions", "list", filters]
["auctions", "detail", auctionId]
["vip", "tribes", filters]
["vaults", "list", filters]
["storage", "boxes", filters]
["bot", "runtime"]
["bot", "backups", page]
["bot", "discord-templates"]
["priceCatalog", "catalog"]
["priceCatalog", "overrides"]

Règles :

  • toujours mettre le domaine en premier ;
  • mettre les filtres dans la key ;
  • ne jamais mettre de secret dans une query key ;
  • éviter les keys vagues comme ["data"] ou ["list"] ;
  • utiliser les mêmes keys dans les mutations et les invalidations.

Règles pour les fetchers

Les fetchers doivent être fins.

Ils appellent les routes API et retournent un payload typé.

Ils ne doivent pas :

  • construire de SQL ;
  • lire de variables serveur ;
  • appeler Discord directement ;
  • appeler MinIO directement ;
  • contenir de logique de permission ;
  • masquer une erreur métier importante.

Exemple de structure :

src/lib/api/tasks-client.ts
src/lib/api/users-client.ts
src/lib/api/auctions-client.ts
src/lib/api/bot-client.ts
src/lib/api/vip-client.ts
src/lib/api/price-catalog-client.ts

Règles pour les hooks

Les hooks TanStack Query doivent rester proches du domaine métier.

Exemples :

src/hooks/queries/useTasks.ts
src/hooks/queries/useUsers.ts
src/hooks/queries/useAuctions.ts
src/hooks/queries/useBotRuntime.ts
src/hooks/queries/useVipTribes.ts
src/hooks/queries/usePriceCatalog.ts

Les composants doivent consommer ces hooks plutôt que de réimplémenter fetch.

Mutations et invalidation

Chaque mutation doit définir ses invalidations.

Exemples :

MutationInvalidation minimale
Créer une tâche["tasks"]
Modifier une tâche["tasks"]
Valider une tâche["tasks"], ["staff", "dashboard"]
Modifier un rôle utilisateur["users"], ["staff", "permissions"]
Synchroniser Discord["users"], ["staff", "me"]
Annuler une enchère["auctions"], ["auctions", "detail", id]
Attribuer un coffre["vaults"], ["vip"], ["bot", "logs"]
Lancer backup["bot", "backups"], ["bot", "runtime"]
Modifier template webhook["bot", "discord-templates"]
Modifier prix catalogue["priceCatalog"]

Règle :

Une mutation qui change une donnée doit invalider toutes les vues qui affichent cette donnée.

Optimistic updates

Les optimistic updates doivent être rares au début.

Autorisé plus tard :

  • bascule d'un toggle UI simple ;
  • sélection visuelle ;
  • état de filtre local ;
  • feedback immédiat sur une action non critique.

À éviter au début :

  • validation de tâche ;
  • changement de rôle ;
  • suppression utilisateur ;
  • attribution coffre ;
  • annulation d'enchère ;
  • start / stop / restart du bot ;
  • actions qui ping Discord ;
  • actions qui écrivent en base ou dans MinIO.

Pour ces actions, il vaut mieux attendre la réponse serveur puis invalider les queries.

Gestion des erreurs

Les erreurs doivent rester lisibles pour le staff.

Une route API devrait retourner une erreur structurée :

{
"error": "Permission insuffisante",
"code": "FORBIDDEN"
}

TanStack Query doit transformer cela en UI claire :

  • toast ;
  • message inline ;
  • bouton réessayer ;
  • action désactivée si nécessaire.

Ne jamais afficher :

  • stack trace ;
  • token ;
  • URL de base contenant identifiants ;
  • contenu brut d'une erreur Discord ou Coolify avec secret.

Sécurité

TanStack Query ne change pas le modèle de sécurité.

Les contrôles restent côté serveur :

  • session NextAuth ;
  • rôle staff ;
  • permissions ;
  • validation du payload ;
  • vérification de l'environnement ;
  • secrets uniquement côté serveur ;
  • logs sans secret.

Le cache client ne doit pas contenir :

  • tokens Discord ;
  • secrets Coolify ;
  • secrets Infisical ;
  • chaînes de connexion DB ;
  • URL signées privées trop longues ;
  • données qui ne doivent pas survivre à une session.

Données sensibles et cache

Certaines données peuvent être cachées côté client :

  • listes de tâches ;
  • liste utilisateurs staff ;
  • statut public d'un service ;
  • historique de backups sans liens sensibles ;
  • templates de messages ;
  • catalogue prix.

D'autres données doivent être évitées ou très courtes en cache :

  • actions bot sensibles ;
  • logs contenant des IDs ou messages privés ;
  • détails d'erreurs ;
  • payloads d'administration ;
  • résultats d'opérations de sécurité.

Interaction avec Next.js App Router

Approche recommandée :

Server Components pour les shells de page et les checks serveur.
Client Components pour les surfaces interactives.
TanStack Query dans les Client Components.
Routes API comme frontière de sécurité.

On évite de transformer toute l'application en client-only.

Le provider TanStack Query doit être ajouté au layout ou à un provider global déjà existant.

Interaction avec NextAuth

TanStack Query ne remplace pas NextAuth.

Les routes API doivent continuer à valider la session.

Quand une session expire :

  • les queries doivent recevoir un 401 ;
  • l'UI doit rediriger ou afficher une action de reconnexion ;
  • les mutations doivent échouer proprement.

Interaction avec PostgreSQL VPS

Les hooks ne parlent jamais à PostgreSQL.

Flux attendu :

hook TanStack Query
-> route API Next.js
-> session NextAuth
-> permissions
-> PostgreSQL VPS
-> réponse typée
-> cache TanStack Query

Si une route utilise la session DB app.discord_id, cela reste invisible côté client.

Interaction avec Coolify

Les opérations Coolify restent côté serveur.

TanStack Query peut piloter :

  • lecture runtime ;
  • déclenchement start ;
  • déclenchement stop ;
  • déclenchement restart ;
  • lecture status ;
  • lecture historique backups ;
  • test notification.

Mais la route API garde :

  • le token Coolify ;
  • les validations ;
  • les confirmations ;
  • les logs d'audit.

Interaction avec Discord

Même principe :

client -> route API -> Discord API

TanStack Query peut gérer :

  • loading ;
  • erreurs ;
  • invalidation ;
  • refetch après sync ;
  • affichage de résultats.

Il ne doit jamais exposer le token Discord.

Interaction avec MinIO

Pour les images d'enchères et assets :

  • les uploads passent par une route API ;
  • la route API parle à MinIO ;
  • l'interface invalide les queries liées aux images ;
  • la rétention reste côté MinIO ou jobs serveur.

TanStack Query peut aider à afficher :

  • progression logique ;
  • liste des images ;
  • statut de purge ;
  • erreurs de chargement.

Ordre d'adoption recommandé

Phase 0 - Stabilisation

Attendre que la migration VPS prod soit stable.

Critères :

  • logs prod propres ;
  • staff prod testé ;
  • bot prod OK ;
  • backups OK ;
  • aucun chantier DB urgent.

Phase 1 - Provider et conventions

Ajouter :

  • dépendance @tanstack/react-query ;
  • provider global ;
  • fichier de query keys ;
  • helpers fetch JSON ;
  • conventions d'erreur ;
  • tests de base.

Ne migrer aucune page complexe dans cette phase si possible.

Phase 2 - Page faible risque

Commencer par une page à risque modéré :

  • /admin/bot lecture runtime ;
  • historique backups ;
  • templates simples ;
  • page users en lecture seule.

Objectif :

  • valider provider ;
  • valider conventions ;
  • valider invalidation simple ;
  • vérifier logs ;
  • vérifier UX.

Phase 3 - Mutations admin contrôlées

Ajouter les mutations :

  • synchroniser users ;
  • notification test ;
  • rafraîchir backups ;
  • modifier templates.

Les actions dangereuses gardent une confirmation côté UI et côté route API.

Phase 4 - Pages métier principales

Migrer progressivement :

  • /tasks ;
  • /encheres ;
  • /vip ;
  • /coffre-banque ;
  • /box-stockage ;
  • /grille-tarifaire.

Une page à la fois.

Phase 5 - Commu Rilindra

Si Staff Manager est stable, étudier Commu :

  • quiz ;
  • résultats ;
  • leaderboard ;
  • rewards ;
  • profil ;
  • transactions.

Priorité par module Staff Manager

PrioritéModulePourquoi
P1Dashboard botBeaucoup de refresh, faible dépendance UI profonde
P1UsersMutations claires, invalidation simple
P1BackupsDonnées paginées, refetch évident
P2TasksImportant mais plus sensible
P2EnchèresDonnées volumineuses, images, statuts
P2VIPBeaucoup de règles métier
P3CoffresActions sensibles, logs staff
P3Box stockageActions sensibles, lifecycle
P3Grille tarifaireBeaucoup d'édition, besoin d'un modèle propre

Exemple de matrice query keys

DomaineQuery key
Staff courant["staff", "me"]
Permissions["staff", "permissions"]
Users["users", "list", filters]
Tasks liste["tasks", "list", filters]
Tasks calendrier["tasks", "calendar", month]
Auctions liste["auctions", "list", filters]
Auction détail["auctions", "detail", id]
VIP tribus["vip", "tribes", filters]
Vaults["vaults", "list", filters]
Storage boxes["storage", "boxes", filters]
Bot runtime["bot", "runtime"]
Bot backups["bot", "backups", page]
Templates bot["bot", "templates", type]
Catalogue prix["priceCatalog", "catalog"]

Contrats API à standardiser

Chaque route consommée par TanStack Query devrait tendre vers un format stable.

Succès :

{
"data": {},
"meta": {}
}

Erreur :

{
"error": "Message lisible",
"code": "ERROR_CODE",
"details": {}
}

Pour les listes :

{
"data": [],
"meta": {
"page": 1,
"pageSize": 25,
"total": 120
}
}

Cette standardisation peut être progressive.

Tests à prévoir

Tests unitaires

  • query keys ;
  • fetchers ;
  • gestion erreurs ;
  • mutations ;
  • invalidations.

Tests composants

  • loading ;
  • erreur ;
  • succès ;
  • mutation pending ;
  • invalidation après succès.

Tests intégration UI

  • page chargée ;
  • action réalisée ;
  • donnée rafraîchie ;
  • pas de double action ;
  • pas de 500.

Tests production staging

  • vérifier logs API ;
  • vérifier absence de refetch excessif ;
  • vérifier pagination ;
  • vérifier session expirée ;
  • vérifier boutons dangereux.

Observabilité

Sur les pages migrées, surveiller :

  • nombre d'appels API ;
  • erreurs 401/403 ;
  • erreurs 500 ;
  • temps de réponse ;
  • mutations doublées ;
  • stale data visible ;
  • logs staff ;
  • logs DB ;
  • logs Coolify si action runtime.

Anti-patterns

À éviter :

  • appeler fetch directement dans 20 composants différents ;
  • invalider toutes les queries après chaque mutation ;
  • mettre des tokens dans une query key ;
  • faire de l'optimistic update sur une action critique ;
  • mélanger état local UI et server state ;
  • utiliser TanStack Query pour stocker un formulaire en cours de saisie ;
  • mettre la logique métier dans le hook ;
  • faire un refetch automatique trop agressif ;
  • convertir toute l'application d'un coup.

Décisions à prendre avant implémentation

Avant de coder, décider :

  1. où placer le provider ;
  2. si on installe seulement @tanstack/react-query ou aussi les devtools en dev ;
  3. conventions de query keys ;
  4. format de réponse API cible ;
  5. première page pilote ;
  6. stratégie toast et erreurs ;
  7. staleTime global ;
  8. règles pour refetchOnWindowFocus ;
  9. politique optimistic updates ;
  10. limites de cache pour données sensibles.

Première page pilote recommandée

La meilleure première page est probablement le Dashboard Bot.

Pourquoi :

  • déjà très orienté API ;
  • beaucoup de données runtime ;
  • refresh actuel utile ;
  • actions séparables ;
  • risque métier plus contrôlable si les actions dangereuses gardent leurs confirmations ;
  • impact visible immédiatement.

Plan pilote :

  1. query ["bot", "runtime"] ;
  2. query ["bot", "backups", page] ;
  3. mutation restartBot avec confirmation ;
  4. invalidation ["bot", "runtime"] ;
  5. mutation sendTestNotification ;
  6. tests composant et route ;
  7. vérification staging.

Critères de réussite

TanStack Query apporte de la valeur si :

  • moins de code de chargement dupliqué ;
  • moins de refresh manuel ;
  • moins d'états incohérents après mutation ;
  • moins d'appels API inutiles ;
  • erreurs plus claires ;
  • UX plus fluide ;
  • tests plus simples à écrire.

Si une page devient plus complexe après migration, il faut ralentir et revoir les abstractions.

Critères de refus temporaire

Ne pas commencer si :

  • la prod vient de recevoir une migration critique non validée ;
  • les logs prod ne sont pas propres ;
  • les routes API d'une page ne sont pas stabilisées ;
  • les réponses API sont trop hétérogènes ;
  • une page a encore une dette métier importante ;
  • les tests de base ne passent pas.

Résumé opérationnel

TanStack Query est un bon choix pour Staff Manager.
On l'utilise pour server state côté client.
On garde PostgreSQL, Discord, MinIO, Coolify et Infisical côté serveur.
On migre par petites surfaces.
On commence par Dashboard Bot ou Users.
On évite les optimistic updates sur les actions critiques.
On standardise query keys, fetchers, mutations et invalidations.

Références

  • TanStack Query v5, documentation React : provider QueryClientProvider, QueryClient, staleTime, mutations et invalidation.
  • Documentation Next.js App Router dans TanStack Query : provider client et stratégie SSR/hydratation.
  • Conventions internes Rilindra : PostgreSQL VPS comme source de vérité, API routes comme frontière de sécurité, Infisical/Coolify pour les secrets et le runtime.