> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wethehivers.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Modèle Candidat

> Schéma du profil candidat, visibilité et relations

# Candidat

Un **candidat** représente une personne physique à la recherche d'un emploi. Lié à un `User` via `user_id`.

## Schéma

```mermaid theme={null}
classDiagram
    class Candidat {
        +Long id
        +Long userId
        +String firstName
        +String lastName
        +String phone
        +LocalDate dateNaissance
        +String genre  "M|F|NS"
        +String niveauExperience
        +Integer anneesExperience
        +String niveauEtude
        +String[] competences
        +String[] langues
        +Long cvActifId
        +Long villeId
        +String photoKey
        +String biographie
        +Boolean profilPublic
        +String linkedinUrl
        +String portfolioUrl
        +Instant createdAt
    }

    class CV {
        +Long id
        +Long candidatId
        +String r2Key
        +String fileName
        +Integer fileSize
        +String mimeType
        +String scanStatus
        +Instant uploadedAt
    }

    class Ville {
        +Long id
        +String nom
        +Long regionId
    }

    Candidat "1" --> "0..*" CV : upload
    Candidat "1" --> "1" CV : cv actif
    Candidat "N" --> "1" Ville
```

## Exemple JSON

```json theme={null}
{
  "id": 42,
  "userId": 108,
  "firstName": "Jean",
  "lastName": "Ngassa",
  "email": "jean@example.com",
  "phone": "+237690123456",
  "niveauExperience": "INTERMEDIAIRE",
  "anneesExperience": 4,
  "niveauEtude": "MASTER",
  "competences": ["Java", "Spring Boot", "PostgreSQL", "Docker"],
  "langues": ["fr", "en"],
  "cvActif": {
    "id": 17,
    "fileName": "cv-jean-ngassa.pdf",
    "downloadUrl": "/v1/api/files/cv/17"
  },
  "ville": { "id": 101, "nom": "Douala" },
  "profilPublic": true,
  "biographie": "Développeur backend passionné...",
  "linkedinUrl": "https://linkedin.com/in/jeanngassa"
}
```

## Visibilité

```mermaid theme={null}
flowchart TD
    C[Candidat] --> CH{profilPublic?}
    CH -->|true| PUB[Visible par recruteurs via vivier]
    CH -->|false| PRV[Uniquement via candidatures actives]
    PUB --> R1[Nom + compétences + expérience + ville]
    PUB --> HIDE1[CV masqué sauf candidature]
    PRV --> R2[Nom + CV visibles uniquement\n sur offres du recruteur]
```

## Règles

* Un candidat ne peut postuler à une offre qu'une fois (unicité `candidature(offreId, candidatId)` sur statuts actifs).
* Changement d'email = reconfirmation + invalidation refresh tokens.
* Suppression RGPD = anonymisation (prénom/nom → `Anonyme`, email → `anon-<id>@wethehivers.com`).

```mermaid theme={null}
stateDiagram-v2
    [*] --> ACTIVE: inscription + validation email
    ACTIVE --> SUSPENDED: admin sanction
    ACTIVE --> ANONYMIZED: suppression RGPD
    SUSPENDED --> ACTIVE: admin reactivate
    ANONYMIZED --> [*]
```

## Endpoints principaux

| Méthode | Path                            | Rôle           |
| ------- | ------------------------------- | -------------- |
| `POST`  | `/v1/api/candidats/register`    | Inscription    |
| `GET`   | `/v1/api/candidats/profile`     | Profil courant |
| `PUT`   | `/v1/api/candidats/profile`     | Mettre à jour  |
| `POST`  | `/v1/api/candidats/me/cv`       | Upload CV      |
| `GET`   | `/v1/api/candidats/dashboard`   | KPIs candidat  |
| `GET`   | `/v1/api/admin/candidates/{id}` | Fiche admin    |

## Complétude du profil

```mermaid theme={null}
flowchart LR
    BASE[Nom + email] --> P1[+20%]
    PHO[Photo] --> P2[+10%]
    BIO[Biographie] --> P3[+10%]
    COMP[Compétences] --> P4[+20%]
    CV[CV uploadé] --> P5[+30%]
    VIL[Ville renseignée] --> P6[+10%]
    P1 --> TOT[Score %]
    P2 --> TOT
    P3 --> TOT
    P4 --> TOT
    P5 --> TOT
    P6 --> TOT
```

Le score apparaît dans `dashboard.profileCompletion`. Un profil \< 60% est pénalisé dans le ranking de la recherche recruteur.
