> ## 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 AlerteEmploi

> Alertes candidats : critères, fréquences, matching, cron

# AlerteEmploi

Une **alerte emploi** est un filtre sauvegardé par un candidat pour recevoir par email les nouvelles offres matchantes.

## Schéma

```mermaid theme={null}
classDiagram
    class AlerteEmploi {
        +Long id
        +Long candidatId
        +String nom "ex: Java senior Douala"
        +Object criteres
        +String frequence "DAILY|WEEKLY"
        +Boolean active
        +Instant lastRunAt
        +Integer totalMatchs
        +Instant createdAt
    }

    class Match {
        +Long id
        +Long alerteId
        +Long offreId
        +Instant matchedAt
        +Boolean notifie
    }

    AlerteEmploi "1" --> "0..*" Match
```

## Structure des critères

```json theme={null}
{
  "query": "développeur java",
  "secteur": ["SOFTWARE", "FINANCE"],
  "typeContrat": ["CDI", "CDD"],
  "niveauExperience": ["INTERMEDIAIRE", "SENIOR"],
  "villeIds": [101, 102],
  "salaireMin": 500000,
  "teletravail": true
}
```

## Flow de matching

```mermaid theme={null}
flowchart TD
    CRON[Cron daily 07:00 / weekly lundi 07:00] --> SEL[SELECT alertes active=true\n frequence=? AND lastRunAt < seuil]
    SEL --> ITER{Pour chaque alerte}
    ITER --> Q[Construire requête tsvector + filtres]
    Q --> MATCH[SELECT offres PUBLISHED\n publishedAt > lastRunAt\n matchantes]
    MATCH --> ST{Matchs trouvés?}
    ST -->|non| SKIP[Pas d'email]
    ST -->|oui| MAIL[Email FR: Top 10 offres]
    MAIL --> INS[INSERT matches + notifie=true]
    INS --> UPD[UPDATE alerte.lastRunAt=NOW]
    SKIP --> UPD
```

## Exemple JSON de réponse

```json theme={null}
{
  "id": 77,
  "nom": "Java senior Douala",
  "criteres": {
    "query": "java spring",
    "typeContrat": ["CDI"],
    "niveauExperience": ["SENIOR"],
    "villeIds": [101]
  },
  "frequence": "DAILY",
  "active": true,
  "lastRunAt": "2026-04-18T07:00:12Z",
  "totalMatchs": 47,
  "prochaineExecution": "2026-04-19T07:00:00Z"
}
```

## Email d'alerte

```mermaid theme={null}
sequenceDiagram
    participant CR as Cron
    participant API as Backend
    participant TPL as Template FR
    participant M as Mailer
    participant C as Candidat

    CR->>API: Exécuter alerte 77
    API->>API: Chercher offres matchantes
    API->>TPL: Render "alerte-quotidienne"\n avec top 10
    TPL-->>API: HTML email
    API->>M: Envoi
    M->>C: Email "10 nouvelles offres pour 'Java senior Douala'"
```

## Désabonnement

Chaque email contient un **lien one-click** avec un token signé qui désactive l'alerte sans login :

```
GET /v1/api/alertes/unsubscribe?token=eyJ...
```

```mermaid theme={null}
flowchart LR
    C[Candidat clique lien email] --> API[GET /alertes/unsubscribe]
    API --> V{Token valide?}
    V -->|non| R400[400]
    V -->|oui| UPD[UPDATE active=false]
    UPD --> PAGE[Confirmation: Alerte désactivée]
```

## Limites

| Plan candidat   | Alertes max |   Fréquences   |
| --------------- | :---------: | :------------: |
| Inscrit gratuit |      5      | DAILY + WEEKLY |
| Anonyme         |      0      |        —       |

## Endpoints principaux

| Méthode  | Path                                       | Description        |
| -------- | ------------------------------------------ | ------------------ |
| `GET`    | `/v1/api/candidats/me/alertes`             | Liste alertes      |
| `POST`   | `/v1/api/candidats/me/alertes`             | Créer              |
| `PATCH`  | `/v1/api/candidats/me/alertes/{id}`        | Modifier critères  |
| `DELETE` | `/v1/api/candidats/me/alertes/{id}`        | Supprimer          |
| `POST`   | `/v1/api/candidats/me/alertes/{id}/toggle` | Activer/désactiver |
| `GET`    | `/v1/api/alertes/unsubscribe`              | Lien email         |

## Déduplication

Une offre déjà notifiée pour une alerte ne sera pas renvoyée (table `alerte_matches` avec index unique `(alerteId, offreId)`).

```sql theme={null}
CREATE UNIQUE INDEX uq_alerte_match ON alerte_matches(alerte_id, offre_id);
```
