WakaStart
Sécurité

Bonnes pratiques — Performance & Observabilité

Cache, refresh proactif, pagination, TanStack Query, métriques Prometheus et structured logging.

Version v1.03 min de lecture

Bonnes pratiques — Performance & Observabilité

Ce chapitre couvre les patterns de performance, de cache et d'observabilité. Lisez Bonnes pratiques sécurité en complément.


Performance

9. Cacher /me — un seul appel au login

typescript
// BIEN : stocker dans un React context, ne jamais re-fetcher à la navigation const AuthProvider = ({ children }) => { const [user, setUser] = useState(null); useEffect(() => { // Appelé une seule fois au mount du provider (= au login) fetchMe().then(setUser); }, []); return <AuthContext.Provider value={{ user }}>{children}</AuthContext.Provider>; }; // MAL : re-fetcher /me à chaque page/composant const UserPage = () => { const { data: user } = useQuery({ queryKey: ["me"], queryFn: fetchMe }); // refetch sur chaque mount };

10. Refresh proactif avant l'expiration

typescript
// BIEN : vérifier exp - now < 60s et rafraîchir avant l'expiration const REFRESH_THRESHOLD = 60; // secondes function scheduleTokenRefresh(expiresIn: number) { const refreshIn = Math.max(0, expiresIn - REFRESH_THRESHOLD) * 1000; setTimeout(async () => { await refreshTokens(); }, refreshIn); } // MAL : rafraîchir après un 401 (le call a déjà échoué, UX dégradée) catch (err) { if (err.status === 401) await refreshTokens(); // trop tard }

11. Pagination — ne jamais charger tout

typescript
// BIEN : paginer, limit max = 100 const { data } = await apiGet("config/users", { page: "1", limit: "50" }); // MAL : tenter de tout charger const { data } = await apiGet("config/users", { page: "1", limit: "10000" }); // timeout

12. TanStack Query — staleTime adapté à la criticité

typescript
// Données qui changent rarement (branding, runtime-config) : 5 minutes useQuery({ queryKey: ["runtime-config"], queryFn: fetchRuntimeConfig, staleTime: 5 * 60 * 1000, }); // Données qui changent souvent (users, invitations) : 30s useQuery({ queryKey: ["users", page], queryFn: () => fetchUsers(page), staleTime: 30_000, });

Architecture

13. Proxy serveur pour tous les appels API

Le browser ne doit jamais appeler directement la Public API.

text
Browser → /api/proxy/[...path] (route Next.js) → Public API └── lit les cookies HttpOnly └── ajoute Authorization + x-enriched-token └── forward la réponse

14. Séparer Discovery et API

typescript
// BIEN : Discovery utilisé une seule fois, avant l'auth const { keycloakUrl } = await discoverStartLogin({ host }); window.location.assign(keycloakUrl); // MAL : appeler Discovery après chaque login ou sur chaque page useEffect(() => { fetchDiscovery(email); // inutile après auth }, []);

15. Respecter la hiérarchie dans votre modèle de données

typescript
// Vos entités doivent refléter la hiérarchie Wakastart interface AppContext { partnerId: string; // pid du wakaToken networkId: string; // nid customerId: string; // cid appId: string; // votre app (WID) }

16. Utiliser les WIDs dans les URLs

text
BIEN : /users/WKST05 (lisible, stable) MAL : /users/550e8400-... (UUID interne)

Observabilité

17. Propager le x-trace-id

typescript
// Inclure l'ID de trace dans toutes vos requêtes API const traceId = crypto.randomUUID(); headers["x-trace-id"] = traceId; // Logger côté frontend avec le même ID logger.info("API call", { traceId, url, method });

18. Métriques recommandées

Exposez des métriques Prometheus depuis votre Wakapp :

text
wakapp_api_calls_total{endpoint, status} wakapp_token_refresh_total{success} wakapp_invitations_created_total{customer} wakapp_invitations_accepted_total{customer} wakapp_auth_flow_duration_seconds (histogram)

19. Structured logging

typescript
// BIEN : JSON structuré, parsable par Loki / CloudWatch logger.info({ event: "user_login_success", userId: user.wid, customerId: user.customer.wid, adminLevel: user.adminLevel, duration_ms: Date.now() - startTime, }); // MAL : texte libre impossible à filtrer console.log(`User ${email} logged in successfully in ${elapsed}ms`);

Checklist performance pré-production

  • Refresh proactif implémenté (threshold 60s)
  • Rate limit géré (backoff exponentiel)
  • /me chargé une fois, mis en cache, invalidé au refresh
  • runtime-config chargé une fois au démarrage
  • TanStack Query configuré avec des staleTime adaptés
  • Pagination correcte (limit ≤ 100)
  • x-trace-id propagé dans tous les appels API

Aller plus loin