Aller au contenu principal
Wilook Backoffice - Gestion E-commerce Mode
Terminé
DASHBOARD

Étude de cas

Wilook Backoffice - Gestion E-commerce Mode

Application d'administration d'un e-commerce de mode, construite en Nuxt 4 rendu côté client avec Vue 3, Vuetify 4 et une base PostgreSQL managée. Elle couvre la gestion CRUD des produits avec filtres avancés et upload d'images, la composition visuelle de looks en cinq emplacements par glisser-déposer, et le suivi des clients. L'accès aux données passe par une couche service qui normalise les erreurs de la base, consommée par des composables Vue ; les filtres vivent dans l'URL et la pagination est résolue côté serveur.

Durée
Novembre 2022 à mai 2023
Équipe
1 personne
Statut
Terminé
Partager sur TwitterPartager sur LinkedInPartager sur FacebookCopier le lien

En chiffres

51 → 1

Requêtes par grille produits

N+1 éliminés sur une grille de 50 produits

5

Emplacements look

Composition visuelle de tenues

SPA

Rendu

Nuxt 4 sans SSR, sortie Bun

7 mois

Durée

Novembre 2022 à mai 2023, en solo

D’où vient le projet

Avant cet outil, les looks se composaient dans un tableur partagé. Le tableur tenait lieu d’interface de travail, et chaque sélection préparée pour un client demandait une suite de manipulations qui allongeait le processus.

Le backoffice a été construit pour ça. Composer une tenue se fait désormais sur un seul écran, avec les visuels des articles sous les yeux, ce qui a fortement réduit le temps de préparation d’un look. Les questionnaires de style remplis par les clients, eux, sont devenus visibles au moment de composer, au lieu d’être consultés à part.

Le contexte

Wilook Backoffice est l’outil d’administration d’un e-commerce de mode. Il couvre trois usages quotidiens : tenir le catalogue produits à jour, composer des tenues en associant plusieurs articles, et suivre les clients avec leurs préférences de style. C’est un outil de poste de travail, utilisé longuement et de façon répétitive, ce qui place la fluidité des listes avant l’effet visuel.

L’application est une SPA Nuxt : le rendu serveur est désactivé, parce qu’aucun de ces écrans n’a de raison d’être indexé et qu’ils sont tous derrière authentification. Projet mené seul de la conception au déploiement, pendant mon alternance chez Quanted Square, de novembre 2022 à mai 2023.

Le code décrit ici tourne sur des versions actuelles, Nuxt 4 et une sortie Bun : je maintiens la base à jour depuis. C’est le même projet et les mêmes choix d’architecture, pas une réécriture.

Un backoffice se juge sur des critères peu spectaculaires, et trois contraintes ont porté les décisions.

Des listes qui grossissent. Un catalogue mode se compte en milliers de références déclinées en tailles et coloris. Recherche, tri et pagination doivent rester stables à mesure qu’il s’étoffe.

Des cartes qui se paient au pluriel. Une carte produit qui va chercher sa propre vignette est indolore à l’unité et ruineuse par cinquante. Le coût réel d’un écran se mesure en requêtes par affichage, pas par composant.

Un back-office ne s’expose pas. Les données produits et clients ne doivent être lisibles qu’authentifié, sans casser au passage la diffusion publique des images.

Le chemin d’une donnée

La décision structurante du projet tient dans ce trajet : un composant affiche, il n’atteint jamais la base.

Du composant à la source de données

affichage

Composant Vue

Il affiche ce qu'on lui passe, il n'atteint jamais la base.

état

Composable métier

Un par domaine : état réactif, pagination, erreurs.

accès

Couche service

Une classe par domaine, seul point de contact avec la base.

données

Base managée

PostgreSQL, authentification et stockage des images.

serveur

Route serveur

Le tableau de bord compte côté serveur, avec la session de l'utilisateur.

La base de service traduit les erreurs de la base en erreurs applicatives typées : introuvable, réseau, serveur. Aucun composant n'a jamais à reconnaître un code d'erreur de la couche de données.

Cette frontière n’a pas été posée pour l’élégance. C’est elle qui a permis de remplacer les requêtes unitaires par des chargements groupés sans toucher un seul écran.

Les choix techniques

Accès aux données

Une couche service par domaine

Une classe abstraite porte l'exécution des requêtes et la traduction des erreurs ; une classe par domaine hérite d'elle. Les composants ne voient que des objets métier et des erreurs typées.

État des filtres

Stockage dans l'URL

Une vue filtrée devient une adresse : partageable, remise en favori, et compatible avec le bouton retour. Neuf paramètres nommés, relus par la requête au lieu d'être dupliqués en mémoire.

Listes volumineuses

Pagination serveur en scroll infini

