Étude de cas · Personnel

Générateur de CV lisible par les ATS, avec serveur MCP

Bibliothèque de CV bilingue rendue en PDF d’une page stricte, contrôlée pour les ATS, avec un serveur MCP dont les outils d’écriture ne créent que des propositions.

En bref

  • Outil personnel pour adapter un CV d’une page et une lettre à chaque offre, en français ou en anglais, sans perdre de contenu ni laisser une IA inventer des faits.
  • Monorepo TypeScript  API Hono, interface React, rendu Typst avec contrôle automatique de lisibilité ATS, et serveur MCP de 21 outils dont les écritures ne sont que des propositions.
  • Spécifié, conçu, relu et recetté par moi  code écrit avec Claude Code. Il tourne en ligne derrière une connexion par clé d’accès et alimente ce portfolio.

En résumé

Rôle
Développeur unique
Équipe
Projet individuel
Période
Statut
Utilisé pour mes propres candidatures
Assistance IA
importante Spécification, architecture, revue, tests et recette par moi  code écrit avec Claude Code.
Technologies
  • TypeScript
  • Node.js
  • Hono
  • React
  • Vite
  • Zod
  • Typst
  • MCP
  • WebAuthn
  • Vitest
  • nginx
  • systemd

Contexte

Projet personnel, commencé en octobre 2026 pour mes propres candidatures d’emploi et de stage. Je voulais une source unique pour le contenu de mon CV en français et en anglais, et un moyen d’adapter un CV d’une page à chaque offre.

Problème

Adapter un CV à la main produit des copies qui divergent, des traductions qui vieillissent et des pages qui débordent. Demander à un assistant IA va plus vite, mais il peut reformuler des faits en affirmations fausses. Je voulais aussi savoir ce qu’un logiciel de recrutement (ATS) lit réellement dans le PDF.

Mon rôle, l’équipe et la part de l’IA

Projet solo. J’ai écrit le cahier des charges (environ 1 100 lignes) et les 20 décisions d’architecture, choisi l’architecture, relu le code et mené les tests et la recette. Le code a été écrit avec Claude Code à partir de ce cahier des charges.

Contraintes

  • Aucune invention  une IA peut suggérer, jamais décider  chaque chiffre et chaque compétence doivent venir de la bibliothèque.
  • Une page, strictement  un export qui déborde est refusé, avec le dépassement chiffré en lignes.
  • Bilingue  un CV anglais ne peut pas être exporté tant qu’un champ affiché n’est pas traduit.
  • Confidentialité  les coordonnées et la photo ne sont jamais renvoyées à l’IA  les vraies données n’entrent jamais dans le dépôt.

Solution et architecture

  • Données  une bibliothèque JSON de 10 collections (expériences, formations, projets, compétences…) à champs bilingues validés par Zod  une traduction manquante vaut null, jamais une chaîne vide. Presets et candidatures sont des sélections à trois états sur la bibliothèque.
  • Rendu  des modèles Typst (ATS, visuel, lettre) produisent un PDF déterministe, ainsi qu’une version DOCX.
  • Contrôle ATS  le texte est réextrait du PDF avec deux extracteurs différents pour vérifier coordonnées, intertitres et dates  une batterie de 72 cas couvre mises en page, langues et polices.
  • Interfaces  une API Hono, une interface React/Vite et un serveur MCP de 21 outils et 3 prompts guidés. Ses outils d’écriture ne créent que des propositions, que j’accepte ou rejette dans l’interface, et des garde-fous côté serveur rejettent les chiffres ou compétences absents de la source.
  • Imports  un export de données LinkedIn et des CV existants deviennent des propositions dédoublonnées  les lettres sont versionnées, jamais écrasées.
  • Instance en ligne  connexion par clé d’accès (WebAuthn), en-têtes de sécurité et CSP stricts, service durci, et script de déploiement qui revient automatiquement à la version précédente si le contrôle de santé échoue.

Stack

TypeScript, Node.js, npm workspaces, Hono, React 19, Vite, Zustand, Zod, Typst, docx, pdf.js, SDK Model Context Protocol, WebAuthn, Vitest, ESLint, nginx, systemd.

Qualité et vérification

  • Environ 410 cas Vitest  unitaires, API, serveur MCP en mémoire et en stdio, et connexion par clé d’accès avec un authentificateur logiciel.
  • La batterie de 72 cas de lisibilité ATS, et 8 scénarios de recette écrits, rejoués avant la mise en ligne.
  • Un hook de pré-commit bloque les vraies données et les secrets  les jeux de test utilisent des personnes fictives.

Résultats et statut

Je l’utilise pour mes propres candidatures, et les expériences, formations et compétences de ce portfolio sont exportées de sa bibliothèque. L’instance en ligne est privée.

Ce que je ferais autrement

  • Ajouter une intégration continue qui lance les tests à chaque push, au lieu de compter sur les exécutions locales avant déploiement.
  • Produire dès le départ des captures publiques à partir des personnes fictives, pour pouvoir montrer le projet sans exposer de vraies données.
  • Séparer le README public des notes d’exploitation, pour pouvoir ouvrir le dépôt sans réécrire l’historique.

Liens

  • Code source  dépôt privé, à ouvrir après nettoyage.
  • Captures d’écran  à venir, réalisées avec des données fictives.