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

# Rechercher des offres

> Autocomplete, recherche plein-texte, filtres combinables

# Rechercher des offres

L'API expose une recherche PostgreSQL `tsvector` + trigram pour l'autocomplete.

## Vue d'ensemble

```mermaid theme={null}
flowchart LR
    U[Utilisateur saisit] --> AC[Autocomplete\n /offres/autocomplete]
    AC --> SUG[Suggestions pg_trgm]
    U --> SR[Search\n /offres/search?q=...]
    SR --> FTS[tsvector + filtres]
    FTS --> RES[Résultats triés rank + date]
```

## Autocomplete (suggestions)

Utilise **pg\_trgm** (trigram similarity) — tolère les fautes.

### Requête

```http theme={null}
GET /v1/api/offres/autocomplete?q=dev HTTP/1.1
```

### Réponse

```json theme={null}
{
  "suggestions": [
    "Développeur Backend Java (H/F)",
    "Développeur Frontend React (H/F)",
    "Développeur Fullstack",
    "DevOps Engineer"
  ]
}
```

Cache Redis 60 secondes.

## Recherche plein-texte

### Syntaxe utilisateur

```mermaid theme={null}
flowchart TD
    Q1["java spring"] --> R1[java ET spring]
    Q2["java OR python"] --> R2[java OU python]
    Q3["\"lead developer\""] --> R3[Phrase exacte]
    Q4["java -senior"] --> R4[java SANS senior]
```

| Entrée             | Comportement                       |
| ------------------ | ---------------------------------- |
| `java spring`      | Les deux termes doivent apparaître |
| `java OR python`   | L'un ou l'autre                    |
| `"lead developer"` | Phrase exacte                      |
| `java -junior`     | Contient java, exclut junior       |

### Filtres combinables

```http theme={null}
GET /v1/api/offres/search?q=java
  &secteur=SOFTWARE
  &typeContrat=CDI,CDD
  &niveauExperience=SENIOR
  &villeId=101
  &salaireMin=600000
  &teletravail=true
  &page=0&size=20
  &sort=relevance,desc
```

### Réponse

```json theme={null}
{
  "content": [
    {
      "id": 123,
      "slug": "dev-backend-java-douala-123",
      "titre": "Développeur Backend Java (H/F)",
      "entreprise": { "nom": "Tech Corp", "logoUrl": "..." },
      "ville": { "nom": "Douala" },
      "typeContrat": "CDI",
      "salaire": { "min": 600000, "max": 900000, "devise": "XAF" },
      "publishedAt": "2026-04-15T09:30:00Z",
      "rank": 0.85
    }
  ],
  "page": 0,
  "size": 20,
  "totalElements": 47,
  "totalPages": 3
}
```

## Diagramme de requête

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant C as Client
    participant API as Backend
    participant DB as PostgreSQL
    participant R as Redis cache

    C->>API: GET /offres/search?q=java&ville=Douala
    API->>R: GET cache key
    alt cache hit
        R-->>API: résultats
    else cache miss
        API->>DB: websearch_to_tsquery + filtres
        DB-->>API: offres triées
        API->>R: SET cache 30s
    end
    API-->>C: 200 JSON
```

## Tri

| Valeur `sort`         | Comportement                             |
| --------------------- | ---------------------------------------- |
| `relevance,desc`      | Rank tsvector (défaut quand `q` présent) |
| `published_at,desc`   | Date (défaut si pas de `q`)              |
| `salaire_max,desc`    | Salaire maximum                          |
| `date_expiration,asc` | Expirant bientôt                         |

## Compter sans charger

```http theme={null}
GET /v1/api/offres/count?secteur=SOFTWARE HTTP/1.1
```

```json theme={null}
{ "count": 128 }
```

## Pagination

Voir [Pagination](/pagination). Cap : `size ≤ 100`, `page ≤ 500`.

## Cas pratiques

### Offres récentes Douala

```http theme={null}
GET /v1/api/offres/search?villeId=101&size=10&sort=published_at,desc
```

### Candidatures ouvertes pour dev senior

```http theme={null}
GET /v1/api/offres/search?q=developpeur&niveauExperience=SENIOR&size=50
```

### Télétravail partout

```http theme={null}
GET /v1/api/offres/search?teletravail=true
```

## Snippet JS

```javascript theme={null}
async function searchOffres(q, filters = {}) {
  const params = new URLSearchParams({ q, ...filters, page: 0, size: 20 });
  const r = await fetch(`/v1/api/offres/search?${params}`);
  return r.json();
}

const data = await searchOffres('java spring', {
  typeContrat: 'CDI',
  niveauExperience: 'SENIOR',
  villeId: 101,
});
console.log(`${data.totalElements} offres`);
```

## Limitations

```mermaid theme={null}
flowchart TD
    L1[q longueur max 200] --> LIM
    L2[size max 100] --> LIM
    L3[page max 500] --> LIM
    L4[stopwords FR ignorés: le, de, un, ...] --> LIM
    LIM[Contraintes]
```

Voir [Recherche plein-texte](/concepts/recherche-plein-texte) pour les détails techniques.
