Back to sh0
sh0

L'interface qui semblait complète

Le tableau de bord de backup avait des modales, un CronBuilder, des assistants en 3 étapes et un tableau de planifications. Tout semblait terminé. Rien ne fonctionnait. Voici ce que nous avons corrigé et ce que cela nous a appris.

Thales (Juste Gnimavo) | March 30, 2026 7 min sh0
EN/ FR/ ES
uxdashboardsveltebackupmodalsdesignfalse-confidenceintegration-testing

J'ai ouvert la page de backups. Elle avait des onglets pour l'Historique et les Planifications. Un bouton « Déclencher un backup » avec un dégradé bleu. Un bouton « Créer une planification ». Un composant CronBuilder avec 17 préréglages et un éditeur de champs en 5 colonnes. La configuration des fournisseurs de stockage avec 13 backends supportés. Des assistants en trois étapes pour le déclenchement et la planification. Un état vide avec une belle illustration. Des notifications toast. La pagination.

J'ai cliqué sur « Déclencher un backup ». J'ai sélectionné mon instance PostgreSQL. J'ai cliqué sur « Sauvegarder maintenant ». Le toast a affiché « Backup déclenché ». Une carte est apparue dans la liste d'historique : badge jaune, « en attente ».

J'ai attendu. J'ai rafraîchi. Toujours en attente. J'ai vérifié les logs. Rien. Le moteur de backup n'avait pas été appelé. Le bouton était connecté à un handler d'API qui créait une ligne en base de données et retournait 202. C'est tout.

L'interface était parfaite. Le backend était un cul-de-sac.

Tout ce que l'utilisateur pouvait voir

Voici à quoi ressemblait la page de backup avant la session de corrections :

  • Une mise en page professionnelle avec des onglets (Historique | Planifications)
  • Une bannière d'information affichant « 2 planifications actives -- Prochaine exécution : demain à 02:00 »
  • Un CronBuilder avec des préréglages (toutes les heures, quotidien à 2 h, jours ouvrés à 9 h)
  • Des cartes de backup avec des en-têtes de statut colorés (vert pour terminé, jaune pour en attente)
  • Des icônes de type de source (base de données ou volume)
  • Affichage de la taille du fichier, labels de destination, badges de chiffrement
  • Bouton de restauration, bouton de suppression, bouton de téléchargement (désactivé, « bientôt disponible »)
  • Cartes de fournisseurs de stockage avec test de connexion

Du point de vue d'une démo produit, c'est convaincant. Du point de vue de la production, rien derrière les boutons ne fonctionnait :

FonctionnalitéStatut de l'interfaceStatut du backend
Déclencher un backupLe bouton fonctionne, le toast s'afficheLe handler crée un enregistrement, ne l'exécute jamais
Planifier un backupLe formulaire s'envoie, la planification est sauvegardéeLe planificateur n'est jamais lancé
Exécuter maintenantL'icône est cliquableAppelle le même endpoint de déclenchement cassé
TéléchargerBouton désactivéAucun endpoint n'existait
SupprimerUtilise confirm() du navigateurFonctionne mais UX non professionnelle
Modifier une planificationAucun bouton n'existeL'endpoint API fonctionne
Liste des bases de donnéesAffiche « 0 bases de données »N'interroge que la table databases, ignore les apps

Sept fonctionnalités. Deux fonctionnaient (supprimer et activer/désactiver une planification). Cinq étaient cassées ou manquantes.

Ce que nous avons livré en une seule session

1. Modale de confirmation de suppression

L'ancien code utilisait confirm() -- un dialogue natif du navigateur. Il a un aspect différent sur chaque OS, ne peut pas être stylisé et ne fournit aucun contexte sur ce qui va être supprimé. Nous l'avons remplacé par une modale appropriée :

Une bannière de danger rouge avec le nom de la source, des boutons Annuler et Supprimer, un état de chargement pendant l'appel API. Une interface professionnelle pour une action destructrice.

2. Cartes de planification au lieu d'un tableau

La liste des planifications était un tableau à 7 colonnes : Statut, Source, Planification, Destination, Rétention, Dernière exécution, Actions. Sur un écran de laptop standard, les colonnes étaient compressées et l'expression cron à peine lisible.

