Aller au contenu

WonderWork

WonderWork est une plateforme SaaS B2B RH qui met en relation des candidats (chercheurs d'emploi) et des recruteurs (entreprises qui recrutent) via un algorithme de compatibilité.

Le problème qu'elle résout : le matching RH traditionnel repose sur des CVs libres et des mots-clés. Les candidats envoient des candidatures non ciblées, les recruteurs trient des centaines de profils manuellement. WonderWork structure les deux côtés — un passport candidat normalisé, des offres avec critères précis — pour calculer un score de compatibilité objectif et présenter à chaque candidat uniquement les offres qui lui correspondent vraiment.


Acteurs

Acteur App Rôle
Candidate candidate/ — PWA responsive Complète son Employment Passport, consulte les offres classées par score de compatibilité, suit ses candidatures
Recruiter recruiter/ — Web app desktop Publie des offres, gère les candidatures via un pipeline ATS Kanban, headhunte des candidats
Admin admin/ — Back-office interne Gestion des comptes entreprises, supervision de la plateforme (WonderWork team uniquement)

Concepts clés

Employment Passport
Profil structuré du candidat — remplace le CV. Collecté via un questionnaire guidé en onboarding. Contient : expériences professionnelles avec codes ROME, compétences du catalogue WonderWork, valeurs culturelles recherchées, contraintes logistiques (salaire minimum, mobilité, disponibilité). Sert de base au calcul du score de matching.
Matching Score
Score de compatibilité 0–100 calculé entre un passport et une offre d'emploi. Décomposé en 6 blocs pondérés indépendants. Pré-calculé et stocké en base — jamais calculé à la demande pour les performances.
Bloc Critère Poids Ce qu'il mesure
BLOC 1 Intitulé de poste (ROME) 20 % Alignement du métier cible du candidat avec le code ROME de l'offre
BLOC 2 Compétences techniques 41 % Recouvrement compétences/langages candidat ↔ compétences requises de l'offre
BLOC 3 Expérience & séniorité 17 % Années d'expérience calculées vs niveau requis par l'offre
BLOC 4 Valeurs culturelles 10 % Intersection valeurs candidat ↔ valeurs de l'entreprise
BLOC 5 Logistique 7 % Salaire, lieu, mode de travail, disponibilité
BLOC 6 Langues 5 % Langues maîtrisées vs langues requises de l'offre
Multi-tenant
Chaque Company possède un ou plusieurs comptes Recruiter. Les données sont strictement isolées par company_id — un recruteur ne voit que les offres et candidatures de son entreprise. Les comptes entreprise sont créés par l'équipe WonderWork — pas d'auto-inscription publique.
Référentiel ROME
WonderWork utilise le référentiel ROME 4.0 (France Travail) comme vocabulaire contrôlé pour les métiers. Chaque expérience professionnelle et chaque offre d'emploi est associée à un code ROME — ce qui rend le matching sémantique possible sans dépendre du libellé libre du titre de poste.

Comment ça marche — flux principal

sequenceDiagram
    participant C as Candidat
    participant API as API Symfony
    participant W as Worker async
    participant R as Recruteur

    C->>API: Complète son Employment Passport
    API->>W: Message Symfony Messenger
    W->>API: Calcule scores matching (6 blocs)
    Note over W,API: Pré-calcul stocké en match_scores

    C->>API: GET /v1/me/matches
    API-->>C: Offres triées par score desc

    C->>API: Postule à une offre
    API-->>R: Notification nouvelle candidature

    R->>API: Déplace la candidature dans le pipeline
    API-->>C: Notification changement de statut

Le calcul du score n'est jamais fait à la demande — il est déclenché en arrière-plan (Symfony Messenger) à chaque modification du passport ou publication d'une offre. La liste des matches affichée au candidat est une lecture directe de la table match_scores.


Structure du monorepo

wonderwork/
├── api/          ← Symfony 7.4 + API Platform 4.x  (REST API, logique métier, async)
├── candidate/    ← Next.js 15 PWA                  (app candidat, responsive)
├── recruiter/    ← Next.js 15                       (app recruteur, desktop-first)
├── admin/        ← Next.js 15                       (back-office interne)
├── infra/
│   ├── ansible/  ← Déploiement applicatif (Docker Swarm + Nginx + TLS)
│   └── terraform/← Provisionnement infrastructure (OVH DNS + firewall)
├── docs/         ← Cette documentation
├── CLAUDE.md     ← Contexte IA
└── DESIGN.md     ← Design system

Tout le code vit dans un seul dépôt Git. Chaque app a son propre pipeline CI avec des path filters — un push dans candidate/ ne déclenche pas le build de l'API.


Modèle de déploiement

flowchart LR
    Browser["Navigateur / Mobile"] --> Nginx
    subgraph VPS["VPS OVH (staging.wonderwork.fr)"]
        Nginx["Nginx\n(reverse proxy + TLS)"]
        Nginx --> Candidate["candidate:3000"]
        Nginx --> Recruiter["recruiter:3001"]
        Nginx --> API["api:8000"]
        API --> DB[(PostgreSQL)]
        API --> Redis[(Redis)]
    end
    API -->|SMTP| Brevo["Brevo\n(emails transactionnels)"]
    GHCR["GHCR\n(ghcr.io)"] -->|pull images| VPS

Tous les services tournent dans des conteneurs Docker sur un unique VPS OVH. Nginx est le seul point d'entrée public — il route le trafic vers les bons conteneurs selon le nom de domaine et gère la terminaison TLS.


Contraintes de souveraineté

Toute l'infrastructure de production est hébergée sur des serveurs français (OVH). Aucun service US en production — exigence légale liée au CLOUD Act américain et différenciateur commercial pour les clients entreprise et secteur public français.

Service Hébergement
VPS + base de données OVH (Roubaix, FR)
Emails transactionnels Brevo (FR, serveurs EU)
Registre de conteneurs GHCR (GitHub — acceptable pour les images binaires, pas pour les données personnelles)