Journal des mises à jour

L'historique des évolutions techniques et fonctionnelles du site, jour par jour.

Lundi 4 mai 2026

Dashboard utilisateur — carte profil unifiée et grille épurée

La page /account/home a été retravaillée. Le profil (avatar, prénom, badge "Compte Pro/Gratuit") et l'activité du compte (statut Recruteur, statut Candidat) tiennent maintenant dans une seule carte unifiée plutôt que deux blocs séparés mal alignés. Les statuts s'affichent en tuiles horizontales compactes avec icône à gauche, compteur en gras et libellé court — vous voyez d'un coup d'œil "1 annonce active", "Profil candidat actif", etc. La grille des raccourcis (favoris, messagerie, recherches sauvegardées…) reste inchangée mais les cartes spéciales "Comment ça marche ?" et "Offre Pro" passent désormais en fin de grille au lieu d'apparaître en tête sur mobile.

ImpactCôté visuel : alignement général sur les tokens du design system (border douce soft-border, halos décoratifs en tokens chart-* du theme plutôt qu'en couleurs hardcodées), suppression des décorations incohérentes entre clair/sombre. Côté navigation : les actions principales du compte sont mises en avant, et l'invitation à passer Pro reste visible mais ne court-circuite plus le flow. Le bouton Admin a été retiré (n'était pas relié à une page) et l'icône de l'offre Pro est passée de la couronne à l'étoile (Sparkles), convention plus moderne pour un upgrade payant.

Refonte du menu mobile

Le panneau qui s'ouvre depuis le bouton burger en mobile a été entièrement repensé. Plus de liste plate à bordures : les actions sont regroupées en sections distinctes (navigation principale puis "Mon espace" pour les utilisateurs connectés), avec des icônes en pastille colorée et un séparateur sober entre les blocs.

ImpactQuand vous êtes connecté, votre avatar et votre prénom ouvrent désormais "Mon espace" en tête de section, suivis de vos raccourcis personnels (favoris, messages, recherches sauvegardées, abonnement). Les badges de messages non lus sont plus lisibles. La déconnexion reste discrète au repos et ne se colore en rouge qu'au moment où vous la survolez. Côté visiteur non connecté, "Se connecter" et "Créer un compte" prennent naturellement la place de "Mon espace" dans la même position pour une lecture symétrique.

Icônes brand officielles partout, et X remplace Twitter

Généralisation de la bibliothèque d'icônes brand introduite il y a quelques jours : les composants partagés (grille d'icônes des cards, formulaire de coordonnées, modale de contact, bandeau de partage) utilisent désormais les vrais logos officiels au lieu des icônes génériques. Twitter a été retiré de l'interface au profit de X (logo et libellé).

ImpactSur les cards d'offres et de candidats, les pastilles de réseaux sociaux et de coordonnées affichent les couleurs officielles des marques, avec un état désactivé (opacité réduite) quand l'information n'est pas renseignée. Le formulaire de saisie des coordonnées d'une page entreprise affiche les mêmes logos. Quelques boutons de partage qui utilisent un fond coloré (par exemple le bouton "Partager sur Facebook") restent lisibles grâce à une variante monochrome du logo.

Environnement Docker de développement allégé et plus rapide à reconstruire

Refonte des Dockerfiles et de l'orchestration des trois services backend en local (api, background-job-runner, websocket). Chaque image n'installe désormais que les dépendances réellement consommées par son service grâce au filtrage pnpm par chaîne de packages, au lieu d'embarquer tout le monorepo. Le téléchargement des paquets est mis en cache BuildKit entre les rebuilds, et la découverte des manifests package.json passe en glob automatique (COPY --parents) — plus besoin d'éditer trois Dockerfiles à chaque ajout d'un nouveau package partagé. Les commandes docker:dev:build, :rebuild, et leurs équivalents int-test / e2e-test ont été harmonisées sur un même pattern propre (stop → rm -fv → up) qui ne laisse plus traîner de volumes orphelins.

ImpactAucun changement visible côté utilisateur. Côté équipe, les images Docker de dev passent de ~3 Go à 1,3-1,8 Go chacune selon le service, le rebuild d'une image avec dépendances inchangées tombe de plusieurs minutes à quelques secondes (cache pnpm chaud), et l'onboarding d'un nouveau dev sur le repo demande maintenant nettement moins de disque et d'attente. Au passage, ~96 Go de volumes Docker orphelins ont été nettoyés sur les machines locales — héritage d'un filtre de prune qui ne matchait jamais les volumes anonymes générés par compose, désormais corrigé en amont.

Module Médias — couverture de tests complète sur le cycle de vie des fichiers

Ajout de la suite de tests automatisés pour le module Media dont les fondations avaient été posées la veille. Sept commandes critiques sont maintenant testées à deux niveaux : unitaire (la logique métier en isolation, rapide) et intégration (avec une vraie base de données Postgres et un faux S3 via MinIO, plus lent mais représentatif). Sont couverts : la demande d'upload, l'extraction des métadonnées d'image et de PDF, la génération de vignettes, le marquage des orphelins, la suppression des fichiers expirés et l'abandon des uploads inachevés. Trois jeux de fixtures partagés (base de données, MinIO, données métier) factorisent la mise en place de chaque scénario. Une stack Docker dédiée aux tests end-to-end a aussi été créée, séparée de celle des tests d'intégration, pour pouvoir faire tourner les deux en parallèle sans collision de ports.

ImpactLe module Media est maintenant prêt à être branché aux vrais flux du site (avatars, photos d'offres, documents) avec un filet de sécurité solide : toute régression sur la suppression des fichiers orphelins ou la génération des vignettes sera détectée avant le déploiement. C'est l'étape qui débloque l'enchaînement des features dépendantes du stockage centralisé.

Mise à jour de Node.js vers la version 24

Bascule de l'ensemble du backend (les trois services applicatifs et les packages partagés du monorepo) ainsi que des deux frontends sur Node.js 24, la dernière version LTS. Les images Docker de développement et de production tirent désormais node:24-alpine, le pipeline d'intégration continue a été aligné, et un fichier .nvmrc a été ajouté pour que chaque dev passe automatiquement sur la bonne version au moment où il rentre dans le repo. Les types @types/node et la cible TypeScript ont été mis à jour en conséquence.

ImpactAucun changement visible côté utilisateur. Côté technique, on récupère plusieurs années d'optimisations du moteur V8 (gain de performances mesurable sur les opérations cryptographiques et les streams), un fetch natif stabilisé, et les correctifs de sécurité les plus récents. Surtout, ça remet la chaîne d'outils au niveau des versions supportées sur le long terme, ce qui simplifiera les prochaines mises à jour de dépendances.

Dimanche 3 mai 2026

Migration de tout le backend vers les modules JavaScript modernes (ESM)

Bascule de l'ensemble du code serveur (api, worker, websocket) et de la dizaine de packages partagés du monorepo vers ECMAScript Modules, le système de modules natif et standard de JavaScript — en remplacement de CommonJS, l'ancien format historique de Node.js. Concrètement, les imports passent de require() à import, avec extension .js explicite sur les imports relatifs. Le harnais de tests backend a été migré en parallèle de Jest vers Vitest, qui partage la même infrastructure que le bundler de développement et reste compatible nativement avec ESM. Côté front, retour à webpack par défaut sur Next.js — Turbopack ne résolvait pas correctement les packages workspace en ESM strict.

ImpactAucun changement visible côté utilisateur. Côté technique, ça débloque les mises à jour d'une longue file de dépendances qui ne publient plus qu'en ESM depuis deux ans (la migration était bloquée par cet effet domino), et la suite de tests backend tourne nettement plus vite. C'était le dernier gros chantier d'infrastructure avant la reprise des features visibles.

Médias — fondations du futur système de stockage et de gestion d'images

Mise en place du squelette d'un module Media autonome qui centralisera toutes les images et fichiers du site (avatars, photos d'offres, documents, illustrations de jeux, pièces jointes de messages…). Le cycle de vie complet est modélisé — de la demande d'upload jusqu'à la suppression définitive — avec une state machine stricte qui empêche tout fichier de se retrouver dans un état incohérent. Le stockage Cloudflare R2 est mutualisé : un seul client réseau partagé entre tous les usages, isolé par environnement (dev / prod) pour éviter les croisements. Tout passe par une couche d'adapter pattern qui rend le code testable et migrable sans réécriture lourde.

ImpactAucun changement visible aujourd'hui — c'est de la préparation. Une fois branché, le système supprimera automatiquement les fichiers orphelins (uploads abandonnés, images d'offres détachées) au lieu de les laisser s'accumuler sur le stockage, et générera les vignettes de manière fiable même en cas d'erreur transitoire. Côté équipe, l'audit de qui possède quel fichier devient trivial.

Samedi 2 mai 2026

Files d'attente — uniformisation des patterns et nettoyage

Reprise complète du package qui orchestre les traitements en arrière-plan (envoi d'emails, revalidation du cache, messagerie temps réel, jobs récurrents). Treize fichiers de constantes regroupés en deux, cinq adaptateurs convertis en classes avec une signature uniforme, deux adaptateurs renommés pour cohérence, validations manuelles redondantes retirées, et quatre files d'attente mortes (instanciées mais jamais utilisées) supprimées du registre et du tableau de bord d'admin.

ImpactLe code suit désormais un patron homogène — chaque adaptateur est une classe typée qui implémente un port explicite, avec un constructeur identique partout. Quand un nouveau type de job apparaît, le nombre d'endroits à toucher est documenté et stable. Le tableau de bord d'admin ne liste plus que les files réellement actives, ce qui simplifie la lecture en cas d'incident. La logique métier (events typés, revalidation Next.js asynchrone) restera telle quelle au moment de la future migration vers NestJS.

Architecture backend — bus de commandes/requêtes et traçage des appels

Mise en place du pattern CQRS côté API : chaque action qui modifie des données passe désormais par un CommandBus, et chaque lecture par un QueryBus. Toutes les requêtes HTTP reçoivent un identifiant de corrélation qui suit l'appel à travers les couches (controller, handler, base de données, événements asynchrones), via une bulle AsyncLocalStorage ouverte dès le premier middleware. Le fichier d'amorçage app.ts, qui faisait près de 400 lignes, a été éclaté en huit classes XxxBootstrap ordonnées (infra, shared, cqrs, modules, outbox, express, routes, shutdown).

ImpactQuand un incident survient, on peut désormais reconstituer toute la chaîne d'un appel à partir d'un seul identifiant — y compris les événements partis en tâche de fond après la réponse HTTP. Les nouveaux modules suivent un patron uniforme (handlers standardisés, validation à trois niveaux, erreurs typées) qui réduit le risque de régression et prépare une migration future vers NestJS sans réécriture lourde.

Modernisation du design — icônes officielles et coordonnées repensées

Création d'une bibliothèque d'icônes brand officielles (Google, X, Facebook, LinkedIn, Instagram) et de contact (téléphone, email, site web) reprenant les vraies couleurs des marques. Au passage, gros ménage et réorganisation interne de la bibliothèque de composants pour séparer ce qui est générique de ce qui est spécifique au métier.

ImpactLa modale de contact des annonces a été redessinée : chaque coordonnée est maintenant une carte cliquable avec son icône colorée, un bouton de copie et un lien direct (téléphone, email, réseau social). Les boutons "Continuer avec Google" et "Continuer avec Facebook" affichent les logos officiels exacts, ce qui inspire davantage confiance au moment de la connexion.

Fondations des tests backend — harnais Jest mutualisé

Refonte du setup de tests des apps backend (api, worker) : création d'un nouveau package partagé @workspace/backend-test-utils qui factorise la connexion à la base de tests, l'application des migrations, le nettoyage des tables entre chaque test, et les "factories" qui composent des agrégats reliés (utilisateur + employeur + offre, etc.). En parallèle, le package @workspace/fixtures a été déplacé dans la zone shared du monorepo pour pouvoir être réutilisé aussi côté front.

ImpactLa base de tests reste cohérente même quand plusieurs fichiers tournent en parallèle (un bug subtil de contrainte de clé étrangère lors des inserts en parallèle a été éliminé). Ajouter des tests dans une nouvelle app backend ne demande plus que quelques fichiers d'une ligne au lieu de dupliquer 250 lignes de configuration — ce qui ouvre la voie à une couverture de tests plus large sans dette d'infrastructure.

Vendredi 1 mai 2026

Allégement de l'infrastructure de production

Les serveurs (API, worker, temps réel) ont été restructurés pour ne plus embarquer en production que le strict nécessaire à leur exécution. Tout l'outillage de développement et de migration de base de données qui s'y trouvait jusque-là a été extrait pour ne s'exécuter qu'au moment où on en a vraiment besoin.

ImpactLes images de production sont nettement plus légères (de plusieurs centaines de mégaoctets à quelques dizaines), les containers démarrent plus vite et la surface exposée en runtime est minimale — autant de petits gains qui se traduisent par des déploiements plus rapides et plus fiables.

Stabilité de l'infrastructure — refonte des files d'attente

Refonte complète du système de files d'attente (BullMQ) côté API et worker : centralisation des connexions Redis dans un registre unique (QueueRegistry), désactivation des écouteurs d'évènements inutilisés, et fermeture propre de toutes les ressources au redéploiement.

ImpactLe serveur ouvrait beaucoup plus de connexions Redis qu'il n'en avait besoin (≈ 32, dont 10 inutilisées et 6 doublons). À chaque déploiement, l'ancienne et la nouvelle instance se chevauchaient et l'API saturait le quota Redis (ERR max number of clients reached) — ce qui se traduisait par des erreurs CORS fantômes côté navigateur. Le compte est maintenant stable autour de 18 connexions, et le shutdown propre garantit qu'il n'y a plus de pic au redeploy.