Construire un espace d’administration moderne avec Vue 3 : retour d’expérience
Crédit : Olivier Fillol
Une amie travaille sur des projets d’énergies renouvelables. À l’issue des élections municipales, pour plusieurs dizaines voire centaines de communes, elle doit croiser manuellement des fichiers CSV du ministère de l’Intérieur pour distinguer les maires renouvelés des nouveaux élus. Un tableur et beaucoup de patience. Je lui ai proposé de lui construire un petit outil pour automatiser tout ça — et, au passage, de m’en servir comme vitrine technique.
C’est ainsi qu’est née cette application d’administration légère, aujourd’hui entièrement côté client, conçue d’abord comme un shell réutilisable sur lequel la fonctionnalité électorale vient se greffer. L’idée étant que le socle puisse accueillir d’autres modules demain sans toucher à la structure. À terme, il sera bien sûr possible de le lier à une véritable API, comme Stater-API, pour des fonctionnalités plus avancées.
Un shell avant une fonctionnalité
Plutôt que de construire l’interface autour de la fonctionnalité principale, j’ai commencé par le cadre : la mise en place d’un layout classique pour un espace d’administration. Il est structuré avec la librairie Shadcn-vue : une sidebar collapsible (réductible en rail d’icônes), un header contextuel avec breadcrumbs automatiques, un système de préférences utilisateur (thème clair/sombre/système, langue) persisté dans le navigateur, et un catalogue de composants UI cohérent et accessible.


La stack
L’application repose sur Vue 3 (Composition API), TypeScript, Vite et Pinia pour l’état global. Le style est assuré par Tailwind CSS 4, les composants UI par reka-ui, des primitives accessibles (ARIA, gestion du focus, navigation clavier), et les icônes par lucide-vue-next. Les traductions français/anglais sont gérées par vue-i18n avec des fichiers YAML, transformés en JavaScript au build par un plugin Vite maison. L’ensemble forme une Single Page Application statique : un fichier HTML et un bundle JS, aucun serveur requis.
L’interface
Le layout est partagé par toutes les pages : sidebar à gauche, zone de contenu à droite. La sidebar se réduit en un clic ; dans cet état, les labels disparaissent et réapparaissent en tooltips au survol, et le logo complet laisse place au favicon. Tout est piloté par des attributs CSS que Tailwind interroge, sans JavaScript supplémentaire.
Les breadcrumbs sont entièrement automatiques : chaque route déclare une clé de traduction dans ses métadonnées, et le layout reconstruit le fil d’Ariane en temps réel. Ajouter une page au fil d’Ariane ne demande aucun code dans la vue elle-même.
Les composants UI suivent le pattern shadcn/ui adapté à Vue : ils font partie du code source du projet, sont lisibles et modifiables, sans dépendance opaque. Deux composants génériques — AppContent et AppContentHeader — structurent toutes les pages avec un titre, une description et un séparateur, garantissant une cohérence visuelle sans duplication.
Préférences et internationalisation
L’utilisateur peut configurer ses préférences d’interface, et l’application y réagit instantanément.
Le thème propose trois modes (Clair, Sombre, Système), chacun illustré par un aperçu miniature de l’application rendu en HTML/CSS. La langue bascule instantanément entre français et anglais, sans rechargement — breadcrumbs, menus et contenus se mettent à jour en temps réel.
Les traductions en YAML sont plus lisibles que du JSON pour des textes imbriqués. Le plugin Vite qui les transforme est partagé avec l’environnement de test : les tests unitaires accèdent aux mêmes traductions que l’application en production.
La fonctionnalité : analyse du renouvellement des maires
C’est la raison d’être concrète du projet. L’utilisateur importe des fichiers CSV officiels du Répertoire National des Élus (data.gouv.fr) directement dans son navigateur — aucune donnée ne transite par un serveur. Les fichiers parsés sont stockés dans IndexedDB, la base de données native du navigateur, pour éviter de les réimporter à chaque visite.
Un stepper en trois étapes guide le processus : import des données, sélection des communes (par recherche textuelle ou code INSEE), puis affichage des résultats — maire sortant, maire entrant, statut réélu ou nouvel élu. Un export CSV permet de récupérer les résultats pour les traiter dans un tableur.



