- Outil personnel
- En production
- IA générative
JobHunter
Un assistant de recherche d'emploi qui centralise les offres de plusieurs plateformes, prépare les candidatures avec l'IA et rappelle de relancer, sans jamais rien envoyer à votre place.
- Contexte
- Projet personnel, de bout en bout
- Période
- 2026
- Type
- Outil personnel en production
- Hébergement
- Vercel et Supabase
Le projet
Préparer, jamais postuler à votre place.
Chercher un emploi, c'est jongler entre des dizaines d'offres, plusieurs versions de CV, des lettres de motivation à personnaliser et un tableau de suivi qui devient vite ingérable. JobHunter centralise tout dans un seul espace : recherche automatique chaque jour, boîte de réception à trier, suivi de candidature guidé, relances et CV générés par IA.
Une règle guide tout le projet : aucune candidature n'est jamais envoyée automatiquement. L'app prépare, analyse et rappelle ; c'est toujours l'utilisateur qui clique sur « postuler », envoie l'email ou copie le message.
L'app tourne en production sur Vercel, mais reste un outil personnel : plusieurs sites scannés, dont LinkedIn, interdisent le scraping dans leurs conditions d'utilisation, ce qui exclut de l'ouvrir à d'autres. Les inscriptions sont donc fermées côté serveur, et seuls les comptes existants peuvent se connecter.
Ce que j'ai construit
De l'offre à l'entretien
- 01
Recherche multi-sources
LinkedIn, Indeed, Welcome to the Jungle, HelloWork, Glassdoor, Google Jobs et d'autres, relancés chaque matin pour chaque recherche favorite.
- 02
Boîte de réception
Chaque offre arrive dans une file à trier, classée par score de correspondance avec le profil, sans les doublons ni les republications.
- 03
Préparation par IA
Choix ou génération du CV, lettre de motivation, message LinkedIn et réponses aux formulaires, régénérables selon vos retours.
- 04
Suivi et relances
Étapes guidées jusqu'à l'entretien, rappels de relance, journal des entretiens, synchronisation Gmail, échéances du jour signalées au tableau de bord et récap matinal par email.
Architecture
Chercher, préparer, rappeler
Python ne fait que chercher et normaliser les offres ; Next.js orchestre le reste, et les clés sensibles restent côté serveur.
1 · Déclencheurs
- GitHub ActionRecherches quotidiennes
- Script GmailMails de recruteurs toutes les 15 minutes
- pg_cronPréparation et mails toutes les 10 minutes
- Cron VercelRécap email de secours
2 · Collecte
- Sites d'emploiLinkedIn, Indeed, WTTJ, Glassdoor, Google Jobs…
- Scraper PythonFonction Vercel isolée, normalisation et doublons
3 · Application
- Next.jsServer Actions et routes API
- better-authComptes et sessions
- Isolation par compteChaque requête filtrée côté serveur
4 · Données et services
- SupabasePostgres et Storage
- IAGroq, Claude ou Ollama
- ResendRécap du matin, mots de passe
- Flux ICSCalendrier en webcal
Parcours
La vie d'une offre
- 1Offre trouvéePar le scraper
- 2À étudierBoîte de réception
- 3À candidaterPréparée par l'IA
- 4Candidature envoyéePar vous, jamais par l'app
- 5EntretienDates et notes
- AcceptéeRefusée
Une offre écartée part dans les archives et peut être restaurée. Les relances suivent les candidatures envoyées, et un statut mis à jour par un mail de recruteur ne recule jamais.
Zoom technique
Une candidature préparée, jamais envoyée
Dès qu'une offre passe en « À postuler », une file de préparation tourne en arrière-plan (pg_cron toutes les 10 minutes) : choix ou génération du CV, lettre et message LinkedIn. Tout reste à relire et à utiliser soi-même.
Le fournisseur d'IA est interchangeable : Groq en production, Claude ou un modèle Ollama local. L'IA ne reçoit que le profil et les CV réels, avec l'instruction explicite de ne jamais inventer une expérience, un diplôme ou une compétence.
- 1Offre trouvéeScraper Python lancé chaque matin par une GitHub Action
- 2Offre triéeBoîte de réception classée par score de correspondance
- 3Candidature préparéeCV, lettre et message générés en arrière-plan
- 4Envoyée par vousRelances, entretiens et mails de recruteurs suivis
Les défis
Ce qui rendait le projet difficile
La même offre partout
Une offre est publiée sur plusieurs sites, avec des variantes du nom d'entreprise ou des intitulés genrés.
Ma réponse
Détection des doublons et des republications, tenus à l'écart de la boîte de réception.
Une IA qui n'invente rien
Une lettre ou un CV généré ne doit jamais mentionner une expérience absente du profil.
Ma réponse
L'IA ne reçoit que les données réelles de l'utilisateur, et chaque texte reste à relire avant usage.
Un quota d'IA serré
L'offre gratuite de Groq autorise environ 8 000 tokens par minute, pour des CV, des lettres et des mails à classer.
Ma réponse
Des prompts courts, un contexte candidat partagé, des limites de débit gérées et des étapes reprenables là où elles se sont arrêtées.
Synchronisation Gmail
Un statut qui suit vos mails, sans jamais reculer
Un script Google Apps Script transmet les mails de recruteurs à l'app, authentifié par un jeton propre à chaque compte dont seule l'empreinte SHA-256 est stockée. L'IA classe chaque mail (accusé de réception, refus, entretien, offre) et le rapproche d'une candidature : fil Gmail, domaine de l'expéditeur, nom de l'entreprise, puis intitulé du poste.
Seul un rapprochement sûr, unique et sans conflit met le statut à jour, et un statut ne recule jamais : un accusé de réception tardif n'écrase pas un refus. Le reste arrive dans « À valider », d'où l'on peut aussi créer la candidature en un clic.
Fréquence
15 min
entre deux envois de mails par le script Gmail
Confidentialité
Seuls l'expéditeur, l'objet, la date et un court extrait sont conservés. Le corps du mail est effacé après 24 heures au plus, et il n'apparaît jamais dans les journaux.
Décisions techniques
Les choix, et pourquoi
- Scraper Python isolé
- python-jobspy et des scrapers dédiés, hébergés comme fonction Vercel séparée : Python ne fait que chercher et normaliser les offres.
- Accès serveur uniquement
- La base n'est jamais interrogée depuis le navigateur ; chaque requête est filtrée par compte côté serveur, avec RLS activé sans règle publique et une CSP qui bloque tout appel externe depuis le client.
- better-auth
- Connexion par email et mot de passe, inscriptions fermées côté serveur, réinitialisation par email et suppression complète du compte en un clic.
- IA interchangeable
- Groq, Claude ou Ollama derrière une même interface, pour choisir entre coût, fiabilité et exécution locale.
- Tâches planifiées
- GitHub Action quotidienne pour les recherches, pg_cron pour la préparation et le classement des mails, cron Vercel de secours pour le récap email.
Limites assumées
Ce que JobHunter ne fait pas (encore)
- Une couverture limitée aux sites intégrésNeuf sources aujourd'hui, Joinrs est prévu mais pas encore branché. Certains sites limitent les requêtes répétées, et Google Jobs passe par une clé SerpApi.
- Des CV en texte structuréLes CV générés ne sont pas mis en page en PDF : ils se recopient dans l'outil de mise en forme de son choix.
- Un calendrier en lecture seuleLe flux ICS fonctionne avec Google Calendar et Apple Calendar, sans synchronisation bidirectionnelle.
Stack
Les outils du projet
- Next.js
- React
- TypeScript
- Tailwind CSS
- shadcn/ui
- better-auth
- Supabase
- PostgreSQL
- Groq
- Claude
- Ollama
- Resend
- Python
- GitHub Actions
- Vercel
- Zod
- Vitest
- pytest