Backend Kotlin (API, sécurité, jobs images), intégration front PWA et pipeline CI/CD

API marketplace — compression WebP et CSRF distribué

Monolithe Spring Boot + PWA React : images remplacées en WebP seulement si plus légères, CSRF partagé via Redis, déploiement conteneurisé automatisé.

40-45 %
réduction moyenne (images déjà compactes)
98,5 %
réduction sur photo source non optimisée
1024 px
redimensionnement max avant encodage

Contexte

Plateforme marketplace (espaces / produits / modération) : API unique Spring Boot, front React/Vite, back-office admin, déploiement conteneurisé. Redis est obligatoire pour le CSRF et le cache entre instances.

Le problème

Les images produits gonflaient le stockage objet et la bande passante ; une compression naïve pouvait produire un WebP plus lourd que l'original. En parallèle, un store CSRF en mémoire cassait les POST authentifiés dès qu'il y avait plusieurs instances derrière le reverse-proxy.

L'approche

  • Encodeur WebP côté backend (qualité 0,8) avec règle explicite : ne remplacer le fichier objet et la référence DB que si le WebP est strictement plus léger ; sinon conserver l'original.
  • Job async de compression admin (suivi de tâche, journal des skips « WebP plus lourd »).
  • CSRF via Redis (`csrf:{sessionId}`) pour partager les tokens entre instances ; PostgreSQL pour le métier, Redis pour état de session/cache.
  • CI GitHub Actions : build Docker multi-stage, push vers un registre de conteneurs, déclenchement webhook de déploiement sur main ; front en PWA (vite-plugin-pwa / Workbox) pour le shell installable.

Pourquoi ce choix

Conserver l'original quand le WebP n'apporte rien évite de dégrader la taille « pour le principe ». Redis pour le CSRF plutôt qu'un sticky-session seul : les instances restent interchangeables derrière le reverse-proxy.

Résultat mesuré

  • Réduction moyenne de 40 à 45 % sur des images déjà compactes (15-170 Ko), jusqu'à 65 % sur les plus lourdes de cet échantillon
  • Jusqu'à 98,5 % de réduction sur une photo source non optimisée (smartphone, plusieurs Mo), portée surtout par le redimensionnement à 1024 px
  • Skip automatique si le WebP produit un fichier plus lourd que l'original — aucun cas rencontré sur les échantillons testés