Vingt éléments par page, offset dérivé de la liste courante, appels concurrents ignorés et fin de liste détectée. Le navigateur ne détient jamais le catalogue entier.

Sécurité

Verrou au niveau de la base, avec la session

La route serveur du tableau de bord construit son accès à partir des cookies de la requête, jamais avec une clé d'administration. Le verrou reste celui de la base, même quand le calcul est déporté.

Deux choix complètent ces décisions. L’état serveur vit dans des composables Vue, sans bibliothèque de cache : chaque domaine expose ses références de liste, chargement, erreur, total et fin de liste, et le périmètre ne justifiait pas d’ajouter une couche de plus. Et le magasin global se réduit à ce qui est strictement local à l’écran, la visibilité du tiroir de filtres, puisque le reste vit dans le serveur ou dans l’URL.

L’architecture qui en découle

Le trajet d'une donnée
tableau de bordverrou de la base conservéComposants Vueils affichent, ils n'atteignent pas la baseFiltres dans l'URLvue partageable, retour arrièreComposables métierétat réactif · pagination · erreursCouche servicerequêtes et erreurs normaliséesRoute serveuragrégats, avec la sessionBase managéePostgreSQL · authentification · stockage
Faites défiler le schéma horizontalement.
Aucun composant n'atteint la base : c'est ce qui a rendu la passe de performance possible sans toucher aux écrans.

L’éditeur de looks est la seule partie où l’interface prime : cinq emplacements nommés, du glisser-déposer depuis le catalogue, et l’affectation du look à un client. Le reste de l’application est délibérément sobre, c’est un outil de travail et pas une vitrine.

La passe qui a le plus compté

Le sujet de départ était « déporter du travail sur le serveur ». L’évaluation a montré que la piste envisagée ne s’appliquait pas ici, et que le vrai coût était ailleurs : dans le nombre de requêtes qu’un simple affichage déclenchait.

Avant

  • ✗Grille de 50 produits : 51 requêtes, chaque carte allant chercher sa vignette
  • ✗Grille de looks : jusqu'à six requêtes séquentielles par carte, qui suspendaient le rendu
  • ✗Listes chargées en select complet, images et descriptions comprises
  • ✗Tableau de bord : trois comptages depuis le navigateur, ni parallèles ni attendus

Après

  • ✓Grille de 50 produits : une requête, la vignette étant déjà dans la ligne
  • ✓Looks hydratés en deux requêtes groupées quel que soit leur nombre
  • ✓Projection dédiée aux listes, reflétée dans un type de résumé
  • ✓Tableau de bord : une route serveur, trois comptages parallèles

La piste des composants serveur a été écartée sur constat, pas par principe : un fragment rendu côté serveur par le framework n’a pas accès au client de données privilégié, qui n’est exposé qu’à la couche serveur. Le bénéfice recherché a été obtenu par la voie native de la pile, une route serveur, où cet accès existe.

Ce que le projet n’a pas

Il n’y a pas de suite de tests automatisés sur ce dépôt. Le contrôle qualité y repose sur le typage strict, l’analyse statique du linter et la vérification manuelle des écrans. C’est un choix de périmètre assumé en solo, et c’est aussi la première chose que je reprendrais : la couche service, isolée du reste et sans dépendance à l’interface, est précisément la frontière qui rendrait ces tests peu coûteux à écrire.

Où en est le produit

Livré en mai 2023, après sept mois. L’application gère le catalogue, la composition de looks et les profils clients, avec filtres dans l’URL, pagination résolue côté base et lecture verrouillée au niveau de la base. La passe de performance a ramené les écrans de liste à une poignée de requêtes là où ils en déclenchaient des dizaines.

L'interface

Interface du backoffice Wilook avec la liste des produits

Gestion du catalogue produits avec filtres et scroll infini

Leçons apprisesLeçons apprises

Technical

Le coût d'une liste se joue par carte, pas par page

Technique

Chaque vignette produit allait chercher son image alors que la donnée était déjà dans la ligne chargée par la liste. Cinquante cartes, cinquante et une requêtes. Un composant qui requête pour son propre compte ne coûte rien à l'unité et tout au pluriel.

Design

L'URL est un magasin d'état sous-estimé

Design

Mettre les filtres dans l'URL les rend partageables et permet le retour arrière, tout en retirant autant d'état à gérer côté application. Encore faut-il que la requête les relise : le tiroir écrivait l'URL, le fetch l'ignorait.

Technical

Un scroll infini se juge sur ses gardes

Technique

Charger la page suivante est la partie facile. Ce qui casse en production, c'est l'appel concurrent qui duplique une page, la liste écrasée au lieu d'être complétée, et l'absence de fin détectée.

Navigation

Articles

Projets

Actions