Architecture hexagonale
Le code métier suit les principes de l’architecture Ports & Adapters : un domaine pur (entités et interfaces, aucune dépendance externe), une couche application (cas d’usage), une couche infrastructure (parseur CSV, IndexedDB, i18n) et une couche interface (router, vues, composants). Les couches internes ignorent les couches externes, dans l’esprit des principes SOLID.
En pratique, je m’y retrouve bien mieux qu’avec une organisation classique par feature : chaque responsabilité a sa place, le code est plus facile à maintenir, et les fonctions métier sont testables comme de simples fonctions TypeScript, sans monter de composant ni simuler de requête.
Qualité
Les tests unitaires (Vitest) sont co-localisés avec le code testé. La séparation hexagonale permet de tester la logique métier comme de simples fonctions, données en entrée, vérification en sortie. IndexedDB est couverte via fake-indexeddb, une implémentation en mémoire fidèle au comportement du navigateur.
Le linting s’effectue en deux passes : oxlint (Rust, quasi-instantané) traite les règles courantes, puis ESLint prend le relais pour les règles spécifiques à Vue et TypeScript. Les deux appliquent les corrections automatiquement. Prettier gère le formatage indépendamment.
D’application web à application desktop avec Electron
Le projet fonctionnait parfaitement comme SPA. Il était possible de transmettre directement le dossier contenant l’application buildée, mais cela complique la distribution : ouvrir un dossier et chercher le bon fichier, ce n’est pas ce à quoi les utilisateurs sont habitués, notamment sous Windows. Un installeur classique, un double-clic, et c’est parti, voilà ce qu’on attend.
Electron répond exactement à ce besoin en empaquetant l’application web dans un exécutable natif. Sous le capot, Electron embarque un navigateur Chromium et un runtime Node.js ; l’application Vue tourne exactement comme dans un navigateur classique, mais dans sa propre fenêtre, avec sa propre icône dans la barre des tâches.
La conversion a été légère : un point d’entrée Electron qui crée une fenêtre et charge l’application buildée, un script de preload pour l’isolation de contexte, et une configuration electron-builder pour produire les installeurs, AppImage pour Linux, NSIS pour Windows, DMG pour macOS. Le code Vue n’a pas été modifié : la même application tourne indifféremment dans un navigateur ou dans Electron.
Le résultat : mon amie télécharge un fichier, l’installe, et dispose d’un outil prêt à l’emploi pour analyser ses données électorales, sans rien connaître de Node.js, de Vite ou de npm.
Démonstration
L’application étant destinée à un usage privé, le code source n’est pas public. La vidéo ci-dessous présente l’application en fonctionnement : le layout général, la gestion des préférences, et le parcours complet d’analyse des données électorales.
Bilan
Ce projet montre qu’un espace d’administration soigné n’exige ni serveur, ni framework full-stack, ni bibliothèque de composants opaque. Et qu’avec Electron, la même base de code peut devenir une application desktop installable en quelques clics, accessible à des utilisateurs qui ne sont pas développeurs. Le shell reste stable pendant que les fonctionnalités métier évoluent et s’ajoutent indépendamment.
Mon retour d’expérience, partir d’un besoin concret et limité — croiser des fichiers CSV pour une utilisatrice non-développeuse — s’est révélé être une contrainte productive. Quand l’utilisateur final est identifié et que son besoin est précis, les décisions techniques se simplifient : pas de sur-ingénierie, pas de fonctionnalités spéculatives.
L’application de l’architecture hexagonale à une application front ne va pas de soi et nécessite quelques concessions. Cependant un tel design pattern offre un résultat sans appel : le code métier est plus lisible, les tests sont plus simples à écrire, et l’ajout d’un nouvel adaptateur — une autre source de données, un autre format d’export — ne nécessite pas de toucher au domaine. C’est une approche que j’intègre désormais systématiquement dans mes projets.
Enfin, la conversion vers Electron a confirmé quelque chose d’important : une bonne séparation entre le code métier et la couche de présentation rend une application naturellement portable. Le fait de n’avoir eu aucune modification à apporter au code Vue pour le faire tourner dans Electron n’est pas un hasard — c’est la conséquence directe de l’architecture choisie.
L’application a été livrée et semble donner satisfaction. Désormais elle doit être présentée en équipe et peut-être y aura-t-il des suites. A suivre…
Une question ou un projet ?
Je suis disponible pour en discuter.