Nous l'avons remplacé par une mise en page en cartes correspondant aux cartes d'historique de backup. Chaque carte affiche : un badge de statut et l'expression cron dans l'en-tête, le nom de la source avec l'icône du type, une grille à 3 colonnes pour destination/rétention/dernière exécution, et l'heure de la prochaine exécution. Les boutons d'action (Exécuter maintenant, Modifier, Pause, Supprimer) sont dans l'en-tête de la carte.

3. Bouton de planification dans l'onglet Historique

Le bouton « Créer une planification » n'apparaissait que quand l'utilisateur passait à l'onglet Planifications. Mais le moment le plus naturel pour créer une planification est juste après avoir déclenché un backup manuel -- « ça a marché, maintenant je veux que ça se fasse automatiquement ». Nous avons ajouté un bouton Planifier avec une icône de calendrier à côté du bouton Déclencher un backup dans l'onglet Historique.

4. Téléchargement des backups

Le bouton de téléchargement était désactivé avec une infobulle « bientôt disponible ». Nous avons ajouté :

Backend : GET /api/v1/backups/:id/download -- lit le fichier de backup depuis le stockage, définit Content-Disposition: attachment avec un nom de fichier descriptif (backup-database-2a6705b2.gz) et envoie les octets en streaming.

Frontend : backupsApi.download(id) -- récupère le fichier en blob, crée un élément <a> temporaire avec l'attribut download, le clique programmatiquement et nettoie. Le téléchargement démarre immédiatement avec le bon nom de fichier.

5. Confirmation « Exécuter maintenant »

Le bouton Play sur les planifications déclenchait un backup immédiat sans confirmation. Un clic accidentel et un dump de base de données volumineux démarre. Nous avons ajouté une modale de confirmation affichant le nom de la source, le type, la destination et l'expression cron avant l'exécution.

6. Modale d'édition de planification

Les planifications pouvaient être créées mais pas modifiées. L'endpoint API (PATCH /api/v1/backup-schedules/:id) supportait déjà les mises à jour, et schedulesApi.update() existait dans le client API du frontend. Nous avons ajouté un bouton avec une icône Crayon et une modale avec le CronBuilder, le sélecteur de destination et le champ de rétention pré-remplis avec les valeurs actuelles.

7. Nettoyage du CronBuilder

Le CronBuilder affichait à la fois un champ texte et un menu déroulant pour chacun des 5 champs cron, soit 10 éléments d'interface en ligne. Pour la plupart des utilisateurs, les menus déroulants couvrent tous les cas d'utilisation. Nous avons supprimé les champs texte (en ne gardant que les menus déroulants), masqué l'éditeur de champs quand un préréglage est sélectionné (puisque le préréglage définit déjà tous les champs) et resserré l'espacement.

L'écart de confiance

Ce qu'il y a de dangereux avec une interface qui semble complète, c'est qu'elle crée de la confiance. Quand j'ai vu la page de backup avec ses modales, son CronBuilder et ses assistants en 3 étapes, j'ai supposé que tout fonctionnait. L'interface était la preuve. La revue de code a confirmé l'hypothèse -- le handler acceptait une requête et retournait une réponse, le planificateur avait une méthode tick, le moteur avait une fonction create_backup.

L'écart se trouvait dans le câblage. Le handler n'appelait pas le moteur. Le planificateur n'était pas lancé. Le backup de volume utilisait la mauvaise API. Le nom de la base de données était faux. Chacun de ces problèmes est une seule ligne manquante ou une mauvaise variable -- invisible en revue de code, évident en test.

La solution n'est pas plus de revue de code. C'est le test d'intégration. Un test qui :

  1. Déclenche un backup via l'API
  2. Attend que le statut passe de « pending » à « completed »
  3. Télécharge le fichier de backup
  4. Vérifie que le fichier est une archive gzip valide
  5. Pour les backups de base de données : vérifie que le contenu SQL contient les tables attendues

Ce test aurait détecté chaque bug de cet article. Nous ne l'avions pas. Maintenant si.

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles