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

> Schéma de l'offre d'emploi, indexation et contraintes

# Offre

Une **offre** est une annonce d'emploi publiée par un recruteur pour le compte de son entreprise.

## Schéma

```mermaid theme={null}
classDiagram
    class Offre {
        +Long id
        +Long recruteurId
        +Long entrepriseId
        +String titre
        +String slug
        +Text description
        +String typeContrat
        +String niveauExperience
        +Long villeId
        +Boolean teletravail
        +Integer salaireMin
        +Integer salaireMax
        +String devise "XAF|EUR|USD"
        +String[] competencesRequises
        +String[] competencesSouhaitees
        +String[] avantages
        +LocalDate dateExpiration
        +String status "DRAFT|PUBLISHED|CLOSED|ARCHIVED"
        +Integer vuesCount
        +Integer candidaturesCount
        +TSVector searchVector
        +Instant publishedAt
        +Instant createdAt
    }

    class Entreprise {
        +Long id
        +String nom
    }

    class Candidature {
        +Long id
        +Long offreId
        +String status
    }

    Entreprise "1" --> "0..*" Offre
    Offre "1" --> "0..*" Candidature
```

## Exemple JSON (détail)

```json theme={null}
{
  "id": 123,
  "slug": "developpeur-backend-java-h-f-douala-123",
  "titre": "Développeur Backend Java (H/F)",
  "description": "Nous cherchons un développeur Java expérimenté...",
  "typeContrat": "CDI",
  "niveauExperience": "INTERMEDIAIRE",
  "ville": { "id": 101, "nom": "Douala", "region": "Littoral" },
  "teletravail": false,
  "salaire": { "min": 600000, "max": 900000, "devise": "XAF" },
  "competencesRequises": ["Java 17+", "Spring Boot", "PostgreSQL"],
  "competencesSouhaitees": ["Docker", "Kubernetes", "Kafka"],
  "avantages": ["Santé", "Transport", "Formation continue"],
  "dateExpiration": "2026-05-18",
  "status": "PUBLISHED",
  "publishedAt": "2026-04-15T09:30:00Z",
  "entreprise": {
    "id": 18,
    "nom": "Tech Corp SARL",
    "logoUrl": "https://cdn.wethehivers.com/public/entreprises/18/logo.png"
  },
  "recruteur": { "id": 42, "firstName": "Marie" },
  "metrics": { "vues": 312, "candidatures": 27 }
}
```

## Cycle de vie

Voir [Cycle de vie d'une offre](/concepts/cycle-de-vie-offre).

```mermaid theme={null}
stateDiagram-v2
    [*] --> DRAFT
    DRAFT --> PUBLISHED: publish
    PUBLISHED --> CLOSED: expiration / close manuel
    PUBLISHED --> DRAFT: unpublish
    CLOSED --> PUBLISHED: republish
    * --> ARCHIVED
    ARCHIVED --> [*]
```

## Indexation full-text

```mermaid theme={null}
flowchart LR
    T[titre] -->|weight A| V[searchVector]
    C[competencesRequises] -->|weight B| V
    S[secteur, typeContrat, ville] -->|weight C| V
    D[description] -->|weight D| V
    V --> GIN[Index GIN]
```

## Contraintes métier

```mermaid theme={null}
flowchart TD
    N[Nouvelle offre] --> C1{recruteur.status = ACTIVE?}
    C1 -->|non| E1[403]
    C1 -->|oui| C2{quota entreprise ok?}
    C2 -->|non| E2[402]
    C2 -->|oui| C3{titre + description + typeContrat?}
    C3 -->|non| E3[422]
    C3 -->|oui| C4{dateExpiration > aujourd'hui?}
    C4 -->|non| E4[422]
    C4 -->|oui| OK[DRAFT créé]
```

## Publication

```mermaid theme={null}
sequenceDiagram
    participant R as Recruteur
    participant API as Backend
    participant DB as DB
    participant IDX as Index FTS
    participant N as Notifications

    R->>API: POST /offres/123/publish
    API->>DB: Validations métier
    API->>DB: UPDATE status=PUBLISHED, publishedAt=NOW
    API->>IDX: Trigger tsvector update
    API->>N: offre.published → alertes matchantes
    API-->>R: 200
```

## Endpoints principaux

| Méthode | Path                                 | Description        |
| ------- | ------------------------------------ | ------------------ |
| `GET`   | `/v1/api/offres/search`              | Recherche publique |
| `GET`   | `/v1/api/offres/{id}`                | Détail public      |
| `POST`  | `/v1/api/offres`                     | Créer DRAFT        |
| `PUT`   | `/v1/api/offres/{id}`                | Modifier           |
| `POST`  | `/v1/api/offres/{id}/publish`        | Publier            |
| `POST`  | `/v1/api/offres/{id}/close`          | Fermer             |
| `POST`  | `/v1/api/offres/{id}/archive`        | Archiver           |
| `GET`   | `/v1/api/recruteur/dashboard/offres` | Mes offres         |

## Tracking

Chaque vue est comptabilisée côté backend (dédupliquée par IP + user sur 24h). Chaque candidature incrémente `candidaturesCount`. Affiché en temps réel sur le dashboard recruteur.
