Whoa Jobs
Une plateforme de recherche d'emploi qui collecte les offres de plusieurs job boards, les centralise dans un seul dashboard et aide à candidater.
- Python
- Postgres (Supabase)
- SSE
Toutes les offres, un seul dashboard.
Une plateforme full-stack qui collecte les offres d'alternance et de CDI de plusieurs job boards, les dédoublonne et permet de les suivre et d'y candidater depuis un seul endroit.
GitHub· Fonctionnalités·Architecture
À propos
Chercher une alternance ou un premier emploi, c'est consulter LinkedIn, Indeed, HelloWork et les autres tous les jours, retrouver trois fois la même offre et perdre le fil de ses candidatures.
Whoa Jobs règle ça avec une idée simple :
Ce sont les job boards qui viennent à vous, pas l'inverse.
Un moteur de collecte en Python récupère les offres en arrière-plan, une API les normalise et les sert, et un dashboard permet aux candidats de les parcourir, les filtrer et y candidater — pendant que les admins pilotent tout le moteur en direct, sans jamais le redémarrer.
✨ Fonctionnalités
🔎 Un flux d'offres unique
Toutes les sources dans une seule liste, avec recherche et filtres par source, lieu, type de contrat et date.
Quand une même offre apparaît sur plusieurs sites, elle est regroupée entre les sources au lieu de s'afficher trois fois.
📄 Documents
Le CV et la lettre de motivation sont envoyés une seule fois, stockés dans un bucket privé et prévisualisés directement dans la barre latérale (PDF et DOCX).
🚀 Auto-candidature
Un clic retrouve où l'offre accepte les candidatures, vérifie les documents et les envoie — avec une garde atomique pour qu'une candidature ne parte jamais deux fois, et une reprise en cas d'échec.
🔔 Notifications en temps réel
Les notifications arrivent dans le dashboard via SSE dès qu'elles sont enregistrées dans Postgres (LISTEN/NOTIFY), avec niveaux d'importance et statut lu/non lu.
🏢 Espaces de travail & équipes
Entreprises, invitations, équipes, rôles des membres et personnalisation de l'apparence — construits sur les organisations Better Auth.
🎛️ Salle de contrôle du moteur
Les super-admins disposent d'une vraie salle de contrôle pour le moteur de collecte :
- Live ops — profondeur des files, workers actifs vs cible, requêtes par minute, taux d'erreur, état du disjoncteur
- Réglages à chaud — activer le moteur ou une source, « Run now », ajuster limites de débit et mise à l'échelle, le tout appliqué en quelques secondes, sans redémarrage
- Cron jobs & logs — planifications et événements alimentés par les vraies données du moteur
- Audit, impersonation & broadcast — chaque action sensible tracée, « voir en tant que » un utilisateur, notifier tout le monde
🧱 Architecture
Job boards ── HTTP poli ──► Moteur (Python)
LinkedIn · Indeed · HelloWork ├── Orchestrateur : scheduler + autoscaling
└── Workers × N : fetch → parse → upsert
│
Redis (files BullMQ)
│
▼
Postgres (Supabase) ◄──── NOTIFY engine_control
▲ │
│ │
API — NestJS + tRPC ──────────────────┘
▲
│ tRPC / SSE
Dashboard — TanStack StartLe projet est un monorepo Nx qui mélange TypeScript (Bun) et Python (uv) :
apps/
dashboard/ Front-end TanStack Start
server/ API NestJS
engine/ Moteur de collecte Python
fumadocs/ Documentation utilisateur
packages/
api/ Routers tRPC, middlewares, logique métier
auth/ Configuration Better Auth
db/ Schéma Prisma & migrations
ui/ Composants shadcn/ui partagés🕷️ Le moteur de collecte
La partie la plus intéressante du projet. C'est un collecteur scalable horizontalement et poli par conception :
- Files de tâches sur Redis (BullMQ) — une tâche = une recherche ou une offre. Livraison « au moins une fois », upserts idempotents, clés de déduplication : une tâche rejouée ne crée jamais de doublon.
- Autoscaling — l'orchestrateur dimensionne le pool de workers selon la profondeur des files, en processus locaux, conteneurs Docker ou réplicas fixes.
- Un seul client poli, partagé —
robots.txt, token bucket global plafonné en dur à 2 req/s, concurrence par domaine, disjoncteur commun à tous les workers, backoff exponentiel avec gigue, User-Agent honnête. - Aucun contournement, jamais — pas de rotation de proxy, pas d'usurpation d'empreinte, pas de résolution de captcha. Une source bloquée est mise en pause et signalée dans le dashboard, jamais contournée.
- Pages brutes conservées — les parsers peuvent être relancés sur tout ce qui a déjà été téléchargé, sans une seule requête réseau.
- Configuration à chaud — réglages runtime validés des deux côtés (API et moteur) contre une seule spec JSON, rechargés via
NOTIFYPostgres.
🛠️ Stack technique
| Couche | Technologies |
|---|---|
| Front-end | TanStack Start, React 19, Tailwind CSS 4, shadcn/ui, Motion, Recharts |
| API | NestJS 11, tRPC 11, Zod 4 |
| Auth | Better Auth (organisations, équipes, admin, impersonation) |
| Données | PostgreSQL (Supabase), Prisma, Supabase Storage |
| Moteur | Python 3.12, BullMQ, Redis, httpx, SQLAlchemy, BeautifulSoup, Typer |
| Outillage | Nx, Bun, uv, Varlock, Oxlint, Oxfmt, pytest, mypy, Docker |
💡 Ce que j'en retiens
- Concevoir un système distribué qui reste poli. Ajouter des workers est facile ; garantir que dix workers envoient toujours moins de requêtes qu'un humain attentif, c'est là le vrai défi — d'où des limites de débit et un disjoncteur partagés via Redis plutôt que par processus.
- Faire partager une seule source de vérité à un service Python et une API TypeScript. Le schéma de base appartient à Prisma, le moteur ne fait que le refléter ; les réglages runtime sont validés contre la même spec JSON des deux côtés.
- Modifier un système en marche sans risque. Chaque changement de réglage est validé, audité et appliqué en direct via
LISTEN/NOTIFY, avec une relecture périodique si une notification se perd. - Traiter la conformité comme une fonctionnalité. Le respect des conditions de chaque site a autant façonné l'architecture que la performance.
📸 Captures d'écran
🛣️ Roadmap
- Moteur de collecte (LinkedIn, Indeed, HelloWork)
- Dédoublonnage inter-sources
- Salle de contrôle du moteur (live ops, réglages à chaud, logs, cron)
- Documents avec aperçu
- Notifications en temps réel
- Envoi des auto-candidatures par source
- Synchronisation e-mail pour suivre les réponses
- Davantage de job boards
- Autoscaling Kubernetes (KEDA)
🌐 Liens
- Code source : https://github.com/WhoaStudio/whoa-jobs